All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] Use common Linux tools to control DPDK ports
@ 2016-01-27 16:24 Ferruh Yigit
  2016-01-27 16:24 ` [PATCH 1/3] kcp: add kernel control path kernel module Ferruh Yigit
                   ` (3 more replies)
  0 siblings, 4 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-01-27 16:24 UTC (permalink / raw)
  To: dev

This work is to make DPDK ports more visible and to enable using common
Linux tools to configure DPDK ports.

Patch is based on KNI but contains only control functionality of it,
also this patch does not include any Linux kernel network driver as
part of it.

Basically with the help of a kernel module (KCP), virtual Linux network
interfaces named as "dpdk$" are created per DPDK port, control messages
sent to these virtual interfaces are forwarded to DPDK, and response
sent back to Linux application.

Virtual interfaces created when DPDK application started and destroyed
automatically when DPDK application terminated.

Communication between kernel-space and DPDK done using netlink socket.

Currently implementation is not complete, sample support added for the
RFC, more functionality can be added based on community response.

With this RFC Patch, supported: get/set mac address/mtu of DPDK devices,
getting stats from DPDK devices and some set of ethtool commands.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

Samples:

$ ifconfig
dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 90:e2:ba:0e:49:b8  txqueuelen 1000  (Ethernet)
        RX packets 33  bytes 2058 (2.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 33  bytes 2058 (2.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

After some traffic on port 0:

$ ifconfig
dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 90:e2:ba:0e:49:77  txqueuelen 1000  (Ethernet)
        RX packets 962  bytes 57798 (56.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 962  bytes 57798 (56.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


$ ethtool -i dpdk0
driver: rte_ixgbe_pmd
version: RTE 2.3.0-rc0
firmware-version: 
expansion-rom-version: 
bus-info: 0000:08:00.0
supports-statistics: yes
supports-test: no
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no


$ ip l show dpdk0
25: dpdk0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:b8 brd ff:ff:ff:ff:ff:ff

$ ip l set dpdk0 addr 90:e2:ba:0e:49:77

$ ip l show dpdk0
25: dpdk0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:77 brd ff:ff:ff:ff:ff:ff

Ferruh Yigit (3):
  kcp: add kernel control path kernel module
  rte_ctrl_if: add control interface library
  examples/ethtool: add control interface support to the application

 config/common_linuxapp                             |   9 +-
 doc/api/doxy-api-index.md                          |   3 +-
 doc/api/doxy-api.conf                              |   1 +
 doc/guides/rel_notes/release_2_3.rst               |   9 +
 doc/guides/sample_app_ug/ethtool.rst               |  41 +++
 examples/ethtool/ethtool-app/main.c                |  10 +-
 lib/Makefile                                       |   3 +-
 lib/librte_ctrl_if/Makefile                        |  58 ++++
 lib/librte_ctrl_if/rte_ctrl_if.c                   | 162 ++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h                   | 115 +++++++
 lib/librte_ctrl_if/rte_ctrl_if_version.map         |   9 +
 lib/librte_ctrl_if/rte_ethtool.c                   | 354 +++++++++++++++++++++
 lib/librte_ctrl_if/rte_ethtool.h                   |  54 ++++
 lib/librte_ctrl_if/rte_nl.c                        | 259 +++++++++++++++
 lib/librte_ctrl_if/rte_nl.h                        |  60 ++++
 lib/librte_eal/common/include/rte_log.h            |   3 +-
 lib/librte_eal/linuxapp/Makefile                   |   5 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h |  86 +++++
 lib/librte_eal/linuxapp/kcp/Makefile               |  58 ++++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  65 ++++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 261 +++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_misc.c             | 282 ++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 209 ++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 194 +++++++++++
 mk/rte.app.mk                                      |   3 +-
 26 files changed, 2307 insertions(+), 9 deletions(-)
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_misc.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c

-- 
2.5.0

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

* [PATCH 1/3] kcp: add kernel control path kernel module
  2016-01-27 16:24 [PATCH 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
@ 2016-01-27 16:24 ` Ferruh Yigit
  2016-01-28  9:49   ` Remy Horton
                     ` (2 more replies)
  2016-01-27 16:24 ` [PATCH 2/3] rte_ctrl_if: add control interface library Ferruh Yigit
                   ` (2 subsequent siblings)
  3 siblings, 3 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-01-27 16:24 UTC (permalink / raw)
  To: dev

This kernel module is based on KNI module, but this one is stripped
version of it and only for control messages, no data transfer
functionality provided.

This Linux kernel module helps userspace application create virtual
interfaces and when a control command issued into that virtual
interface, module pushes the command to the userspace and gets the
response back for the caller application.

The Linux tools like ethtool/ifconfig/ip can be used on virtual
interfaces but not ones for related data, like tcpdump.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 config/common_linuxapp                             |   6 +
 lib/librte_eal/linuxapp/Makefile                   |   5 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h |  86 +++++++
 lib/librte_eal/linuxapp/kcp/Makefile               |  58 +++++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  65 +++++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 261 +++++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_misc.c             | 282 +++++++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 209 +++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 194 ++++++++++++++
 10 files changed, 1167 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_misc.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c

diff --git a/config/common_linuxapp b/config/common_linuxapp
index 74bc515..5d5e3e4 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -503,6 +503,12 @@ CONFIG_RTE_KNI_VHOST_DEBUG_RX=n
 CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 
 #
+# Compile librte_ctrl_if
+#
+CONFIG_RTE_KCP_KMOD=y
+CONFIG_RTE_KCP_KO_DEBUG=n
+
+#
 # Compile vhost library
 # fuse-devel is needed to run vhost-cuse.
 # fuse-devel enables user space char driver development
diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile
index d9c5233..d1fa3a3 100644
--- a/lib/librte_eal/linuxapp/Makefile
+++ b/lib/librte_eal/linuxapp/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal
 ifeq ($(CONFIG_RTE_KNI_KMOD),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kni
 endif
+ifeq ($(CONFIG_RTE_KCP_KMOD),y)
+DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kcp
+endif
 ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += xen_dom0
 endif
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 26eced5..dded8cb 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -116,6 +116,7 @@ CFLAGS_eal_thread.o += -Wno-return-type
 endif
 
 INC := rte_interrupts.h rte_kni_common.h rte_dom0_common.h
+INC += rte_kcp_common.h
 
 SYMLINK-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP)-include/exec-env := \
 	$(addprefix include/exec-env/,$(INC))
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
new file mode 100644
index 0000000..b3a6ee3
--- /dev/null
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
@@ -0,0 +1,86 @@
+/*-
+ *   This file is provided under a dual BSD/LGPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GNU LESSER GENERAL PUBLIC LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2.1 of the GNU Lesser General Public License
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this program;
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ *
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_KCP_COMMON_H_
+#define _RTE_KCP_COMMON_H_
+
+#ifdef __KERNEL__
+#include <linux/if.h>
+#endif
+
+/*
+ * Request id.
+ */
+enum rte_kcp_req_id {
+	RTE_KCP_REQ_UNKNOWN = (1 << 16),
+	RTE_KCP_REQ_CHANGE_MTU,
+	RTE_KCP_REQ_CFG_NETWORK_IF,
+	RTE_KCP_REQ_GET_STATS,
+	RTE_KCP_REQ_GET_MAC,
+	RTE_KCP_REQ_SET_MAC,
+	RTE_KCP_REQ_START_PORT,
+	RTE_KCP_REQ_STOP_PORT,
+	RTE_KCP_REQ_MAX,
+};
+
+#define KCP_DEVICE "kcp"
+
+#define RTE_KCP_IOCTL_TEST    _IOWR(0, 1, int)
+#define RTE_KCP_IOCTL_CREATE  _IOWR(0, 2, int)
+#define RTE_KCP_IOCTL_RELEASE _IOWR(0, 3, int)
+
+#endif /* _RTE_KCP_COMMON_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/Makefile b/lib/librte_eal/linuxapp/kcp/Makefile
new file mode 100644
index 0000000..b2c44bd
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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
+
+#
+# module name and path
+#
+MODULE = rte_kcp
+
+#
+# CFLAGS
+#
+MODULE_CFLAGS += -I$(SRCDIR)
+MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
+MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
+MODULE_CFLAGS += -Wall -Werror
+
+# this lib needs main eal
+DEPDIRS-y += lib/librte_eal/linuxapp/eal
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y += kcp_misc.c
+SRCS-y += kcp_net.c
+SRCS-y += kcp_ethtool.c
+SRCS-y += kcp_nl.c
+
+include $(RTE_SDK)/mk/rte.module.mk
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_dev.h b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
new file mode 100644
index 0000000..e537821
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
@@ -0,0 +1,65 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#ifndef _KCP_DEV_H_
+#define _KCP_DEV_H_
+
+#include <linux/netdevice.h>
+#include <exec-env/rte_kcp_common.h>
+
+#define RTE_KCP_NAMESIZE 32
+
+struct kcp_dev {
+	/* kcp list */
+	struct list_head list;
+
+	char name[RTE_KCP_NAMESIZE]; /* Network device name */
+
+	/* kcp device */
+	struct net_device *net_dev;
+
+	int port_id;
+	struct completion msg_received;
+};
+
+void kcp_net_init(struct net_device *dev);
+
+void kcp_nl_init(void);
+void kcp_nl_release(void);
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data, int in_len,
+		void *out_data, int out_len);
+
+void kcp_set_ethtool_ops(struct net_device *netdev);
+
+#define KCP_ERR(args...) printk(KERN_ERR "KCP: " args)
+#define KCP_INFO(args...) printk(KERN_INFO "KCP: " args)
+#define KCP_PRINT(args...) printk(KERN_DEBUG "KCP: " args)
+
+#ifdef RTE_KCP_KO_DEBUG
+#define KCP_DBG(args...) printk(KERN_DEBUG "KCP: " args)
+#else
+#define KCP_DBG(args...)
+#endif
+
+#endif /* _KCP_DEV_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
new file mode 100644
index 0000000..3a22dba
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
@@ -0,0 +1,261 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include "kcp_dev.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int
+kcp_check_if_running(struct net_device *dev)
+{
+	return 0;
+}
+
+static void
+kcp_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	int ret;
+
+	ret = kcp_nl_exec(info->cmd, dev, NULL, 0,
+			info, sizeof(struct ethtool_drvinfo));
+	if (ret < 0)
+		memset(info, 0, sizeof(struct ethtool_drvinfo));
+}
+
+static int
+kcp_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, NULL, 0,
+			ecmd, sizeof(struct ethtool_cmd));
+}
+
+static int
+kcp_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, ecmd, sizeof(struct ethtool_cmd),
+			NULL, 0);
+}
+
+static void
+kcp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	int ret;
+
+	ret = kcp_nl_exec(wol->cmd, dev, NULL, 0,
+			wol, sizeof(struct ethtool_wolinfo));
+	if (ret < 0)
+		memset(wol, 0, sizeof(struct ethtool_wolinfo));
+}
+
+static int
+kcp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	return kcp_nl_exec(wol->cmd, dev, wol, sizeof(struct ethtool_wolinfo),
+			NULL, 0);
+}
+
+static int
+kcp_nway_reset(struct net_device *dev)
+{
+	return kcp_nl_exec(ETHTOOL_NWAY_RST, dev, NULL, 0, NULL, 0);
+}
+
+static int
+kcp_get_eeprom_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GEEPROM_LEN, dev, NULL, 0,
+			&data, sizeof(int));
+	if (ret < 0)
+		return ret;
+
+	return data;
+}
+
+static int
+kcp_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+		u8 *bytes)
+{
+	int ret;
+
+	ret = kcp_nl_exec(eeprom->cmd, dev,
+			eeprom, sizeof(struct ethtool_eeprom),
+			bytes, eeprom->len);
+	*bytes = 0;
+	return ret;
+}
+
+static int
+kcp_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+		u8 *bytes)
+{
+	int ret;
+
+	ret = kcp_nl_exec(eeprom->cmd, dev,
+			eeprom, sizeof(struct ethtool_eeprom),
+			bytes, eeprom->len);
+	*bytes = 0;
+	return ret;
+}
+
+static void
+kcp_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
+{
+
+	kcp_nl_exec(ring->cmd, dev, NULL, 0,
+			ring, sizeof(struct ethtool_ringparam));
+}
+
+static int
+kcp_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
+{
+	int ret;
+
+	ret = kcp_nl_exec(ring->cmd, dev,
+			ring, sizeof(struct ethtool_ringparam),
+			NULL, 0);
+	return ret;
+}
+
+static void
+kcp_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
+{
+
+	kcp_nl_exec(pause->cmd, dev, NULL, 0,
+			pause, sizeof(struct ethtool_pauseparam));
+}
+
+static int
+kcp_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
+{
+	return kcp_nl_exec(pause->cmd, dev,
+			pause, sizeof(struct ethtool_pauseparam),
+			NULL, 0);
+}
+
+static u32
+kcp_get_msglevel(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GMSGLVL, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return ret;
+
+	return data;
+}
+
+static void
+kcp_set_msglevel(struct net_device *dev, u32 data)
+{
+
+	kcp_nl_exec(ETHTOOL_SMSGLVL, dev, &data, sizeof(int), NULL, 0);
+}
+
+static int
+kcp_get_regs_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GREGS_LEN, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return ret;
+
+	return data;
+}
+
+static void
+kcp_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
+{
+
+	kcp_nl_exec(regs->cmd, dev, regs, sizeof(struct ethtool_regs),
+			p, regs->len);
+}
+
+static void
+kcp_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+
+	kcp_nl_exec(ETHTOOL_GSTRINGS, dev, &stringset, sizeof(u32), data, 0);
+}
+
+static int
+kcp_get_sset_count(struct net_device *dev, int sset)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GSSET_COUNT, dev, &sset, sizeof(int),
+			&data, sizeof(int));
+	if (ret < 0)
+		return ret;
+
+	return data;
+}
+
+static void
+kcp_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats,
+		u64 *data)
+{
+
+	kcp_nl_exec(stats->cmd, dev, stats, sizeof(struct ethtool_stats),
+			data, stats->n_stats);
+}
+
+static const struct ethtool_ops kcp_ethtool_ops = {
+	.begin			= kcp_check_if_running,
+	.get_drvinfo		= kcp_get_drvinfo,
+	.get_settings		= kcp_get_settings,
+	.set_settings		= kcp_set_settings,
+	.get_regs_len		= kcp_get_regs_len,
+	.get_regs		= kcp_get_regs,
+	.get_wol		= kcp_get_wol,
+	.set_wol		= kcp_set_wol,
+	.nway_reset		= kcp_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_eeprom_len		= kcp_get_eeprom_len,
+	.get_eeprom		= kcp_get_eeprom,
+	.set_eeprom		= kcp_set_eeprom,
+	.get_ringparam		= kcp_get_ringparam,
+	.set_ringparam		= kcp_set_ringparam,
+	.get_pauseparam		= kcp_get_pauseparam,
+	.set_pauseparam		= kcp_set_pauseparam,
+	.get_msglevel		= kcp_get_msglevel,
+	.set_msglevel		= kcp_set_msglevel,
+	.get_strings		= kcp_get_strings,
+	.get_sset_count		= kcp_get_sset_count,
+	.get_ethtool_stats	= kcp_get_ethtool_stats,
+};
+
+void
+kcp_set_ethtool_ops(struct net_device *netdev)
+{
+	netdev->ethtool_ops = &kcp_ethtool_ops;
+}
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_misc.c b/lib/librte_eal/linuxapp/kcp/kcp_misc.c
new file mode 100644
index 0000000..6df0d1b
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_misc.c
@@ -0,0 +1,282 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+
+#include "kcp_dev.h"
+
+#define KCP_DEV_IN_USE_BIT_NUM 0 /* Bit number for device in use */
+
+static volatile unsigned long device_in_use; /* device in use flag */
+
+/* kcp list lock */
+static DECLARE_RWSEM(kcp_list_lock);
+
+/* kcp list */
+static struct list_head kcp_list_head = LIST_HEAD_INIT(kcp_list_head);
+
+static int
+kcp_open(struct inode *inode, struct file *file)
+{
+	/* kcp device can be opened by one user only, test and set bit */
+	if (test_and_set_bit(KCP_DEV_IN_USE_BIT_NUM, &device_in_use))
+		return -EBUSY;
+
+	KCP_PRINT("/dev/kcp opened\n");
+
+	kcp_nl_init();
+
+	return 0;
+}
+
+static int
+kcp_dev_remove(struct kcp_dev *dev)
+{
+	if (!dev)
+		return -ENODEV;
+
+	if (dev->net_dev) {
+		unregister_netdev(dev->net_dev);
+		free_netdev(dev->net_dev);
+	}
+
+	return 0;
+}
+
+static int
+kcp_release(struct inode *inode, struct file *file)
+{
+	struct kcp_dev *dev, *n;
+
+	down_write(&kcp_list_lock);
+	list_for_each_entry_safe(dev, n, &kcp_list_head, list) {
+		kcp_dev_remove(dev);
+		list_del(&dev->list);
+	}
+	up_write(&kcp_list_lock);
+
+	kcp_nl_release();
+
+	/* Clear the bit of device in use */
+	clear_bit(KCP_DEV_IN_USE_BIT_NUM, &device_in_use);
+
+	KCP_PRINT("/dev/kcp closed\n");
+
+	return 0;
+}
+
+static int
+kcp_check_param(struct kcp_dev *kcp, char *name)
+{
+	if (!kcp)
+		return -1;
+
+	/* Check if network name has been used */
+	if (!strncmp(kcp->name, name, RTE_KCP_NAMESIZE)) {
+		KCP_ERR("KCP interface name %s duplicated\n", name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+kcp_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param)
+{
+	int ret;
+	struct net_device *net_dev = NULL;
+	struct kcp_dev *kcp, *dev, *n;
+	struct net *net;
+	char name[RTE_KCP_NAMESIZE];
+	unsigned int instance = ioctl_param;
+	char mac[ETH_ALEN];
+
+	KCP_PRINT("Creating kcp...\n");
+
+	snprintf(name, RTE_KCP_NAMESIZE, "dpdk%u", instance);
+
+	/* Check if it has been created */
+	down_read(&kcp_list_lock);
+	list_for_each_entry_safe(dev, n, &kcp_list_head, list) {
+		if (kcp_check_param(dev, name) < 0) {
+			up_read(&kcp_list_lock);
+			return -EINVAL;
+		}
+	}
+	up_read(&kcp_list_lock);
+
+	net_dev = alloc_netdev(sizeof(struct kcp_dev), name,
+#ifdef NET_NAME_UNKNOWN
+							NET_NAME_UNKNOWN,
+#endif
+							kcp_net_init);
+	if (net_dev == NULL) {
+		KCP_ERR("error allocating device \"%s\"\n", name);
+		return -EBUSY;
+	}
+
+	net = get_net_ns_by_pid(task_pid_vnr(current));
+	if (IS_ERR(net)) {
+		free_netdev(net_dev);
+		return PTR_ERR(net);
+	}
+	dev_net_set(net_dev, net);
+	put_net(net);
+
+	kcp = netdev_priv(net_dev);
+
+	kcp->net_dev = net_dev;
+	kcp->port_id = instance;
+	init_completion(&kcp->msg_received);
+	strncpy(kcp->name, name, RTE_KCP_NAMESIZE);
+
+	kcp_nl_exec(RTE_KCP_REQ_GET_MAC, net_dev, NULL, 0, mac, ETH_ALEN);
+	memcpy(net_dev->dev_addr, mac, net_dev->addr_len);
+
+	kcp_set_ethtool_ops(net_dev);
+	ret = register_netdev(net_dev);
+	if (ret) {
+		KCP_ERR("error %i registering device \"%s\"\n", ret, name);
+		kcp_dev_remove(kcp);
+		return -ENODEV;
+	}
+
+	down_write(&kcp_list_lock);
+	list_add(&kcp->list, &kcp_list_head);
+	up_write(&kcp_list_lock);
+
+	return 0;
+}
+
+static int
+kcp_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param)
+{
+	int ret = -EINVAL;
+	struct kcp_dev *dev;
+	struct kcp_dev *n;
+	char name[RTE_KCP_NAMESIZE];
+	unsigned int instance = ioctl_param;
+
+	snprintf(name, RTE_KCP_NAMESIZE, "dpdk%u", instance);
+
+	down_write(&kcp_list_lock);
+	list_for_each_entry_safe(dev, n, &kcp_list_head, list) {
+		if (strncmp(dev->name, name, RTE_KCP_NAMESIZE) != 0)
+			continue;
+		kcp_dev_remove(dev);
+		list_del(&dev->list);
+		ret = 0;
+		break;
+	}
+	up_write(&kcp_list_lock);
+	KCP_INFO("%s release kcp named %s\n",
+		(ret == 0 ? "Successfully" : "Unsuccessfully"), name);
+
+	return ret;
+}
+
+static int
+kcp_ioctl(struct inode *inode, unsigned int ioctl_num,
+	unsigned long ioctl_param)
+{
+	int ret = -EINVAL;
+
+	KCP_DBG("IOCTL num=0x%0x param=0x%0lx\n", ioctl_num, ioctl_param);
+
+	/*
+	 * Switch according to the ioctl called
+	 */
+	switch (_IOC_NR(ioctl_num)) {
+	case _IOC_NR(RTE_KCP_IOCTL_TEST):
+		/* For test only, not used */
+		break;
+	case _IOC_NR(RTE_KCP_IOCTL_CREATE):
+		ret = kcp_ioctl_create(ioctl_num, ioctl_param);
+		break;
+	case _IOC_NR(RTE_KCP_IOCTL_RELEASE):
+		ret = kcp_ioctl_release(ioctl_num, ioctl_param);
+		break;
+	default:
+		KCP_DBG("IOCTL default\n");
+		break;
+	}
+
+	return ret;
+}
+
+static int
+kcp_compat_ioctl(struct inode *inode, unsigned int ioctl_num,
+		unsigned long ioctl_param)
+{
+	/* 32 bits app on 64 bits OS to be supported later */
+	KCP_PRINT("Not implemented.\n");
+
+	return -EINVAL;
+}
+
+static const struct file_operations kcp_fops = {
+	.owner = THIS_MODULE,
+	.open = kcp_open,
+	.release = kcp_release,
+	.unlocked_ioctl = (void *)kcp_ioctl,
+	.compat_ioctl = (void *)kcp_compat_ioctl,
+};
+
+static struct miscdevice kcp_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = KCP_DEVICE,
+	.fops = &kcp_fops,
+};
+
+static int __init
+kcp_init(void)
+{
+	KCP_PRINT("DPDK kcp module loading\n");
+
+	if (misc_register(&kcp_misc) != 0) {
+		KCP_ERR("Misc registration failed\n");
+		return -EPERM;
+	}
+
+	/* Clear the bit of device in use */
+	clear_bit(KCP_DEV_IN_USE_BIT_NUM, &device_in_use);
+
+	KCP_PRINT("DPDK kcp module loaded\n");
+
+	return 0;
+}
+module_init(kcp_init);
+
+static void __exit
+kcp_exit(void)
+{
+	misc_deregister(&kcp_misc);
+	KCP_PRINT("DPDK kcp module unloaded\n");
+}
+module_exit(kcp_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Kernel Module for managing kcp devices");
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_net.c b/lib/librte_eal/linuxapp/kcp/kcp_net.c
new file mode 100644
index 0000000..9dacaaa
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_net.c
@@ -0,0 +1,209 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+/*
+ * This code is inspired from the book "Linux Device Drivers" by
+ * Alessandro Rubini and Jonathan Corbet, published by O'Reilly & Associates
+ */
+
+#include <linux/version.h>
+#include <linux/etherdevice.h> /* eth_type_trans */
+
+#include "kcp_dev.h"
+
+/*
+ * Open and close
+ */
+static int
+kcp_net_open(struct net_device *dev)
+{
+	kcp_nl_exec(RTE_KCP_REQ_START_PORT, dev, NULL, 0, NULL, 0);
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int
+kcp_net_release(struct net_device *dev)
+{
+	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+	netif_stop_queue(dev); /* can't transmit any more */
+	return 0;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+static int
+kcp_net_config(struct net_device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP) /* can't act on a running interface */
+		return -EBUSY;
+
+	/* ignore other fields */
+	return 0;
+}
+
+static int
+kcp_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int err;
+
+	KCP_DBG("kcp_net_change_mtu new mtu %d to be set\n", new_mtu);
+	err = kcp_nl_exec(RTE_KCP_REQ_CHANGE_MTU, dev, &new_mtu, sizeof(int),
+			NULL, 0);
+
+	if (err == 0)
+		dev->mtu = new_mtu;
+
+	return err;
+}
+
+/*
+ * Ioctl commands
+ */
+static int
+kcp_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	KCP_DBG("kcp_net_ioctl\n");
+
+	return 0;
+}
+
+/*
+ * Return statistics to the caller
+ */
+static struct  rtnl_link_stats64 *
+kcp_net_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+	int err;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_GET_STATS, dev, NULL, 0,
+			stats, sizeof(struct rtnl_link_stats64));
+
+	return stats;
+}
+
+/**
+ * kcp_net_set_mac - Change the Ethernet Address of the KCP NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int
+kcp_net_set_mac(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	int err;
+
+	if (!is_valid_ether_addr((unsigned char *)(addr->sa_data)))
+		return -EADDRNOTAVAIL;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_SET_MAC, dev, addr->sa_data,
+			dev->addr_len, NULL, 0);
+	if (err < 0)
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	return 0;
+}
+
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+static int
+kcp_net_change_carrier(struct net_device *dev, bool new_carrier)
+{
+	if (new_carrier)
+		netif_carrier_on(dev);
+	else
+		netif_carrier_off(dev);
+	return 0;
+}
+#endif
+
+static const struct net_device_ops kcp_net_netdev_ops = {
+	.ndo_open = kcp_net_open,
+	.ndo_stop = kcp_net_release,
+	.ndo_set_config = kcp_net_config,
+	.ndo_change_mtu = kcp_net_change_mtu,
+	.ndo_do_ioctl = kcp_net_ioctl,
+	.ndo_get_stats64 = kcp_net_stats64,
+	.ndo_set_mac_address = kcp_net_set_mac,
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+	.ndo_change_carrier = kcp_net_change_carrier,
+#endif
+};
+
+/*
+ *  Fill the eth header
+ */
+static int
+kcp_net_header(struct sk_buff *skb, struct net_device *dev,
+		unsigned short type, const void *daddr,
+		const void *saddr, unsigned int len)
+{
+	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+
+	memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest,   daddr ? daddr : dev->dev_addr, dev->addr_len);
+	eth->h_proto = htons(type);
+
+	return dev->hard_header_len;
+}
+
+/*
+ * Re-fill the eth header
+ */
+#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
+static int
+kcp_net_rebuild_header(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	struct ethhdr *eth = (struct ethhdr *) skb->data;
+
+	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
+
+	return 0;
+}
+#endif
+
+static const struct header_ops kcp_net_header_ops = {
+	.create  = kcp_net_header,
+#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
+	.rebuild = kcp_net_rebuild_header,
+#endif
+	.cache   = NULL,  /* disable caching */
+};
+
+void
+kcp_net_init(struct net_device *dev)
+{
+	KCP_DBG("kcp_net_init\n");
+
+	ether_setup(dev); /* assign some of the fields */
+	dev->netdev_ops      = &kcp_net_netdev_ops;
+	dev->header_ops      = &kcp_net_header_ops;
+
+	dev->flags |= IFF_UP;
+}
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_nl.c b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
new file mode 100644
index 0000000..e989d2d
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
@@ -0,0 +1,194 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <net/sock.h>
+
+#include "kcp_dev.h"
+
+#define KCP_NL_GRP 31
+
+#define KCP_ETHTOOL_MSG_LEN 500
+struct kcp_ethtool_msg {
+	int cmd_id;
+	int port_id;
+	char input_buffer[KCP_ETHTOOL_MSG_LEN];
+	char output_buffer[KCP_ETHTOOL_MSG_LEN];
+	int input_buf_len;
+	int output_buf_len;
+	int err;
+};
+
+static struct ethtool_input_buffer {
+	int magic;
+	void *buffer;
+	int length;
+	struct completion *msg_received;
+	int *err;
+} ethtool_input_buffer;
+
+static struct sock *nl_sock;
+static int pid __read_mostly = -1;
+static struct mutex sync_lock;
+
+static int
+kcp_input_buffer_register(int magic, void *buffer, int length,
+		struct completion *msg_received, int *err)
+{
+	if (ethtool_input_buffer.buffer == NULL) {
+		ethtool_input_buffer.magic = magic;
+		ethtool_input_buffer.buffer = buffer;
+		ethtool_input_buffer.length = length;
+		ethtool_input_buffer.msg_received = msg_received;
+		ethtool_input_buffer.err = err;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+kcp_input_buffer_unregister(int magic)
+{
+	if (ethtool_input_buffer.buffer != NULL) {
+		if (magic == ethtool_input_buffer.magic) {
+			ethtool_input_buffer.magic = -1;
+			ethtool_input_buffer.buffer = NULL;
+			ethtool_input_buffer.length = 0;
+			ethtool_input_buffer.msg_received = NULL;
+			ethtool_input_buffer.err = NULL;
+		}
+	}
+}
+
+static void
+nl_recv(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	if (pid < 0) {
+		pid = nlh->nlmsg_pid;
+		KCP_INFO("PID: %d\n", pid);
+		return;
+	} else if (pid != nlh->nlmsg_pid) {
+		KCP_INFO("Message from unexpected peer: %d", nlh->nlmsg_pid);
+		return;
+	}
+
+	memcpy(&ethtool_msg, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
+	KCP_DBG("CMD: %d\n", ethtool_msg.cmd_id);
+
+	if (ethtool_input_buffer.magic > 0) {
+		if (ethtool_input_buffer.buffer != NULL) {
+			memcpy(ethtool_input_buffer.buffer,
+					&ethtool_msg.output_buffer,
+					ethtool_input_buffer.length);
+		}
+		*ethtool_input_buffer.err = ethtool_msg.err;
+		complete(ethtool_input_buffer.msg_received);
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+	}
+}
+
+static int
+kcp_nl_send(int cmd_id, int port_id, void *input_buffer, int input_buf_len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	memset(&ethtool_msg, 0, sizeof(struct kcp_ethtool_msg));
+	ethtool_msg.cmd_id = cmd_id;
+	ethtool_msg.port_id = port_id;
+
+	if (input_buffer) {
+		if (input_buf_len == 0 || input_buf_len > KCP_ETHTOOL_MSG_LEN)
+			return -EINVAL;
+		ethtool_msg.input_buf_len = input_buf_len;
+		memcpy(ethtool_msg.input_buffer, input_buffer, input_buf_len);
+	}
+
+	skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct kcp_ethtool_msg)),
+			GFP_ATOMIC);
+	nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, sizeof(struct kcp_ethtool_msg),
+			0);
+
+	NETLINK_CB(skb).dst_group = 0;
+
+	memcpy(nlmsg_data(nlh), &ethtool_msg, sizeof(struct kcp_ethtool_msg));
+
+	nlmsg_unicast(nl_sock, skb, pid);
+	KCP_DBG("Sent cmd:%d port:%d\n", cmd_id, port_id);
+
+	/*nlmsg_free(skb);*/
+
+	return 0;
+}
+
+int
+kcp_nl_exec(int cmd, struct net_device *dev, void *in_data, int in_len,
+		void *out_data, int out_len)
+{
+	struct kcp_dev *priv = netdev_priv(dev);
+	int err = -EINVAL;
+	int ret;
+
+	mutex_lock(&sync_lock);
+	ret = kcp_input_buffer_register(cmd, out_data, out_len,
+			&priv->msg_received, &err);
+	if (ret) {
+		mutex_unlock(&sync_lock);
+		return -EINVAL;
+	}
+
+	kcp_nl_send(cmd, priv->port_id, in_data, in_len);
+	ret = wait_for_completion_interruptible_timeout(&priv->msg_received,
+			 msecs_to_jiffies(10));
+	if (ret == 0 || err < 0) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		return ret == 0 ? -EINVAL : err;
+	}
+	mutex_unlock(&sync_lock);
+
+	return 0;
+}
+
+static struct netlink_kernel_cfg cfg = {
+	.input = nl_recv,
+};
+
+void
+kcp_nl_init(void)
+{
+	nl_sock = netlink_kernel_create(&init_net, KCP_NL_GRP, &cfg);
+	mutex_init(&sync_lock);
+}
+
+void
+kcp_nl_release(void)
+{
+	netlink_kernel_release(nl_sock);
+	pid = -1;
+}
-- 
2.5.0

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

* [PATCH 2/3] rte_ctrl_if: add control interface library
  2016-01-27 16:24 [PATCH 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
  2016-01-27 16:24 ` [PATCH 1/3] kcp: add kernel control path kernel module Ferruh Yigit
@ 2016-01-27 16:24 ` Ferruh Yigit
  2016-01-28 11:14   ` Remy Horton
  2016-01-27 16:24 ` [PATCH 3/3] examples/ethtool: add control interface support to the application Ferruh Yigit
  2016-02-12 13:45 ` [PATCH v2 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
  3 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-01-27 16:24 UTC (permalink / raw)
  To: dev

This library gets control messages form kernelspace and forwards them to
librte_ether and returns response back to the kernelspace.

Library does:
1) Trigger Linux virtual interface creation
2) Initialize the netlink socket communication
3) Provides process() API to the application that does processing the
received messages

This library requires corresponding kernel module to be inserted.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 config/common_linuxapp                     |   3 +-
 doc/api/doxy-api-index.md                  |   3 +-
 doc/api/doxy-api.conf                      |   1 +
 doc/guides/rel_notes/release_2_3.rst       |   9 +
 lib/Makefile                               |   3 +-
 lib/librte_ctrl_if/Makefile                |  58 +++++
 lib/librte_ctrl_if/rte_ctrl_if.c           | 162 +++++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h           | 115 ++++++++++
 lib/librte_ctrl_if/rte_ctrl_if_version.map |   9 +
 lib/librte_ctrl_if/rte_ethtool.c           | 354 +++++++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ethtool.h           |  54 +++++
 lib/librte_ctrl_if/rte_nl.c                | 259 +++++++++++++++++++++
 lib/librte_ctrl_if/rte_nl.h                |  60 +++++
 lib/librte_eal/common/include/rte_log.h    |   3 +-
 mk/rte.app.mk                              |   3 +-
 15 files changed, 1091 insertions(+), 5 deletions(-)
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h

diff --git a/config/common_linuxapp b/config/common_linuxapp
index 5d5e3e4..f72ba0e 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -507,6 +507,7 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 #
 CONFIG_RTE_KCP_KMOD=y
 CONFIG_RTE_KCP_KO_DEBUG=n
+CONFIG_RTE_LIBRTE_CTRL_IF=y
 
 #
 # Compile vhost library
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 7a91001..214d16e 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -149,4 +149,5 @@ There are many libraries, so their headers may be grouped by topics:
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
   [keepalive]          (@ref rte_keepalive.h),
-  [version]            (@ref rte_version.h)
+  [version]            (@ref rte_version.h),
+  [control interface]  (@ref rte_ctrl_if.h)
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index 57e8b5d..fd69bf1 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -39,6 +39,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_cmdline \
                           lib/librte_compat \
                           lib/librte_cryptodev \
+                          lib/librte_ctrl_if \
                           lib/librte_distributor \
                           lib/librte_ether \
                           lib/librte_hash \
diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst
index 99de186..39725e4 100644
--- a/doc/guides/rel_notes/release_2_3.rst
+++ b/doc/guides/rel_notes/release_2_3.rst
@@ -4,6 +4,14 @@ DPDK Release 2.3
 New Features
 ------------
 
+* **Control interface support added.**
+
+  To enable controlling DPDK ports by common Linux tools.
+  Following modules added to DPDK:
+
+  * librte_ctrl_if library
+  * librte_eal/linuxapp/kcp kernel module
+
 
 Resolved Issues
 ---------------
@@ -51,6 +59,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_acl.so.2
      librte_cfgfile.so.2
      librte_cmdline.so.1
+   + librte_ctrl_if.so.1
      librte_distributor.so.1
      librte_eal.so.2
      librte_hash.so.2
diff --git a/lib/Makefile b/lib/Makefile
index ef172ea..a50bc1e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
 DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_CTRL_IF) += librte_ctrl_if
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_ctrl_if/Makefile b/lib/librte_ctrl_if/Makefile
new file mode 100644
index 0000000..4e82966
--- /dev/null
+++ b/lib/librte_ctrl_if/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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_ctrl_if.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_ctrl_if_version.map
+
+LIBABIVER := 1
+
+SRCS-y += rte_ctrl_if.c
+SRCS-y += rte_nl.c
+SRCS-y += rte_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ctrl_if.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c
new file mode 100644
index 0000000..a84eea0
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.c
@@ -0,0 +1,162 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <fcntl.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+
+#include <rte_ethdev.h>
+#include "rte_ctrl_if.h"
+#include "rte_nl.h"
+
+static int kcp_fd = -1;
+static int kcp_fd_ref;
+
+static int
+control_interface_init(void)
+{
+	int ret;
+	kcp_fd = open("/dev/" KCP_DEVICE, O_RDWR);
+
+	if (kcp_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF,
+				"Failed to initialize control interface.\n");
+		return -1;
+	}
+
+	ret = control_interface_nl_init();
+	if (ret < 0)
+		close(kcp_fd);
+
+	return ret;
+}
+
+static int
+control_interface_ref_get(void)
+{
+	int ret = 0;
+
+	if (kcp_fd_ref == 0)
+		ret = control_interface_init();
+
+	if (ret == 0)
+		kcp_fd_ref++;
+
+	return kcp_fd_ref;
+}
+
+static void
+control_interface_release(void)
+{
+	close(kcp_fd);
+	control_interface_nl_release();
+}
+
+static int
+control_interface_ref_put(void)
+{
+	if (kcp_fd_ref == 0)
+		return 0;
+
+	kcp_fd_ref--;
+
+	if (kcp_fd_ref == 0)
+		control_interface_release();
+
+	return kcp_fd_ref;
+}
+
+static int
+rte_eth_control_interface_create_one(uint8_t port_id)
+{
+	if (control_interface_ref_get() != 0) {
+		ioctl(kcp_fd, RTE_KCP_IOCTL_CREATE, port_id);
+		RTE_LOG(DEBUG, CTRL_IF,
+				"Control interface created for port:%u\n",
+			port_id);
+	}
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_create(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			ret = rte_eth_control_interface_create_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int
+rte_eth_control_interface_destroy_one(uint8_t port_id)
+{
+	ioctl(kcp_fd, RTE_KCP_IOCTL_RELEASE, port_id);
+	control_interface_ref_put();
+	RTE_LOG(DEBUG, CTRL_IF, "Control interface destroyed for port:%u\n",
+			port_id);
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_destroy(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			ret = rte_eth_control_interface_destroy_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+int
+rte_eth_control_interface_process_msg(int flag, unsigned int timeout_sec)
+{
+	return control_interface_process_msg(flag, timeout_sec);
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.h b/lib/librte_ctrl_if/rte_ctrl_if.h
new file mode 100644
index 0000000..dcaf6dd
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.h
@@ -0,0 +1,115 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_CTRL_IF_H_
+#define _RTE_CTRL_IF_H_
+
+/**
+ * @file
+ *
+ * Control Interface Library for RTE
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <exec-env/rte_kcp_common.h>
+
+/**
+ * Flags values for rte_eth_control_interface_process_msg() API
+ */
+enum control_interface_process_flag {
+	/**< Process if msg available. */
+	RTE_ETHTOOL_CTRL_IF_PROCESS_MSG,
+
+	/**< Discard msg if available, respond with a error value. */
+	RTE_ETHTOOL_CTRL_IF_DISCARD_MSG,
+};
+
+/**
+ * Creates control interfaces (Linux virtual network interface)for
+ * each existing eal port.
+ *
+ * This API opens device created by supportive kernel module and initializes
+ * kernel communication interface.
+ *
+ * If supportive kernel module is not inserted this API will return
+ * an error.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_create(void);
+
+/**
+ * Destroys control interfaces.
+ *
+ * This API close device created by supportive kernel module and release
+ * underlying communication interface.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_destroy(void);
+
+/**
+ * Process if any received message is available.
+ *
+ * This function can be blocking or unblocking according timeout_sec
+ * parameter value. If function will be continuous loop, like can be
+ * called by any forwarding lcore, nonblocking mode should be preferred.
+ * If a separate thread created to handle control messages, blocking
+ * mode can be preferred to save CPU cycles.
+ *
+ * @param flag
+ *  Defines what to do with message, can be process or discard.
+ *
+ * @param timeout_sec
+ *  if 0, function is in nonblocking mode.
+ *  if > 0, blocks for given time, if there is no message available,
+ *  sleeps again same amount of time. Value is in seconds.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_process_msg(int flag, unsigned int timeout_sec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_IF_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if_version.map b/lib/librte_ctrl_if/rte_ctrl_if_version.map
new file mode 100644
index 0000000..8b27e26
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if_version.map
@@ -0,0 +1,9 @@
+DPDK_2.3 {
+	global:
+
+	rte_eth_control_interface_create;
+	rte_eth_control_interface_destroy;
+	rte_eth_control_interface_process_msg;
+
+	local: *;
+};
diff --git a/lib/librte_ctrl_if/rte_ethtool.c b/lib/librte_ctrl_if/rte_ethtool.c
new file mode 100644
index 0000000..1caeab4
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ethtool.c
@@ -0,0 +1,354 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <linux/if_link.h>
+
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int
+get_drvinfo(int port_id, void *data, int *data_len)
+{
+	struct ethtool_drvinfo *info = data;
+	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(info->driver, sizeof(info->driver), "%s",
+		dev_info.driver_name);
+	snprintf(info->version, sizeof(info->version), "%s",
+		rte_version());
+	snprintf(info->bus_info, sizeof(info->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);
+	info->regdump_len = n < 0 ? 0 : n;
+
+	n = rte_eth_dev_get_eeprom_length(port_id);
+	info->eedump_len = n < 0 ? 0 : n;
+
+	info->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	info->testinfo_len = 0;
+
+	*data_len = sizeof(struct ethtool_drvinfo);
+
+	return 0;
+}
+
+static int
+get_reg_len(int port_id, void *data, int *data_len)
+{
+	int reg_length = 0;
+
+	reg_length = rte_eth_dev_get_reg_length(port_id);
+	if (reg_length < 0)
+		return reg_length;
+
+	*(int *)data = reg_length * sizeof(uint32_t);
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_reg(int port_id, void *in_data, void *out_data, int *out_data_len)
+{
+	unsigned int reg_length;
+	int reg_length_out_len;
+	struct ethtool_regs *ethtool_regs = in_data;
+	struct rte_dev_reg_info regs = {
+		.data = out_data,
+		.length = 0,
+	};
+	int ret;
+
+	ret = get_reg_len(port_id, &reg_length, &reg_length_out_len);
+	if (ret < 0 || reg_length > ethtool_regs->len)
+		return -1;
+
+	ret = rte_eth_dev_get_reg_info(port_id, &regs);
+	if (ret < 0)
+		return ret;
+
+	ethtool_regs->version = regs.version;
+	*out_data_len = reg_length;
+
+	return 0;
+}
+
+static int
+get_link(int port_id, void *data, int *data_len)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+
+	*(int *)data = link.link_status;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom_length(int port_id, void *data, int *data_len)
+{
+	int eeprom_length = 0;
+
+	eeprom_length = rte_eth_dev_get_eeprom_length(port_id);
+	if (eeprom_length < 0)
+		return eeprom_length;
+
+	*(int *)data = eeprom_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom(int port_id, void *in_data, void *out_data)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	struct rte_dev_eeprom_info eeprom_info = {
+		.data = out_data,
+		.offset = eeprom->offset,
+		.length = eeprom->len,
+	};
+	int ret;
+
+	ret = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (ret < 0)
+		return ret;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+static int
+set_eeprom(int port_id, void *in_data, void *out_data)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	struct rte_dev_eeprom_info eeprom_info = {
+		.data = out_data,
+		.offset = eeprom->offset,
+		.length = eeprom->len,
+	};
+	int ret;
+
+	ret = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (ret < 0)
+		return ret;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+static int
+get_pauseparam(int port_id, void *data, void *data_len)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+	struct rte_eth_fc_conf fc_conf;
+	int ret;
+
+	ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (ret)
+		return ret;
+
+	pauseparam->tx_pause = 0;
+	pauseparam->rx_pause = 0;
+
+	switch (fc_conf.mode) {
+	case RTE_FC_RX_PAUSE:
+		pauseparam->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pauseparam->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pauseparam->rx_pause = 1;
+		pauseparam->tx_pause = 1;
+	default:
+		break;
+	}
+	pauseparam->autoneg = (uint32_t)fc_conf.autoneg;
+
+	*(int *)data_len = sizeof(struct ethtool_pauseparam);
+
+	return 0;
+}
+
+int
+rte_eth_dev_ethtool_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len)
+{
+	int ret = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case ETHTOOL_GDRVINFO:
+		return get_drvinfo(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS_LEN:
+		return get_reg_len(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS:
+		return get_reg(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_GLINK:
+		return get_link(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM_LEN:
+		return get_eeprom_length(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM:
+		return get_eeprom(port_id, in_data, out_data);
+	case ETHTOOL_SEEPROM:
+		return set_eeprom(port_id, in_data, out_data);
+	case ETHTOOL_GPAUSEPARAM:
+		return get_pauseparam(port_id, out_data, out_data_len);
+	default:
+		ret = -95 /* EOPNOTSUPP */;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+set_mtu(int port_id, void *in_data)
+{
+	int *mtu = in_data;
+
+	return rte_eth_dev_set_mtu(port_id, *mtu);
+}
+
+static int
+get_stats(int port_id, void *data, int *data_len)
+{
+	struct rte_eth_stats stats;
+	struct rtnl_link_stats64 *if_stats = data;
+	int ret;
+
+	ret = rte_eth_stats_get(port_id, &stats);
+	if (ret < 0)
+		return -EOPNOTSUPP;
+
+	if_stats->rx_packets = stats.ipackets;
+	if_stats->tx_packets = stats.opackets;
+	if_stats->rx_bytes = stats.ibytes;
+	if_stats->tx_bytes = stats.obytes;
+	if_stats->rx_errors = stats.ierrors;
+	if_stats->tx_errors = stats.oerrors;
+	if_stats->rx_dropped = stats.imissed;
+	if_stats->multicast = stats.imcasts;
+
+	*data_len = sizeof(struct rtnl_link_stats64);
+
+	return 0;
+}
+
+static int
+get_mac(int port_id, void *data, int *data_len)
+{
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(port_id, &addr);
+	memcpy(data, &addr, sizeof(struct ether_addr));
+
+	*data_len = sizeof(struct ether_addr);
+
+	return 0;
+}
+
+static int
+set_mac(int port_id, void *in_data)
+{
+	struct ether_addr addr;
+
+	memcpy(&addr, in_data, ETHER_ADDR_LEN);
+
+	return rte_eth_dev_default_mac_addr_set(port_id, &addr);
+}
+
+static int
+start_port(int port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return rte_eth_dev_start(port_id);
+}
+
+static int
+stop_port(int port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return 0;
+}
+
+int
+rte_eth_dev_control_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len)
+{
+	int ret = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case RTE_KCP_REQ_CHANGE_MTU:
+		return set_mtu(port_id, in_data);
+	case RTE_KCP_REQ_GET_STATS:
+		return get_stats(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_GET_MAC:
+		return get_mac(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_SET_MAC:
+		return set_mac(port_id, in_data);
+	case RTE_KCP_REQ_START_PORT:
+		return start_port(port_id);
+	case RTE_KCP_REQ_STOP_PORT:
+		return stop_port(port_id);
+	default:
+		ret = -95 /* EOPNOTSUPP */;
+		break;
+	}
+
+	return ret;
+}
diff --git a/lib/librte_ctrl_if/rte_ethtool.h b/lib/librte_ctrl_if/rte_ethtool.h
new file mode 100644
index 0000000..19f364f
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ethtool.h
@@ -0,0 +1,54 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/ethtool.h>
+
+#include <exec-env/rte_kcp_common.h>
+
+int rte_eth_dev_ethtool_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len);
+int rte_eth_dev_control_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/lib/librte_ctrl_if/rte_nl.c b/lib/librte_ctrl_if/rte_nl.c
new file mode 100644
index 0000000..33f1319
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.c
@@ -0,0 +1,259 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <rte_spinlock.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+#include "rte_nl.h"
+#include "rte_ctrl_if.h"
+
+#define KCP_NL_GRP 31
+#define MAX_PAYLOAD 1024
+
+struct ctrl_if_nl {
+	struct nlmsghdr *nlh;
+	struct msghdr msg;
+	struct iovec iov;
+};
+
+static int sock_fd = -1;
+pthread_t thread_id;
+pthread_cond_t cond  = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t msg_lock = PTHREAD_MUTEX_INITIALIZER;
+static uint8_t nlmsg[NLMSG_SPACE(MAX_PAYLOAD) * 2];
+static struct sockaddr_nl dest_addr;
+static struct sockaddr_nl src_addr;
+
+static struct ctrl_if_nl nl_s = {
+	.nlh = (struct nlmsghdr *)nlmsg,
+};
+
+static struct ctrl_if_nl nl_r = {
+	.nlh = (struct nlmsghdr *)(nlmsg + NLMSG_SPACE(MAX_PAYLOAD)),
+};
+
+static int kcp_ethtool_msg_count;
+static struct kcp_ethtool_msg msg_storage;
+
+static void
+control_interface_nl_send(void *buf, size_t len)
+{
+	int ret;
+
+	/* Fill in the netlink message payload */
+	memcpy(NLMSG_DATA(nl_s.nlh), buf, len);
+
+	ret = sendmsg(sock_fd, &nl_s.msg, 0);
+
+	if (ret < 0)
+		RTE_LOG(ERR, CTRL_IF, "Failed nl msg send. ret:%d, err:%d\n",
+				ret, errno);
+}
+
+static void
+control_interface_nl_process_msg(struct kcp_ethtool_msg *msg)
+{
+	if (msg->cmd_id > RTE_KCP_REQ_UNKNOWN) {
+		msg->err = rte_eth_dev_control_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	} else {
+		msg->err = rte_eth_dev_ethtool_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	}
+
+	control_interface_nl_send((void *)msg,
+			sizeof(struct kcp_ethtool_msg));
+}
+
+int
+control_interface_process_msg(int flag, unsigned int timeout_sec)
+{
+	int ret = 0;
+	struct timespec ts;
+
+	pthread_mutex_lock(&msg_lock);
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+	ts.tv_sec += timeout_sec;
+	while (timeout_sec && !kcp_ethtool_msg_count && !ret)
+		ret = pthread_cond_timedwait(&cond, &msg_lock, &ts);
+
+	switch (flag) {
+	case RTE_ETHTOOL_CTRL_IF_PROCESS_MSG:
+		if (kcp_ethtool_msg_count) {
+			control_interface_nl_process_msg(&msg_storage);
+			kcp_ethtool_msg_count = 0;
+		}
+		ret = 0;
+		break;
+
+	case RTE_ETHTOOL_CTRL_IF_DISCARD_MSG:
+		if (kcp_ethtool_msg_count) {
+			msg_storage.err = -1;
+			control_interface_nl_send((void *)&msg_storage,
+					sizeof(struct kcp_ethtool_msg));
+			kcp_ethtool_msg_count = 0;
+		}
+		ret = 0;
+		break;
+
+	default:
+		ret = -1;
+		break;
+	}
+	pthread_mutex_unlock(&msg_lock);
+
+	return ret;
+}
+
+static int
+msg_add_and_signal(struct nlmsghdr *nlh)
+{
+	pthread_mutex_lock(&msg_lock);
+
+	memcpy(&msg_storage, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
+	kcp_ethtool_msg_count = 1;
+
+	pthread_cond_signal(&cond);
+
+	pthread_mutex_unlock(&msg_lock);
+
+	return 0;
+}
+
+static void *
+control_interface_nl_recv(void *arg)
+{
+	int ret;
+
+	for (;;) {
+		ret = recvmsg(sock_fd, &nl_r.msg, 0);
+		if (ret < 0)
+			continue;
+
+		if ((unsigned)ret < sizeof(struct kcp_ethtool_msg)) {
+			RTE_LOG(WARNING, CTRL_IF,
+					"Received %u bytes, payload %lu\n",
+					ret, sizeof(struct kcp_ethtool_msg));
+			continue;
+		}
+
+		msg_add_and_signal(nl_r.nlh);
+	}
+
+	return arg;
+}
+
+static void
+nl_setup_header(struct ctrl_if_nl *nl, struct sockaddr_nl *daddr)
+{
+	memset(nl->nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
+
+	/* Fill the netlink message header */
+	nl->nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
+	nl->nlh->nlmsg_pid = getpid();  /* self pid */
+	nl->nlh->nlmsg_flags = 0;
+
+	nl->iov.iov_base = (void *)nl->nlh;
+	nl->iov.iov_len = nl->nlh->nlmsg_len;
+	memset(&nl->msg, 0, sizeof(struct msghdr));
+	nl->msg.msg_name = (void *)daddr;
+	nl->msg.msg_namelen = sizeof(struct sockaddr_nl);
+	nl->msg.msg_iov = &nl->iov;
+	nl->msg.msg_iovlen = 1;
+}
+
+static int
+control_interface_nl_socket_init(void)
+{
+	int fd;
+	int ret;
+
+	fd = socket(PF_NETLINK, SOCK_RAW, KCP_NL_GRP);
+	if (fd < 0)
+		return -1;
+
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	ret = bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
+	if (ret) {
+		close(fd);
+		return -1;
+	}
+
+	dest_addr.nl_family = AF_NETLINK;
+	dest_addr.nl_pid = 0;   /*  For Linux Kernel */
+	dest_addr.nl_groups = 0;
+
+	nl_setup_header(&nl_s, &dest_addr);
+	nl_setup_header(&nl_r, &dest_addr);
+
+	return fd;
+}
+
+int
+control_interface_nl_init(void)
+{
+	int ret;
+	char buf[] = "pid";
+	sock_fd = control_interface_nl_socket_init();
+
+	if (sock_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF,
+				"Failed to initialize control interface.\n");
+		return -1;
+	}
+
+	ret = pthread_create(&thread_id, NULL, control_interface_nl_recv,
+			NULL);
+	if (ret != 0)
+		return -1;
+	control_interface_nl_send((void *)buf, sizeof(buf));
+
+	return 0;
+}
+
+void
+control_interface_nl_release(void)
+{
+	pthread_cancel(thread_id);
+	pthread_join(thread_id, NULL);
+	close(sock_fd);
+}
diff --git a/lib/librte_ctrl_if/rte_nl.h b/lib/librte_ctrl_if/rte_nl.h
new file mode 100644
index 0000000..e422bf9
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.h
@@ -0,0 +1,60 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_NL_H_
+#define _RTE_NL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define KCP_ETHTOOL_MSG_LEN 500
+struct kcp_ethtool_msg {
+	int cmd_id;
+	int port_id;
+	char input_buffer[KCP_ETHTOOL_MSG_LEN];
+	char output_buffer[KCP_ETHTOOL_MSG_LEN];
+	int input_buffer_len;
+	int output_buffer_len;
+	int err;
+};
+
+int control_interface_nl_init(void);
+void control_interface_nl_release(void);
+int control_interface_process_msg(int flag, unsigned int timeout_sec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_NL_H_ */
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 2e47e7f..a0a2c9f 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
 #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
 #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
 #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#define RTE_LOGTYPE_CTRL_IF 0x00040000 /**< Log related to control interface. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8ecab41..e1638f0 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -122,6 +122,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF_OFFLOAD)   += -lrte_mbuf_offload
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CTRL_IF)        += -lrte_ctrl_if
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.5.0

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

* [PATCH 3/3] examples/ethtool: add control interface support to the application
  2016-01-27 16:24 [PATCH 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
  2016-01-27 16:24 ` [PATCH 1/3] kcp: add kernel control path kernel module Ferruh Yigit
  2016-01-27 16:24 ` [PATCH 2/3] rte_ctrl_if: add control interface library Ferruh Yigit
@ 2016-01-27 16:24 ` Ferruh Yigit
  2016-02-12 13:45 ` [PATCH v2 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
  3 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-01-27 16:24 UTC (permalink / raw)
  To: dev

Control interface APIs added into the sample application.

To have the support corresponding kernel module (KCP) needs to be inserted.
If kernel module is not there, application will run as it is without
kernel control path support.

When KCP module inserted, running application creates a virtual Linux
network interface (dpdk$) per DPDK port. This interface can be used by
traditional Linux tools.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 doc/guides/sample_app_ug/ethtool.rst | 41 ++++++++++++++++++++++++++++++++++++
 examples/ethtool/ethtool-app/main.c  | 10 +++++++--
 2 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
index 4d1697e..2174288 100644
--- a/doc/guides/sample_app_ug/ethtool.rst
+++ b/doc/guides/sample_app_ug/ethtool.rst
@@ -131,6 +131,47 @@ application`_. Individual call-back functions handle the detail
 associated with each command, which make use of the functions
 defined in the `Ethtool interface`_ to the DPDK functions.
 
+Control Interface
+~~~~~~~~~~~~~~~~~
+
+If Kernel Control Path (KCP) kernel module (rte_kcp.ko) inserted,
+virtual interfaces created for each DPDK port for control purposes.
+
+Created interfaces are named as dpdk#, like:
+
+.. code-block:: console
+
+        # ifconfig dpdk0; ifconfig dpdk1
+        dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 90:e2:ba:0e:49:b9  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+        dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+Regular Linux commands can be issued on interfaces:
+
+.. code-block:: console
+
+        # ethtool -i dpdk0
+        driver: rte_ixgbe_pmd
+        version: RTE 2.3.0-rc0
+        firmware-version:
+        expansion-rom-version:
+        bus-info: 0000:08:00.1
+        supports-statistics: yes
+        supports-test: no
+        supports-eeprom-access: yes
+        supports-register-dump: yes
+        supports-priv-flags: no
+
 Ethtool interface
 -----------------
 
diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
index e21abcd..68b13ad 100644
--- a/examples/ethtool/ethtool-app/main.c
+++ b/examples/ethtool/ethtool-app/main.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <rte_memory.h>
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
+#include <rte_ctrl_if.h>
 
 #include "ethapp.h"
 
@@ -54,7 +55,6 @@
 #define PKTPOOL_EXTRA_SIZE 512
 #define PKTPOOL_CACHE 32
 
-
 struct txq_port {
 	uint16_t cnt_unsent;
 	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
@@ -254,6 +254,8 @@ static int slave_main(__attribute__((unused)) void *ptr_data)
 			}
 			rte_spinlock_unlock(&ptr_port->lock);
 		} /* end for( idx_port ) */
+		rte_eth_control_interface_process_msg(
+				RTE_ETHTOOL_CTRL_IF_PROCESS_MSG, 0);
 	} /* end for(;;) */
 
 	return 0;
@@ -293,6 +295,8 @@ int main(int argc, char **argv)
 	id_core = rte_get_next_lcore(id_core, 1, 1);
 	rte_eal_remote_launch(slave_main, NULL, id_core);
 
+	rte_eth_control_interface_create();
+
 	ethapp_main();
 
 	app_cfg.exit_now = 1;
@@ -301,5 +305,7 @@ int main(int argc, char **argv)
 			return -1;
 	}
 
+	rte_eth_control_interface_destroy();
+
 	return 0;
 }
-- 
2.5.0

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-01-27 16:24 ` [PATCH 1/3] kcp: add kernel control path kernel module Ferruh Yigit
@ 2016-01-28  9:49   ` Remy Horton
  2016-01-28 13:50     ` Ferruh Yigit
  2016-02-28 15:34   ` Avi Kivity
  2016-02-29 20:11   ` Stephen Hemminger
  2 siblings, 1 reply; 83+ messages in thread
From: Remy Horton @ 2016-01-28  9:49 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

Comments inline

..Remy


On 27/01/2016 16:24, Ferruh Yigit wrote:
 > This kernel module is based on KNI module, but this one is stripped
 > version of it and only for control messages, no data transfer
 > functionality provided.
 >
 > This Linux kernel module helps userspace application create virtual
 > interfaces and when a control command issued into that virtual
 > interface, module pushes the command to the userspace and gets the
 > response back for the caller application.
 >
 > Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
 > ---


 > +	net_dev = alloc_netdev(sizeof(struct kcp_dev), name,
 > +#ifdef NET_NAME_UNKNOWN
 > +							NET_NAME_UNKNOWN,
 > +#endif
 > +							kcp_net_init);

Something doesn't feel quite right here. In cases where NET_NAME_UNKNOWN 
is undefined, is the signature for alloc_netdev different?


 > +MODULE_LICENSE("Dual BSD/GPL");
 > +MODULE_AUTHOR("Intel Corporation");
 > +MODULE_DESCRIPTION("Kernel Module for managing kcp devices");

I'm not up to speed on this area, but some of the file headers only 
mention GPL/LGPL. This correct?


 > +	nlmsg_unicast(nl_sock, skb, pid);
 > +	KCP_DBG("Sent cmd:%d port:%d\n", cmd_id, port_id);
 > +
 > +	/*nlmsg_free(skb);*/
 > +
 > +	return 0;
 > +}

Oops.. :)
Possible memory leak, or is *skb statically allocated?

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

* Re: [PATCH 2/3] rte_ctrl_if: add control interface library
  2016-01-27 16:24 ` [PATCH 2/3] rte_ctrl_if: add control interface library Ferruh Yigit
@ 2016-01-28 11:14   ` Remy Horton
  2016-01-28 13:15     ` Ferruh Yigit
  0 siblings, 1 reply; 83+ messages in thread
From: Remy Horton @ 2016-01-28 11:14 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On 27/01/2016 16:24, Ferruh Yigit wrote:

 > +	default:
 > +		ret = -95 /* EOPNOTSUPP */;
 > +		break;

Is this intentional? -EOPNOTSUPP is -122 (-95 is -ENOTSOCK)..

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

* Re: [PATCH 2/3] rte_ctrl_if: add control interface library
  2016-01-28 11:14   ` Remy Horton
@ 2016-01-28 13:15     ` Ferruh Yigit
  2016-01-28 13:24       ` Jay Rolette
  2016-01-28 13:57       ` Ananyev, Konstantin
  0 siblings, 2 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-01-28 13:15 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

On Thu, Jan 28, 2016 at 11:14:47AM +0000, Remy Horton wrote:
> On 27/01/2016 16:24, Ferruh Yigit wrote:
>
> > +	default:
> > +		ret = -95 /* EOPNOTSUPP */;
> > +		break;
>
> Is this intentional? -EOPNOTSUPP is -122 (-95 is -ENOTSOCK)..
>
Return value is not significant, callee just checks for negative value,
I can remove comment to prevent confusion.

Thanks,
ferruh 

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

* Re: [PATCH 2/3] rte_ctrl_if: add control interface library
  2016-01-28 13:15     ` Ferruh Yigit
@ 2016-01-28 13:24       ` Jay Rolette
  2016-01-28 13:56         ` Ferruh Yigit
  2016-01-28 13:57       ` Ananyev, Konstantin
  1 sibling, 1 reply; 83+ messages in thread
From: Jay Rolette @ 2016-01-28 13:24 UTC (permalink / raw)
  To: Remy Horton, DPDK

On Thu, Jan 28, 2016 at 7:15 AM, Ferruh Yigit <ferruh.yigit@intel.com>
wrote:

> On Thu, Jan 28, 2016 at 11:14:47AM +0000, Remy Horton wrote:
> > On 27/01/2016 16:24, Ferruh Yigit wrote:
> >
> > > +   default:
> > > +           ret = -95 /* EOPNOTSUPP */;
> > > +           break;
> >
> > Is this intentional? -EOPNOTSUPP is -122 (-95 is -ENOTSOCK)..
> >
> Return value is not significant, callee just checks for negative value,
> I can remove comment to prevent confusion.
>

No, please fix the return value. Return values are significant when you are
trying to debug or understand the intent of the code.

Jay

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-01-28  9:49   ` Remy Horton
@ 2016-01-28 13:50     ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-01-28 13:50 UTC (permalink / raw)
  To: Remy Horton; +Cc: dev

On Thu, Jan 28, 2016 at 09:49:49AM +0000, Remy Horton wrote:
> Comments inline
>
> ..Remy
>
>
> On 27/01/2016 16:24, Ferruh Yigit wrote:
> > This kernel module is based on KNI module, but this one is stripped
> > version of it and only for control messages, no data transfer
> > functionality provided.
> >
> > This Linux kernel module helps userspace application create virtual
> > interfaces and when a control command issued into that virtual
> > interface, module pushes the command to the userspace and gets the
> > response back for the caller application.
> >
> > Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> > ---
>
>
> > +	net_dev = alloc_netdev(sizeof(struct kcp_dev), name,
> > +#ifdef NET_NAME_UNKNOWN
> > +							NET_NAME_UNKNOWN,
> > +#endif
> > +							kcp_net_init);
>
> Something doesn't feel quite right here. In cases where NET_NAME_UNKNOWN is 
> undefined, is the signature for alloc_netdev different?
>
Yes, this is because of API change between kernel versions,
when NET_NAME_* introduced, alloc_netdev() also updated to have this.

>
> > +MODULE_LICENSE("Dual BSD/GPL");
> > +MODULE_AUTHOR("Intel Corporation");
> > +MODULE_DESCRIPTION("Kernel Module for managing kcp devices");
>
> I'm not up to speed on this area, but some of the file headers only mention 
> GPL/LGPL. This correct?
>
This is because a header file (rte_kcp_common.h) shared by this kernel module and user-space application is dual licensed (BSD + GPL)
I mimicked this from exiting KNI.
>
> > +	nlmsg_unicast(nl_sock, skb, pid);
> > +	KCP_DBG("Sent cmd:%d port:%d\n", cmd_id, port_id);
> > +
> > +	/*nlmsg_free(skb);*/
> > +
> > +	return 0;
> > +}
>
> Oops.. :)
> Possible memory leak, or is *skb statically allocated?
>
No leak, not statically allocated, but taken care by nlmsg_unicast()
But commented code needs to be removed.

Thanks,
ferruh

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

* Re: [PATCH 2/3] rte_ctrl_if: add control interface library
  2016-01-28 13:24       ` Jay Rolette
@ 2016-01-28 13:56         ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-01-28 13:56 UTC (permalink / raw)
  To: Jay Rolette; +Cc: DPDK

On Thu, Jan 28, 2016 at 07:24:51AM -0600, Jay Rolette wrote:
> On Thu, Jan 28, 2016 at 7:15 AM, Ferruh Yigit <ferruh.yigit@intel.com>
> wrote:
> 
> > On Thu, Jan 28, 2016 at 11:14:47AM +0000, Remy Horton wrote:
> > > On 27/01/2016 16:24, Ferruh Yigit wrote:
> > >
> > > > +   default:
> > > > +           ret = -95 /* EOPNOTSUPP */;
> > > > +           break;
> > >
> > > Is this intentional? -EOPNOTSUPP is -122 (-95 is -ENOTSOCK)..
> > >
> > Return value is not significant, callee just checks for negative value,
> > I can remove comment to prevent confusion.
> >
> 
> No, please fix the return value. Return values are significant when you are
> trying to debug or understand the intent of the code.
> 
There is nothing to fix in return value here. I am simply planning to do something like:
#define NOT_SUPPORTED -2
ret = NOT_SUPPORTED;

But the value of -95 or -110 or -2 does not differ.

Thanks,
ferruh

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

* Re: [PATCH 2/3] rte_ctrl_if: add control interface library
  2016-01-28 13:15     ` Ferruh Yigit
  2016-01-28 13:24       ` Jay Rolette
@ 2016-01-28 13:57       ` Ananyev, Konstantin
  2016-01-28 14:22         ` Yigit, Ferruh
  1 sibling, 1 reply; 83+ messages in thread
From: Ananyev, Konstantin @ 2016-01-28 13:57 UTC (permalink / raw)
  To: Yigit, Ferruh, Horton, Remy; +Cc: dev

Hi Ferruh,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
> Sent: Thursday, January 28, 2016 1:15 PM
> To: Horton, Remy
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 2/3] rte_ctrl_if: add control interface library
> 
> On Thu, Jan 28, 2016 at 11:14:47AM +0000, Remy Horton wrote:
> > On 27/01/2016 16:24, Ferruh Yigit wrote:
> >
> > > +	default:
> > > +		ret = -95 /* EOPNOTSUPP */;
> > > +		break;
> >
> > Is this intentional? -EOPNOTSUPP is -122 (-95 is -ENOTSOCK)..
> >
> Return value is not significant, callee just checks for negative value,
> I can remove comment to prevent confusion.

Please use values defined in errno.h, there are plenty of them,
no need to invent your own error codes.
Also pls don't forget to address all comments I gave you offline.
Thanks
Konstantin

> 
> Thanks,
> ferruh

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

* Re: [PATCH 2/3] rte_ctrl_if: add control interface library
  2016-01-28 13:57       ` Ananyev, Konstantin
@ 2016-01-28 14:22         ` Yigit, Ferruh
  0 siblings, 0 replies; 83+ messages in thread
From: Yigit, Ferruh @ 2016-01-28 14:22 UTC (permalink / raw)
  To: Ananyev, Konstantin; +Cc: dev

On Thu, Jan 28, 2016 at 01:57:04PM +0000, Ananyev, Konstantin wrote:
> Hi Ferruh,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
> > Sent: Thursday, January 28, 2016 1:15 PM
> > To: Horton, Remy
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH 2/3] rte_ctrl_if: add control interface library
> > 
> > On Thu, Jan 28, 2016 at 11:14:47AM +0000, Remy Horton wrote:
> > > On 27/01/2016 16:24, Ferruh Yigit wrote:
> > >
> > > > +	default:
> > > > +		ret = -95 /* EOPNOTSUPP */;
> > > > +		break;
> > >
> > > Is this intentional? -EOPNOTSUPP is -122 (-95 is -ENOTSOCK)..
> > >
> > Return value is not significant, callee just checks for negative value,
> > I can remove comment to prevent confusion.
> 
> Please use values defined in errno.h, there are plenty of them,
> no need to invent your own error codes.
OK

> Also pls don't forget to address all comments I gave you offline.
Yes, I also remember your comment when I saw this J, it seems this one missed.
I will address in next revision.

Thanks,
ferruh

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

* [PATCH v2 0/3] Use common Linux tools to control DPDK ports
  2016-01-27 16:24 [PATCH 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
                   ` (2 preceding siblings ...)
  2016-01-27 16:24 ` [PATCH 3/3] examples/ethtool: add control interface support to the application Ferruh Yigit
@ 2016-02-12 13:45 ` Ferruh Yigit
  2016-02-12 13:45   ` [PATCH v2 1/3] kcp: add kernel control path kernel module Ferruh Yigit
                     ` (3 more replies)
  3 siblings, 4 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-12 13:45 UTC (permalink / raw)
  To: dev

This work is to make DPDK ports more visible and to enable using common
Linux tools to configure DPDK ports.

Patch is based on KNI but contains only control functionality of it,
also this patch does not include any Linux kernel network driver as
part of it.

Basically with the help of a kernel module (KCP), virtual Linux network
interfaces named as "dpdk$" are created per DPDK port, control messages
sent to these virtual interfaces are forwarded to DPDK, and response
sent back to Linux application.

Virtual interfaces created when DPDK application started and destroyed
automatically when DPDK application terminated.

Communication between kernel-space and DPDK done using netlink socket.

Currently implementation is not complete, sample support added for the
RFC, more functionality can be added based on community response.

With this RFC Patch, supported: get/set mac address/mtu of DPDK devices,
getting stats from DPDK devices and some set of ethtool commands.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

v2:
* Use rtnetlink to create interfaces
* Add more ethtool support: get/set ringparam, set pauseparam.
* fix ethtool get/set eeprom
* lots of minor updates, enhancements in the code


Samples:

$ ifconfig
dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 90:e2:ba:0e:49:b8  txqueuelen 1000  (Ethernet)
        RX packets 33  bytes 2058 (2.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 33  bytes 2058 (2.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

After some traffic on port 0:

$ ifconfig
dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 90:e2:ba:0e:49:77  txqueuelen 1000  (Ethernet)
        RX packets 962  bytes 57798 (56.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 962  bytes 57798 (56.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


$ ethtool -i dpdk0
driver: rte_ixgbe_pmd
version: DPDK 16.04.0-rc0
firmware-version: 
expansion-rom-version: 
bus-info: 0000:08:00.0
supports-statistics: no
supports-test: no
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no


$ ethtool -e dpdk0 offset 20 length 10
Offset          Values
------          ------
0x0014:         b7 01 bf 01 c7 01 cf 01 09 02 


$ ip l show dpdk0
25: dpdk0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:b8 brd ff:ff:ff:ff:ff:ff

$ ip l set dpdk0 addr 90:e2:ba:0e:49:77

$ ip l show dpdk0
25: dpdk0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:77 brd ff:ff:ff:ff:ff:ff

Ferruh Yigit (3):
  kcp: add kernel control path kernel module
  rte_ctrl_if: add control interface library
  examples/ethtool: add control interface support to the application

 MAINTAINERS                                        |   5 +
 config/common_linuxapp                             |   9 +-
 doc/api/doxy-api-index.md                          |   3 +-
 doc/api/doxy-api.conf                              |   1 +
 doc/guides/rel_notes/release_16_04.rst             |   9 +
 doc/guides/sample_app_ug/ethtool.rst               |  41 ++
 examples/ethtool/ethtool-app/main.c                |  10 +-
 lib/Makefile                                       |   3 +-
 lib/librte_ctrl_if/Makefile                        |  58 +++
 lib/librte_ctrl_if/rte_ctrl_if.c                   | 385 ++++++++++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h                   | 115 ++++++
 lib/librte_ctrl_if/rte_ctrl_if_version.map         |   9 +
 lib/librte_ctrl_if/rte_ethtool.c                   | 450 +++++++++++++++++++++
 lib/librte_ctrl_if/rte_ethtool.h                   |  54 +++
 lib/librte_ctrl_if/rte_nl.c                        | 274 +++++++++++++
 lib/librte_ctrl_if/rte_nl.h                        |  49 +++
 lib/librte_eal/common/include/rte_log.h            |   3 +-
 lib/librte_eal/linuxapp/Makefile                   |   5 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h | 107 +++++
 lib/librte_eal/linuxapp/kcp/Makefile               |  57 +++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  53 +++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 288 +++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 257 ++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 210 ++++++++++
 mk/rte.app.mk                                      |   3 +-
 26 files changed, 2452 insertions(+), 9 deletions(-)
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c

-- 
2.5.0

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

* [PATCH v2 1/3] kcp: add kernel control path kernel module
  2016-02-12 13:45 ` [PATCH v2 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
@ 2016-02-12 13:45   ` Ferruh Yigit
  2016-02-12 13:45   ` [PATCH v2 2/3] rte_ctrl_if: add control interface library Ferruh Yigit
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-12 13:45 UTC (permalink / raw)
  To: dev

This kernel module is based on KNI module, but this one is stripped
version of it and only for control messages, no data transfer
functionality provided.

This Linux kernel module helps userspace application create virtual
interfaces and when a control command issued into that virtual
interface, module pushes the command to the userspace and gets the
response back for the caller application.

The Linux tools like ethtool/ifconfig/ip can be used on virtual
interfaces but not ones for related data, like tcpdump.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>

---

v2:
* Use rtnetlink to create interfaces
* fix ethtool get/set eeprom
* Remove commented out code
---
 MAINTAINERS                                        |   4 +
 config/common_linuxapp                             |   6 +
 lib/librte_eal/linuxapp/Makefile                   |   5 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h | 107 ++++++++
 lib/librte_eal/linuxapp/kcp/Makefile               |  57 ++++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  53 ++++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 288 +++++++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 257 ++++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 210 +++++++++++++++
 10 files changed, 988 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b90aeea..09c56c7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -253,6 +253,10 @@ F: app/test/test_kni.c
 F: examples/kni/
 F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 
+Linux KCP
+M: Ferruh Yigit <ferruh.yigit@intel.com>
+F: lib/librte_eal/linuxapp/kcp/
+
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
 F: drivers/net/af_packet/
diff --git a/config/common_linuxapp b/config/common_linuxapp
index f1638db..2f4eb1d 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -497,6 +497,12 @@ CONFIG_RTE_KNI_VHOST_DEBUG_RX=n
 CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 
 #
+# Compile librte_ctrl_if
+#
+CONFIG_RTE_KCP_KMOD=y
+CONFIG_RTE_KCP_KO_DEBUG=n
+
+#
 # Compile vhost library
 # fuse-devel is needed to run vhost-cuse.
 # fuse-devel enables user space char driver development
diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile
index d9c5233..d1fa3a3 100644
--- a/lib/librte_eal/linuxapp/Makefile
+++ b/lib/librte_eal/linuxapp/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal
 ifeq ($(CONFIG_RTE_KNI_KMOD),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kni
 endif
+ifeq ($(CONFIG_RTE_KCP_KMOD),y)
+DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kcp
+endif
 ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += xen_dom0
 endif
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 6e26250..f6a3a41 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,7 @@ CFLAGS_eal_thread.o += -Wno-return-type
 endif
 
 INC := rte_interrupts.h rte_kni_common.h rte_dom0_common.h
+INC += rte_kcp_common.h
 
 SYMLINK-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP)-include/exec-env := \
 	$(addprefix include/exec-env/,$(INC))
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
new file mode 100644
index 0000000..4d1ba2e
--- /dev/null
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
@@ -0,0 +1,107 @@
+/*-
+ *   This file is provided under a dual BSD/LGPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GNU LESSER GENERAL PUBLIC LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2.1 of the GNU Lesser General Public License
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this program;
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ *
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_KCP_COMMON_H_
+#define _RTE_KCP_COMMON_H_
+
+#define KCP_DEVICE "kcp"
+
+#define KCP_NL_GRP 31
+
+#define KCP_ETHTOOL_MSG_LEN 500
+struct kcp_ethtool_msg {
+	int cmd_id;
+	int port_id;
+	unsigned int flag;
+	char input_buffer[KCP_ETHTOOL_MSG_LEN];
+	char output_buffer[KCP_ETHTOOL_MSG_LEN];
+	int input_buffer_len;
+	int output_buffer_len;
+	int err;
+};
+
+enum kcp_ethtool_msg_flag {
+	KCP_MSG_FLAG_NONE,
+	KCP_MSG_FLAG_REQUEST,
+	KCP_MSG_FLAG_RESPONSE,
+};
+
+enum {
+	IFLA_KCP_UNSPEC,
+	IFLA_KCP_PORTID,
+	IFLA_KCP_PID,
+	__IFLA_KCP_MAX,
+};
+
+#define IFLA_KCP_MAX (__IFLA_KCP_MAX - 1)
+
+/*
+ * Request id.
+ */
+enum rte_kcp_req_id {
+	RTE_KCP_REQ_UNKNOWN = (1 << 16),
+	RTE_KCP_REQ_CHANGE_MTU,
+	RTE_KCP_REQ_CFG_NETWORK_IF,
+	RTE_KCP_REQ_GET_STATS,
+	RTE_KCP_REQ_GET_MAC,
+	RTE_KCP_REQ_SET_MAC,
+	RTE_KCP_REQ_START_PORT,
+	RTE_KCP_REQ_STOP_PORT,
+	RTE_KCP_REQ_MAX,
+};
+
+#endif /* _RTE_KCP_COMMON_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/Makefile b/lib/librte_eal/linuxapp/kcp/Makefile
new file mode 100644
index 0000000..46d9dd8
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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
+
+#
+# module name and path
+#
+MODULE = rte_kcp
+
+#
+# CFLAGS
+#
+MODULE_CFLAGS += -I$(SRCDIR)
+MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
+MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
+MODULE_CFLAGS += -Wall -Werror
+
+# this lib needs main eal
+DEPDIRS-y += lib/librte_eal/linuxapp/eal
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y += kcp_net.c
+SRCS-y += kcp_ethtool.c
+SRCS-y += kcp_nl.c
+
+include $(RTE_SDK)/mk/rte.module.mk
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_dev.h b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
new file mode 100644
index 0000000..7551c8b
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
@@ -0,0 +1,53 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#ifndef _KCP_DEV_H_
+#define _KCP_DEV_H_
+
+#include <linux/netdevice.h>
+#include <exec-env/rte_kcp_common.h>
+
+struct kcp_dev {
+	int port_id;
+	unsigned int pid;
+	struct completion msg_received;
+};
+
+void kcp_nl_init(void);
+void kcp_nl_release(void);
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data, int in_len,
+		void *out_data, int out_len);
+
+void kcp_set_ethtool_ops(struct net_device *netdev);
+
+#define KCP_ERR(args...) printk(KERN_ERR "KCP: " args)
+#define KCP_INFO(args...) printk(KERN_INFO "KCP: " args)
+
+#ifdef RTE_KCP_KO_DEBUG
+#define KCP_DBG(args...) printk(KERN_DEBUG "KCP: " args)
+#else
+#define KCP_DBG(args...)
+#endif
+
+#endif /* _KCP_DEV_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
new file mode 100644
index 0000000..a1fa793
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
@@ -0,0 +1,288 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include "kcp_dev.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int kcp_check_if_running(struct net_device *dev)
+{
+	return 0;
+}
+
+static void kcp_get_drvinfo(struct net_device *dev,
+		struct ethtool_drvinfo *info)
+{
+	int ret;
+
+	ret = kcp_nl_exec(info->cmd, dev, NULL, 0,
+			info, sizeof(struct ethtool_drvinfo));
+	if (ret < 0)
+		memset(info, 0, sizeof(struct ethtool_drvinfo));
+}
+
+static int kcp_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, NULL, 0,
+			ecmd, sizeof(struct ethtool_cmd));
+}
+
+static int kcp_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, ecmd, sizeof(struct ethtool_cmd),
+			NULL, 0);
+}
+
+static void kcp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	int ret;
+
+	ret = kcp_nl_exec(wol->cmd, dev, NULL, 0,
+			wol, sizeof(struct ethtool_wolinfo));
+	if (ret < 0)
+		memset(wol, 0, sizeof(struct ethtool_wolinfo));
+}
+
+static int kcp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	return kcp_nl_exec(wol->cmd, dev, wol, sizeof(struct ethtool_wolinfo),
+			NULL, 0);
+}
+
+static int kcp_nway_reset(struct net_device *dev)
+{
+	return kcp_nl_exec(ETHTOOL_NWAY_RST, dev, NULL, 0, NULL, 0);
+}
+
+static int kcp_get_eeprom_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GEEPROM_LEN, dev, NULL, 0,
+			&data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static int kcp_get_eeprom(struct net_device *dev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct ethtool_eeprom eeprom_tmp;
+	int ret = 0;
+	int remaining;
+	int offset = 0;
+
+	eeprom_tmp = *eeprom;
+
+	remaining = eeprom_tmp.len;
+	while (remaining > 0 && ret == 0) {
+		eeprom_tmp.len = min(remaining, KCP_ETHTOOL_MSG_LEN);
+
+		ret = kcp_nl_exec(eeprom_tmp.cmd, dev,
+				&eeprom_tmp, sizeof(struct ethtool_eeprom),
+				data + offset, eeprom_tmp.len);
+		eeprom_tmp.offset += eeprom_tmp.len;
+		offset += eeprom_tmp.len;
+		remaining -= eeprom_tmp.len;
+	}
+
+	return ret;
+}
+
+static int kcp_set_eeprom(struct net_device *dev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct ethtool_eeprom *eeprom_tmp;
+	int ret = 0;
+	int remaining;
+	int offset = 0;
+	int payload;
+
+	if (sizeof(struct ethtool_eeprom) > KCP_ETHTOOL_MSG_LEN)
+		return -1;
+
+	eeprom_tmp = kmalloc(KCP_ETHTOOL_MSG_LEN, GFP_KERNEL);
+	payload = KCP_ETHTOOL_MSG_LEN - sizeof(struct ethtool_eeprom);
+
+	*eeprom_tmp = *eeprom;
+	remaining = eeprom->len;
+
+	while (remaining > 0 && ret == 0) {
+		eeprom_tmp->len = min(remaining, payload);
+
+		memcpy(eeprom_tmp->data, data + offset, payload);
+
+		ret = kcp_nl_exec(eeprom->cmd, dev, eeprom,
+				KCP_ETHTOOL_MSG_LEN, NULL, 0);
+
+		eeprom_tmp->offset += eeprom_tmp->len;
+		offset += eeprom_tmp->len;
+		remaining -= eeprom_tmp->len;
+	}
+
+	kfree(eeprom_tmp);
+
+	return ret;
+}
+
+static void kcp_get_ringparam(struct net_device *dev,
+		struct ethtool_ringparam *ring)
+{
+
+	kcp_nl_exec(ring->cmd, dev, NULL, 0,
+			ring, sizeof(struct ethtool_ringparam));
+}
+
+static int kcp_set_ringparam(struct net_device *dev,
+		struct ethtool_ringparam *ring)
+{
+	return kcp_nl_exec(ring->cmd, dev,
+			ring, sizeof(struct ethtool_ringparam),
+			NULL, 0);
+}
+
+static void kcp_get_pauseparam(struct net_device *dev,
+		struct ethtool_pauseparam *pause)
+{
+
+	kcp_nl_exec(pause->cmd, dev, NULL, 0,
+			pause, sizeof(struct ethtool_pauseparam));
+}
+
+static int kcp_set_pauseparam(struct net_device *dev,
+		struct ethtool_pauseparam *pause)
+{
+	return kcp_nl_exec(pause->cmd, dev,
+			pause, sizeof(struct ethtool_pauseparam),
+			NULL, 0);
+}
+
+static u32 kcp_get_msglevel(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GMSGLVL, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_set_msglevel(struct net_device *dev, u32 data)
+{
+
+	kcp_nl_exec(ETHTOOL_SMSGLVL, dev, &data, sizeof(int), NULL, 0);
+}
+
+static int kcp_get_regs_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GREGS_LEN, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+		void *p)
+{
+	struct ethtool_regs regs_tmp;
+	int len = regs->len;
+
+	regs_tmp = *regs;
+
+	if (len > KCP_ETHTOOL_MSG_LEN) {
+		len = KCP_ETHTOOL_MSG_LEN;
+		regs_tmp.len = len;
+	}
+
+	kcp_nl_exec(regs->cmd, dev, &regs_tmp, sizeof(struct ethtool_regs),
+			p, len);
+}
+
+static void kcp_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+
+	kcp_nl_exec(ETHTOOL_GSTRINGS, dev, &stringset, sizeof(u32), data, 0);
+}
+
+static int kcp_get_sset_count(struct net_device *dev, int sset)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GSSET_COUNT, dev, &sset, sizeof(int),
+			&data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_get_ethtool_stats(struct net_device *dev,
+		struct ethtool_stats *stats, u64 *data)
+{
+
+	kcp_nl_exec(stats->cmd, dev, stats, sizeof(struct ethtool_stats),
+			data, stats->n_stats);
+}
+
+static const struct ethtool_ops kcp_ethtool_ops = {
+	.begin			= kcp_check_if_running,
+	.get_drvinfo		= kcp_get_drvinfo,
+	.get_settings		= kcp_get_settings,
+	.set_settings		= kcp_set_settings,
+	.get_regs_len		= kcp_get_regs_len,
+	.get_regs		= kcp_get_regs,
+	.get_wol		= kcp_get_wol,
+	.set_wol		= kcp_set_wol,
+	.nway_reset		= kcp_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_eeprom_len		= kcp_get_eeprom_len,
+	.get_eeprom		= kcp_get_eeprom,
+	.set_eeprom		= kcp_set_eeprom,
+	.get_ringparam		= kcp_get_ringparam,
+	.set_ringparam		= kcp_set_ringparam,
+	.get_pauseparam		= kcp_get_pauseparam,
+	.set_pauseparam		= kcp_set_pauseparam,
+	.get_msglevel		= kcp_get_msglevel,
+	.set_msglevel		= kcp_set_msglevel,
+	.get_strings		= kcp_get_strings,
+	.get_sset_count		= kcp_get_sset_count,
+	.get_ethtool_stats	= kcp_get_ethtool_stats,
+};
+
+void kcp_set_ethtool_ops(struct net_device *netdev)
+{
+	netdev->ethtool_ops = &kcp_ethtool_ops;
+}
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_net.c b/lib/librte_eal/linuxapp/kcp/kcp_net.c
new file mode 100644
index 0000000..e1df901
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_net.c
@@ -0,0 +1,257 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <net/rtnetlink.h>
+
+#include "kcp_dev.h"
+
+/*
+ * Open and close
+ */
+static int kcp_net_open(struct net_device *dev)
+{
+	kcp_nl_exec(RTE_KCP_REQ_START_PORT, dev, NULL, 0, NULL, 0);
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int kcp_net_close(struct net_device *dev)
+{
+	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+	netif_stop_queue(dev); /* can't transmit any more */
+	return 0;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+static int kcp_net_config(struct net_device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP) /* can't act on a running interface */
+		return -EBUSY;
+
+	/* ignore other fields */
+	return 0;
+}
+
+static int
+kcp_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static int kcp_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int err = 0;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_CHANGE_MTU, dev, &new_mtu, sizeof(int),
+			NULL, 0);
+
+	if (err == 0)
+		dev->mtu = new_mtu;
+
+	return err;
+}
+
+/*
+ * Ioctl commands
+ */
+static int kcp_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	return 0;
+}
+
+/*
+ * Return statistics to the caller
+ */
+static struct rtnl_link_stats64 *kcp_net_stats64(struct net_device *dev,
+		struct rtnl_link_stats64 *stats)
+{
+	int err;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_GET_STATS, dev, NULL, 0,
+			stats, sizeof(struct rtnl_link_stats64));
+
+	return stats;
+}
+
+/*
+ * Change the Ethernet Address of the KCP NIC
+ */
+static int kcp_net_set_mac(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	int err = 0;
+
+	if (!is_valid_ether_addr((unsigned char *)(addr->sa_data)))
+		return -EADDRNOTAVAIL;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_SET_MAC, dev, addr->sa_data,
+			dev->addr_len, NULL, 0);
+	if (err < 0)
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	return 0;
+}
+
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+static int kcp_net_change_carrier(struct net_device *dev, bool new_carrier)
+{
+	if (new_carrier)
+		netif_carrier_on(dev);
+	else
+		netif_carrier_off(dev);
+	return 0;
+}
+#endif
+
+static const struct net_device_ops kcp_net_netdev_ops = {
+	.ndo_open = kcp_net_open,
+	.ndo_stop = kcp_net_close,
+	.ndo_set_config = kcp_net_config,
+	.ndo_start_xmit = kcp_net_xmit,
+	.ndo_change_mtu = kcp_net_change_mtu,
+	.ndo_do_ioctl = kcp_net_ioctl,
+	.ndo_get_stats64 = kcp_net_stats64,
+	.ndo_set_mac_address = kcp_net_set_mac,
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+	.ndo_change_carrier = kcp_net_change_carrier,
+#endif
+};
+
+/*
+ *  Fill the eth header
+ */
+static int kcp_net_header(struct sk_buff *skb, struct net_device *dev,
+		unsigned short type, const void *daddr, const void *saddr,
+		unsigned int len)
+{
+	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+
+	memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest,   daddr ? daddr : dev->dev_addr, dev->addr_len);
+	eth->h_proto = htons(type);
+
+	return dev->hard_header_len;
+}
+
+/*
+ * Re-fill the eth header
+ */
+#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
+static int
+kcp_net_rebuild_header(struct sk_buff *skb)
+{
+	struct net_device *dev = skb->dev;
+	struct ethhdr *eth = (struct ethhdr *) skb->data;
+
+	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+	memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
+
+	return 0;
+}
+#endif
+
+static const struct header_ops kcp_net_header_ops = {
+	.create  = kcp_net_header,
+#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
+	.rebuild = kcp_net_rebuild_header,
+#endif
+	.cache   = NULL,  /* disable caching */
+};
+
+static void kcp_net_setup(struct net_device *dev)
+{
+	struct kcp_dev *kcp;
+
+	ether_setup(dev);
+	dev->netdev_ops = &kcp_net_netdev_ops;
+	dev->header_ops = &kcp_net_header_ops;
+
+	kcp = netdev_priv(dev);
+	init_completion(&kcp->msg_received);
+
+	kcp_set_ethtool_ops(dev);
+
+	dev->flags |= IFF_UP;
+}
+
+static int kcp_net_newlink(struct net *net, struct net_device *dev,
+		struct nlattr *tb[], struct nlattr *data[])
+{
+	int ret;
+	struct kcp_dev *kcp;
+	char mac[ETH_ALEN] = {0};
+
+	kcp = netdev_priv(dev);
+
+	if (data && data[IFLA_KCP_PORTID])
+		kcp->port_id = nla_get_u8(data[IFLA_KCP_PORTID]);
+	else
+		kcp->port_id = 0;
+
+	if (data && data[IFLA_KCP_PID])
+		kcp->pid = nla_get_u32(data[IFLA_KCP_PID]);
+	else
+		kcp->pid = 0;
+
+	kcp_nl_exec(RTE_KCP_REQ_GET_MAC, dev, NULL, 0, mac, ETH_ALEN);
+	memcpy(dev->dev_addr, mac, dev->addr_len);
+
+	ret = register_netdevice(dev);
+
+	return ret;
+}
+
+static struct rtnl_link_ops kcp_link_ops __read_mostly = {
+	.kind = KCP_DEVICE,
+	.priv_size = sizeof(struct kcp_dev),
+	.setup = kcp_net_setup,
+	.maxtype = IFLA_KCP_MAX,
+	.newlink = kcp_net_newlink,
+};
+
+static int __init kcp_init(void)
+{
+	kcp_nl_init();
+	return rtnl_link_register(&kcp_link_ops);
+}
+module_init(kcp_init);
+
+static void __exit kcp_exit(void)
+{
+	rtnl_link_unregister(&kcp_link_ops);
+	kcp_nl_release();
+}
+module_exit(kcp_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Kernel Module for managing kcp devices");
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_nl.c b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
new file mode 100644
index 0000000..7d6faa8
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
@@ -0,0 +1,210 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <net/sock.h>
+
+#include "kcp_dev.h"
+
+static struct ethtool_input_buffer {
+	int magic;
+	void *buffer;
+	int length;
+	struct completion *msg_received;
+	int *err;
+	int in_use;
+} ethtool_input_buffer;
+
+static struct sock *nl_sock;
+static struct mutex sync_lock;
+
+static int kcp_input_buffer_register(int magic, void *buffer, int length,
+		struct completion *msg_received, int *err)
+{
+	if (ethtool_input_buffer.in_use == 0) {
+		ethtool_input_buffer.magic = magic;
+		ethtool_input_buffer.buffer = buffer;
+		ethtool_input_buffer.length = length;
+		ethtool_input_buffer.msg_received = msg_received;
+		ethtool_input_buffer.err = err;
+		ethtool_input_buffer.in_use = 1;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void kcp_input_buffer_unregister(int magic)
+{
+	if (ethtool_input_buffer.in_use == 1) {
+		if (magic == ethtool_input_buffer.magic) {
+			ethtool_input_buffer.magic = -1;
+			ethtool_input_buffer.buffer = NULL;
+			ethtool_input_buffer.length = 0;
+			ethtool_input_buffer.msg_received = NULL;
+			ethtool_input_buffer.err = NULL;
+			ethtool_input_buffer.in_use = 0;
+		} else {
+			KCP_ERR("Unregister magic mismatch\n");
+		}
+	}
+}
+
+static void nl_recv_user_request(struct kcp_ethtool_msg *ethtool_msg)
+{
+	KCP_DBG("Request from userspace received\n");
+}
+
+static void nl_recv_user_response(struct kcp_ethtool_msg *ethtool_msg)
+{
+	struct completion *msg_received;
+	int recv_len;
+	int expected_len;
+
+	if (ethtool_input_buffer.in_use == 1) {
+		if (ethtool_input_buffer.buffer != NULL) {
+			recv_len = ethtool_msg->output_buffer_len;
+			expected_len = ethtool_input_buffer.length;
+
+			memcpy(ethtool_input_buffer.buffer,
+					ethtool_msg->output_buffer,
+					ethtool_input_buffer.length);
+
+			if (ethtool_msg->err == 0 && recv_len != expected_len)
+				KCP_INFO("Expected and received not match"
+					"%d - %d\n", recv_len, expected_len);
+		}
+
+		*ethtool_input_buffer.err = ethtool_msg->err;
+		msg_received = ethtool_input_buffer.msg_received;
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		complete(msg_received);
+	}
+}
+
+static void nl_recv(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	nlh = (struct nlmsghdr *)skb->data;
+
+	memcpy(&ethtool_msg, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
+	KCP_DBG("CMD: %d\n", ethtool_msg.cmd_id);
+
+	if (ethtool_msg.flag & KCP_MSG_FLAG_REQUEST) {
+		nl_recv_user_request(&ethtool_msg);
+		return;
+	}
+
+	nl_recv_user_response(&ethtool_msg);
+}
+
+static int kcp_nl_send(int cmd_id, int port_id, unsigned int pid,
+		void *in_data, int in_data_len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	if (pid == 0)
+		return -1;
+
+	memset(&ethtool_msg, 0, sizeof(struct kcp_ethtool_msg));
+	ethtool_msg.cmd_id = cmd_id;
+	ethtool_msg.port_id = port_id;
+
+	if (in_data) {
+		if (in_data_len == 0 || in_data_len > KCP_ETHTOOL_MSG_LEN)
+			return -EINVAL;
+		ethtool_msg.input_buffer_len = in_data_len;
+		memcpy(ethtool_msg.input_buffer, in_data, in_data_len);
+	}
+
+	skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct kcp_ethtool_msg)),
+			GFP_ATOMIC);
+	nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, sizeof(struct kcp_ethtool_msg),
+			0);
+
+	NETLINK_CB(skb).dst_group = 0;
+
+	memcpy(nlmsg_data(nlh), &ethtool_msg, sizeof(struct kcp_ethtool_msg));
+
+	nlmsg_unicast(nl_sock, skb, pid);
+	KCP_DBG("Sent cmd:%d port:%d pid:%u\n", cmd_id, port_id, pid);
+
+	return 0;
+}
+
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data,
+		int in_data_len, void *out_data, int out_data_len)
+{
+	struct kcp_dev *priv = netdev_priv(dev);
+	int err = -EINVAL;
+	int ret;
+
+	if (out_data_len > KCP_ETHTOOL_MSG_LEN) {
+		KCP_ERR("Message is too big to receive:%u\n", out_data_len);
+		return err;
+	}
+
+	mutex_lock(&sync_lock);
+	ret = kcp_input_buffer_register(cmd, out_data, out_data_len,
+			&priv->msg_received, &err);
+	if (ret) {
+		mutex_unlock(&sync_lock);
+		return -EINVAL;
+	}
+
+	ret = kcp_nl_send(cmd, priv->port_id, priv->pid, in_data, in_data_len);
+	if (ret) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		return ret;
+	}
+
+	ret = wait_for_completion_interruptible_timeout(&priv->msg_received,
+			 msecs_to_jiffies(100));
+	if (ret == 0 || err < 0) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		return ret == 0 ? -EINVAL : err;
+	}
+	mutex_unlock(&sync_lock);
+
+	return 0;
+}
+
+static struct netlink_kernel_cfg cfg = {
+	.input = nl_recv,
+};
+
+void kcp_nl_init(void)
+{
+	nl_sock = netlink_kernel_create(&init_net, KCP_NL_GRP, &cfg);
+	mutex_init(&sync_lock);
+}
+
+void kcp_nl_release(void)
+{
+	netlink_kernel_release(nl_sock);
+}
-- 
2.5.0

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

* [PATCH v2 2/3] rte_ctrl_if: add control interface library
  2016-02-12 13:45 ` [PATCH v2 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
  2016-02-12 13:45   ` [PATCH v2 1/3] kcp: add kernel control path kernel module Ferruh Yigit
@ 2016-02-12 13:45   ` Ferruh Yigit
  2016-02-17 19:58     ` Ananyev, Konstantin
  2016-02-12 13:45   ` [PATCH v2 3/3] examples/ethtool: add control interface support to the application Ferruh Yigit
  2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  3 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-12 13:45 UTC (permalink / raw)
  To: dev

This library gets control messages form kernelspace and forwards them to
librte_ether and returns response back to the kernelspace.

Library does:
1) Trigger Linux virtual interface creation
2) Initialize the netlink socket communication
3) Provides process() API to the application that does processing the
received messages

This library requires corresponding kernel module to be inserted.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>

---

v2:
* User rtnetlink to create interfaces.
* Add more ethtool support: get/set ringparam, set pauseparam.
* return defined error instead of hardcoded value
---
 MAINTAINERS                                |   1 +
 config/common_linuxapp                     |   3 +-
 doc/api/doxy-api-index.md                  |   3 +-
 doc/api/doxy-api.conf                      |   1 +
 doc/guides/rel_notes/release_16_04.rst     |   9 +
 lib/Makefile                               |   3 +-
 lib/librte_ctrl_if/Makefile                |  58 ++++
 lib/librte_ctrl_if/rte_ctrl_if.c           | 385 ++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h           | 115 ++++++++
 lib/librte_ctrl_if/rte_ctrl_if_version.map |   9 +
 lib/librte_ctrl_if/rte_ethtool.c           | 450 +++++++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ethtool.h           |  54 ++++
 lib/librte_ctrl_if/rte_nl.c                | 274 ++++++++++++++++++
 lib/librte_ctrl_if/rte_nl.h                |  49 ++++
 lib/librte_eal/common/include/rte_log.h    |   3 +-
 mk/rte.app.mk                              |   3 +-
 16 files changed, 1415 insertions(+), 5 deletions(-)
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 09c56c7..91c98bc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -256,6 +256,7 @@ F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 Linux KCP
 M: Ferruh Yigit <ferruh.yigit@intel.com>
 F: lib/librte_eal/linuxapp/kcp/
+F: lib/librte_ctrl_if/
 
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 2f4eb1d..4bcd508 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -501,6 +501,7 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 #
 CONFIG_RTE_KCP_KMOD=y
 CONFIG_RTE_KCP_KO_DEBUG=n
+CONFIG_RTE_LIBRTE_CTRL_IF=y
 
 #
 # Compile vhost library
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 7a91001..214d16e 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -149,4 +149,5 @@ There are many libraries, so their headers may be grouped by topics:
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
   [keepalive]          (@ref rte_keepalive.h),
-  [version]            (@ref rte_version.h)
+  [version]            (@ref rte_version.h),
+  [control interface]  (@ref rte_ctrl_if.h)
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index 57e8b5d..fd69bf1 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -39,6 +39,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_cmdline \
                           lib/librte_compat \
                           lib/librte_cryptodev \
+                          lib/librte_ctrl_if \
                           lib/librte_distributor \
                           lib/librte_ether \
                           lib/librte_hash \
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 27fc624..1b1d34c 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -39,6 +39,14 @@ This section should contain new features added in this release. Sample format:
 
   Enabled virtio 1.0 support for virtio pmd driver.
 
+* **Control interface support added.**
+
+  To enable controlling DPDK ports by common Linux tools.
+  Following modules added to DPDK:
+
+  * librte_ctrl_if library
+  * librte_eal/linuxapp/kcp kernel module
+
 
 Resolved Issues
 ---------------
@@ -113,6 +121,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_acl.so.2
      librte_cfgfile.so.2
      librte_cmdline.so.1
+   + librte_ctrl_if.so.1
      librte_distributor.so.1
      librte_eal.so.2
      librte_hash.so.2
diff --git a/lib/Makefile b/lib/Makefile
index ef172ea..a50bc1e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
 DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_CTRL_IF) += librte_ctrl_if
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_ctrl_if/Makefile b/lib/librte_ctrl_if/Makefile
new file mode 100644
index 0000000..4e82966
--- /dev/null
+++ b/lib/librte_ctrl_if/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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_ctrl_if.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_ctrl_if_version.map
+
+LIBABIVER := 1
+
+SRCS-y += rte_ctrl_if.c
+SRCS-y += rte_nl.c
+SRCS-y += rte_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ctrl_if.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c
new file mode 100644
index 0000000..d16398f
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.c
@@ -0,0 +1,385 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <rte_ethdev.h>
+#include "rte_ctrl_if.h"
+#include "rte_nl.h"
+
+#define NAMESZ 32
+#define IFNAME "dpdk"
+#define BUFSZ 1024
+
+static int kcp_rtnl_fd = -1;
+static int kcp_fd_ref;
+
+struct kcp_request {
+	struct nlmsghdr nlmsg;
+	char buf[BUFSZ];
+};
+
+static int
+conrol_interface_rtnl_init(void)
+{
+	struct sockaddr_nl src;
+	int ret;
+
+	kcp_rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (kcp_rtnl_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF, "socket for create failed.\n");
+		return -1;
+	}
+
+	memset(&src, 0, sizeof(struct sockaddr_nl));
+
+	src.nl_family = AF_NETLINK;
+	src.nl_pid = getpid();
+
+	ret = bind(kcp_rtnl_fd, (struct sockaddr *)&src,
+			sizeof(struct sockaddr_nl));
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Bind for create failed.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+control_interface_init(void)
+{
+	int ret;
+
+	ret = conrol_interface_rtnl_init();
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize rtnetlink.\n");
+		return -1;
+	}
+
+	ret = control_interface_nl_init();
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink.\n");
+		close(kcp_rtnl_fd);
+		kcp_rtnl_fd = -1;
+	}
+
+	return ret;
+}
+
+static int
+control_interface_ref_get(void)
+{
+	int ret = 0;
+
+	if (kcp_fd_ref == 0)
+		ret = control_interface_init();
+
+	if (ret == 0)
+		kcp_fd_ref++;
+	else
+		RTE_LOG(ERR, CTRL_IF,
+				"Failed to initialize control interface.\n");
+
+	return kcp_fd_ref;
+}
+
+static void
+control_interface_release(void)
+{
+	close(kcp_rtnl_fd);
+	control_interface_nl_release();
+}
+
+static int
+control_interface_ref_put(void)
+{
+	if (kcp_fd_ref == 0)
+		return 0;
+
+	kcp_fd_ref--;
+
+	if (kcp_fd_ref == 0)
+		control_interface_release();
+
+	return kcp_fd_ref;
+}
+
+static int
+add_attr(struct kcp_request *req, unsigned short type, void *buf, size_t len)
+{
+	struct rtattr *rta;
+	int nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(len) > sizeof(struct kcp_request))
+		return -1;
+	rta->rta_type = type;
+	rta->rta_len = RTA_LENGTH(len);
+	memcpy(RTA_DATA(rta), buf, len);
+	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(len);
+
+	return 0;
+}
+
+static struct
+rtattr *add_attr_nested(struct kcp_request *req, unsigned short type)
+{
+	struct rtattr *rta;
+	int nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(0) > sizeof(struct kcp_request))
+		return NULL;
+	rta->rta_type = type;
+	rta->rta_len = nlmsg_len;
+	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(0);
+
+	return rta;
+}
+
+static void
+end_attr_nested(struct kcp_request *req, struct rtattr *rta)
+{
+	rta->rta_len = req->nlmsg.nlmsg_len - rta->rta_len;
+}
+
+static int
+rte_eth_rtnl_create(uint8_t port_id)
+{
+	struct kcp_request req;
+	struct ifinfomsg *info;
+	struct rtattr *rta1;
+	struct rtattr *rta2;
+	unsigned int pid = getpid();
+	char name[NAMESZ];
+	char type[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+	char buf[BUFSZ];
+
+	memset(&req, 0, sizeof(struct kcp_request));
+
+	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
+	req.nlmsg.nlmsg_flags |= NLM_F_ACK;
+	req.nlmsg.nlmsg_type = RTM_NEWLINK;
+
+	info = NLMSG_DATA(&req.nlmsg);
+
+	info->ifi_family = AF_UNSPEC;
+	info->ifi_index = 0;
+
+	snprintf(name, NAMESZ, IFNAME"%u", port_id);
+	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
+	if (ret < 0)
+		return -1;
+
+	rta1 = add_attr_nested(&req, IFLA_LINKINFO);
+	if (rta1 == NULL)
+		return -1;
+
+	snprintf(type, NAMESZ, KCP_DEVICE);
+	ret = add_attr(&req, IFLA_INFO_KIND, type, strlen(type) + 1);
+	if (ret < 0)
+		return -1;
+
+	rta2 = add_attr_nested(&req, IFLA_INFO_DATA);
+	if (rta2 == NULL)
+		return -1;
+
+	ret = add_attr(&req, IFLA_KCP_PORTID, &port_id, sizeof(uint8_t));
+	if (ret < 0)
+		return -1;
+
+	ret = add_attr(&req, IFLA_KCP_PID, &pid, sizeof(unsigned int));
+	if (ret < 0)
+		return -1;
+
+	end_attr_nested(&req, rta2);
+	end_attr_nested(&req, rta1);
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for create failed %d.\n", errno);
+		return -1;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	iov.iov_base = buf;
+	iov.iov_len = sizeof(buf);
+
+	ret = recvmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Recv for create failed.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+rte_eth_control_interface_create_one(uint8_t port_id)
+{
+	int ret;
+
+	if (control_interface_ref_get() != 0) {
+		ret = rte_eth_rtnl_create(port_id);
+		RTE_LOG(DEBUG, CTRL_IF,
+			"Control interface %s for port:%u\n",
+			ret < 0 ? "failed" : "created", port_id);
+	}
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_create(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			ret = rte_eth_control_interface_create_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int
+rte_eth_rtnl_destroy(uint8_t port_id)
+{
+	struct kcp_request req;
+	struct ifinfomsg *info;
+	char name[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+
+	memset(&req, 0, sizeof(struct kcp_request));
+
+	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlmsg.nlmsg_flags = NLM_F_REQUEST;
+	req.nlmsg.nlmsg_type = RTM_DELLINK;
+
+	info = NLMSG_DATA(&req.nlmsg);
+
+	info->ifi_family = AF_UNSPEC;
+	info->ifi_index = 0;
+
+	snprintf(name, NAMESZ, IFNAME"%u", port_id);
+	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
+	if (ret < 0)
+		return -1;
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for destroy failed.\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+rte_eth_control_interface_destroy_one(uint8_t port_id)
+{
+	rte_eth_rtnl_destroy(port_id);
+	control_interface_ref_put();
+	RTE_LOG(DEBUG, CTRL_IF, "Control interface destroyed for port:%u\n",
+			port_id);
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_destroy(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			ret = rte_eth_control_interface_destroy_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+int
+rte_eth_control_interface_process_msg(int flag, unsigned int timeout_sec)
+{
+	return control_interface_process_msg(flag, timeout_sec);
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.h b/lib/librte_ctrl_if/rte_ctrl_if.h
new file mode 100644
index 0000000..dcaf6dd
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.h
@@ -0,0 +1,115 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_CTRL_IF_H_
+#define _RTE_CTRL_IF_H_
+
+/**
+ * @file
+ *
+ * Control Interface Library for RTE
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <exec-env/rte_kcp_common.h>
+
+/**
+ * Flags values for rte_eth_control_interface_process_msg() API
+ */
+enum control_interface_process_flag {
+	/**< Process if msg available. */
+	RTE_ETHTOOL_CTRL_IF_PROCESS_MSG,
+
+	/**< Discard msg if available, respond with a error value. */
+	RTE_ETHTOOL_CTRL_IF_DISCARD_MSG,
+};
+
+/**
+ * Creates control interfaces (Linux virtual network interface)for
+ * each existing eal port.
+ *
+ * This API opens device created by supportive kernel module and initializes
+ * kernel communication interface.
+ *
+ * If supportive kernel module is not inserted this API will return
+ * an error.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_create(void);
+
+/**
+ * Destroys control interfaces.
+ *
+ * This API close device created by supportive kernel module and release
+ * underlying communication interface.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_destroy(void);
+
+/**
+ * Process if any received message is available.
+ *
+ * This function can be blocking or unblocking according timeout_sec
+ * parameter value. If function will be continuous loop, like can be
+ * called by any forwarding lcore, nonblocking mode should be preferred.
+ * If a separate thread created to handle control messages, blocking
+ * mode can be preferred to save CPU cycles.
+ *
+ * @param flag
+ *  Defines what to do with message, can be process or discard.
+ *
+ * @param timeout_sec
+ *  if 0, function is in nonblocking mode.
+ *  if > 0, blocks for given time, if there is no message available,
+ *  sleeps again same amount of time. Value is in seconds.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_process_msg(int flag, unsigned int timeout_sec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_IF_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if_version.map b/lib/librte_ctrl_if/rte_ctrl_if_version.map
new file mode 100644
index 0000000..8b27e26
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if_version.map
@@ -0,0 +1,9 @@
+DPDK_2.3 {
+	global:
+
+	rte_eth_control_interface_create;
+	rte_eth_control_interface_destroy;
+	rte_eth_control_interface_process_msg;
+
+	local: *;
+};
diff --git a/lib/librte_ctrl_if/rte_ethtool.c b/lib/librte_ctrl_if/rte_ethtool.c
new file mode 100644
index 0000000..def968a
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ethtool.c
@@ -0,0 +1,450 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <error.h>
+
+#include <linux/if_link.h>
+
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int
+get_drvinfo(int port_id, void *data, int *data_len)
+{
+	struct ethtool_drvinfo *info = data;
+	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(info->driver, sizeof(info->driver), "%s",
+		dev_info.driver_name);
+	snprintf(info->version, sizeof(info->version), "%s",
+		rte_version());
+	snprintf(info->bus_info, sizeof(info->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);
+	info->regdump_len = n < 0 ? 0 : n;
+
+	n = rte_eth_dev_get_eeprom_length(port_id);
+	info->eedump_len = n < 0 ? 0 : n;
+
+	info->n_stats = sizeof(struct rte_eth_stats) / sizeof(uint64_t);
+	info->testinfo_len = 0;
+
+	*data_len = sizeof(struct ethtool_drvinfo);
+
+	return 0;
+}
+
+static int
+get_reg_len(int port_id, void *data, int *data_len)
+{
+	int reg_length = 0;
+
+	reg_length = rte_eth_dev_get_reg_length(port_id);
+	if (reg_length < 0)
+		return reg_length;
+
+	*(int *)data = reg_length * sizeof(uint32_t);
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_reg(int port_id, void *in_data, void *out_data, int *out_data_len)
+{
+	unsigned int reg_length;
+	int reg_length_out_len;
+	struct ethtool_regs *ethtool_regs = in_data;
+	struct rte_dev_reg_info regs = {
+		.data = out_data,
+		.length = ethtool_regs->len,
+	};
+	int ret;
+
+	ret = get_reg_len(port_id, &reg_length, &reg_length_out_len);
+	if (ret < 0 || reg_length > ethtool_regs->len)
+		return -1;
+
+	ret = rte_eth_dev_get_reg_info(port_id, &regs);
+	if (ret < 0)
+		return ret;
+
+	ethtool_regs->version = regs.version;
+	*out_data_len = reg_length;
+
+	return 0;
+}
+
+static int
+get_link(int port_id, void *data, int *data_len)
+{
+	struct rte_eth_link link;
+
+	rte_eth_link_get(port_id, &link);
+
+	*(int *)data = link.link_status;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom_length(int port_id, void *data, int *data_len)
+{
+	int eeprom_length = 0;
+
+	eeprom_length = rte_eth_dev_get_eeprom_length(port_id);
+	if (eeprom_length < 0)
+		return eeprom_length;
+
+	*(int *)data = eeprom_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom(int port_id, void *in_data, void *out_data, int *out_data_len)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	struct rte_dev_eeprom_info eeprom_info = {
+		.data = out_data,
+		.offset = eeprom->offset,
+		.length = eeprom->len,
+	};
+	int ret;
+
+	ret = rte_eth_dev_get_eeprom(port_id, &eeprom_info);
+	if (ret < 0)
+		return ret;
+
+	eeprom->magic = eeprom_info.magic;
+	*out_data_len = eeprom->len;
+
+	return 0;
+}
+
+static int
+set_eeprom(int port_id, void *in_data)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	struct rte_dev_eeprom_info eeprom_info = {
+		.data = eeprom->data,
+		.offset = eeprom->offset,
+		.length = eeprom->len,
+	};
+	int ret;
+
+	ret = rte_eth_dev_set_eeprom(port_id, &eeprom_info);
+	if (ret < 0)
+		return ret;
+
+	eeprom->magic = eeprom_info.magic;
+
+	return 0;
+}
+
+static int
+get_ringparam(int port_id, void *data, int *data_len)
+{
+	struct ethtool_ringparam *ringparam = data;
+	struct rte_eth_dev_info dev_info;
+	struct rte_eth_rxq_info rx_qinfo;
+	struct rte_eth_txq_info tx_qinfo;
+	int ret;
+
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	ret = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+	if (ret != 0)
+		return -1;
+
+	ret = rte_eth_tx_queue_info_get(port_id, 0, &tx_qinfo);
+	if (ret != 0)
+		return -1;
+
+	memset(ringparam, 0, sizeof(struct ethtool_ringparam));
+	ringparam->rx_pending = rx_qinfo.nb_desc;
+	ringparam->rx_max_pending = dev_info.rx_desc_lim.nb_max;
+	ringparam->tx_pending = tx_qinfo.nb_desc;
+	ringparam->tx_max_pending = dev_info.tx_desc_lim.nb_max;
+
+	*data_len = sizeof(struct ethtool_ringparam);
+
+	return 0;
+}
+
+static int
+set_ringparam(int port_id, void *data)
+{
+	struct ethtool_ringparam *ringparam = data;
+	struct rte_eth_rxq_info rx_qinfo;
+	int ret;
+
+	ret = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+	if (ret != 0)
+		return -1;
+
+	rte_eth_dev_stop(port_id);
+
+	ret = rte_eth_tx_queue_setup(port_id, 0, ringparam->tx_pending,
+		rte_socket_id(), NULL);
+	if (ret != 0)
+		return -1;
+
+	ret = rte_eth_rx_queue_setup(port_id, 0, ringparam->rx_pending,
+		rte_socket_id(), NULL, rx_qinfo.mp);
+	if (ret != 0)
+		return -1;
+
+	return rte_eth_dev_start(port_id);
+}
+
+static int
+get_pauseparam(int port_id, void *data, int *data_len)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+	struct rte_eth_fc_conf fc_conf;
+	int ret;
+
+	ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (ret)
+		return -1;
+
+	pauseparam->tx_pause = 0;
+	pauseparam->rx_pause = 0;
+
+	switch (fc_conf.mode) {
+	case RTE_FC_RX_PAUSE:
+		pauseparam->rx_pause = 1;
+		break;
+	case RTE_FC_TX_PAUSE:
+		pauseparam->tx_pause = 1;
+		break;
+	case RTE_FC_FULL:
+		pauseparam->rx_pause = 1;
+		pauseparam->tx_pause = 1;
+	default:
+		break;
+	}
+	pauseparam->autoneg = (uint32_t)fc_conf.autoneg;
+
+	*data_len = sizeof(struct ethtool_pauseparam);
+
+	return 0;
+}
+
+static int
+set_pauseparam(int port_id, void *data)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+	struct rte_eth_fc_conf fc_conf;
+	int ret;
+
+	ret = rte_eth_dev_flow_ctrl_get(port_id, &fc_conf);
+	if (ret)
+		return -1;
+
+	fc_conf.autoneg = pauseparam->autoneg;
+
+	if (pauseparam->tx_pause) {
+		if (pauseparam->rx_pause)
+			fc_conf.mode = RTE_FC_FULL;
+		else
+			fc_conf.mode = RTE_FC_TX_PAUSE;
+	} else {
+		if (pauseparam->rx_pause)
+			fc_conf.mode = RTE_FC_RX_PAUSE;
+		else
+			fc_conf.mode = RTE_FC_NONE;
+	}
+
+	ret = rte_eth_dev_flow_ctrl_set(port_id, &fc_conf);
+	if (ret)
+		return -1;
+
+	return 0;
+}
+
+int
+rte_eth_dev_ethtool_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len)
+{
+	int ret = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case ETHTOOL_GDRVINFO:
+		return get_drvinfo(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS_LEN:
+		return get_reg_len(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS:
+		return get_reg(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_GLINK:
+		return get_link(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM_LEN:
+		return get_eeprom_length(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM:
+		return get_eeprom(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_SEEPROM:
+		return set_eeprom(port_id, in_data);
+	case ETHTOOL_GRINGPARAM:
+		return get_ringparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SRINGPARAM:
+		return set_ringparam(port_id, in_data);
+	case ETHTOOL_GPAUSEPARAM:
+		return get_pauseparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SPAUSEPARAM:
+		return set_pauseparam(port_id, in_data);
+	default:
+		ret = EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+set_mtu(int port_id, void *in_data)
+{
+	int *mtu = in_data;
+
+	return rte_eth_dev_set_mtu(port_id, *mtu);
+}
+
+static int
+get_stats(int port_id, void *data, int *data_len)
+{
+	struct rte_eth_stats stats;
+	struct rtnl_link_stats64 *if_stats = data;
+	int ret;
+
+	ret = rte_eth_stats_get(port_id, &stats);
+	if (ret < 0)
+		return -EOPNOTSUPP;
+
+	if_stats->rx_packets = stats.ipackets;
+	if_stats->tx_packets = stats.opackets;
+	if_stats->rx_bytes = stats.ibytes;
+	if_stats->tx_bytes = stats.obytes;
+	if_stats->rx_errors = stats.ierrors;
+	if_stats->tx_errors = stats.oerrors;
+	if_stats->rx_dropped = stats.imissed;
+	if_stats->multicast = stats.imcasts;
+
+	*data_len = sizeof(struct rtnl_link_stats64);
+
+	return 0;
+}
+
+static int
+get_mac(int port_id, void *data, int *data_len)
+{
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(port_id, &addr);
+	memcpy(data, &addr, sizeof(struct ether_addr));
+
+	*data_len = sizeof(struct ether_addr);
+
+	return 0;
+}
+
+static int
+set_mac(int port_id, void *in_data)
+{
+	struct ether_addr addr;
+
+	memcpy(&addr, in_data, ETHER_ADDR_LEN);
+
+	return rte_eth_dev_default_mac_addr_set(port_id, &addr);
+}
+
+static int
+start_port(int port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return rte_eth_dev_start(port_id);
+}
+
+static int
+stop_port(int port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return 0;
+}
+
+int
+rte_eth_dev_control_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len)
+{
+	int ret = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case RTE_KCP_REQ_CHANGE_MTU:
+		return set_mtu(port_id, in_data);
+	case RTE_KCP_REQ_GET_STATS:
+		return get_stats(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_GET_MAC:
+		return get_mac(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_SET_MAC:
+		return set_mac(port_id, in_data);
+	case RTE_KCP_REQ_START_PORT:
+		return start_port(port_id);
+	case RTE_KCP_REQ_STOP_PORT:
+		return stop_port(port_id);
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
diff --git a/lib/librte_ctrl_if/rte_ethtool.h b/lib/librte_ctrl_if/rte_ethtool.h
new file mode 100644
index 0000000..19f364f
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ethtool.h
@@ -0,0 +1,54 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/ethtool.h>
+
+#include <exec-env/rte_kcp_common.h>
+
+int rte_eth_dev_ethtool_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len);
+int rte_eth_dev_control_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETHTOOL_H_ */
diff --git a/lib/librte_ctrl_if/rte_nl.c b/lib/librte_ctrl_if/rte_nl.c
new file mode 100644
index 0000000..adc5fa8
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.c
@@ -0,0 +1,274 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <rte_spinlock.h>
+#include <rte_ethdev.h>
+#include "rte_ethtool.h"
+#include "rte_nl.h"
+#include "rte_ctrl_if.h"
+
+#define MAX_PAYLOAD sizeof(struct kcp_ethtool_msg)
+
+struct ctrl_if_nl {
+	union {
+		struct nlmsghdr nlh;
+		uint8_t nlmsg[NLMSG_SPACE(MAX_PAYLOAD)];
+	};
+	struct msghdr msg;
+	struct iovec iov;
+};
+
+static int sock_fd = -1;
+pthread_t thread_id;
+
+struct sockaddr_nl dest_addr;
+
+pthread_cond_t cond  = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t msg_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static struct ctrl_if_nl nl_s;
+static struct ctrl_if_nl nl_r;
+
+static int kcp_ethtool_msg_count;
+static struct kcp_ethtool_msg msg_storage;
+
+static int
+nl_send(void *buf, size_t len)
+{
+	int ret;
+
+	if (nl_s.nlh.nlmsg_len < len) {
+		RTE_LOG(ERR, CTRL_IF, "Message is too big, len:%zu\n", len);
+		return -1;
+	}
+
+	if (!NLMSG_OK(&nl_s.nlh, NLMSG_SPACE(MAX_PAYLOAD))) {
+		RTE_LOG(ERR, CTRL_IF, "Message is not OK\n");
+		return -1;
+	}
+
+	/* Fill in the netlink message payload */
+	memcpy(NLMSG_DATA(nl_s.nlmsg), buf, len);
+
+	ret = sendmsg(sock_fd, &nl_s.msg, 0);
+
+	if (ret < 0)
+		RTE_LOG(ERR, CTRL_IF, "Failed nl msg send. ret:%d, err:%d\n",
+				ret, errno);
+	return ret;
+}
+
+static int
+nl_ethtool_msg_send(struct kcp_ethtool_msg *msg)
+{
+	return nl_send((void *)msg, sizeof(struct kcp_ethtool_msg));
+}
+
+static void
+process_msg(struct kcp_ethtool_msg *msg)
+{
+	if (msg->cmd_id > RTE_KCP_REQ_UNKNOWN) {
+		msg->err = rte_eth_dev_control_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	} else {
+		msg->err = rte_eth_dev_ethtool_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	}
+
+	if (msg->err)
+		memset(msg->output_buffer, 0, msg->output_buffer_len);
+
+	nl_ethtool_msg_send(msg);
+}
+
+int
+control_interface_process_msg(int flag, unsigned int timeout_sec)
+{
+	int ret = 0;
+	struct timespec ts;
+
+	pthread_mutex_lock(&msg_lock);
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+	ts.tv_sec += timeout_sec;
+	while (timeout_sec && !kcp_ethtool_msg_count && !ret)
+		ret = pthread_cond_timedwait(&cond, &msg_lock, &ts);
+
+	switch (flag) {
+	case RTE_ETHTOOL_CTRL_IF_PROCESS_MSG:
+		if (kcp_ethtool_msg_count) {
+			process_msg(&msg_storage);
+			kcp_ethtool_msg_count = 0;
+		}
+		ret = 0;
+		break;
+
+	case RTE_ETHTOOL_CTRL_IF_DISCARD_MSG:
+		if (kcp_ethtool_msg_count) {
+			msg_storage.err = -1;
+			nl_ethtool_msg_send(&msg_storage);
+			kcp_ethtool_msg_count = 0;
+		}
+		ret = 0;
+		break;
+
+	default:
+		ret = -1;
+		break;
+	}
+	pthread_mutex_unlock(&msg_lock);
+
+	return ret;
+}
+
+static int
+msg_add_and_signal(struct nlmsghdr *nlh)
+{
+	pthread_mutex_lock(&msg_lock);
+
+	memcpy(&msg_storage, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
+	kcp_ethtool_msg_count = 1;
+	msg_storage.flag = KCP_MSG_FLAG_RESPONSE;
+
+	pthread_cond_signal(&cond);
+
+	pthread_mutex_unlock(&msg_lock);
+
+	return 0;
+}
+
+static void *
+nl_recv(void *arg)
+{
+	int ret;
+
+	for (;;) {
+		ret = recvmsg(sock_fd, &nl_r.msg, 0);
+		if (ret < 0)
+			continue;
+
+		if ((unsigned)ret < sizeof(struct kcp_ethtool_msg)) {
+			RTE_LOG(WARNING, CTRL_IF,
+					"Received %u bytes, payload %lu\n",
+					ret, sizeof(struct kcp_ethtool_msg));
+			continue;
+		}
+
+		msg_add_and_signal(&nl_r.nlh);
+	}
+
+	return arg;
+}
+
+static void
+nl_setup_header(struct ctrl_if_nl *nl)
+{
+	dest_addr.nl_family = AF_NETLINK;
+	dest_addr.nl_pid = 0;   /*  For Linux Kernel */
+	dest_addr.nl_groups = 0;
+
+	memset(nl->nlmsg, 0, NLMSG_SPACE(MAX_PAYLOAD));
+
+	/* Fill the netlink message header */
+	nl->nlh.nlmsg_len = NLMSG_LENGTH(MAX_PAYLOAD);
+	nl->nlh.nlmsg_pid = getpid();  /* self pid */
+	nl->nlh.nlmsg_flags = 0;
+
+	nl->iov.iov_base = (void *)nl->nlmsg;
+	nl->iov.iov_len = nl->nlh.nlmsg_len;
+	memset(&nl->msg, 0, sizeof(struct msghdr));
+	nl->msg.msg_name = (void *)&dest_addr;
+	nl->msg.msg_namelen = sizeof(struct sockaddr_nl);
+	nl->msg.msg_iov = &nl->iov;
+	nl->msg.msg_iovlen = 1;
+}
+
+static int
+nl_socket_init(void)
+{
+	struct sockaddr_nl src_addr;
+	int fd;
+	int ret;
+
+	fd = socket(PF_NETLINK, SOCK_RAW, KCP_NL_GRP);
+	if (fd < 0)
+		return -1;
+
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	ret = bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
+	if (ret) {
+		close(fd);
+		return -1;
+	}
+
+	nl_setup_header(&nl_s);
+	nl_setup_header(&nl_r);
+
+	return fd;
+}
+
+int
+control_interface_nl_init(void)
+{
+	int ret;
+
+	sock_fd = nl_socket_init();
+	if (sock_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink socket\n");
+		return -1;
+	}
+
+	ret = pthread_create(&thread_id, NULL, nl_recv, NULL);
+	if (ret != 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to create receive thread.\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void
+control_interface_nl_release(void)
+{
+	pthread_cancel(thread_id);
+	pthread_join(thread_id, NULL);
+	close(sock_fd);
+}
diff --git a/lib/librte_ctrl_if/rte_nl.h b/lib/librte_ctrl_if/rte_nl.h
new file mode 100644
index 0000000..ee06d90
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.h
@@ -0,0 +1,49 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_NL_H_
+#define _RTE_NL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int control_interface_nl_init(void);
+void control_interface_nl_release(void);
+int control_interface_process_msg(int flag, unsigned int timeout_sec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_NL_H_ */
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 2e47e7f..a0a2c9f 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
 #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
 #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
 #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#define RTE_LOGTYPE_CTRL_IF 0x00040000 /**< Log related to control interface. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8ecab41..e1638f0 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -122,6 +122,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF_OFFLOAD)   += -lrte_mbuf_offload
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CTRL_IF)        += -lrte_ctrl_if
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.5.0

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

* [PATCH v2 3/3] examples/ethtool: add control interface support to the application
  2016-02-12 13:45 ` [PATCH v2 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
  2016-02-12 13:45   ` [PATCH v2 1/3] kcp: add kernel control path kernel module Ferruh Yigit
  2016-02-12 13:45   ` [PATCH v2 2/3] rte_ctrl_if: add control interface library Ferruh Yigit
@ 2016-02-12 13:45   ` Ferruh Yigit
  2016-02-17 19:39     ` Ananyev, Konstantin
  2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  3 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-12 13:45 UTC (permalink / raw)
  To: dev

Control interface APIs added into the sample application.

To have the support corresponding kernel module (KCP) needs to be inserted.
If kernel module is not there, application will run as it is without
kernel control path support.

When KCP module inserted, running application creates a virtual Linux
network interface (dpdk$) per DPDK port. This interface can be used by
traditional Linux tools.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 doc/guides/sample_app_ug/ethtool.rst | 41 ++++++++++++++++++++++++++++++++++++
 examples/ethtool/ethtool-app/main.c  | 10 +++++++--
 2 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
index 4d1697e..2174288 100644
--- a/doc/guides/sample_app_ug/ethtool.rst
+++ b/doc/guides/sample_app_ug/ethtool.rst
@@ -131,6 +131,47 @@ application`_. Individual call-back functions handle the detail
 associated with each command, which make use of the functions
 defined in the `Ethtool interface`_ to the DPDK functions.
 
+Control Interface
+~~~~~~~~~~~~~~~~~
+
+If Kernel Control Path (KCP) kernel module (rte_kcp.ko) inserted,
+virtual interfaces created for each DPDK port for control purposes.
+
+Created interfaces are named as dpdk#, like:
+
+.. code-block:: console
+
+        # ifconfig dpdk0; ifconfig dpdk1
+        dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 90:e2:ba:0e:49:b9  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+        dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+Regular Linux commands can be issued on interfaces:
+
+.. code-block:: console
+
+        # ethtool -i dpdk0
+        driver: rte_ixgbe_pmd
+        version: RTE 2.3.0-rc0
+        firmware-version:
+        expansion-rom-version:
+        bus-info: 0000:08:00.1
+        supports-statistics: yes
+        supports-test: no
+        supports-eeprom-access: yes
+        supports-register-dump: yes
+        supports-priv-flags: no
+
 Ethtool interface
 -----------------
 
diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
index e21abcd..68b13ad 100644
--- a/examples/ethtool/ethtool-app/main.c
+++ b/examples/ethtool/ethtool-app/main.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <rte_memory.h>
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
+#include <rte_ctrl_if.h>
 
 #include "ethapp.h"
 
@@ -54,7 +55,6 @@
 #define PKTPOOL_EXTRA_SIZE 512
 #define PKTPOOL_CACHE 32
 
-
 struct txq_port {
 	uint16_t cnt_unsent;
 	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
@@ -254,6 +254,8 @@ static int slave_main(__attribute__((unused)) void *ptr_data)
 			}
 			rte_spinlock_unlock(&ptr_port->lock);
 		} /* end for( idx_port ) */
+		rte_eth_control_interface_process_msg(
+				RTE_ETHTOOL_CTRL_IF_PROCESS_MSG, 0);
 	} /* end for(;;) */
 
 	return 0;
@@ -293,6 +295,8 @@ int main(int argc, char **argv)
 	id_core = rte_get_next_lcore(id_core, 1, 1);
 	rte_eal_remote_launch(slave_main, NULL, id_core);
 
+	rte_eth_control_interface_create();
+
 	ethapp_main();
 
 	app_cfg.exit_now = 1;
@@ -301,5 +305,7 @@ int main(int argc, char **argv)
 			return -1;
 	}
 
+	rte_eth_control_interface_destroy();
+
 	return 0;
 }
-- 
2.5.0

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

* Re: [PATCH v2 3/3] examples/ethtool: add control interface support to the application
  2016-02-12 13:45   ` [PATCH v2 3/3] examples/ethtool: add control interface support to the application Ferruh Yigit
@ 2016-02-17 19:39     ` Ananyev, Konstantin
  2016-02-18 10:11       ` Yigit, Ferruh
  0 siblings, 1 reply; 83+ messages in thread
From: Ananyev, Konstantin @ 2016-02-17 19:39 UTC (permalink / raw)
  To: Yigit, Ferruh, dev

Hi Ferruh,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
> Sent: Friday, February 12, 2016 1:46 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v2 3/3] examples/ethtool: add control interface support to the application
> 
> Control interface APIs added into the sample application.
> 
> To have the support corresponding kernel module (KCP) needs to be inserted.
> If kernel module is not there, application will run as it is without
> kernel control path support.
> 
> When KCP module inserted, running application creates a virtual Linux
> network interface (dpdk$) per DPDK port. This interface can be used by
> traditional Linux tools.
> 
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> ---
>  doc/guides/sample_app_ug/ethtool.rst | 41 ++++++++++++++++++++++++++++++++++++
>  examples/ethtool/ethtool-app/main.c  | 10 +++++++--
>  2 files changed, 49 insertions(+), 2 deletions(-)
> 
> diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
> index 4d1697e..2174288 100644
> --- a/doc/guides/sample_app_ug/ethtool.rst
> +++ b/doc/guides/sample_app_ug/ethtool.rst
> @@ -131,6 +131,47 @@ application`_. Individual call-back functions handle the detail
>  associated with each command, which make use of the functions
>  defined in the `Ethtool interface`_ to the DPDK functions.

There is ~100% code duplication between
lib/librte_ctrl_if/rte_ethtool.c and examples/ethtool/lib/rte_ethtool.c
That need to be addressed somehow.

> 
> +Control Interface
> +~~~~~~~~~~~~~~~~~
> +
> +If Kernel Control Path (KCP) kernel module (rte_kcp.ko) inserted,
> +virtual interfaces created for each DPDK port for control purposes.
> +
> +Created interfaces are named as dpdk#, like:
> +
> +.. code-block:: console
> +
> +        # ifconfig dpdk0; ifconfig dpdk1
> +        dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
> +                ether 90:e2:ba:0e:49:b9  txqueuelen 1000  (Ethernet)
> +                RX packets 0  bytes 0 (0.0 B)
> +                RX errors 0  dropped 0  overruns 0  frame 0
> +                TX packets 0  bytes 0 (0.0 B)
> +                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
> +
> +        dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
> +                ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
> +                RX packets 0  bytes 0 (0.0 B)
> +                RX errors 0  dropped 0  overruns 0  frame 0
> +                TX packets 0  bytes 0 (0.0 B)
> +                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
> +
> +Regular Linux commands can be issued on interfaces:
> +
> +.. code-block:: console
> +
> +        # ethtool -i dpdk0
> +        driver: rte_ixgbe_pmd
> +        version: RTE 2.3.0-rc0
> +        firmware-version:
> +        expansion-rom-version:
> +        bus-info: 0000:08:00.1
> +        supports-statistics: yes
> +        supports-test: no
> +        supports-eeprom-access: yes
> +        supports-register-dump: yes
> +        supports-priv-flags: no
> +
>  Ethtool interface
>  -----------------
> 
> diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
> index e21abcd..68b13ad 100644
> --- a/examples/ethtool/ethtool-app/main.c
> +++ b/examples/ethtool/ethtool-app/main.c
> @@ -1,7 +1,7 @@
>  /*-
>   *   BSD LICENSE
>   *
> - *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
>   *   All rights reserved.
>   *
>   *   Redistribution and use in source and binary forms, with or without
> @@ -44,6 +44,7 @@
>  #include <rte_memory.h>
>  #include <rte_mempool.h>
>  #include <rte_mbuf.h>
> +#include <rte_ctrl_if.h>
> 
>  #include "ethapp.h"
> 
> @@ -54,7 +55,6 @@
>  #define PKTPOOL_EXTRA_SIZE 512
>  #define PKTPOOL_CACHE 32
> 
> -
>  struct txq_port {
>  	uint16_t cnt_unsent;
>  	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
> @@ -254,6 +254,8 @@ static int slave_main(__attribute__((unused)) void *ptr_data)
>  			}
>  			rte_spinlock_unlock(&ptr_port->lock);
>  		} /* end for( idx_port ) */
> +		rte_eth_control_interface_process_msg(
> +				RTE_ETHTOOL_CTRL_IF_PROCESS_MSG, 0);


As I can see, few problems here:
1. Race condition was introduced between slave_main() and ethapp_main() -
both can try to do dev_start()/dev_stop() or other intrusive things over the same port  
simultaneously.
2. Better to avoid calling rte_eth_control_interface_process_msg() from RT code path
     that doing RX/TX packets - it is too slow for that.
3. Right now - if you'll have to postpone any RX/TX on any ports when calling  rte_eth_control_interface_process_msg().
     As it can't distinguish message for what particular port it is going to process.
    Need to address it somehow - either add function that would return current message port_id,
   or introduce a sync callback function and add is a parameter for  rte_eth_control_interface_process_msg() ,
  or probably something else.

Konstantin
  

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

* Re: [PATCH v2 2/3] rte_ctrl_if: add control interface library
  2016-02-12 13:45   ` [PATCH v2 2/3] rte_ctrl_if: add control interface library Ferruh Yigit
@ 2016-02-17 19:58     ` Ananyev, Konstantin
  2016-02-18 10:43       ` Yigit, Ferruh
  0 siblings, 1 reply; 83+ messages in thread
From: Ananyev, Konstantin @ 2016-02-17 19:58 UTC (permalink / raw)
  To: Yigit, Ferruh, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
> Sent: Friday, February 12, 2016 1:46 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v2 2/3] rte_ctrl_if: add control interface library
> 
> This library gets control messages form kernelspace and forwards them to
> librte_ether and returns response back to the kernelspace.
> 
> Library does:
> 1) Trigger Linux virtual interface creation
> 2) Initialize the netlink socket communication
> 3) Provides process() API to the application that does processing the
> received messages
> 
> This library requires corresponding kernel module to be inserted.
> 
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> 
> ---
> 
> v2:
> * User rtnetlink to create interfaces.
> * Add more ethtool support: get/set ringparam, set pauseparam.
> * return defined error instead of hardcoded value
> ---
>  MAINTAINERS                                |   1 +
>  config/common_linuxapp                     |   3 +-
>  doc/api/doxy-api-index.md                  |   3 +-
>  doc/api/doxy-api.conf                      |   1 +
>  doc/guides/rel_notes/release_16_04.rst     |   9 +
>  lib/Makefile                               |   3 +-
>  lib/librte_ctrl_if/Makefile                |  58 ++++
>  lib/librte_ctrl_if/rte_ctrl_if.c           | 385 ++++++++++++++++++++++++
>  lib/librte_ctrl_if/rte_ctrl_if.h           | 115 ++++++++
>  lib/librte_ctrl_if/rte_ctrl_if_version.map |   9 +
>  lib/librte_ctrl_if/rte_ethtool.c           | 450 +++++++++++++++++++++++++++++
>  lib/librte_ctrl_if/rte_ethtool.h           |  54 ++++
>  lib/librte_ctrl_if/rte_nl.c                | 274 ++++++++++++++++++
>  lib/librte_ctrl_if/rte_nl.h                |  49 ++++
>  lib/librte_eal/common/include/rte_log.h    |   3 +-
>  mk/rte.app.mk                              |   3 +-
>  16 files changed, 1415 insertions(+), 5 deletions(-)
>  create mode 100644 lib/librte_ctrl_if/Makefile
>  create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
>  create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
>  create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
>  create mode 100644 lib/librte_ctrl_if/rte_ethtool.c
>  create mode 100644 lib/librte_ctrl_if/rte_ethtool.h
>  create mode 100644 lib/librte_ctrl_if/rte_nl.c
>  create mode 100644 lib/librte_ctrl_if/rte_nl.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 09c56c7..91c98bc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -256,6 +256,7 @@ F: doc/guides/sample_app_ug/kernel_nic_interface.rst
>  Linux KCP
>  M: Ferruh Yigit <ferruh.yigit@intel.com>
>  F: lib/librte_eal/linuxapp/kcp/
> +F: lib/librte_ctrl_if/
> 
>  Linux AF_PACKET
>  M: John W. Linville <linville@tuxdriver.com>
> diff --git a/config/common_linuxapp b/config/common_linuxapp
> index 2f4eb1d..4bcd508 100644
> --- a/config/common_linuxapp
> +++ b/config/common_linuxapp
> @@ -1,6 +1,6 @@
>  #   BSD LICENSE
>  #
> -#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> +#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
>  #   All rights reserved.
>  #
>  #   Redistribution and use in source and binary forms, with or without
> @@ -501,6 +501,7 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
>  #
>  CONFIG_RTE_KCP_KMOD=y
>  CONFIG_RTE_KCP_KO_DEBUG=n
> +CONFIG_RTE_LIBRTE_CTRL_IF=y
> 
>  #
>  # Compile vhost library
> diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
> index 7a91001..214d16e 100644
> --- a/doc/api/doxy-api-index.md
> +++ b/doc/api/doxy-api-index.md
> @@ -149,4 +149,5 @@ There are many libraries, so their headers may be grouped by topics:
>    [common]             (@ref rte_common.h),
>    [ABI compat]         (@ref rte_compat.h),
>    [keepalive]          (@ref rte_keepalive.h),
> -  [version]            (@ref rte_version.h)
> +  [version]            (@ref rte_version.h),
> +  [control interface]  (@ref rte_ctrl_if.h)
> diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
> index 57e8b5d..fd69bf1 100644
> --- a/doc/api/doxy-api.conf
> +++ b/doc/api/doxy-api.conf
> @@ -39,6 +39,7 @@ INPUT                   = doc/api/doxy-api-index.md \
>                            lib/librte_cmdline \
>                            lib/librte_compat \
>                            lib/librte_cryptodev \
> +                          lib/librte_ctrl_if \
>                            lib/librte_distributor \
>                            lib/librte_ether \
>                            lib/librte_hash \
> diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
> index 27fc624..1b1d34c 100644
> --- a/doc/guides/rel_notes/release_16_04.rst
> +++ b/doc/guides/rel_notes/release_16_04.rst
> @@ -39,6 +39,14 @@ This section should contain new features added in this release. Sample format:
> 
>    Enabled virtio 1.0 support for virtio pmd driver.
> 
> +* **Control interface support added.**
> +
> +  To enable controlling DPDK ports by common Linux tools.
> +  Following modules added to DPDK:
> +
> +  * librte_ctrl_if library
> +  * librte_eal/linuxapp/kcp kernel module
> +
> 
>  Resolved Issues
>  ---------------
> @@ -113,6 +121,7 @@ The libraries prepended with a plus sign were incremented in this version.
>       librte_acl.so.2
>       librte_cfgfile.so.2
>       librte_cmdline.so.1
> +   + librte_ctrl_if.so.1
>       librte_distributor.so.1
>       librte_eal.so.2
>       librte_hash.so.2
> diff --git a/lib/Makefile b/lib/Makefile
> index ef172ea..a50bc1e 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -1,6 +1,6 @@
>  #   BSD LICENSE
>  #
> -#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> +#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
>  #   All rights reserved.
>  #
>  #   Redistribution and use in source and binary forms, with or without
> @@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
>  DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
>  DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
>  DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
> +DIRS-$(CONFIG_RTE_LIBRTE_CTRL_IF) += librte_ctrl_if
> 
>  ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
>  DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
> diff --git a/lib/librte_ctrl_if/Makefile b/lib/librte_ctrl_if/Makefile
> new file mode 100644
> index 0000000..4e82966
> --- /dev/null
> +++ b/lib/librte_ctrl_if/Makefile
> @@ -0,0 +1,58 @@
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2016 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_ctrl_if.a
> +
> +CFLAGS += -O3
> +CFLAGS += $(WERROR_FLAGS)
> +
> +EXPORT_MAP := rte_ctrl_if_version.map
> +
> +LIBABIVER := 1
> +
> +SRCS-y += rte_ctrl_if.c
> +SRCS-y += rte_nl.c
> +SRCS-y += rte_ethtool.c
> +
> +#
> +# Export include files
> +#
> +SYMLINK-y-include += rte_ctrl_if.h
> +
> +# this lib depends upon:
> +DEPDIRS-y += lib/librte_ether
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c
> new file mode 100644
> index 0000000..d16398f
> --- /dev/null
> +++ b/lib/librte_ctrl_if/rte_ctrl_if.c
> @@ -0,0 +1,385 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2016 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 <fcntl.h>
> +#include <unistd.h>
> +#include <time.h>
> +
> +#include <sys/ioctl.h>
> +#include <sys/socket.h>
> +#include <linux/netlink.h>
> +#include <linux/rtnetlink.h>
> +
> +#include <rte_ethdev.h>
> +#include "rte_ctrl_if.h"
> +#include "rte_nl.h"
> +
> +#define NAMESZ 32
> +#define IFNAME "dpdk"
> +#define BUFSZ 1024
> +
> +static int kcp_rtnl_fd = -1;
> +static int kcp_fd_ref;
> +
> +struct kcp_request {
> +	struct nlmsghdr nlmsg;
> +	char buf[BUFSZ];
> +};
> +
> +static int
> +conrol_interface_rtnl_init(void)
> +{
> +	struct sockaddr_nl src;
> +	int ret;
> +
> +	kcp_rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
> +	if (kcp_rtnl_fd < 0) {
> +		RTE_LOG(ERR, CTRL_IF, "socket for create failed.\n");
> +		return -1;
> +	}
> +
> +	memset(&src, 0, sizeof(struct sockaddr_nl));
> +
> +	src.nl_family = AF_NETLINK;
> +	src.nl_pid = getpid();
> +
> +	ret = bind(kcp_rtnl_fd, (struct sockaddr *)&src,
> +			sizeof(struct sockaddr_nl));
> +	if (ret < 0) {
> +		RTE_LOG(ERR, CTRL_IF, "Bind for create failed.\n");
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +control_interface_init(void)
> +{
> +	int ret;
> +
> +	ret = conrol_interface_rtnl_init();
> +	if (ret < 0) {
> +		RTE_LOG(ERR, CTRL_IF, "Failed to initialize rtnetlink.\n");
> +		return -1;
> +	}
> +
> +	ret = control_interface_nl_init();
> +	if (ret < 0) {
> +		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink.\n");
> +		close(kcp_rtnl_fd);
> +		kcp_rtnl_fd = -1;
> +	}
> +
> +	return ret;
> +}
> +
> +static int
> +control_interface_ref_get(void)
> +{
> +	int ret = 0;
> +
> +	if (kcp_fd_ref == 0)
> +		ret = control_interface_init();
> +
> +	if (ret == 0)
> +		kcp_fd_ref++;
> +	else
> +		RTE_LOG(ERR, CTRL_IF,
> +				"Failed to initialize control interface.\n");
> +
> +	return kcp_fd_ref;
> +}
> +
> +static void
> +control_interface_release(void)
> +{
> +	close(kcp_rtnl_fd);
> +	control_interface_nl_release();
> +}
> +
> +static int
> +control_interface_ref_put(void)
> +{
> +	if (kcp_fd_ref == 0)
> +		return 0;
> +
> +	kcp_fd_ref--;
> +
> +	if (kcp_fd_ref == 0)
> +		control_interface_release();
> +
> +	return kcp_fd_ref;
> +}
> +
> +static int
> +add_attr(struct kcp_request *req, unsigned short type, void *buf, size_t len)
> +{
> +	struct rtattr *rta;
> +	int nlmsg_len;
> +
> +	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
> +	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
> +	if (nlmsg_len + RTA_LENGTH(len) > sizeof(struct kcp_request))
> +		return -1;
> +	rta->rta_type = type;
> +	rta->rta_len = RTA_LENGTH(len);
> +	memcpy(RTA_DATA(rta), buf, len);
> +	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(len);
> +
> +	return 0;
> +}
> +
> +static struct
> +rtattr *add_attr_nested(struct kcp_request *req, unsigned short type)
> +{
> +	struct rtattr *rta;
> +	int nlmsg_len;
> +
> +	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
> +	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
> +	if (nlmsg_len + RTA_LENGTH(0) > sizeof(struct kcp_request))
> +		return NULL;
> +	rta->rta_type = type;
> +	rta->rta_len = nlmsg_len;
> +	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(0);
> +
> +	return rta;
> +}
> +
> +static void
> +end_attr_nested(struct kcp_request *req, struct rtattr *rta)
> +{
> +	rta->rta_len = req->nlmsg.nlmsg_len - rta->rta_len;
> +}
> +
> +static int
> +rte_eth_rtnl_create(uint8_t port_id)
> +{
> +	struct kcp_request req;
> +	struct ifinfomsg *info;
> +	struct rtattr *rta1;
> +	struct rtattr *rta2;
> +	unsigned int pid = getpid();
> +	char name[NAMESZ];
> +	char type[NAMESZ];
> +	struct iovec iov;
> +	struct msghdr msg;
> +	struct sockaddr_nl nladdr;
> +	int ret;
> +	char buf[BUFSZ];
> +
> +	memset(&req, 0, sizeof(struct kcp_request));
> +
> +	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
> +	req.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
> +	req.nlmsg.nlmsg_flags |= NLM_F_ACK;
> +	req.nlmsg.nlmsg_type = RTM_NEWLINK;
> +
> +	info = NLMSG_DATA(&req.nlmsg);
> +
> +	info->ifi_family = AF_UNSPEC;
> +	info->ifi_index = 0;
> +
> +	snprintf(name, NAMESZ, IFNAME"%u", port_id);
> +	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
> +	if (ret < 0)
> +		return -1;
> +
> +	rta1 = add_attr_nested(&req, IFLA_LINKINFO);
> +	if (rta1 == NULL)
> +		return -1;
> +
> +	snprintf(type, NAMESZ, KCP_DEVICE);
> +	ret = add_attr(&req, IFLA_INFO_KIND, type, strlen(type) + 1);
> +	if (ret < 0)
> +		return -1;
> +
> +	rta2 = add_attr_nested(&req, IFLA_INFO_DATA);
> +	if (rta2 == NULL)
> +		return -1;
> +
> +	ret = add_attr(&req, IFLA_KCP_PORTID, &port_id, sizeof(uint8_t));
> +	if (ret < 0)
> +		return -1;
> +
> +	ret = add_attr(&req, IFLA_KCP_PID, &pid, sizeof(unsigned int));
> +	if (ret < 0)
> +		return -1;
> +
> +	end_attr_nested(&req, rta2);
> +	end_attr_nested(&req, rta1);
> +
> +	memset(&nladdr, 0, sizeof(nladdr));
> +	nladdr.nl_family = AF_NETLINK;
> +
> +	iov.iov_base = (void *)&req.nlmsg;
> +	iov.iov_len = req.nlmsg.nlmsg_len;
> +
> +	memset(&msg, 0, sizeof(struct msghdr));
> +	msg.msg_name = &nladdr;
> +	msg.msg_namelen = sizeof(nladdr);
> +	msg.msg_iov = &iov;
> +	msg.msg_iovlen = 1;
> +
> +	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
> +	if (ret < 0) {
> +		RTE_LOG(ERR, CTRL_IF, "Send for create failed %d.\n", errno);
> +		return -1;
> +	}
> +
> +	memset(buf, 0, sizeof(buf));
> +	iov.iov_base = buf;
> +	iov.iov_len = sizeof(buf);
> +
> +	ret = recvmsg(kcp_rtnl_fd, &msg, 0);
> +	if (ret < 0) {
> +		RTE_LOG(ERR, CTRL_IF, "Recv for create failed.\n");
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +

It is probably would be good to make
rte_eth_control_interface_create_one()/rte_eth_control_interface_destroy_one()
a public API, so the user can decide which ports to expose to KCP, which not.
If that is not possible by some reason - then seems no reason to keep 
control_interface_ref_get/ control_interface_ref_put.

> +static int
> +rte_eth_control_interface_create_one(uint8_t port_id)
> +{
> +	int ret;
> +
> +	if (control_interface_ref_get() != 0) {
> +		ret = rte_eth_rtnl_create(port_id);
> +		RTE_LOG(DEBUG, CTRL_IF,
> +			"Control interface %s for port:%u\n",
> +			ret < 0 ? "failed" : "created", port_id);
> +	}
> +
> +	return 0;
> +}
> +
> +int
> +rte_eth_control_interface_create(void)
> +{
> +	int i;
> +	int ret = 0;
> +
> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
> +		if (rte_eth_dev_is_valid_port(i)) {
> +			ret = rte_eth_control_interface_create_one(i);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int
> +rte_eth_rtnl_destroy(uint8_t port_id)
> +{
> +	struct kcp_request req;
> +	struct ifinfomsg *info;
> +	char name[NAMESZ];
> +	struct iovec iov;
> +	struct msghdr msg;
> +	struct sockaddr_nl nladdr;
> +	int ret;
> +
> +	memset(&req, 0, sizeof(struct kcp_request));
> +
> +	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
> +	req.nlmsg.nlmsg_flags = NLM_F_REQUEST;
> +	req.nlmsg.nlmsg_type = RTM_DELLINK;
> +
> +	info = NLMSG_DATA(&req.nlmsg);
> +
> +	info->ifi_family = AF_UNSPEC;
> +	info->ifi_index = 0;
> +
> +	snprintf(name, NAMESZ, IFNAME"%u", port_id);
> +	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
> +	if (ret < 0)
> +		return -1;
> +
> +	memset(&nladdr, 0, sizeof(nladdr));
> +	nladdr.nl_family = AF_NETLINK;
> +
> +	iov.iov_base = (void *)&req.nlmsg;
> +	iov.iov_len = req.nlmsg.nlmsg_len;
> +
> +	memset(&msg, 0, sizeof(struct msghdr));
> +	msg.msg_name = &nladdr;
> +	msg.msg_namelen = sizeof(nladdr);
> +	msg.msg_iov = &iov;
> +	msg.msg_iovlen = 1;
> +
> +	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
> +	if (ret < 0) {
> +		RTE_LOG(ERR, CTRL_IF, "Send for destroy failed.\n");
> +		return -1;
> +	}
> +	return 0;
> +}
> +
> +static int
> +rte_eth_control_interface_destroy_one(uint8_t port_id)
> +{
> +	rte_eth_rtnl_destroy(port_id);
> +	control_interface_ref_put();
> +	RTE_LOG(DEBUG, CTRL_IF, "Control interface destroyed for port:%u\n",
> +			port_id);
> +
> +	return 0;
> +}
> +
> +int
> +rte_eth_control_interface_destroy(void)
> +{
> +	int i;
> +	int ret = 0;
> +
> +	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
> +		if (rte_eth_dev_is_valid_port(i)) {
> +			ret = rte_eth_control_interface_destroy_one(i);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +int
> +rte_eth_control_interface_process_msg(int flag, unsigned int timeout_sec)
> +{
> +	return control_interface_process_msg(flag, timeout_sec);
> +}
> +};
....

> diff --git a/lib/librte_ctrl_if/rte_nl.c b/lib/librte_ctrl_if/rte_nl.c
> new file mode 100644
> index 0000000..adc5fa8
> --- /dev/null
> +++ b/lib/librte_ctrl_if/rte_nl.c
> @@ -0,0 +1,274 @@
> +/*-
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2016 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 <unistd.h>
> +
> +#include <sys/socket.h>
> +#include <linux/netlink.h>
> +
> +#include <rte_spinlock.h>
> +#include <rte_ethdev.h>
> +#include "rte_ethtool.h"
> +#include "rte_nl.h"
> +#include "rte_ctrl_if.h"
> +
> +#define MAX_PAYLOAD sizeof(struct kcp_ethtool_msg)
> +
> +struct ctrl_if_nl {
> +	union {
> +		struct nlmsghdr nlh;
> +		uint8_t nlmsg[NLMSG_SPACE(MAX_PAYLOAD)];
> +	};
> +	struct msghdr msg;
> +	struct iovec iov;
> +};
> +
> +static int sock_fd = -1;
> +pthread_t thread_id;
> +
> +struct sockaddr_nl dest_addr;
> +
> +pthread_cond_t cond  = PTHREAD_COND_INITIALIZER;
> +pthread_mutex_t msg_lock = PTHREAD_MUTEX_INITIALIZER;

Could you group related global variables into some struct.
Then at least people would realise what lock and cond are supposed to synchronise.
Another good thing to do - make them static, if possible. 

> +
> +static struct ctrl_if_nl nl_s;
> +static struct ctrl_if_nl nl_r;
> +
> +static int kcp_ethtool_msg_count;
> +static struct kcp_ethtool_msg msg_storage;
> +
> +static int
> +nl_send(void *buf, size_t len)
> +{
> +	int ret;
> +
> +	if (nl_s.nlh.nlmsg_len < len) {
> +		RTE_LOG(ERR, CTRL_IF, "Message is too big, len:%zu\n", len);
> +		return -1;
> +	}
> +
> +	if (!NLMSG_OK(&nl_s.nlh, NLMSG_SPACE(MAX_PAYLOAD))) {
> +		RTE_LOG(ERR, CTRL_IF, "Message is not OK\n");
> +		return -1;
> +	}
> +
> +	/* Fill in the netlink message payload */
> +	memcpy(NLMSG_DATA(nl_s.nlmsg), buf, len);
> +
> +	ret = sendmsg(sock_fd, &nl_s.msg, 0);
> +
> +	if (ret < 0)
> +		RTE_LOG(ERR, CTRL_IF, "Failed nl msg send. ret:%d, err:%d\n",
> +				ret, errno);
> +	return ret;
> +}
> +
> +static int
> +nl_ethtool_msg_send(struct kcp_ethtool_msg *msg)
> +{
> +	return nl_send((void *)msg, sizeof(struct kcp_ethtool_msg));
> +}
> +
> +static void
> +process_msg(struct kcp_ethtool_msg *msg)
> +{
> +	if (msg->cmd_id > RTE_KCP_REQ_UNKNOWN) {
> +		msg->err = rte_eth_dev_control_process(msg->cmd_id,
> +				msg->port_id, msg->input_buffer,
> +				msg->output_buffer, &msg->output_buffer_len);
> +	} else {
> +		msg->err = rte_eth_dev_ethtool_process(msg->cmd_id,
> +				msg->port_id, msg->input_buffer,
> +				msg->output_buffer, &msg->output_buffer_len);
> +	}
> +
> +	if (msg->err)
> +		memset(msg->output_buffer, 0, msg->output_buffer_len);
> +
> +	nl_ethtool_msg_send(msg);
> +}
> +
> +int
> +control_interface_process_msg(int flag, unsigned int timeout_sec)
> +{
> +	int ret = 0;
> +	struct timespec ts;
> +
> +	pthread_mutex_lock(&msg_lock);
> +
> +	clock_gettime(CLOCK_REALTIME, &ts);
> +	ts.tv_sec += timeout_sec;
> +	while (timeout_sec && !kcp_ethtool_msg_count && !ret)
> +		ret = pthread_cond_timedwait(&cond, &msg_lock, &ts);


Better to avoid holding lock while calling process_msg().
That is a good programming practice, as msg_lock protects only contents of the msg_storage.
Again if by some reason process() would take a while, wouldn't stop your control thread. 
lock(); copy_message_into_local_buffer; unlock(); process();

> +
> +	switch (flag) {
> +	case RTE_ETHTOOL_CTRL_IF_PROCESS_MSG:
> +		if (kcp_ethtool_msg_count) {
> +			process_msg(&msg_storage);
> +			kcp_ethtool_msg_count = 0;
> +		}
> +		ret = 0;
> +		break;
> +
> +	case RTE_ETHTOOL_CTRL_IF_DISCARD_MSG:
> +		if (kcp_ethtool_msg_count) {
> +			msg_storage.err = -1;
> +			nl_ethtool_msg_send(&msg_storage);
> +			kcp_ethtool_msg_count = 0;
> +		}
> +		ret = 0;
> +		break;
> +
> +	default:
> +		ret = -1;
> +		break;
> +	}
> +	pthread_mutex_unlock(&msg_lock);
> +
> +	return ret;
> +}
> +

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

* Re: [PATCH v2 3/3] examples/ethtool: add control interface support to the application
  2016-02-17 19:39     ` Ananyev, Konstantin
@ 2016-02-18 10:11       ` Yigit, Ferruh
  0 siblings, 0 replies; 83+ messages in thread
From: Yigit, Ferruh @ 2016-02-18 10:11 UTC (permalink / raw)
  To: Ananyev, Konstantin; +Cc: dev

On Wed, Feb 17, 2016 at 07:39:05PM +0000, Ananyev, Konstantin wrote:
> Hi Ferruh,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
> > Sent: Friday, February 12, 2016 1:46 PM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH v2 3/3] examples/ethtool: add control interface support to the application
> > 
> > Control interface APIs added into the sample application.
> > 
> > To have the support corresponding kernel module (KCP) needs to be inserted.
> > If kernel module is not there, application will run as it is without
> > kernel control path support.
> > 
> > When KCP module inserted, running application creates a virtual Linux
> > network interface (dpdk$) per DPDK port. This interface can be used by
> > traditional Linux tools.
> > 
> > Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> > ---
> >  doc/guides/sample_app_ug/ethtool.rst | 41 ++++++++++++++++++++++++++++++++++++
> >  examples/ethtool/ethtool-app/main.c  | 10 +++++++--
> >  2 files changed, 49 insertions(+), 2 deletions(-)
> > 
> > diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
> > index 4d1697e..2174288 100644
> > --- a/doc/guides/sample_app_ug/ethtool.rst
> > +++ b/doc/guides/sample_app_ug/ethtool.rst
> > @@ -131,6 +131,47 @@ application`_. Individual call-back functions handle the detail
> >  associated with each command, which make use of the functions
> >  defined in the `Ethtool interface`_ to the DPDK functions.
> 
> There is ~100% code duplication between
> lib/librte_ctrl_if/rte_ethtool.c and examples/ethtool/lib/rte_ethtool.c
> That need to be addressed somehow.
> 
Yes you are right, there is dublication.
In next revision, I will move examples/ethtool/lib to lib/ folder
and update according both ctrl_if library and ethtool sample app use it

> > 
> > +Control Interface
> > +~~~~~~~~~~~~~~~~~
> > +
> > +If Kernel Control Path (KCP) kernel module (rte_kcp.ko) inserted,
> > +virtual interfaces created for each DPDK port for control purposes.
> > +
> > +Created interfaces are named as dpdk#, like:
> > +
> > +.. code-block:: console
> > +
> > +        # ifconfig dpdk0; ifconfig dpdk1
> > +        dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
> > +                ether 90:e2:ba:0e:49:b9  txqueuelen 1000  (Ethernet)
> > +                RX packets 0  bytes 0 (0.0 B)
> > +                RX errors 0  dropped 0  overruns 0  frame 0
> > +                TX packets 0  bytes 0 (0.0 B)
> > +                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
> > +
> > +        dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
> > +                ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
> > +                RX packets 0  bytes 0 (0.0 B)
> > +                RX errors 0  dropped 0  overruns 0  frame 0
> > +                TX packets 0  bytes 0 (0.0 B)
> > +                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
> > +
> > +Regular Linux commands can be issued on interfaces:
> > +
> > +.. code-block:: console
> > +
> > +        # ethtool -i dpdk0
> > +        driver: rte_ixgbe_pmd
> > +        version: RTE 2.3.0-rc0
> > +        firmware-version:
> > +        expansion-rom-version:
> > +        bus-info: 0000:08:00.1
> > +        supports-statistics: yes
> > +        supports-test: no
> > +        supports-eeprom-access: yes
> > +        supports-register-dump: yes
> > +        supports-priv-flags: no
> > +
> >  Ethtool interface
> >  -----------------
> > 
> > diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
> > index e21abcd..68b13ad 100644
> > --- a/examples/ethtool/ethtool-app/main.c
> > +++ b/examples/ethtool/ethtool-app/main.c
> > @@ -1,7 +1,7 @@
> >  /*-
> >   *   BSD LICENSE
> >   *
> > - *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> > + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> >   *   All rights reserved.
> >   *
> >   *   Redistribution and use in source and binary forms, with or without
> > @@ -44,6 +44,7 @@
> >  #include <rte_memory.h>
> >  #include <rte_mempool.h>
> >  #include <rte_mbuf.h>
> > +#include <rte_ctrl_if.h>
> > 
> >  #include "ethapp.h"
> > 
> > @@ -54,7 +55,6 @@
> >  #define PKTPOOL_EXTRA_SIZE 512
> >  #define PKTPOOL_CACHE 32
> > 
> > -
> >  struct txq_port {
> >  	uint16_t cnt_unsent;
> >  	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
> > @@ -254,6 +254,8 @@ static int slave_main(__attribute__((unused)) void *ptr_data)
> >  			}
> >  			rte_spinlock_unlock(&ptr_port->lock);
> >  		} /* end for( idx_port ) */
> > +		rte_eth_control_interface_process_msg(
> > +				RTE_ETHTOOL_CTRL_IF_PROCESS_MSG, 0);
> 
> 
> As I can see, few problems here:
> 1. Race condition was introduced between slave_main() and ethapp_main() -
> both can try to do dev_start()/dev_stop() or other intrusive things over the same port  
> simultaneously.
> 2. Better to avoid calling rte_eth_control_interface_process_msg() from RT code path
>      that doing RX/TX packets - it is too slow for that.
> 3. Right now - if you'll have to postpone any RX/TX on any ports when calling  rte_eth_control_interface_process_msg().
>      As it can't distinguish message for what particular port it is going to process.
>     Need to address it somehow - either add function that would return current message port_id,
>    or introduce a sync callback function and add is a parameter for  rte_eth_control_interface_process_msg() ,
>   or probably something else.
> 
I will address these in next version of the patch.

Thanks for the comments,
ferruh

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

* Re: [PATCH v2 2/3] rte_ctrl_if: add control interface library
  2016-02-17 19:58     ` Ananyev, Konstantin
@ 2016-02-18 10:43       ` Yigit, Ferruh
  0 siblings, 0 replies; 83+ messages in thread
From: Yigit, Ferruh @ 2016-02-18 10:43 UTC (permalink / raw)
  To: Ananyev, Konstantin; +Cc: dev

On Wed, Feb 17, 2016 at 07:58:16PM +0000, Ananyev, Konstantin wrote:
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
> > Sent: Friday, February 12, 2016 1:46 PM
> > To: dev@dpdk.org
> > Subject: [dpdk-dev] [PATCH v2 2/3] rte_ctrl_if: add control interface library
> > 
> > This library gets control messages form kernelspace and forwards them to
> > librte_ether and returns response back to the kernelspace.
> > 
> > Library does:
> > 1) Trigger Linux virtual interface creation
> > 2) Initialize the netlink socket communication
> > 3) Provides process() API to the application that does processing the
> > received messages
> > 
> > This library requires corresponding kernel module to be inserted.
> > 
> > Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> > 
> > ---
> > 
> > v2:
> > * User rtnetlink to create interfaces.
> > * Add more ethtool support: get/set ringparam, set pauseparam.
> > * return defined error instead of hardcoded value
> > ---
> >  MAINTAINERS                                |   1 +
> >  config/common_linuxapp                     |   3 +-
> >  doc/api/doxy-api-index.md                  |   3 +-
> >  doc/api/doxy-api.conf                      |   1 +
> >  doc/guides/rel_notes/release_16_04.rst     |   9 +
> >  lib/Makefile                               |   3 +-
> >  lib/librte_ctrl_if/Makefile                |  58 ++++
> >  lib/librte_ctrl_if/rte_ctrl_if.c           | 385 ++++++++++++++++++++++++
> >  lib/librte_ctrl_if/rte_ctrl_if.h           | 115 ++++++++
> >  lib/librte_ctrl_if/rte_ctrl_if_version.map |   9 +
> >  lib/librte_ctrl_if/rte_ethtool.c           | 450 +++++++++++++++++++++++++++++
> >  lib/librte_ctrl_if/rte_ethtool.h           |  54 ++++
> >  lib/librte_ctrl_if/rte_nl.c                | 274 ++++++++++++++++++
> >  lib/librte_ctrl_if/rte_nl.h                |  49 ++++
> >  lib/librte_eal/common/include/rte_log.h    |   3 +-
> >  mk/rte.app.mk                              |   3 +-
> >  16 files changed, 1415 insertions(+), 5 deletions(-)
> >  create mode 100644 lib/librte_ctrl_if/Makefile
> >  create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
> >  create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
> >  create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
> >  create mode 100644 lib/librte_ctrl_if/rte_ethtool.c
> >  create mode 100644 lib/librte_ctrl_if/rte_ethtool.h
> >  create mode 100644 lib/librte_ctrl_if/rte_nl.c
> >  create mode 100644 lib/librte_ctrl_if/rte_nl.h
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 09c56c7..91c98bc 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -256,6 +256,7 @@ F: doc/guides/sample_app_ug/kernel_nic_interface.rst
> >  Linux KCP
> >  M: Ferruh Yigit <ferruh.yigit@intel.com>
> >  F: lib/librte_eal/linuxapp/kcp/
> > +F: lib/librte_ctrl_if/
> > 
> >  Linux AF_PACKET
> >  M: John W. Linville <linville@tuxdriver.com>
> > diff --git a/config/common_linuxapp b/config/common_linuxapp
> > index 2f4eb1d..4bcd508 100644
> > --- a/config/common_linuxapp
> > +++ b/config/common_linuxapp
> > @@ -1,6 +1,6 @@
> >  #   BSD LICENSE
> >  #
> > -#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> > +#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
> >  #   All rights reserved.
> >  #
> >  #   Redistribution and use in source and binary forms, with or without
> > @@ -501,6 +501,7 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
> >  #
> >  CONFIG_RTE_KCP_KMOD=y
> >  CONFIG_RTE_KCP_KO_DEBUG=n
> > +CONFIG_RTE_LIBRTE_CTRL_IF=y
> > 
> >  #
> >  # Compile vhost library
> > diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
> > index 7a91001..214d16e 100644
> > --- a/doc/api/doxy-api-index.md
> > +++ b/doc/api/doxy-api-index.md
> > @@ -149,4 +149,5 @@ There are many libraries, so their headers may be grouped by topics:
> >    [common]             (@ref rte_common.h),
> >    [ABI compat]         (@ref rte_compat.h),
> >    [keepalive]          (@ref rte_keepalive.h),
> > -  [version]            (@ref rte_version.h)
> > +  [version]            (@ref rte_version.h),
> > +  [control interface]  (@ref rte_ctrl_if.h)
> > diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
> > index 57e8b5d..fd69bf1 100644
> > --- a/doc/api/doxy-api.conf
> > +++ b/doc/api/doxy-api.conf
> > @@ -39,6 +39,7 @@ INPUT                   = doc/api/doxy-api-index.md \
> >                            lib/librte_cmdline \
> >                            lib/librte_compat \
> >                            lib/librte_cryptodev \
> > +                          lib/librte_ctrl_if \
> >                            lib/librte_distributor \
> >                            lib/librte_ether \
> >                            lib/librte_hash \
> > diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
> > index 27fc624..1b1d34c 100644
> > --- a/doc/guides/rel_notes/release_16_04.rst
> > +++ b/doc/guides/rel_notes/release_16_04.rst
> > @@ -39,6 +39,14 @@ This section should contain new features added in this release. Sample format:
> > 
> >    Enabled virtio 1.0 support for virtio pmd driver.
> > 
> > +* **Control interface support added.**
> > +
> > +  To enable controlling DPDK ports by common Linux tools.
> > +  Following modules added to DPDK:
> > +
> > +  * librte_ctrl_if library
> > +  * librte_eal/linuxapp/kcp kernel module
> > +
> > 
> >  Resolved Issues
> >  ---------------
> > @@ -113,6 +121,7 @@ The libraries prepended with a plus sign were incremented in this version.
> >       librte_acl.so.2
> >       librte_cfgfile.so.2
> >       librte_cmdline.so.1
> > +   + librte_ctrl_if.so.1
> >       librte_distributor.so.1
> >       librte_eal.so.2
> >       librte_hash.so.2
> > diff --git a/lib/Makefile b/lib/Makefile
> > index ef172ea..a50bc1e 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -1,6 +1,6 @@
> >  #   BSD LICENSE
> >  #
> > -#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> > +#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
> >  #   All rights reserved.
> >  #
> >  #   Redistribution and use in source and binary forms, with or without
> > @@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
> >  DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
> >  DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
> >  DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
> > +DIRS-$(CONFIG_RTE_LIBRTE_CTRL_IF) += librte_ctrl_if
> > 
> >  ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
> >  DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
> > diff --git a/lib/librte_ctrl_if/Makefile b/lib/librte_ctrl_if/Makefile
> > new file mode 100644
> > index 0000000..4e82966
> > --- /dev/null
> > +++ b/lib/librte_ctrl_if/Makefile
> > @@ -0,0 +1,58 @@
> > +#   BSD LICENSE
> > +#
> > +#   Copyright(c) 2016 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_ctrl_if.a
> > +
> > +CFLAGS += -O3
> > +CFLAGS += $(WERROR_FLAGS)
> > +
> > +EXPORT_MAP := rte_ctrl_if_version.map
> > +
> > +LIBABIVER := 1
> > +
> > +SRCS-y += rte_ctrl_if.c
> > +SRCS-y += rte_nl.c
> > +SRCS-y += rte_ethtool.c
> > +
> > +#
> > +# Export include files
> > +#
> > +SYMLINK-y-include += rte_ctrl_if.h
> > +
> > +# this lib depends upon:
> > +DEPDIRS-y += lib/librte_ether
> > +
> > +include $(RTE_SDK)/mk/rte.lib.mk
> > diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c
> > new file mode 100644
> > index 0000000..d16398f
> > --- /dev/null
> > +++ b/lib/librte_ctrl_if/rte_ctrl_if.c
> > @@ -0,0 +1,385 @@
> > +/*-
> > + *   BSD LICENSE
> > + *
> > + *   Copyright(c) 2016 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 <fcntl.h>
> > +#include <unistd.h>
> > +#include <time.h>
> > +
> > +#include <sys/ioctl.h>
> > +#include <sys/socket.h>
> > +#include <linux/netlink.h>
> > +#include <linux/rtnetlink.h>
> > +
> > +#include <rte_ethdev.h>
> > +#include "rte_ctrl_if.h"
> > +#include "rte_nl.h"
> > +
> > +#define NAMESZ 32
> > +#define IFNAME "dpdk"
> > +#define BUFSZ 1024
> > +
> > +static int kcp_rtnl_fd = -1;
> > +static int kcp_fd_ref;
> > +
> > +struct kcp_request {
> > +	struct nlmsghdr nlmsg;
> > +	char buf[BUFSZ];
> > +};
> > +
> > +static int
> > +conrol_interface_rtnl_init(void)
> > +{
> > +	struct sockaddr_nl src;
> > +	int ret;
> > +
> > +	kcp_rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
> > +	if (kcp_rtnl_fd < 0) {
> > +		RTE_LOG(ERR, CTRL_IF, "socket for create failed.\n");
> > +		return -1;
> > +	}
> > +
> > +	memset(&src, 0, sizeof(struct sockaddr_nl));
> > +
> > +	src.nl_family = AF_NETLINK;
> > +	src.nl_pid = getpid();
> > +
> > +	ret = bind(kcp_rtnl_fd, (struct sockaddr *)&src,
> > +			sizeof(struct sockaddr_nl));
> > +	if (ret < 0) {
> > +		RTE_LOG(ERR, CTRL_IF, "Bind for create failed.\n");
> > +		return -1;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int
> > +control_interface_init(void)
> > +{
> > +	int ret;
> > +
> > +	ret = conrol_interface_rtnl_init();
> > +	if (ret < 0) {
> > +		RTE_LOG(ERR, CTRL_IF, "Failed to initialize rtnetlink.\n");
> > +		return -1;
> > +	}
> > +
> > +	ret = control_interface_nl_init();
> > +	if (ret < 0) {
> > +		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink.\n");
> > +		close(kcp_rtnl_fd);
> > +		kcp_rtnl_fd = -1;
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static int
> > +control_interface_ref_get(void)
> > +{
> > +	int ret = 0;
> > +
> > +	if (kcp_fd_ref == 0)
> > +		ret = control_interface_init();
> > +
> > +	if (ret == 0)
> > +		kcp_fd_ref++;
> > +	else
> > +		RTE_LOG(ERR, CTRL_IF,
> > +				"Failed to initialize control interface.\n");
> > +
> > +	return kcp_fd_ref;
> > +}
> > +
> > +static void
> > +control_interface_release(void)
> > +{
> > +	close(kcp_rtnl_fd);
> > +	control_interface_nl_release();
> > +}
> > +
> > +static int
> > +control_interface_ref_put(void)
> > +{
> > +	if (kcp_fd_ref == 0)
> > +		return 0;
> > +
> > +	kcp_fd_ref--;
> > +
> > +	if (kcp_fd_ref == 0)
> > +		control_interface_release();
> > +
> > +	return kcp_fd_ref;
> > +}
> > +
> > +static int
> > +add_attr(struct kcp_request *req, unsigned short type, void *buf, size_t len)
> > +{
> > +	struct rtattr *rta;
> > +	int nlmsg_len;
> > +
> > +	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
> > +	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
> > +	if (nlmsg_len + RTA_LENGTH(len) > sizeof(struct kcp_request))
> > +		return -1;
> > +	rta->rta_type = type;
> > +	rta->rta_len = RTA_LENGTH(len);
> > +	memcpy(RTA_DATA(rta), buf, len);
> > +	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(len);
> > +
> > +	return 0;
> > +}
> > +
> > +static struct
> > +rtattr *add_attr_nested(struct kcp_request *req, unsigned short type)
> > +{
> > +	struct rtattr *rta;
> > +	int nlmsg_len;
> > +
> > +	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
> > +	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
> > +	if (nlmsg_len + RTA_LENGTH(0) > sizeof(struct kcp_request))
> > +		return NULL;
> > +	rta->rta_type = type;
> > +	rta->rta_len = nlmsg_len;
> > +	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(0);
> > +
> > +	return rta;
> > +}
> > +
> > +static void
> > +end_attr_nested(struct kcp_request *req, struct rtattr *rta)
> > +{
> > +	rta->rta_len = req->nlmsg.nlmsg_len - rta->rta_len;
> > +}
> > +
> > +static int
> > +rte_eth_rtnl_create(uint8_t port_id)
> > +{
> > +	struct kcp_request req;
> > +	struct ifinfomsg *info;
> > +	struct rtattr *rta1;
> > +	struct rtattr *rta2;
> > +	unsigned int pid = getpid();
> > +	char name[NAMESZ];
> > +	char type[NAMESZ];
> > +	struct iovec iov;
> > +	struct msghdr msg;
> > +	struct sockaddr_nl nladdr;
> > +	int ret;
> > +	char buf[BUFSZ];
> > +
> > +	memset(&req, 0, sizeof(struct kcp_request));
> > +
> > +	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
> > +	req.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
> > +	req.nlmsg.nlmsg_flags |= NLM_F_ACK;
> > +	req.nlmsg.nlmsg_type = RTM_NEWLINK;
> > +
> > +	info = NLMSG_DATA(&req.nlmsg);
> > +
> > +	info->ifi_family = AF_UNSPEC;
> > +	info->ifi_index = 0;
> > +
> > +	snprintf(name, NAMESZ, IFNAME"%u", port_id);
> > +	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
> > +	if (ret < 0)
> > +		return -1;
> > +
> > +	rta1 = add_attr_nested(&req, IFLA_LINKINFO);
> > +	if (rta1 == NULL)
> > +		return -1;
> > +
> > +	snprintf(type, NAMESZ, KCP_DEVICE);
> > +	ret = add_attr(&req, IFLA_INFO_KIND, type, strlen(type) + 1);
> > +	if (ret < 0)
> > +		return -1;
> > +
> > +	rta2 = add_attr_nested(&req, IFLA_INFO_DATA);
> > +	if (rta2 == NULL)
> > +		return -1;
> > +
> > +	ret = add_attr(&req, IFLA_KCP_PORTID, &port_id, sizeof(uint8_t));
> > +	if (ret < 0)
> > +		return -1;
> > +
> > +	ret = add_attr(&req, IFLA_KCP_PID, &pid, sizeof(unsigned int));
> > +	if (ret < 0)
> > +		return -1;
> > +
> > +	end_attr_nested(&req, rta2);
> > +	end_attr_nested(&req, rta1);
> > +
> > +	memset(&nladdr, 0, sizeof(nladdr));
> > +	nladdr.nl_family = AF_NETLINK;
> > +
> > +	iov.iov_base = (void *)&req.nlmsg;
> > +	iov.iov_len = req.nlmsg.nlmsg_len;
> > +
> > +	memset(&msg, 0, sizeof(struct msghdr));
> > +	msg.msg_name = &nladdr;
> > +	msg.msg_namelen = sizeof(nladdr);
> > +	msg.msg_iov = &iov;
> > +	msg.msg_iovlen = 1;
> > +
> > +	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
> > +	if (ret < 0) {
> > +		RTE_LOG(ERR, CTRL_IF, "Send for create failed %d.\n", errno);
> > +		return -1;
> > +	}
> > +
> > +	memset(buf, 0, sizeof(buf));
> > +	iov.iov_base = buf;
> > +	iov.iov_len = sizeof(buf);
> > +
> > +	ret = recvmsg(kcp_rtnl_fd, &msg, 0);
> > +	if (ret < 0) {
> > +		RTE_LOG(ERR, CTRL_IF, "Recv for create failed.\n");
> > +		return -1;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> 
> It is probably would be good to make
> rte_eth_control_interface_create_one()/rte_eth_control_interface_destroy_one()
> a public API, so the user can decide which ports to expose to KCP, which not.
> If that is not possible by some reason - then seems no reason to keep 
> control_interface_ref_get/ control_interface_ref_put.
> 
It is easy to make them public, they are already as seperate functions,
but my concern is to make it more complex, right now this lib has only three APIs: create, destroy, process; simple.
and there is no overhead of having all interface instead of one.
When they are added as API, it is hard to remove them, is it OK if we kept as it is, and add those APIs if there is any demand?

> > +static int
> > +rte_eth_control_interface_create_one(uint8_t port_id)
> > +{
> > +	int ret;
> > +
> > +	if (control_interface_ref_get() != 0) {
> > +		ret = rte_eth_rtnl_create(port_id);
> > +		RTE_LOG(DEBUG, CTRL_IF,
> > +			"Control interface %s for port:%u\n",
> > +			ret < 0 ? "failed" : "created", port_id);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int
> > +rte_eth_control_interface_create(void)
> > +{
> > +	int i;
> > +	int ret = 0;
> > +
> > +	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
> > +		if (rte_eth_dev_is_valid_port(i)) {
> > +			ret = rte_eth_control_interface_create_one(i);
> > +			if (ret < 0)
> > +				return ret;
> > +		}
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +static int
> > +rte_eth_rtnl_destroy(uint8_t port_id)
> > +{
> > +	struct kcp_request req;
> > +	struct ifinfomsg *info;
> > +	char name[NAMESZ];
> > +	struct iovec iov;
> > +	struct msghdr msg;
> > +	struct sockaddr_nl nladdr;
> > +	int ret;
> > +
> > +	memset(&req, 0, sizeof(struct kcp_request));
> > +
> > +	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
> > +	req.nlmsg.nlmsg_flags = NLM_F_REQUEST;
> > +	req.nlmsg.nlmsg_type = RTM_DELLINK;
> > +
> > +	info = NLMSG_DATA(&req.nlmsg);
> > +
> > +	info->ifi_family = AF_UNSPEC;
> > +	info->ifi_index = 0;
> > +
> > +	snprintf(name, NAMESZ, IFNAME"%u", port_id);
> > +	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
> > +	if (ret < 0)
> > +		return -1;
> > +
> > +	memset(&nladdr, 0, sizeof(nladdr));
> > +	nladdr.nl_family = AF_NETLINK;
> > +
> > +	iov.iov_base = (void *)&req.nlmsg;
> > +	iov.iov_len = req.nlmsg.nlmsg_len;
> > +
> > +	memset(&msg, 0, sizeof(struct msghdr));
> > +	msg.msg_name = &nladdr;
> > +	msg.msg_namelen = sizeof(nladdr);
> > +	msg.msg_iov = &iov;
> > +	msg.msg_iovlen = 1;
> > +
> > +	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
> > +	if (ret < 0) {
> > +		RTE_LOG(ERR, CTRL_IF, "Send for destroy failed.\n");
> > +		return -1;
> > +	}
> > +	return 0;
> > +}
> > +
> > +static int
> > +rte_eth_control_interface_destroy_one(uint8_t port_id)
> > +{
> > +	rte_eth_rtnl_destroy(port_id);
> > +	control_interface_ref_put();
> > +	RTE_LOG(DEBUG, CTRL_IF, "Control interface destroyed for port:%u\n",
> > +			port_id);
> > +
> > +	return 0;
> > +}
> > +
> > +int
> > +rte_eth_control_interface_destroy(void)
> > +{
> > +	int i;
> > +	int ret = 0;
> > +
> > +	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
> > +		if (rte_eth_dev_is_valid_port(i)) {
> > +			ret = rte_eth_control_interface_destroy_one(i);
> > +			if (ret < 0)
> > +				return ret;
> > +		}
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> > +int
> > +rte_eth_control_interface_process_msg(int flag, unsigned int timeout_sec)
> > +{
> > +	return control_interface_process_msg(flag, timeout_sec);
> > +}
> > +};
> ....
> 
> > diff --git a/lib/librte_ctrl_if/rte_nl.c b/lib/librte_ctrl_if/rte_nl.c
> > new file mode 100644
> > index 0000000..adc5fa8
> > --- /dev/null
> > +++ b/lib/librte_ctrl_if/rte_nl.c
> > @@ -0,0 +1,274 @@
> > +/*-
> > + *   BSD LICENSE
> > + *
> > + *   Copyright(c) 2016 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 <unistd.h>
> > +
> > +#include <sys/socket.h>
> > +#include <linux/netlink.h>
> > +
> > +#include <rte_spinlock.h>
> > +#include <rte_ethdev.h>
> > +#include "rte_ethtool.h"
> > +#include "rte_nl.h"
> > +#include "rte_ctrl_if.h"
> > +
> > +#define MAX_PAYLOAD sizeof(struct kcp_ethtool_msg)
> > +
> > +struct ctrl_if_nl {
> > +	union {
> > +		struct nlmsghdr nlh;
> > +		uint8_t nlmsg[NLMSG_SPACE(MAX_PAYLOAD)];
> > +	};
> > +	struct msghdr msg;
> > +	struct iovec iov;
> > +};
> > +
> > +static int sock_fd = -1;
> > +pthread_t thread_id;
> > +
> > +struct sockaddr_nl dest_addr;
> > +
> > +pthread_cond_t cond  = PTHREAD_COND_INITIALIZER;
> > +pthread_mutex_t msg_lock = PTHREAD_MUTEX_INITIALIZER;
> 
> Could you group related global variables into some struct.
> Then at least people would realise what lock and cond are supposed to synchronise.
OK

> Another good thing to do - make them static, if possible. 
> 
Right, I will make them static.

> > +
> > +static struct ctrl_if_nl nl_s;
> > +static struct ctrl_if_nl nl_r;
> > +
> > +static int kcp_ethtool_msg_count;
> > +static struct kcp_ethtool_msg msg_storage;
> > +
> > +static int
> > +nl_send(void *buf, size_t len)
> > +{
> > +	int ret;
> > +
> > +	if (nl_s.nlh.nlmsg_len < len) {
> > +		RTE_LOG(ERR, CTRL_IF, "Message is too big, len:%zu\n", len);
> > +		return -1;
> > +	}
> > +
> > +	if (!NLMSG_OK(&nl_s.nlh, NLMSG_SPACE(MAX_PAYLOAD))) {
> > +		RTE_LOG(ERR, CTRL_IF, "Message is not OK\n");
> > +		return -1;
> > +	}
> > +
> > +	/* Fill in the netlink message payload */
> > +	memcpy(NLMSG_DATA(nl_s.nlmsg), buf, len);
> > +
> > +	ret = sendmsg(sock_fd, &nl_s.msg, 0);
> > +
> > +	if (ret < 0)
> > +		RTE_LOG(ERR, CTRL_IF, "Failed nl msg send. ret:%d, err:%d\n",
> > +				ret, errno);
> > +	return ret;
> > +}
> > +
> > +static int
> > +nl_ethtool_msg_send(struct kcp_ethtool_msg *msg)
> > +{
> > +	return nl_send((void *)msg, sizeof(struct kcp_ethtool_msg));
> > +}
> > +
> > +static void
> > +process_msg(struct kcp_ethtool_msg *msg)
> > +{
> > +	if (msg->cmd_id > RTE_KCP_REQ_UNKNOWN) {
> > +		msg->err = rte_eth_dev_control_process(msg->cmd_id,
> > +				msg->port_id, msg->input_buffer,
> > +				msg->output_buffer, &msg->output_buffer_len);
> > +	} else {
> > +		msg->err = rte_eth_dev_ethtool_process(msg->cmd_id,
> > +				msg->port_id, msg->input_buffer,
> > +				msg->output_buffer, &msg->output_buffer_len);
> > +	}
> > +
> > +	if (msg->err)
> > +		memset(msg->output_buffer, 0, msg->output_buffer_len);
> > +
> > +	nl_ethtool_msg_send(msg);
> > +}
> > +
> > +int
> > +control_interface_process_msg(int flag, unsigned int timeout_sec)
> > +{
> > +	int ret = 0;
> > +	struct timespec ts;
> > +
> > +	pthread_mutex_lock(&msg_lock);
> > +
> > +	clock_gettime(CLOCK_REALTIME, &ts);
> > +	ts.tv_sec += timeout_sec;
> > +	while (timeout_sec && !kcp_ethtool_msg_count && !ret)
> > +		ret = pthread_cond_timedwait(&cond, &msg_lock, &ts);
> 
> 
> Better to avoid holding lock while calling process_msg().
> That is a good programming practice, as msg_lock protects only contents of the msg_storage.
> Again if by some reason process() would take a while, wouldn't stop your control thread. 
> lock(); copy_message_into_local_buffer; unlock(); process();
> 
OK

> > +
> > +	switch (flag) {
> > +	case RTE_ETHTOOL_CTRL_IF_PROCESS_MSG:
> > +		if (kcp_ethtool_msg_count) {
> > +			process_msg(&msg_storage);
> > +			kcp_ethtool_msg_count = 0;
> > +		}
> > +		ret = 0;
> > +		break;
> > +
> > +	case RTE_ETHTOOL_CTRL_IF_DISCARD_MSG:
> > +		if (kcp_ethtool_msg_count) {
> > +			msg_storage.err = -1;
> > +			nl_ethtool_msg_send(&msg_storage);
> > +			kcp_ethtool_msg_count = 0;
> > +		}
> > +		ret = 0;
> > +		break;
> > +
> > +	default:
> > +		ret = -1;
> > +		break;
> > +	}
> > +	pthread_mutex_unlock(&msg_lock);
> > +
> > +	return ret;
> > +}
> > +

Thanks,
ferruh

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

* [PATCH v3 0/4] Use common Linux tools to control DPDK ports
  2016-02-12 13:45 ` [PATCH v2 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
                     ` (2 preceding siblings ...)
  2016-02-12 13:45   ` [PATCH v2 3/3] examples/ethtool: add control interface support to the application Ferruh Yigit
@ 2016-02-26 14:10   ` Ferruh Yigit
  2016-02-26 14:10     ` [PATCH v3 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
                       ` (5 more replies)
  3 siblings, 6 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-26 14:10 UTC (permalink / raw)
  To: dev

This work is to make DPDK ports more visible and to enable using common
Linux tools to configure DPDK ports.

Patch is based on KNI but contains only control functionality of it,
also this patch does not include any Linux kernel network driver as
part of it.

Basically with the help of a kernel module (KCP), virtual Linux network
interfaces named as "dpdk$" are created per DPDK port, control messages
sent to these virtual interfaces are forwarded to DPDK, and response
sent back to Linux application.

Virtual interfaces created when DPDK application started and destroyed
automatically when DPDK application terminated.

Communication between kernel-space and DPDK done using netlink socket.

Currently implementation is not complete, sample support added for the
RFC, more functionality can be added based on community response.

With this RFC Patch, supported: get/set mac address/mtu of DPDK devices,
getting stats from DPDK devices and some set of ethtool commands.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

v3:
* Kernel side changes:
  * Devices are not up by default
  * Add enable/disable promisc, allmulti support
  * Increase timeout to 500ms and print log when a command timedout
* Control library changes:
  * Use librte_ethtool
  * Don't create interfaces for virtual PMDs
  * Add a new API ...msg_exist() to support port based locking
  * Add enable/disable promisc, allmulti support
* Example changes:
  * Use blocking mode control interface processing, instead of poll mode

v2:
* Use rtnetlink to create interfaces
* Add more ethtool support: get/set ringparam, set pauseparam.
* fix ethtool get/set eeprom
* lots of minor updates, enhancements in the code


Samples:

$ ifconfig
dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 90:e2:ba:0e:49:b8  txqueuelen 1000  (Ethernet)
        RX packets 33  bytes 2058 (2.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 33  bytes 2058 (2.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

After some traffic on port 0:

$ ifconfig
dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether 90:e2:ba:0e:49:77  txqueuelen 1000  (Ethernet)
        RX packets 962  bytes 57798 (56.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 962  bytes 57798 (56.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


$ ethtool -i dpdk0
driver: rte_ixgbe_pmd
version: DPDK 16.04.0-rc0
firmware-version: 
expansion-rom-version: 
bus-info: 0000:08:00.0
supports-statistics: no
supports-test: no
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no


$ ethtool -e dpdk0 offset 20 length 10
Offset          Values
------          ------
0x0014:         b7 01 bf 01 c7 01 cf 01 09 02 


$ ip l show dpdk0
25: dpdk0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:b8 brd ff:ff:ff:ff:ff:ff

$ ip l set dpdk0 addr 90:e2:ba:0e:49:77

$ ip l show dpdk0
25: dpdk0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:77 brd ff:ff:ff:ff:ff:ff

Ferruh Yigit (4):
  lib/librte_ethtool: move librte_ethtool form examples to lib folder
  kcp: add kernel control path kernel module
  rte_ctrl_if: add control interface library
  examples/ethtool: add control interface support to the application

 MAINTAINERS                                        |   5 +
 config/common_linuxapp                             |  14 +-
 doc/api/doxy-api-index.md                          |   4 +-
 doc/api/doxy-api.conf                              |   2 +
 doc/api/examples.dox                               |   5 +-
 doc/guides/prog_guide/ctrl_if_lib.rst              |  52 ++
 doc/guides/prog_guide/ethtool_lib.rst              |  62 ++
 doc/guides/prog_guide/index.rst                    |   4 +-
 doc/guides/rel_notes/release_16_04.rst             |  10 +
 doc/guides/sample_app_ug/ethtool.rst               |  77 +-
 examples/ethtool/Makefile                          |  24 +-
 examples/ethtool/ethapp.c                          | 873 +++++++++++++++++++++
 examples/ethtool/ethapp.h                          |  41 +
 examples/ethtool/ethtool-app/Makefile              |  54 --
 examples/ethtool/ethtool-app/ethapp.c              | 873 ---------------------
 examples/ethtool/ethtool-app/ethapp.h              |  41 -
 examples/ethtool/ethtool-app/main.c                | 305 -------
 examples/ethtool/lib/Makefile                      |  57 --
 examples/ethtool/lib/rte_ethtool.c                 | 423 ----------
 examples/ethtool/lib/rte_ethtool.h                 | 410 ----------
 examples/ethtool/main.c                            | 332 ++++++++
 lib/Makefile                                       |   4 +-
 lib/librte_ctrl_if/Makefile                        |  58 ++
 lib/librte_ctrl_if/rte_ctrl_ethtool.c              | 376 +++++++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.h              |  54 ++
 lib/librte_ctrl_if/rte_ctrl_if.c                   | 395 ++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h                   | 129 +++
 lib/librte_ctrl_if/rte_ctrl_if_version.map         |  10 +
 lib/librte_ctrl_if/rte_nl.c                        | 313 ++++++++
 lib/librte_ctrl_if/rte_nl.h                        |  50 ++
 lib/librte_eal/common/include/rte_log.h            |   3 +-
 lib/librte_eal/linuxapp/Makefile                   |   5 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h | 109 +++
 lib/librte_eal/linuxapp/kcp/Makefile               |  57 ++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  54 ++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 300 +++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 225 ++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 215 +++++
 lib/librte_ethtool/Makefile                        |  57 ++
 lib/librte_ethtool/rte_ethtool.c                   | 423 ++++++++++
 lib/librte_ethtool/rte_ethtool.h                   | 413 ++++++++++
 lib/librte_ethtool/rte_ethtool_version.map         |  28 +
 mk/rte.app.mk                                      |   4 +-
 44 files changed, 4738 insertions(+), 2215 deletions(-)
 create mode 100644 doc/guides/prog_guide/ctrl_if_lib.rst
 create mode 100644 doc/guides/prog_guide/ethtool_lib.rst
 create mode 100644 examples/ethtool/ethapp.c
 create mode 100644 examples/ethtool/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/Makefile
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.c
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/main.c
 delete mode 100644 examples/ethtool/lib/Makefile
 delete mode 100644 examples/ethtool/lib/rte_ethtool.c
 delete mode 100644 examples/ethtool/lib/rte_ethtool.h
 create mode 100644 examples/ethtool/main.c
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c
 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.5.0

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

* [PATCH v3 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder
  2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
@ 2016-02-26 14:10     ` Ferruh Yigit
  2016-02-26 14:10     ` [PATCH v3 2/4] kcp: add kernel control path kernel module Ferruh Yigit
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-26 14:10 UTC (permalink / raw)
  To: dev

With KCP, examples/ethtool/lib/ethtool has two users, to prevent code
dublication, moving library from examples folder into lib/ folder.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---
 config/common_linuxapp                     |   5 +
 doc/api/doxy-api-index.md                  |   3 +-
 doc/api/doxy-api.conf                      |   1 +
 doc/api/examples.dox                       |   5 +-
 doc/guides/prog_guide/ethtool_lib.rst      |  62 ++
 doc/guides/prog_guide/index.rst            |   3 +-
 doc/guides/rel_notes/release_16_04.rst     |   1 +
 doc/guides/sample_app_ug/ethtool.rst       |  36 +-
 examples/ethtool/Makefile                  |  24 +-
 examples/ethtool/ethapp.c                  | 873 +++++++++++++++++++++++++++++
 examples/ethtool/ethapp.h                  |  41 ++
 examples/ethtool/ethtool-app/Makefile      |  54 --
 examples/ethtool/ethtool-app/ethapp.c      | 873 -----------------------------
 examples/ethtool/ethtool-app/ethapp.h      |  41 --
 examples/ethtool/ethtool-app/main.c        | 305 ----------
 examples/ethtool/lib/Makefile              |  57 --
 examples/ethtool/lib/rte_ethtool.c         | 423 --------------
 examples/ethtool/lib/rte_ethtool.h         | 410 --------------
 examples/ethtool/main.c                    | 305 ++++++++++
 lib/Makefile                               |   1 +
 lib/librte_ethtool/Makefile                |  57 ++
 lib/librte_ethtool/rte_ethtool.c           | 423 ++++++++++++++
 lib/librte_ethtool/rte_ethtool.h           | 413 ++++++++++++++
 lib/librte_ethtool/rte_ethtool_version.map |  28 +
 mk/rte.app.mk                              |   1 +
 25 files changed, 2236 insertions(+), 2209 deletions(-)
 create mode 100644 doc/guides/prog_guide/ethtool_lib.rst
 create mode 100644 examples/ethtool/ethapp.c
 create mode 100644 examples/ethtool/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/Makefile
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.c
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/main.c
 delete mode 100644 examples/ethtool/lib/Makefile
 delete mode 100644 examples/ethtool/lib/rte_ethtool.c
 delete mode 100644 examples/ethtool/lib/rte_ethtool.h
 create mode 100644 examples/ethtool/main.c
 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/config/common_linuxapp b/config/common_linuxapp
index f1638db..960dde4 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -497,6 +497,11 @@ CONFIG_RTE_KNI_VHOST_DEBUG_RX=n
 CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 
 #
+# Compile librte_ethtool
+#
+CONFIG_RTE_LIBRTE_ETHTOOL=y
+
+#
 # Compile vhost library
 # fuse-devel is needed to run vhost-cuse.
 # fuse-devel enables user space char driver development
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 7a91001..4cdd3f5 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -149,4 +149,5 @@ There are many libraries, so their headers may be grouped by topics:
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
   [keepalive]          (@ref rte_keepalive.h),
-  [version]            (@ref rte_version.h)
+  [version]            (@ref rte_version.h),
+  [ethtool]            (@ref rte_ethtool.h),
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index 57e8b5d..c5b8615 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -41,6 +41,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_cryptodev \
                           lib/librte_distributor \
                           lib/librte_ether \
+                          lib/librte_ethtool \
                           lib/librte_hash \
                           lib/librte_ip_frag \
                           lib/librte_ivshmem \
diff --git a/doc/api/examples.dox b/doc/api/examples.dox
index 200af0b..8763d77 100644
--- a/doc/api/examples.dox
+++ b/doc/api/examples.dox
@@ -8,9 +8,8 @@
 @example distributor/main.c
 @example dpdk_qat/crypto.c
 @example dpdk_qat/main.c
-@example ethtool/ethtool-app/ethapp.c
-@example ethtool/ethtool-app/main.c
-@example ethtool/lib/rte_ethtool.c
+@example ethtool/ethapp.c
+@example ethtool/main.c
 @example exception_path/main.c
 @example helloworld/main.c
 @example ip_fragmentation/main.c
diff --git a/doc/guides/prog_guide/ethtool_lib.rst b/doc/guides/prog_guide/ethtool_lib.rst
new file mode 100644
index 0000000..e161cd0
--- /dev/null
+++ b/doc/guides/prog_guide/ethtool_lib.rst
@@ -0,0 +1,62 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+.. _Ethtool_Library:
+
+Ethtool Library
+===============
+
+Ethtool interface
+-----------------
+
+The Ethtool interface is built as a separate library, and implements
+the following functions:
+
+- ``rte_ethtool_get_drvinfo()``
+- ``rte_ethtool_get_regs_len()``
+- ``rte_ethtool_get_regs()``
+- ``rte_ethtool_get_link()``
+- ``rte_ethtool_get_eeprom_len()``
+- ``rte_ethtool_get_eeprom()``
+- ``rte_ethtool_set_eeprom()``
+- ``rte_ethtool_get_pauseparam()``
+- ``rte_ethtool_set_pauseparam()``
+- ``rte_ethtool_net_open()``
+- ``rte_ethtool_net_stop()``
+- ``rte_ethtool_net_get_mac_addr()``
+- ``rte_ethtool_net_set_mac_addr()``
+- ``rte_ethtool_net_validate_addr()``
+- ``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_net_set_rx_mode()``
+- ``rte_ethtool_get_ringparam()``
+- ``rte_ethtool_set_ringparam()``
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index a9404fb..98f4aca 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -1,5 +1,5 @@
 ..  BSD LICENSE
-    Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+    Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
     All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@ Programmer's Guide
     packet_distrib_lib
     reorder_lib
     ip_fragment_reassembly_lib
+    ethtool_lib
     multi_proc_support
     kernel_nic_interface
     thread_safety_dpdk_functions
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 8273817..70338f1 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -129,6 +129,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_cmdline.so.1
      librte_distributor.so.1
      librte_eal.so.2
+   + librte_ethtool.so.1
      librte_hash.so.2
      librte_ip_frag.so.1
      librte_ivshmem.so.1
diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
index 4d1697e..65240ae 100644
--- a/doc/guides/sample_app_ug/ethtool.rst
+++ b/doc/guides/sample_app_ug/ethtool.rst
@@ -1,6 +1,6 @@
 
 ..  BSD LICENSE
-    Copyright(c) 2015 Intel Corporation. All rights reserved.
+    Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
     All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
@@ -71,7 +71,7 @@ The only available options are the standard ones for the EAL:
 
 .. code-block:: console
 
-    ./ethtool-app/ethtool-app/${RTE_TARGET}/ethtool [EAL options]
+    ./${RTE_TARGET}/ethtool [EAL options]
 
 Refer to the *DPDK Getting Started Guide* for general information on
 running applications and the Environment Abstraction Layer (EAL)
@@ -128,33 +128,5 @@ Ethtool Shell
 The foreground part of the Ethtool sample is a console-based
 interface that accepts commands as described in `using the
 application`_. Individual call-back functions handle the detail
-associated with each command, which make use of the functions
-defined in the `Ethtool interface`_ to the DPDK functions.
-
-Ethtool interface
------------------
-
-The Ethtool interface is built as a separate library, and implements
-the following functions:
-
-- ``rte_ethtool_get_drvinfo()``
-- ``rte_ethtool_get_regs_len()``
-- ``rte_ethtool_get_regs()``
-- ``rte_ethtool_get_link()``
-- ``rte_ethtool_get_eeprom_len()``
-- ``rte_ethtool_get_eeprom()``
-- ``rte_ethtool_set_eeprom()``
-- ``rte_ethtool_get_pauseparam()``
-- ``rte_ethtool_set_pauseparam()``
-- ``rte_ethtool_net_open()``
-- ``rte_ethtool_net_stop()``
-- ``rte_ethtool_net_get_mac_addr()``
-- ``rte_ethtool_net_set_mac_addr()``
-- ``rte_ethtool_net_validate_addr()``
-- ``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_net_set_rx_mode()``
-- ``rte_ethtool_get_ringparam()``
-- ``rte_ethtool_set_ringparam()``
+associated with each command, which make use of librte_ethtool
+library.
diff --git a/examples/ethtool/Makefile b/examples/ethtool/Makefile
index 995cd25..23a6ffd 100644
--- a/examples/ethtool/Makefile
+++ b/examples/ethtool/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -33,17 +33,23 @@ ifeq ($(RTE_SDK),)
 $(error "Please define RTE_SDK environment variable")
 endif
 
-# Default target, can be overwritten by command line or environment
+# Default target, can be overridden 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")
-$(info This application can only operate in a linuxapp environment, \
-please change the definition of the RTE_TARGET environment variable)
-else
+# binary name
+APP = ethtool
+
+# all source are stored in SRCS-y
+SRCS-y := main.c ethapp.c
+
+#CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#LDLIBS += -L$(subst ethtool-app,lib,$(RTE_OUTPUT))/lib
+#LDLIBS += -lrte_ethtool
 
-DIRS-y += lib ethtool-app
-endif
 
-include $(RTE_SDK)/mk/rte.extsubdir.mk
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/ethtool/ethapp.c b/examples/ethtool/ethapp.c
new file mode 100644
index 0000000..fca602b
--- /dev/null
+++ b/examples/ethtool/ethapp.c
@@ -0,0 +1,873 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015-2016 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 <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "rte_ethtool.h"
+#include "ethapp.h"
+
+#define EEPROM_DUMP_CHUNKSIZE 1024
+
+
+struct pcmd_get_params {
+	cmdline_fixed_string_t cmd;
+};
+struct pcmd_int_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+};
+struct pcmd_intstr_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	cmdline_fixed_string_t opt;
+};
+struct pcmd_intmac_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	struct ether_addr mac;
+};
+struct pcmd_str_params {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t opt;
+};
+struct pcmd_vlan_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	cmdline_fixed_string_t mode;
+	uint16_t vid;
+};
+struct pcmd_intintint_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	uint16_t tx;
+	uint16_t rx;
+};
+
+
+/* Parameter-less commands */
+cmdline_parse_token_string_t pcmd_quit_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "quit");
+cmdline_parse_token_string_t pcmd_stats_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "stats");
+cmdline_parse_token_string_t pcmd_drvinfo_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "drvinfo");
+cmdline_parse_token_string_t pcmd_link_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "link");
+
+/* Commands taking just port id */
+cmdline_parse_token_string_t pcmd_open_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "open");
+cmdline_parse_token_string_t pcmd_stop_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "stop");
+cmdline_parse_token_string_t pcmd_rxmode_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "rxmode");
+cmdline_parse_token_string_t pcmd_portstats_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "portstats");
+cmdline_parse_token_num_t pcmd_int_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_int_params, port, UINT16);
+
+/* Commands taking port id and string */
+cmdline_parse_token_string_t pcmd_eeprom_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "eeprom");
+cmdline_parse_token_string_t pcmd_mtu_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "mtu");
+cmdline_parse_token_string_t pcmd_regs_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "regs");
+
+cmdline_parse_token_num_t pcmd_intstr_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_intstr_token_opt =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, opt, NULL);
+
+/* Commands taking port id and a MAC address string */
+cmdline_parse_token_string_t pcmd_macaddr_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "macaddr");
+cmdline_parse_token_num_t pcmd_intmac_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intmac_params, port, UINT16);
+cmdline_parse_token_etheraddr_t pcmd_intmac_token_mac =
+	TOKEN_ETHERADDR_INITIALIZER(struct pcmd_intmac_params, mac);
+
+/* Command taking just a MAC address */
+cmdline_parse_token_string_t pcmd_validate_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "validate");
+
+
+/* Commands taking port id and two integers */
+cmdline_parse_token_string_t pcmd_ringparam_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intintint_params, cmd,
+		"ringparam");
+cmdline_parse_token_num_t pcmd_intintint_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, port, UINT16);
+cmdline_parse_token_num_t pcmd_intintint_token_tx =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, tx, UINT16);
+cmdline_parse_token_num_t pcmd_intintint_token_rx =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, rx, UINT16);
+
+
+/* Pause commands */
+cmdline_parse_token_string_t pcmd_pause_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "pause");
+cmdline_parse_token_num_t pcmd_pause_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_pause_token_opt =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params,
+		opt, "all#tx#rx#none");
+
+/* VLAN commands */
+cmdline_parse_token_string_t pcmd_vlan_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, cmd, "vlan");
+cmdline_parse_token_num_t pcmd_vlan_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_vlan_token_mode =
+	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, mode, "add#del");
+cmdline_parse_token_num_t pcmd_vlan_token_vid =
+	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, vid, UINT16);
+
+
+static void
+pcmd_quit_callback(__rte_unused void *ptr_params,
+	struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	cmdline_quit(ctx);
+}
+
+
+static void
+pcmd_drvinfo_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct ethtool_drvinfo info;
+	int id_port;
+
+	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
+		if (rte_ethtool_get_drvinfo(id_port, &info)) {
+			printf("Error getting info for port %i\n", id_port);
+			return;
+		}
+		printf("Port %i driver: %s (ver: %s)\n",
+			id_port, info.driver, info.version
+		      );
+	}
+}
+
+
+static void
+pcmd_link_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	int num_ports = rte_eth_dev_count();
+	int id_port, stat_port;
+
+	for (id_port = 0; id_port < num_ports; id_port++) {
+		if (!rte_eth_dev_is_valid_port(id_port))
+			continue;
+		stat_port = rte_ethtool_get_link(id_port);
+		switch (stat_port) {
+		case 0:
+			printf("Port %i: Down\n", id_port);
+			break;
+		case 1:
+			printf("Port %i: Up\n", id_port);
+			break;
+		default:
+			printf("Port %i: Error getting link status\n",
+				id_port
+				);
+			break;
+		}
+	}
+	printf("\n");
+}
+
+
+static void
+pcmd_regs_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int len_regs;
+	struct ethtool_regs regs;
+	unsigned char *buf_data;
+	FILE *fp_regs;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	len_regs = rte_ethtool_get_regs_len(params->port);
+	if (len_regs > 0) {
+		printf("Port %i: %i bytes\n", params->port, len_regs);
+		buf_data = malloc(len_regs);
+		if (buf_data == NULL) {
+			printf("Error allocating %i bytes for buffer\n",
+				len_regs);
+			return;
+		}
+		if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
+			fp_regs = fopen(params->opt, "wb");
+			if (fp_regs == NULL) {
+				printf("Error opening '%s' for writing\n",
+					params->opt);
+			} else {
+				if ((int)fwrite(buf_data,
+						1, len_regs,
+						fp_regs) != len_regs)
+					printf("Error writing '%s'\n",
+						params->opt);
+				fclose(fp_regs);
+			}
+		}
+		free(buf_data);
+	} else if (len_regs == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error getting registers\n", params->port);
+}
+
+
+static void
+pcmd_eeprom_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	struct ethtool_eeprom info_eeprom;
+	int len_eeprom;
+	int pos_eeprom;
+	int stat;
+	unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
+	FILE *fp_eeprom;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	len_eeprom = rte_ethtool_get_eeprom_len(params->port);
+	if (len_eeprom > 0) {
+		fp_eeprom = fopen(params->opt, "wb");
+		if (fp_eeprom == NULL) {
+			printf("Error opening '%s' for writing\n",
+				params->opt);
+			return;
+		}
+		printf("Total EEPROM length: %i bytes\n", len_eeprom);
+		info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
+		for (pos_eeprom = 0;
+				pos_eeprom < len_eeprom;
+				pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
+			info_eeprom.offset = pos_eeprom;
+			if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
+				info_eeprom.len = len_eeprom - pos_eeprom;
+			else
+				info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
+			stat = rte_ethtool_get_eeprom(
+				params->port, &info_eeprom, bytes_eeprom
+				);
+			if (stat != 0) {
+				printf("EEPROM read error %i\n", stat);
+				break;
+			}
+			if (fwrite(bytes_eeprom,
+					1, info_eeprom.len,
+					fp_eeprom) != info_eeprom.len) {
+				printf("Error writing '%s'\n", params->opt);
+				break;
+			}
+		}
+		fclose(fp_eeprom);
+	} else if (len_eeprom == 0)
+		printf("Port %i: Device does not have EEPROM\n", params->port);
+	else if (len_eeprom == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error getting EEPROM\n", params->port);
+}
+
+
+static void
+pcmd_pause_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	struct ethtool_pauseparam info;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data != NULL) {
+		stat = rte_ethtool_get_pauseparam(params->port, &info);
+	} else {
+		memset(&info, 0, sizeof(info));
+		if (strcasecmp("all", params->opt) == 0) {
+			info.tx_pause = 1;
+			info.rx_pause = 1;
+		} else if (strcasecmp("tx", params->opt) == 0) {
+			info.tx_pause = 1;
+			info.rx_pause = 0;
+		} else if (strcasecmp("rx", params->opt) == 0) {
+			info.tx_pause = 0;
+			info.rx_pause = 1;
+		} else {
+			info.tx_pause = 0;
+			info.rx_pause = 0;
+		}
+		/* Assume auto-negotiation wanted */
+		info.autoneg = 1;
+		stat = rte_ethtool_set_pauseparam(params->port, &info);
+	}
+	if (stat == 0) {
+		if (info.rx_pause && info.tx_pause)
+			printf("Port %i: Tx & Rx Paused\n", params->port);
+		else if (info.rx_pause)
+			printf("Port %i: Rx Paused\n", params->port);
+		else if (info.tx_pause)
+			printf("Port %i: Tx Paused\n", params->port);
+		else
+			printf("Port %i: Tx & Rx not paused\n", params->port);
+	} else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error %i\n", params->port, stat);
+}
+
+
+static void
+pcmd_open_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	lock_port(params->port);
+	stat = rte_ethtool_net_open(params->port);
+	mark_port_active(params->port);
+	unlock_port(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error opening device\n", params->port);
+}
+
+static void
+pcmd_stop_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	lock_port(params->port);
+	stat = rte_ethtool_net_stop(params->port);
+	mark_port_inactive(params->port);
+	unlock_port(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error stopping device\n", params->port);
+}
+
+
+static void
+pcmd_rxmode_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_set_rx_mode(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error setting rx mode\n", params->port);
+}
+
+
+static void
+pcmd_macaddr_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intmac_params *params = ptr_params;
+	struct ether_addr mac_addr;
+	int stat;
+
+	stat = 0;
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data != NULL) {
+		lock_port(params->port);
+		stat = rte_ethtool_net_set_mac_addr(params->port,
+			&params->mac);
+		mark_port_newmac(params->port);
+		unlock_port(params->port);
+		if (stat == 0) {
+			printf("MAC address changed\n");
+			return;
+		}
+	} else {
+		stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
+		if (stat == 0) {
+			printf(
+				"Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+				params->port,
+				mac_addr.addr_bytes[0],
+				mac_addr.addr_bytes[1],
+				mac_addr.addr_bytes[2],
+				mac_addr.addr_bytes[3],
+				mac_addr.addr_bytes[4],
+				mac_addr.addr_bytes[5]);
+			return;
+		}
+	}
+
+	printf("Port %i: Error %s\n", params->port,
+	       strerror(-stat));
+}
+
+static void
+pcmd_mtu_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int stat;
+	int new_mtu;
+	char *ptr_parse_end;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	new_mtu = atoi(params->opt);
+	new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
+	if (*ptr_parse_end != '\0' ||
+			new_mtu < ETHER_MIN_MTU ||
+			new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
+		printf("Port %i: Invalid MTU value\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
+	if (stat == 0)
+		printf("Port %i: MTU set to %i\n", params->port, new_mtu);
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error setting MTU\n", params->port);
+}
+
+
+
+static void pcmd_portstats_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	struct rte_eth_stats stat_info;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
+	if (stat == 0) {
+		/* Most of rte_eth_stats is deprecated.. */
+		printf("Port %i stats\n", params->port);
+		printf("   In: %" PRIu64 " (%" PRIu64 " bytes)\n"
+			"  Out: %"PRIu64" (%"PRIu64 " bytes)\n"
+			"  Err: %"PRIu64"\n",
+			stat_info.ipackets,
+			stat_info.ibytes,
+			stat_info.opackets,
+			stat_info.obytes,
+			stat_info.ierrors+stat_info.oerrors
+		      );
+	} else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error fetching statistics\n", params->port);
+}
+
+static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intintint_params *params = ptr_params;
+	struct ethtool_ringparam ring_data;
+	struct ethtool_ringparam ring_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data == NULL) {
+		stat = rte_ethtool_get_ringparam(params->port, &ring_data);
+		if (stat == 0) {
+			printf("Port %i ring parameters\n"
+				"  Rx Pending: %i (%i max)\n"
+				"  Tx Pending: %i (%i max)\n",
+				params->port,
+				ring_data.rx_pending,
+				ring_data.rx_max_pending,
+				ring_data.tx_pending,
+				ring_data.tx_max_pending);
+		}
+	} else {
+		if (params->tx < 1 || params->rx < 1) {
+			printf("Error: Invalid parameters\n");
+			return;
+		}
+		memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
+		ring_params.tx_pending = params->tx;
+		ring_params.rx_pending = params->rx;
+		lock_port(params->port);
+		stat = rte_ethtool_set_ringparam(params->port, &ring_params);
+		unlock_port(params->port);
+	}
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error fetching statistics\n", params->port);
+}
+
+static void pcmd_validate_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intmac_params *params = ptr_params;
+
+	if (rte_ethtool_net_validate_addr(0, &params->mac))
+		printf("Address is unicast\n");
+	else
+		printf("Address is not unicast\n");
+}
+
+
+static void pcmd_vlan_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_vlan_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = 0;
+
+	if (strcasecmp("add", params->mode) == 0) {
+		stat = rte_ethtool_net_vlan_rx_add_vid(
+			params->port, params->vid
+			);
+		if (stat == 0)
+			printf("VLAN vid %i added\n", params->vid);
+
+	} else if (strcasecmp("del", params->mode) == 0) {
+		stat = rte_ethtool_net_vlan_rx_kill_vid(
+			params->port, params->vid
+			);
+		if (stat == 0)
+			printf("VLAN vid %i removed\n", params->vid);
+	} else {
+		/* Should not happen! */
+		printf("Error: Bad mode %s\n", params->mode);
+	}
+	if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else if (stat == -ENOSYS)
+		printf("Port %i: VLAN filtering disabled\n", params->port);
+	else if (stat != 0)
+		printf("Port %i: Error changing VLAN setup (code %i)\n",
+			params->port, -stat);
+}
+
+
+cmdline_parse_inst_t pcmd_quit = {
+	.f = pcmd_quit_callback,
+	.data = NULL,
+	.help_str = "quit\n     Exit program",
+	.tokens = {(void *)&pcmd_quit_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_drvinfo = {
+	.f = pcmd_drvinfo_callback,
+	.data = NULL,
+	.help_str = "drvinfo\n     Print driver info",
+	.tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_link = {
+	.f = pcmd_link_callback,
+	.data = NULL,
+	.help_str = "link\n     Print port link states",
+	.tokens = {(void *)&pcmd_link_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_regs = {
+	.f = pcmd_regs_callback,
+	.data = NULL,
+	.help_str = "regs <port_id> <filename>\n"
+		"     Dump port register(s) to file",
+	.tokens = {
+		(void *)&pcmd_regs_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_eeprom = {
+	.f = pcmd_eeprom_callback,
+	.data = NULL,
+	.help_str = "eeprom <port_id> <filename>\n    Dump EEPROM to file",
+	.tokens = {
+		(void *)&pcmd_eeprom_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_pause_noopt = {
+	.f = pcmd_pause_callback,
+	.data = (void *)0x01,
+	.help_str = "pause <port_id>\n     Print port pause state",
+	.tokens = {
+		(void *)&pcmd_pause_token_cmd,
+		(void *)&pcmd_pause_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_pause = {
+	.f = pcmd_pause_callback,
+	.data = NULL,
+	.help_str =
+		"pause <port_id> <all|tx|rx|none>\n     Pause/unpause port",
+	.tokens = {
+		(void *)&pcmd_pause_token_cmd,
+		(void *)&pcmd_pause_token_port,
+		(void *)&pcmd_pause_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_open = {
+	.f = pcmd_open_callback,
+	.data = NULL,
+	.help_str = "open <port_id>\n     Open port",
+	.tokens = {
+		(void *)&pcmd_open_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_stop = {
+	.f = pcmd_stop_callback,
+	.data = NULL,
+	.help_str = "stop <port_id>\n     Stop port",
+	.tokens = {
+		(void *)&pcmd_stop_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_rxmode = {
+	.f = pcmd_rxmode_callback,
+	.data = NULL,
+	.help_str = "rxmode <port_id>\n     Toggle port Rx mode",
+	.tokens = {
+		(void *)&pcmd_rxmode_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_macaddr_get = {
+	.f = pcmd_macaddr_callback,
+	.data = NULL,
+	.help_str = "macaddr <port_id>\n"
+		"     Get MAC address",
+	.tokens = {
+		(void *)&pcmd_macaddr_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_macaddr = {
+	.f = pcmd_macaddr_callback,
+	.data = (void *)0x01,
+	.help_str =
+		"macaddr <port_id> <mac_addr>\n"
+		"     Set MAC address",
+	.tokens = {
+		(void *)&pcmd_macaddr_token_cmd,
+		(void *)&pcmd_intmac_token_port,
+		(void *)&pcmd_intmac_token_mac,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_mtu = {
+	.f = pcmd_mtu_callback,
+	.data = NULL,
+	.help_str = "mtu <port_id> <mtu_value>\n"
+		"     Change MTU",
+	.tokens = {
+		(void *)&pcmd_mtu_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_portstats = {
+	.f = pcmd_portstats_callback,
+	.data = NULL,
+	.help_str = "portstats <port_id>\n"
+		"     Print port eth statistics",
+	.tokens = {
+		(void *)&pcmd_portstats_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_ringparam = {
+	.f = pcmd_ringparam_callback,
+	.data = NULL,
+	.help_str = "ringparam <port_id>\n"
+		"     Print ring parameters",
+	.tokens = {
+		(void *)&pcmd_ringparam_token_cmd,
+		(void *)&pcmd_intintint_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_ringparam_set = {
+	.f = pcmd_ringparam_callback,
+	.data = (void *)1,
+	.help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
+		"     Set ring parameters",
+	.tokens = {
+		(void *)&pcmd_ringparam_token_cmd,
+		(void *)&pcmd_intintint_token_port,
+		(void *)&pcmd_intintint_token_tx,
+		(void *)&pcmd_intintint_token_rx,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_validate = {
+	.f = pcmd_validate_callback,
+	.data = NULL,
+	.help_str = "validate <mac_addr>\n"
+		"     Check that MAC address is valid unicast address",
+	.tokens = {
+		(void *)&pcmd_validate_token_cmd,
+		(void *)&pcmd_intmac_token_mac,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_vlan = {
+	.f = pcmd_vlan_callback,
+	.data = NULL,
+	.help_str = "vlan <port_id> <add|del> <vlan_id>\n"
+		"     Add/remove VLAN id",
+	.tokens = {
+		(void *)&pcmd_vlan_token_cmd,
+		(void *)&pcmd_vlan_token_port,
+		(void *)&pcmd_vlan_token_mode,
+		(void *)&pcmd_vlan_token_vid,
+		NULL
+	},
+};
+
+
+cmdline_parse_ctx_t list_prompt_commands[] = {
+	(cmdline_parse_inst_t *)&pcmd_drvinfo,
+	(cmdline_parse_inst_t *)&pcmd_eeprom,
+	(cmdline_parse_inst_t *)&pcmd_link,
+	(cmdline_parse_inst_t *)&pcmd_macaddr_get,
+	(cmdline_parse_inst_t *)&pcmd_macaddr,
+	(cmdline_parse_inst_t *)&pcmd_mtu,
+	(cmdline_parse_inst_t *)&pcmd_open,
+	(cmdline_parse_inst_t *)&pcmd_pause_noopt,
+	(cmdline_parse_inst_t *)&pcmd_pause,
+	(cmdline_parse_inst_t *)&pcmd_portstats,
+	(cmdline_parse_inst_t *)&pcmd_regs,
+	(cmdline_parse_inst_t *)&pcmd_ringparam,
+	(cmdline_parse_inst_t *)&pcmd_ringparam_set,
+	(cmdline_parse_inst_t *)&pcmd_rxmode,
+	(cmdline_parse_inst_t *)&pcmd_stop,
+	(cmdline_parse_inst_t *)&pcmd_validate,
+	(cmdline_parse_inst_t *)&pcmd_vlan,
+	(cmdline_parse_inst_t *)&pcmd_quit,
+	NULL
+};
+
+
+void ethapp_main(void)
+{
+	struct cmdline *ctx_cmdline;
+
+	ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
+	cmdline_interact(ctx_cmdline);
+	cmdline_stdin_exit(ctx_cmdline);
+}
diff --git a/examples/ethtool/ethapp.h b/examples/ethtool/ethapp.h
new file mode 100644
index 0000000..bd48c7c
--- /dev/null
+++ b/examples/ethtool/ethapp.h
@@ -0,0 +1,41 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015-2016 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.
+ */
+
+
+void ethapp_main(void);
+void print_stats(void);
+void lock_port(int idx_port);
+void unlock_port(int idx_port);
+void mark_port_inactive(int idx_port);
+void mark_port_active(int idx_port);
+void mark_port_newmac(int idx_port);
diff --git a/examples/ethtool/ethtool-app/Makefile b/examples/ethtool/ethtool-app/Makefile
deleted file mode 100644
index 09c66ad..0000000
--- a/examples/ethtool/ethtool-app/Makefile
+++ /dev/null
@@ -1,54 +0,0 @@
-#   BSD LICENSE
-#
-#   Copyright(c) 2010-2014 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 overridden by command line or environment
-RTE_TARGET ?= x86_64-native-linuxapp-gcc
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-# binary name
-APP = ethtool
-
-# all source are stored in SRCS-y
-SRCS-y := main.c ethapp.c
-
-CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
-CFLAGS += $(WERROR_FLAGS)
-
-LDLIBS += -L$(subst ethtool-app,lib,$(RTE_OUTPUT))/lib
-LDLIBS += -lrte_ethtool
-
-
-include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/ethtool/ethtool-app/ethapp.c b/examples/ethtool/ethtool-app/ethapp.c
deleted file mode 100644
index 2ed4796..0000000
--- a/examples/ethtool/ethtool-app/ethapp.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/*-
- *   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 <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
-#include <cmdline.h>
-
-#include "rte_ethtool.h"
-#include "ethapp.h"
-
-#define EEPROM_DUMP_CHUNKSIZE 1024
-
-
-struct pcmd_get_params {
-	cmdline_fixed_string_t cmd;
-};
-struct pcmd_int_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-};
-struct pcmd_intstr_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	cmdline_fixed_string_t opt;
-};
-struct pcmd_intmac_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	struct ether_addr mac;
-};
-struct pcmd_str_params {
-	cmdline_fixed_string_t cmd;
-	cmdline_fixed_string_t opt;
-};
-struct pcmd_vlan_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	cmdline_fixed_string_t mode;
-	uint16_t vid;
-};
-struct pcmd_intintint_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	uint16_t tx;
-	uint16_t rx;
-};
-
-
-/* Parameter-less commands */
-cmdline_parse_token_string_t pcmd_quit_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "quit");
-cmdline_parse_token_string_t pcmd_stats_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "stats");
-cmdline_parse_token_string_t pcmd_drvinfo_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "drvinfo");
-cmdline_parse_token_string_t pcmd_link_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "link");
-
-/* Commands taking just port id */
-cmdline_parse_token_string_t pcmd_open_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "open");
-cmdline_parse_token_string_t pcmd_stop_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "stop");
-cmdline_parse_token_string_t pcmd_rxmode_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "rxmode");
-cmdline_parse_token_string_t pcmd_portstats_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "portstats");
-cmdline_parse_token_num_t pcmd_int_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_int_params, port, UINT16);
-
-/* Commands taking port id and string */
-cmdline_parse_token_string_t pcmd_eeprom_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "eeprom");
-cmdline_parse_token_string_t pcmd_mtu_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "mtu");
-cmdline_parse_token_string_t pcmd_regs_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "regs");
-
-cmdline_parse_token_num_t pcmd_intstr_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_intstr_token_opt =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, opt, NULL);
-
-/* Commands taking port id and a MAC address string */
-cmdline_parse_token_string_t pcmd_macaddr_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "macaddr");
-cmdline_parse_token_num_t pcmd_intmac_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intmac_params, port, UINT16);
-cmdline_parse_token_etheraddr_t pcmd_intmac_token_mac =
-	TOKEN_ETHERADDR_INITIALIZER(struct pcmd_intmac_params, mac);
-
-/* Command taking just a MAC address */
-cmdline_parse_token_string_t pcmd_validate_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "validate");
-
-
-/* Commands taking port id and two integers */
-cmdline_parse_token_string_t pcmd_ringparam_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intintint_params, cmd,
-		"ringparam");
-cmdline_parse_token_num_t pcmd_intintint_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, port, UINT16);
-cmdline_parse_token_num_t pcmd_intintint_token_tx =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, tx, UINT16);
-cmdline_parse_token_num_t pcmd_intintint_token_rx =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, rx, UINT16);
-
-
-/* Pause commands */
-cmdline_parse_token_string_t pcmd_pause_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "pause");
-cmdline_parse_token_num_t pcmd_pause_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_pause_token_opt =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params,
-		opt, "all#tx#rx#none");
-
-/* VLAN commands */
-cmdline_parse_token_string_t pcmd_vlan_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, cmd, "vlan");
-cmdline_parse_token_num_t pcmd_vlan_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_vlan_token_mode =
-	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, mode, "add#del");
-cmdline_parse_token_num_t pcmd_vlan_token_vid =
-	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, vid, UINT16);
-
-
-static void
-pcmd_quit_callback(__rte_unused void *ptr_params,
-	struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	cmdline_quit(ctx);
-}
-
-
-static void
-pcmd_drvinfo_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct ethtool_drvinfo info;
-	int id_port;
-
-	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
-		if (rte_ethtool_get_drvinfo(id_port, &info)) {
-			printf("Error getting info for port %i\n", id_port);
-			return;
-		}
-		printf("Port %i driver: %s (ver: %s)\n",
-			id_port, info.driver, info.version
-		      );
-	}
-}
-
-
-static void
-pcmd_link_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	int num_ports = rte_eth_dev_count();
-	int id_port, stat_port;
-
-	for (id_port = 0; id_port < num_ports; id_port++) {
-		if (!rte_eth_dev_is_valid_port(id_port))
-			continue;
-		stat_port = rte_ethtool_get_link(id_port);
-		switch (stat_port) {
-		case 0:
-			printf("Port %i: Down\n", id_port);
-			break;
-		case 1:
-			printf("Port %i: Up\n", id_port);
-			break;
-		default:
-			printf("Port %i: Error getting link status\n",
-				id_port
-				);
-			break;
-		}
-	}
-	printf("\n");
-}
-
-
-static void
-pcmd_regs_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int len_regs;
-	struct ethtool_regs regs;
-	unsigned char *buf_data;
-	FILE *fp_regs;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	len_regs = rte_ethtool_get_regs_len(params->port);
-	if (len_regs > 0) {
-		printf("Port %i: %i bytes\n", params->port, len_regs);
-		buf_data = malloc(len_regs);
-		if (buf_data == NULL) {
-			printf("Error allocating %i bytes for buffer\n",
-				len_regs);
-			return;
-		}
-		if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
-			fp_regs = fopen(params->opt, "wb");
-			if (fp_regs == NULL) {
-				printf("Error opening '%s' for writing\n",
-					params->opt);
-			} else {
-				if ((int)fwrite(buf_data,
-						1, len_regs,
-						fp_regs) != len_regs)
-					printf("Error writing '%s'\n",
-						params->opt);
-				fclose(fp_regs);
-			}
-		}
-		free(buf_data);
-	} else if (len_regs == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error getting registers\n", params->port);
-}
-
-
-static void
-pcmd_eeprom_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	struct ethtool_eeprom info_eeprom;
-	int len_eeprom;
-	int pos_eeprom;
-	int stat;
-	unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
-	FILE *fp_eeprom;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	len_eeprom = rte_ethtool_get_eeprom_len(params->port);
-	if (len_eeprom > 0) {
-		fp_eeprom = fopen(params->opt, "wb");
-		if (fp_eeprom == NULL) {
-			printf("Error opening '%s' for writing\n",
-				params->opt);
-			return;
-		}
-		printf("Total EEPROM length: %i bytes\n", len_eeprom);
-		info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
-		for (pos_eeprom = 0;
-				pos_eeprom < len_eeprom;
-				pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
-			info_eeprom.offset = pos_eeprom;
-			if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
-				info_eeprom.len = len_eeprom - pos_eeprom;
-			else
-				info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
-			stat = rte_ethtool_get_eeprom(
-				params->port, &info_eeprom, bytes_eeprom
-				);
-			if (stat != 0) {
-				printf("EEPROM read error %i\n", stat);
-				break;
-			}
-			if (fwrite(bytes_eeprom,
-					1, info_eeprom.len,
-					fp_eeprom) != info_eeprom.len) {
-				printf("Error writing '%s'\n", params->opt);
-				break;
-			}
-		}
-		fclose(fp_eeprom);
-	} else if (len_eeprom == 0)
-		printf("Port %i: Device does not have EEPROM\n", params->port);
-	else if (len_eeprom == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error getting EEPROM\n", params->port);
-}
-
-
-static void
-pcmd_pause_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	struct ethtool_pauseparam info;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data != NULL) {
-		stat = rte_ethtool_get_pauseparam(params->port, &info);
-	} else {
-		memset(&info, 0, sizeof(info));
-		if (strcasecmp("all", params->opt) == 0) {
-			info.tx_pause = 1;
-			info.rx_pause = 1;
-		} else if (strcasecmp("tx", params->opt) == 0) {
-			info.tx_pause = 1;
-			info.rx_pause = 0;
-		} else if (strcasecmp("rx", params->opt) == 0) {
-			info.tx_pause = 0;
-			info.rx_pause = 1;
-		} else {
-			info.tx_pause = 0;
-			info.rx_pause = 0;
-		}
-		/* Assume auto-negotiation wanted */
-		info.autoneg = 1;
-		stat = rte_ethtool_set_pauseparam(params->port, &info);
-	}
-	if (stat == 0) {
-		if (info.rx_pause && info.tx_pause)
-			printf("Port %i: Tx & Rx Paused\n", params->port);
-		else if (info.rx_pause)
-			printf("Port %i: Rx Paused\n", params->port);
-		else if (info.tx_pause)
-			printf("Port %i: Tx Paused\n", params->port);
-		else
-			printf("Port %i: Tx & Rx not paused\n", params->port);
-	} else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error %i\n", params->port, stat);
-}
-
-
-static void
-pcmd_open_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	lock_port(params->port);
-	stat = rte_ethtool_net_open(params->port);
-	mark_port_active(params->port);
-	unlock_port(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error opening device\n", params->port);
-}
-
-static void
-pcmd_stop_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	lock_port(params->port);
-	stat = rte_ethtool_net_stop(params->port);
-	mark_port_inactive(params->port);
-	unlock_port(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error stopping device\n", params->port);
-}
-
-
-static void
-pcmd_rxmode_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_set_rx_mode(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error setting rx mode\n", params->port);
-}
-
-
-static void
-pcmd_macaddr_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intmac_params *params = ptr_params;
-	struct ether_addr mac_addr;
-	int stat;
-
-	stat = 0;
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data != NULL) {
-		lock_port(params->port);
-		stat = rte_ethtool_net_set_mac_addr(params->port,
-			&params->mac);
-		mark_port_newmac(params->port);
-		unlock_port(params->port);
-		if (stat == 0) {
-			printf("MAC address changed\n");
-			return;
-		}
-	} else {
-		stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
-		if (stat == 0) {
-			printf(
-				"Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-				params->port,
-				mac_addr.addr_bytes[0],
-				mac_addr.addr_bytes[1],
-				mac_addr.addr_bytes[2],
-				mac_addr.addr_bytes[3],
-				mac_addr.addr_bytes[4],
-				mac_addr.addr_bytes[5]);
-			return;
-		}
-	}
-
-	printf("Port %i: Error %s\n", params->port,
-	       strerror(-stat));
-}
-
-static void
-pcmd_mtu_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int stat;
-	int new_mtu;
-	char *ptr_parse_end;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	new_mtu = atoi(params->opt);
-	new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
-	if (*ptr_parse_end != '\0' ||
-			new_mtu < ETHER_MIN_MTU ||
-			new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
-		printf("Port %i: Invalid MTU value\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
-	if (stat == 0)
-		printf("Port %i: MTU set to %i\n", params->port, new_mtu);
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error setting MTU\n", params->port);
-}
-
-
-
-static void pcmd_portstats_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	struct rte_eth_stats stat_info;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
-	if (stat == 0) {
-		/* Most of rte_eth_stats is deprecated.. */
-		printf("Port %i stats\n", params->port);
-		printf("   In: %" PRIu64 " (%" PRIu64 " bytes)\n"
-			"  Out: %"PRIu64" (%"PRIu64 " bytes)\n"
-			"  Err: %"PRIu64"\n",
-			stat_info.ipackets,
-			stat_info.ibytes,
-			stat_info.opackets,
-			stat_info.obytes,
-			stat_info.ierrors+stat_info.oerrors
-		      );
-	} else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error fetching statistics\n", params->port);
-}
-
-static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intintint_params *params = ptr_params;
-	struct ethtool_ringparam ring_data;
-	struct ethtool_ringparam ring_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data == NULL) {
-		stat = rte_ethtool_get_ringparam(params->port, &ring_data);
-		if (stat == 0) {
-			printf("Port %i ring parameters\n"
-				"  Rx Pending: %i (%i max)\n"
-				"  Tx Pending: %i (%i max)\n",
-				params->port,
-				ring_data.rx_pending,
-				ring_data.rx_max_pending,
-				ring_data.tx_pending,
-				ring_data.tx_max_pending);
-		}
-	} else {
-		if (params->tx < 1 || params->rx < 1) {
-			printf("Error: Invalid parameters\n");
-			return;
-		}
-		memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
-		ring_params.tx_pending = params->tx;
-		ring_params.rx_pending = params->rx;
-		lock_port(params->port);
-		stat = rte_ethtool_set_ringparam(params->port, &ring_params);
-		unlock_port(params->port);
-	}
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error fetching statistics\n", params->port);
-}
-
-static void pcmd_validate_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intmac_params *params = ptr_params;
-
-	if (rte_ethtool_net_validate_addr(0, &params->mac))
-		printf("Address is unicast\n");
-	else
-		printf("Address is not unicast\n");
-}
-
-
-static void pcmd_vlan_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_vlan_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = 0;
-
-	if (strcasecmp("add", params->mode) == 0) {
-		stat = rte_ethtool_net_vlan_rx_add_vid(
-			params->port, params->vid
-			);
-		if (stat == 0)
-			printf("VLAN vid %i added\n", params->vid);
-
-	} else if (strcasecmp("del", params->mode) == 0) {
-		stat = rte_ethtool_net_vlan_rx_kill_vid(
-			params->port, params->vid
-			);
-		if (stat == 0)
-			printf("VLAN vid %i removed\n", params->vid);
-	} else {
-		/* Should not happen! */
-		printf("Error: Bad mode %s\n", params->mode);
-	}
-	if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else if (stat == -ENOSYS)
-		printf("Port %i: VLAN filtering disabled\n", params->port);
-	else if (stat != 0)
-		printf("Port %i: Error changing VLAN setup (code %i)\n",
-			params->port, -stat);
-}
-
-
-cmdline_parse_inst_t pcmd_quit = {
-	.f = pcmd_quit_callback,
-	.data = NULL,
-	.help_str = "quit\n     Exit program",
-	.tokens = {(void *)&pcmd_quit_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_drvinfo = {
-	.f = pcmd_drvinfo_callback,
-	.data = NULL,
-	.help_str = "drvinfo\n     Print driver info",
-	.tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_link = {
-	.f = pcmd_link_callback,
-	.data = NULL,
-	.help_str = "link\n     Print port link states",
-	.tokens = {(void *)&pcmd_link_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_regs = {
-	.f = pcmd_regs_callback,
-	.data = NULL,
-	.help_str = "regs <port_id> <filename>\n"
-		"     Dump port register(s) to file",
-	.tokens = {
-		(void *)&pcmd_regs_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_eeprom = {
-	.f = pcmd_eeprom_callback,
-	.data = NULL,
-	.help_str = "eeprom <port_id> <filename>\n    Dump EEPROM to file",
-	.tokens = {
-		(void *)&pcmd_eeprom_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_pause_noopt = {
-	.f = pcmd_pause_callback,
-	.data = (void *)0x01,
-	.help_str = "pause <port_id>\n     Print port pause state",
-	.tokens = {
-		(void *)&pcmd_pause_token_cmd,
-		(void *)&pcmd_pause_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_pause = {
-	.f = pcmd_pause_callback,
-	.data = NULL,
-	.help_str =
-		"pause <port_id> <all|tx|rx|none>\n     Pause/unpause port",
-	.tokens = {
-		(void *)&pcmd_pause_token_cmd,
-		(void *)&pcmd_pause_token_port,
-		(void *)&pcmd_pause_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_open = {
-	.f = pcmd_open_callback,
-	.data = NULL,
-	.help_str = "open <port_id>\n     Open port",
-	.tokens = {
-		(void *)&pcmd_open_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_stop = {
-	.f = pcmd_stop_callback,
-	.data = NULL,
-	.help_str = "stop <port_id>\n     Stop port",
-	.tokens = {
-		(void *)&pcmd_stop_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_rxmode = {
-	.f = pcmd_rxmode_callback,
-	.data = NULL,
-	.help_str = "rxmode <port_id>\n     Toggle port Rx mode",
-	.tokens = {
-		(void *)&pcmd_rxmode_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_macaddr_get = {
-	.f = pcmd_macaddr_callback,
-	.data = NULL,
-	.help_str = "macaddr <port_id>\n"
-		"     Get MAC address",
-	.tokens = {
-		(void *)&pcmd_macaddr_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_macaddr = {
-	.f = pcmd_macaddr_callback,
-	.data = (void *)0x01,
-	.help_str =
-		"macaddr <port_id> <mac_addr>\n"
-		"     Set MAC address",
-	.tokens = {
-		(void *)&pcmd_macaddr_token_cmd,
-		(void *)&pcmd_intmac_token_port,
-		(void *)&pcmd_intmac_token_mac,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_mtu = {
-	.f = pcmd_mtu_callback,
-	.data = NULL,
-	.help_str = "mtu <port_id> <mtu_value>\n"
-		"     Change MTU",
-	.tokens = {
-		(void *)&pcmd_mtu_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_portstats = {
-	.f = pcmd_portstats_callback,
-	.data = NULL,
-	.help_str = "portstats <port_id>\n"
-		"     Print port eth statistics",
-	.tokens = {
-		(void *)&pcmd_portstats_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_ringparam = {
-	.f = pcmd_ringparam_callback,
-	.data = NULL,
-	.help_str = "ringparam <port_id>\n"
-		"     Print ring parameters",
-	.tokens = {
-		(void *)&pcmd_ringparam_token_cmd,
-		(void *)&pcmd_intintint_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_ringparam_set = {
-	.f = pcmd_ringparam_callback,
-	.data = (void *)1,
-	.help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
-		"     Set ring parameters",
-	.tokens = {
-		(void *)&pcmd_ringparam_token_cmd,
-		(void *)&pcmd_intintint_token_port,
-		(void *)&pcmd_intintint_token_tx,
-		(void *)&pcmd_intintint_token_rx,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_validate = {
-	.f = pcmd_validate_callback,
-	.data = NULL,
-	.help_str = "validate <mac_addr>\n"
-		"     Check that MAC address is valid unicast address",
-	.tokens = {
-		(void *)&pcmd_validate_token_cmd,
-		(void *)&pcmd_intmac_token_mac,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_vlan = {
-	.f = pcmd_vlan_callback,
-	.data = NULL,
-	.help_str = "vlan <port_id> <add|del> <vlan_id>\n"
-		"     Add/remove VLAN id",
-	.tokens = {
-		(void *)&pcmd_vlan_token_cmd,
-		(void *)&pcmd_vlan_token_port,
-		(void *)&pcmd_vlan_token_mode,
-		(void *)&pcmd_vlan_token_vid,
-		NULL
-	},
-};
-
-
-cmdline_parse_ctx_t list_prompt_commands[] = {
-	(cmdline_parse_inst_t *)&pcmd_drvinfo,
-	(cmdline_parse_inst_t *)&pcmd_eeprom,
-	(cmdline_parse_inst_t *)&pcmd_link,
-	(cmdline_parse_inst_t *)&pcmd_macaddr_get,
-	(cmdline_parse_inst_t *)&pcmd_macaddr,
-	(cmdline_parse_inst_t *)&pcmd_mtu,
-	(cmdline_parse_inst_t *)&pcmd_open,
-	(cmdline_parse_inst_t *)&pcmd_pause_noopt,
-	(cmdline_parse_inst_t *)&pcmd_pause,
-	(cmdline_parse_inst_t *)&pcmd_portstats,
-	(cmdline_parse_inst_t *)&pcmd_regs,
-	(cmdline_parse_inst_t *)&pcmd_ringparam,
-	(cmdline_parse_inst_t *)&pcmd_ringparam_set,
-	(cmdline_parse_inst_t *)&pcmd_rxmode,
-	(cmdline_parse_inst_t *)&pcmd_stop,
-	(cmdline_parse_inst_t *)&pcmd_validate,
-	(cmdline_parse_inst_t *)&pcmd_vlan,
-	(cmdline_parse_inst_t *)&pcmd_quit,
-	NULL
-};
-
-
-void ethapp_main(void)
-{
-	struct cmdline *ctx_cmdline;
-
-	ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
-	cmdline_interact(ctx_cmdline);
-	cmdline_stdin_exit(ctx_cmdline);
-}
diff --git a/examples/ethtool/ethtool-app/ethapp.h b/examples/ethtool/ethtool-app/ethapp.h
deleted file mode 100644
index ba438ee..0000000
--- a/examples/ethtool/ethtool-app/ethapp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*-
- *   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.
- */
-
-
-void ethapp_main(void);
-void print_stats(void);
-void lock_port(int idx_port);
-void unlock_port(int idx_port);
-void mark_port_inactive(int idx_port);
-void mark_port_active(int idx_port);
-void mark_port_newmac(int idx_port);
diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
deleted file mode 100644
index 2c655d8..0000000
--- a/examples/ethtool/ethtool-app/main.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*-
- *   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 <rte_common.h>
-#include <rte_spinlock.h>
-#include <rte_eal.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_memory.h>
-#include <rte_mempool.h>
-#include <rte_mbuf.h>
-
-#include "ethapp.h"
-
-#define MAX_PORTS RTE_MAX_ETHPORTS
-#define MAX_BURST_LENGTH 32
-#define PORT_RX_QUEUE_SIZE 128
-#define PORT_TX_QUEUE_SIZE 256
-#define PKTPOOL_EXTRA_SIZE 512
-#define PKTPOOL_CACHE 32
-
-
-struct txq_port {
-	uint16_t cnt_unsent;
-	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
-};
-
-struct app_port {
-	struct ether_addr mac_addr;
-	struct txq_port txq;
-	rte_spinlock_t lock;
-	int port_active;
-	int port_dirty;
-	int idx_port;
-	struct rte_mempool *pkt_pool;
-};
-
-struct app_config {
-	struct app_port ports[MAX_PORTS];
-	int cnt_ports;
-	int exit_now;
-};
-
-
-struct app_config app_cfg;
-
-
-void lock_port(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	rte_spinlock_lock(&ptr_port->lock);
-}
-
-void unlock_port(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	rte_spinlock_unlock(&ptr_port->lock);
-}
-
-void mark_port_active(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_active = 1;
-}
-
-void mark_port_inactive(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_active = 0;
-}
-
-void mark_port_newmac(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_dirty = 1;
-}
-
-static void setup_ports(struct app_config *app_cfg, int cnt_ports)
-{
-	int idx_port;
-	int size_pktpool;
-	struct rte_eth_conf cfg_port;
-	struct rte_eth_dev_info dev_info;
-	char str_name[16];
-
-	memset(&cfg_port, 0, sizeof(cfg_port));
-	cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
-
-	for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
-		struct app_port *ptr_port = &app_cfg->ports[idx_port];
-
-		rte_eth_dev_info_get(idx_port, &dev_info);
-		size_pktpool = dev_info.rx_desc_lim.nb_max +
-			dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
-
-		snprintf(str_name, 16, "pkt_pool%i", idx_port);
-		ptr_port->pkt_pool = rte_pktmbuf_pool_create(
-			str_name,
-			size_pktpool, PKTPOOL_CACHE,
-			0,
-			RTE_MBUF_DEFAULT_BUF_SIZE,
-			rte_socket_id()
-			);
-		if (ptr_port->pkt_pool == NULL)
-			rte_exit(EXIT_FAILURE,
-				"rte_pktmbuf_pool_create failed"
-				);
-
-		printf("Init port %i..\n", idx_port);
-		ptr_port->port_active = 1;
-		ptr_port->port_dirty = 0;
-		ptr_port->idx_port = idx_port;
-
-		if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_dev_configure failed");
-		if (rte_eth_rx_queue_setup(
-			    idx_port, 0, PORT_RX_QUEUE_SIZE,
-			    rte_eth_dev_socket_id(idx_port), NULL,
-			    ptr_port->pkt_pool) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_rx_queue_setup failed"
-				);
-		if (rte_eth_tx_queue_setup(
-			    idx_port, 0, PORT_TX_QUEUE_SIZE,
-			    rte_eth_dev_socket_id(idx_port), NULL) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_tx_queue_setup failed"
-				);
-		if (rte_eth_dev_start(idx_port) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "%s:%i: rte_eth_dev_start failed",
-				 __FILE__, __LINE__
-				);
-		rte_eth_promiscuous_enable(idx_port);
-		rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
-		rte_spinlock_init(&ptr_port->lock);
-	}
-}
-
-static void process_frame(struct app_port *ptr_port,
-	struct rte_mbuf *ptr_frame)
-{
-	struct ether_hdr *ptr_mac_hdr;
-
-	ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct ether_hdr *);
-	ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
-	ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
-}
-
-static int slave_main(__attribute__((unused)) void *ptr_data)
-{
-	struct app_port *ptr_port;
-	struct rte_mbuf *ptr_frame;
-	struct txq_port *txq;
-
-	uint16_t cnt_recv_frames;
-	uint16_t idx_frame;
-	uint16_t cnt_sent;
-	uint16_t idx_port;
-	uint16_t lock_result;
-
-	while (app_cfg.exit_now == 0) {
-		for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
-			/* Check that port is active and unlocked */
-			ptr_port = &app_cfg.ports[idx_port];
-			lock_result = rte_spinlock_trylock(&ptr_port->lock);
-			if (lock_result == 0)
-				continue;
-			if (ptr_port->port_active == 0) {
-				rte_spinlock_unlock(&ptr_port->lock);
-				continue;
-			}
-			txq = &ptr_port->txq;
-
-			/* MAC address was updated */
-			if (ptr_port->port_dirty == 1) {
-				rte_eth_macaddr_get(ptr_port->idx_port,
-					&ptr_port->mac_addr);
-				ptr_port->port_dirty = 0;
-			}
-
-			/* Incoming frames */
-			cnt_recv_frames = rte_eth_rx_burst(
-				ptr_port->idx_port, 0,
-				&txq->buf_frames[txq->cnt_unsent],
-				RTE_DIM(txq->buf_frames) - txq->cnt_unsent
-				);
-			if (cnt_recv_frames > 0) {
-				for (idx_frame = 0;
-					idx_frame < cnt_recv_frames;
-					idx_frame++) {
-					ptr_frame = txq->buf_frames[
-						idx_frame + txq->cnt_unsent];
-					process_frame(ptr_port, ptr_frame);
-				}
-				txq->cnt_unsent += cnt_recv_frames;
-			}
-
-			/* Outgoing frames */
-			if (txq->cnt_unsent > 0) {
-				cnt_sent = rte_eth_tx_burst(
-					ptr_port->idx_port, 0,
-					txq->buf_frames,
-					txq->cnt_unsent
-					);
-				/* Shuffle up unsent frame pointers */
-				for (idx_frame = cnt_sent;
-					idx_frame < txq->cnt_unsent;
-					idx_frame++)
-					txq->buf_frames[idx_frame - cnt_sent] =
-						txq->buf_frames[idx_frame];
-				txq->cnt_unsent -= cnt_sent;
-			}
-			rte_spinlock_unlock(&ptr_port->lock);
-		} /* end for( idx_port ) */
-	} /* end for(;;) */
-
-	return 0;
-}
-
-int main(int argc, char **argv)
-{
-	int cnt_args_parsed;
-	uint32_t id_core;
-	uint32_t cnt_ports;
-
-	/* Init runtime enviornment */
-	cnt_args_parsed = rte_eal_init(argc, argv);
-	if (cnt_args_parsed < 0)
-		rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
-
-	cnt_ports = rte_eth_dev_count();
-	printf("Number of NICs: %i\n", cnt_ports);
-	if (cnt_ports == 0)
-		rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
-	if (cnt_ports > MAX_PORTS) {
-		printf("Info: Using only %i of %i ports\n",
-			cnt_ports, MAX_PORTS
-			);
-		cnt_ports = MAX_PORTS;
-	}
-
-	setup_ports(&app_cfg, cnt_ports);
-
-	app_cfg.exit_now = 0;
-	app_cfg.cnt_ports = cnt_ports;
-
-	if (rte_lcore_count() < 2)
-		rte_exit(EXIT_FAILURE, "No available slave core!\n");
-	/* Assume there is an available slave.. */
-	id_core = rte_lcore_id();
-	id_core = rte_get_next_lcore(id_core, 1, 1);
-	rte_eal_remote_launch(slave_main, NULL, id_core);
-
-	ethapp_main();
-
-	app_cfg.exit_now = 1;
-	RTE_LCORE_FOREACH_SLAVE(id_core) {
-		if (rte_eal_wait_lcore(id_core) < 0)
-			return -1;
-	}
-
-	return 0;
-}
diff --git a/examples/ethtool/lib/Makefile b/examples/ethtool/lib/Makefile
deleted file mode 100644
index d7ee955..0000000
--- a/examples/ethtool/lib/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-#   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
-
-LIBABIVER := 1
-
-# 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/ethtool/lib/rte_ethtool.c b/examples/ethtool/lib/rte_ethtool.c
deleted file mode 100644
index 42e05f1..0000000
--- a/examples/ethtool/lib/rte_ethtool.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*-
- *   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_ether.h>
-#include "rte_ethtool.h"
-
-#define PKTPOOL_SIZE 512
-#define PKTPOOL_CACHE 32
-
-
-int
-rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
-{
-	struct rte_eth_dev_info dev_info;
-	int n;
-
-	if (drvinfo == NULL)
-		return -EINVAL;
-
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-
-	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)
-{
-	int count_regs;
-
-	count_regs = rte_eth_dev_get_reg_length(port_id);
-	if (count_regs > 0)
-		return count_regs * sizeof(uint32_t);
-	return count_regs;
-}
-
-int
-rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
-{
-	struct rte_dev_reg_info reg_info;
-	int status;
-
-	if (regs == NULL || data == NULL)
-		return -EINVAL;
-
-	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;
-
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	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;
-
-	if (eeprom == NULL || words == NULL)
-		return -EINVAL;
-
-	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;
-
-	if (eeprom == NULL || words == NULL || eeprom->offset >= eeprom->len)
-		return -EINVAL;
-
-	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;
-
-	if (pause_param == NULL)
-		return -EINVAL;
-
-	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_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;
-	default:
-		/* dummy block to avoid compiler warning */
-		break;
-	}
-	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;
-
-	if (pause_param == NULL)
-		return -EINVAL;
-
-	/*
-	 * 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)
-{
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	rte_eth_dev_stop(port_id);
-
-	return 0;
-}
-
-int
-rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
-{
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	if (addr == NULL)
-		return -EINVAL;
-	rte_eth_macaddr_get(port_id, addr);
-
-	return 0;
-}
-
-int
-rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
-{
-	if (addr == NULL)
-		return -EINVAL;
-	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)
-{
-	if (addr == NULL)
-		return -EINVAL;
-	return is_valid_assigned_ether_addr(addr);
-}
-
-int
-rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
-{
-	if (mtu < 0 || mtu > UINT16_MAX)
-		return -EINVAL;
-	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)
-{
-	if (stats == NULL)
-		return -EINVAL;
-	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);
-}
-
-/*
- * The set_rx_mode provides driver-specific rx mode setting.
- * This implementation implements rx mode setting based upon
- * ixgbe/igb drivers. Further improvement is to provide a
- * callback op field over struct rte_eth_dev::dev_ops so each
- * driver can register device-specific implementation
- */
-int
-rte_ethtool_net_set_rx_mode(uint8_t port_id)
-{
-	uint16_t num_vfs;
-	struct rte_eth_dev_info dev_info;
-	uint16_t vf;
-
-	memset(&dev_info, 0, sizeof(dev_info));
-	rte_eth_dev_info_get(port_id, &dev_info);
-	num_vfs = dev_info.max_vfs;
-
-	/* Set VF vf_rx_mode, VF unsupport status is discard */
-	for (vf = 0; vf < num_vfs; vf++)
-		rte_eth_dev_set_vf_rxmode(port_id, vf,
-			ETH_VMDQ_ACCEPT_UNTAG, 0);
-
-	/* Enable Rx vlan filter, VF unspport status is discard */
-	rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
-
-	return 0;
-}
-
-
-int
-rte_ethtool_get_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param)
-{
-	struct rte_eth_dev_info dev_info;
-	struct rte_eth_rxq_info rx_qinfo;
-	struct rte_eth_txq_info tx_qinfo;
-	int stat;
-
-	if (ring_param == NULL)
-		return -EINVAL;
-
-	rte_eth_dev_info_get(port_id, &dev_info);
-
-	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	stat = rte_eth_tx_queue_info_get(port_id, 0, &tx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	memset(ring_param, 0, sizeof(*ring_param));
-	ring_param->rx_pending = rx_qinfo.nb_desc;
-	ring_param->rx_max_pending = dev_info.rx_desc_lim.nb_max;
-	ring_param->tx_pending = tx_qinfo.nb_desc;
-	ring_param->tx_max_pending = dev_info.tx_desc_lim.nb_max;
-
-	return 0;
-}
-
-
-int
-rte_ethtool_set_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param)
-{
-	struct rte_eth_rxq_info rx_qinfo;
-	int stat;
-
-	if (ring_param == NULL)
-		return -EINVAL;
-
-	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	rte_eth_dev_stop(port_id);
-
-	stat = rte_eth_tx_queue_setup(port_id, 0, ring_param->tx_pending,
-		rte_socket_id(), NULL);
-	if (stat != 0)
-		return stat;
-
-	stat = rte_eth_rx_queue_setup(port_id, 0, ring_param->rx_pending,
-		rte_socket_id(), NULL, rx_qinfo.mp);
-	if (stat != 0)
-		return stat;
-
-	return rte_eth_dev_start(port_id);
-}
diff --git a/examples/ethtool/lib/rte_ethtool.h b/examples/ethtool/lib/rte_ethtool.h
deleted file mode 100644
index 2e79d45..0000000
--- a/examples/ethtool/lib/rte_ethtool.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/*-
- *   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_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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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);
-
-/**
- * Getting ring paramaters for Ethernet device.
- *
- * @param port_id
- *   The port identifier of the Ethernet device.
- * @param ring_param
- *   Pointer to struct ethrool_ringparam to receive parameters.
- * @return
- *   - (0) if successful.
- *   - (-ENOTSUP) if hardware doesn't support.
- *   - (-ENODEV) if *port_id* invalid.
- *   - others depends on the specific operations implementation.
- * @note
- *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
- *   are used, and the function only gets parameters for queue 0.
- */
-int rte_ethtool_get_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param);
-
-/**
- * Setting ring paramaters for Ethernet device.
- *
- * @param port_id
- *   The port identifier of the Ethernet device.
- * @param ring_param
- *   Pointer to struct ethrool_ringparam with parameters to set.
- * @return
- *   - (0) if successful.
- *   - (-ENOTSUP) if hardware doesn't support.
- *   - (-ENODEV) if *port_id* invalid.
- *   - others depends on the specific operations implementation.
- * @note
- *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
- *   are used, and the function only sets parameters for queue 0.
- */
-int rte_ethtool_set_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/ethtool/main.c b/examples/ethtool/main.c
new file mode 100644
index 0000000..2c655d8
--- /dev/null
+++ b/examples/ethtool/main.c
@@ -0,0 +1,305 @@
+/*-
+ *   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 <rte_common.h>
+#include <rte_spinlock.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_memory.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+
+#include "ethapp.h"
+
+#define MAX_PORTS RTE_MAX_ETHPORTS
+#define MAX_BURST_LENGTH 32
+#define PORT_RX_QUEUE_SIZE 128
+#define PORT_TX_QUEUE_SIZE 256
+#define PKTPOOL_EXTRA_SIZE 512
+#define PKTPOOL_CACHE 32
+
+
+struct txq_port {
+	uint16_t cnt_unsent;
+	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
+};
+
+struct app_port {
+	struct ether_addr mac_addr;
+	struct txq_port txq;
+	rte_spinlock_t lock;
+	int port_active;
+	int port_dirty;
+	int idx_port;
+	struct rte_mempool *pkt_pool;
+};
+
+struct app_config {
+	struct app_port ports[MAX_PORTS];
+	int cnt_ports;
+	int exit_now;
+};
+
+
+struct app_config app_cfg;
+
+
+void lock_port(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	rte_spinlock_lock(&ptr_port->lock);
+}
+
+void unlock_port(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	rte_spinlock_unlock(&ptr_port->lock);
+}
+
+void mark_port_active(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_active = 1;
+}
+
+void mark_port_inactive(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_active = 0;
+}
+
+void mark_port_newmac(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_dirty = 1;
+}
+
+static void setup_ports(struct app_config *app_cfg, int cnt_ports)
+{
+	int idx_port;
+	int size_pktpool;
+	struct rte_eth_conf cfg_port;
+	struct rte_eth_dev_info dev_info;
+	char str_name[16];
+
+	memset(&cfg_port, 0, sizeof(cfg_port));
+	cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
+
+	for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
+		struct app_port *ptr_port = &app_cfg->ports[idx_port];
+
+		rte_eth_dev_info_get(idx_port, &dev_info);
+		size_pktpool = dev_info.rx_desc_lim.nb_max +
+			dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
+
+		snprintf(str_name, 16, "pkt_pool%i", idx_port);
+		ptr_port->pkt_pool = rte_pktmbuf_pool_create(
+			str_name,
+			size_pktpool, PKTPOOL_CACHE,
+			0,
+			RTE_MBUF_DEFAULT_BUF_SIZE,
+			rte_socket_id()
+			);
+		if (ptr_port->pkt_pool == NULL)
+			rte_exit(EXIT_FAILURE,
+				"rte_pktmbuf_pool_create failed"
+				);
+
+		printf("Init port %i..\n", idx_port);
+		ptr_port->port_active = 1;
+		ptr_port->port_dirty = 0;
+		ptr_port->idx_port = idx_port;
+
+		if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_dev_configure failed");
+		if (rte_eth_rx_queue_setup(
+			    idx_port, 0, PORT_RX_QUEUE_SIZE,
+			    rte_eth_dev_socket_id(idx_port), NULL,
+			    ptr_port->pkt_pool) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_rx_queue_setup failed"
+				);
+		if (rte_eth_tx_queue_setup(
+			    idx_port, 0, PORT_TX_QUEUE_SIZE,
+			    rte_eth_dev_socket_id(idx_port), NULL) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_tx_queue_setup failed"
+				);
+		if (rte_eth_dev_start(idx_port) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "%s:%i: rte_eth_dev_start failed",
+				 __FILE__, __LINE__
+				);
+		rte_eth_promiscuous_enable(idx_port);
+		rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
+		rte_spinlock_init(&ptr_port->lock);
+	}
+}
+
+static void process_frame(struct app_port *ptr_port,
+	struct rte_mbuf *ptr_frame)
+{
+	struct ether_hdr *ptr_mac_hdr;
+
+	ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct ether_hdr *);
+	ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
+	ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
+}
+
+static int slave_main(__attribute__((unused)) void *ptr_data)
+{
+	struct app_port *ptr_port;
+	struct rte_mbuf *ptr_frame;
+	struct txq_port *txq;
+
+	uint16_t cnt_recv_frames;
+	uint16_t idx_frame;
+	uint16_t cnt_sent;
+	uint16_t idx_port;
+	uint16_t lock_result;
+
+	while (app_cfg.exit_now == 0) {
+		for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
+			/* Check that port is active and unlocked */
+			ptr_port = &app_cfg.ports[idx_port];
+			lock_result = rte_spinlock_trylock(&ptr_port->lock);
+			if (lock_result == 0)
+				continue;
+			if (ptr_port->port_active == 0) {
+				rte_spinlock_unlock(&ptr_port->lock);
+				continue;
+			}
+			txq = &ptr_port->txq;
+
+			/* MAC address was updated */
+			if (ptr_port->port_dirty == 1) {
+				rte_eth_macaddr_get(ptr_port->idx_port,
+					&ptr_port->mac_addr);
+				ptr_port->port_dirty = 0;
+			}
+
+			/* Incoming frames */
+			cnt_recv_frames = rte_eth_rx_burst(
+				ptr_port->idx_port, 0,
+				&txq->buf_frames[txq->cnt_unsent],
+				RTE_DIM(txq->buf_frames) - txq->cnt_unsent
+				);
+			if (cnt_recv_frames > 0) {
+				for (idx_frame = 0;
+					idx_frame < cnt_recv_frames;
+					idx_frame++) {
+					ptr_frame = txq->buf_frames[
+						idx_frame + txq->cnt_unsent];
+					process_frame(ptr_port, ptr_frame);
+				}
+				txq->cnt_unsent += cnt_recv_frames;
+			}
+
+			/* Outgoing frames */
+			if (txq->cnt_unsent > 0) {
+				cnt_sent = rte_eth_tx_burst(
+					ptr_port->idx_port, 0,
+					txq->buf_frames,
+					txq->cnt_unsent
+					);
+				/* Shuffle up unsent frame pointers */
+				for (idx_frame = cnt_sent;
+					idx_frame < txq->cnt_unsent;
+					idx_frame++)
+					txq->buf_frames[idx_frame - cnt_sent] =
+						txq->buf_frames[idx_frame];
+				txq->cnt_unsent -= cnt_sent;
+			}
+			rte_spinlock_unlock(&ptr_port->lock);
+		} /* end for( idx_port ) */
+	} /* end for(;;) */
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int cnt_args_parsed;
+	uint32_t id_core;
+	uint32_t cnt_ports;
+
+	/* Init runtime enviornment */
+	cnt_args_parsed = rte_eal_init(argc, argv);
+	if (cnt_args_parsed < 0)
+		rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
+
+	cnt_ports = rte_eth_dev_count();
+	printf("Number of NICs: %i\n", cnt_ports);
+	if (cnt_ports == 0)
+		rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
+	if (cnt_ports > MAX_PORTS) {
+		printf("Info: Using only %i of %i ports\n",
+			cnt_ports, MAX_PORTS
+			);
+		cnt_ports = MAX_PORTS;
+	}
+
+	setup_ports(&app_cfg, cnt_ports);
+
+	app_cfg.exit_now = 0;
+	app_cfg.cnt_ports = cnt_ports;
+
+	if (rte_lcore_count() < 2)
+		rte_exit(EXIT_FAILURE, "No available slave core!\n");
+	/* Assume there is an available slave.. */
+	id_core = rte_lcore_id();
+	id_core = rte_get_next_lcore(id_core, 1, 1);
+	rte_eal_remote_launch(slave_main, NULL, id_core);
+
+	ethapp_main();
+
+	app_cfg.exit_now = 1;
+	RTE_LCORE_FOREACH_SLAVE(id_core) {
+		if (rte_eal_wait_lcore(id_core) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/lib/Makefile b/lib/Makefile
index ef172ea..ce8f0f9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
 DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_ethtool/Makefile b/lib/librte_ethtool/Makefile
new file mode 100644
index 0000000..8be7105
--- /dev/null
+++ b/lib/librte_ethtool/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015-2016 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
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ethtool.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_eal 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..d9c5408
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.c
@@ -0,0 +1,423 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 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_ether.h>
+#include "rte_ethtool.h"
+
+#define PKTPOOL_SIZE 512
+#define PKTPOOL_CACHE 32
+
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	if (drvinfo == NULL)
+		return -EINVAL;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	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)
+{
+	int count_regs;
+
+	count_regs = rte_eth_dev_get_reg_length(port_id);
+	if (count_regs > 0)
+		return count_regs * sizeof(uint32_t);
+	return count_regs;
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	if (regs == NULL || data == NULL)
+		return -EINVAL;
+
+	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;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	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;
+
+	if (eeprom == NULL || words == NULL)
+		return -EINVAL;
+
+	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;
+
+	if (eeprom == NULL || words == NULL || eeprom->offset >= eeprom->len)
+		return -EINVAL;
+
+	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;
+
+	if (pause_param == NULL)
+		return -EINVAL;
+
+	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_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;
+	default:
+		/* dummy block to avoid compiler warning */
+		break;
+	}
+	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;
+
+	if (pause_param == NULL)
+		return -EINVAL;
+
+	/*
+	 * 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)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	if (addr == NULL)
+		return -EINVAL;
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	if (addr == NULL)
+		return -EINVAL;
+	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)
+{
+	if (addr == NULL)
+		return -EINVAL;
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	if (mtu < 0 || mtu > UINT16_MAX)
+		return -EINVAL;
+	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)
+{
+	if (stats == NULL)
+		return -EINVAL;
+	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);
+}
+
+/*
+ * The set_rx_mode provides driver-specific rx mode setting.
+ * This implementation implements rx mode setting based upon
+ * ixgbe/igb drivers. Further improvement is to provide a
+ * callback op field over struct rte_eth_dev::dev_ops so each
+ * driver can register device-specific implementation
+ */
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t num_vfs;
+	struct rte_eth_dev_info dev_info;
+	uint16_t vf;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+	num_vfs = dev_info.max_vfs;
+
+	/* Set VF vf_rx_mode, VF unsupport status is discard */
+	for (vf = 0; vf < num_vfs; vf++)
+		rte_eth_dev_set_vf_rxmode(port_id, vf,
+			ETH_VMDQ_ACCEPT_UNTAG, 0);
+
+	/* Enable Rx vlan filter, VF unspport status is discard */
+	rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
+
+	return 0;
+}
+
+
+int
+rte_ethtool_get_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_eth_dev_info dev_info;
+	struct rte_eth_rxq_info rx_qinfo;
+	struct rte_eth_txq_info tx_qinfo;
+	int stat;
+
+	if (ring_param == NULL)
+		return -EINVAL;
+
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	stat = rte_eth_tx_queue_info_get(port_id, 0, &tx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	memset(ring_param, 0, sizeof(*ring_param));
+	ring_param->rx_pending = rx_qinfo.nb_desc;
+	ring_param->rx_max_pending = dev_info.rx_desc_lim.nb_max;
+	ring_param->tx_pending = tx_qinfo.nb_desc;
+	ring_param->tx_max_pending = dev_info.tx_desc_lim.nb_max;
+
+	return 0;
+}
+
+
+int
+rte_ethtool_set_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_eth_rxq_info rx_qinfo;
+	int stat;
+
+	if (ring_param == NULL)
+		return -EINVAL;
+
+	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	rte_eth_dev_stop(port_id);
+
+	stat = rte_eth_tx_queue_setup(port_id, 0, ring_param->tx_pending,
+		rte_socket_id(), NULL);
+	if (stat != 0)
+		return stat;
+
+	stat = rte_eth_rx_queue_setup(port_id, 0, ring_param->rx_pending,
+		rte_socket_id(), NULL, rx_qinfo.mp);
+	if (stat != 0)
+		return stat;
+
+	return rte_eth_dev_start(port_id);
+}
diff --git a/lib/librte_ethtool/rte_ethtool.h b/lib/librte_ethtool/rte_ethtool.h
new file mode 100644
index 0000000..c60f7bb
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.h
@@ -0,0 +1,413 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 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_
+
+/**
+ * @file
+ *
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_drvinfo:         ethtool_ops::get_driverinfo \n
+ * rte_ethtool_get_link:            ethtool_ops::get_link \n
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len \n
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs \n
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len \n
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom \n
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom \n
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam \n
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam \n
+ * rte_ethtool_get_ringparam:       ethtool_ops::set_ringparam \n
+ * rte_ethtool_set_ringparam:       ethtool_ops::set_ringparam \n
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open \n
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop \n
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address \n
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr \n
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu \n
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64 \n
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid \n
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid \n
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode \n
+ *
+ */
+#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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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 regs
+ *   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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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);
+
+/**
+ * Getting ring paramaters for Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *   Pointer to struct ethrool_ringparam to receive parameters.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ * @note
+ *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
+ *   are used, and the function only gets parameters for queue 0.
+ */
+int rte_ethtool_get_ringparam(uint8_t port_id,
+		struct ethtool_ringparam *ring_param);
+
+/**
+ * Setting ring paramaters for Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *   Pointer to struct ethrool_ringparam with parameters to set.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ * @note
+ *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
+ *   are used, and the function only sets parameters for queue 0.
+ */
+int rte_ethtool_set_ringparam(uint8_t port_id,
+		struct ethtool_ringparam *ring_param);
+
+#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..4544c3a
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool_version.map
@@ -0,0 +1,28 @@
+DPDK_2.3 {
+	global:
+
+	rte_ethtool_get_drvinfo;
+	rte_ethtool_get_link;
+	rte_ethtool_get_regs_len;
+	rte_ethtool_get_regs;
+	rte_ethtool_get_eeprom_len;
+	rte_ethtool_get_eeprom;
+	rte_ethtool_set_eeprom;
+	rte_ethtool_get_pauseparam;
+	rte_ethtool_set_pauseparam;
+	rte_ethtool_get_ringparam;
+	rte_ethtool_set_ringparam;
+
+	rte_ethtool_net_open;
+	rte_ethtool_net_stop;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_set_mac_addr;
+	rte_ethtool_net_validate_addr;
+	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_net_set_rx_mode;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8ecab41..32f76b1 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -122,6 +122,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF_OFFLOAD)   += -lrte_mbuf_offload
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.5.0

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

* [PATCH v3 2/4] kcp: add kernel control path kernel module
  2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  2016-02-26 14:10     ` [PATCH v3 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
@ 2016-02-26 14:10     ` Ferruh Yigit
  2016-03-01  1:02       ` Stephen Hemminger
  2016-02-26 14:10     ` [PATCH v3 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
                       ` (3 subsequent siblings)
  5 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-26 14:10 UTC (permalink / raw)
  To: dev

This kernel module is based on KNI module, but this one is stripped
version of it and only for control messages, no data transfer
functionality provided.

This Linux kernel module helps userspace application create virtual
interfaces and when a control command issued into that virtual
interface, module pushes the command to the userspace and gets the
response back for the caller application.

The Linux tools like ethtool/ifconfig/ip can be used on virtual
interfaces but not ones for related data, like tcpdump.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---

v3:
* Devices are not up by default
* Add enable/disable promisc, allmulti support
* Increase timeout to 500ms and print log when a command timedout

v2:
* Use rtnetlink to create interfaces
* Fix ethtool get/set eeprom
* Remove commented out code
---
 MAINTAINERS                                        |   4 +
 config/common_linuxapp                             |   6 +
 lib/librte_eal/linuxapp/Makefile                   |   5 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h | 109 ++++++++
 lib/librte_eal/linuxapp/kcp/Makefile               |  57 ++++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  54 ++++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 300 +++++++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 225 ++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 215 +++++++++++++++
 10 files changed, 976 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 628bc05..6a77728 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -257,6 +257,10 @@ F: app/test/test_kni.c
 F: examples/kni/
 F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 
+Linux KCP
+M: Ferruh Yigit <ferruh.yigit@intel.com>
+F: lib/librte_eal/linuxapp/kcp/
+
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
 F: drivers/net/af_packet/
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 960dde4..0284fae 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -502,6 +502,12 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 CONFIG_RTE_LIBRTE_ETHTOOL=y
 
 #
+# Compile librte_ctrl_if
+#
+CONFIG_RTE_KCP_KMOD=y
+CONFIG_RTE_KCP_KO_DEBUG=n
+
+#
 # Compile vhost library
 # fuse-devel is needed to run vhost-cuse.
 # fuse-devel enables user space char driver development
diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile
index d9c5233..d1fa3a3 100644
--- a/lib/librte_eal/linuxapp/Makefile
+++ b/lib/librte_eal/linuxapp/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal
 ifeq ($(CONFIG_RTE_KNI_KMOD),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kni
 endif
+ifeq ($(CONFIG_RTE_KCP_KMOD),y)
+DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kcp
+endif
 ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += xen_dom0
 endif
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 6e26250..f6a3a41 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,7 @@ CFLAGS_eal_thread.o += -Wno-return-type
 endif
 
 INC := rte_interrupts.h rte_kni_common.h rte_dom0_common.h
+INC += rte_kcp_common.h
 
 SYMLINK-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP)-include/exec-env := \
 	$(addprefix include/exec-env/,$(INC))
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
new file mode 100644
index 0000000..988713e
--- /dev/null
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
@@ -0,0 +1,109 @@
+/*-
+ *   This file is provided under a dual BSD/LGPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GNU LESSER GENERAL PUBLIC LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2.1 of the GNU Lesser General Public License
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this program;
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ *
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_KCP_COMMON_H_
+#define _RTE_KCP_COMMON_H_
+
+#define KCP_DEVICE "kcp"
+
+#define KCP_NL_GRP 31
+
+#define KCP_ETHTOOL_MSG_LEN 500
+struct kcp_ethtool_msg {
+	int cmd_id;
+	int port_id;
+	unsigned int flag;
+	char input_buffer[KCP_ETHTOOL_MSG_LEN];
+	char output_buffer[KCP_ETHTOOL_MSG_LEN];
+	int input_buffer_len;
+	int output_buffer_len;
+	int err;
+};
+
+enum kcp_ethtool_msg_flag {
+	KCP_MSG_FLAG_NONE,
+	KCP_MSG_FLAG_REQUEST,
+	KCP_MSG_FLAG_RESPONSE,
+};
+
+enum {
+	IFLA_KCP_UNSPEC,
+	IFLA_KCP_PORTID,
+	IFLA_KCP_PID,
+	__IFLA_KCP_MAX,
+};
+
+#define IFLA_KCP_MAX (__IFLA_KCP_MAX - 1)
+
+/*
+ * Request id.
+ */
+enum rte_kcp_req_id {
+	RTE_KCP_REQ_UNKNOWN = (1 << 16),
+	RTE_KCP_REQ_CHANGE_MTU,
+	RTE_KCP_REQ_CFG_NETWORK_IF,
+	RTE_KCP_REQ_GET_STATS,
+	RTE_KCP_REQ_GET_MAC,
+	RTE_KCP_REQ_SET_MAC,
+	RTE_KCP_REQ_START_PORT,
+	RTE_KCP_REQ_STOP_PORT,
+	RTE_KCP_REQ_SET_PROMISC,
+	RTE_KCP_REQ_SET_ALLMULTI,
+	RTE_KCP_REQ_MAX,
+};
+
+#endif /* _RTE_KCP_COMMON_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/Makefile b/lib/librte_eal/linuxapp/kcp/Makefile
new file mode 100644
index 0000000..46d9dd8
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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
+
+#
+# module name and path
+#
+MODULE = rte_kcp
+
+#
+# CFLAGS
+#
+MODULE_CFLAGS += -I$(SRCDIR)
+MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
+MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
+MODULE_CFLAGS += -Wall -Werror
+
+# this lib needs main eal
+DEPDIRS-y += lib/librte_eal/linuxapp/eal
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y += kcp_net.c
+SRCS-y += kcp_ethtool.c
+SRCS-y += kcp_nl.c
+
+include $(RTE_SDK)/mk/rte.module.mk
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_dev.h b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
new file mode 100644
index 0000000..5eae51d
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
@@ -0,0 +1,54 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#ifndef _KCP_DEV_H_
+#define _KCP_DEV_H_
+
+#include <linux/netdevice.h>
+#include <exec-env/rte_kcp_common.h>
+
+struct kcp_dev {
+	int port_id;
+	unsigned int pid;
+	struct completion msg_received;
+	unsigned int nb_timedout_msg;
+};
+
+void kcp_nl_init(void);
+void kcp_nl_release(void);
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data, int in_len,
+		void *out_data, int out_len);
+
+void kcp_set_ethtool_ops(struct net_device *netdev);
+
+#define KCP_ERR(args...) printk(KERN_ERR "KCP: " args)
+#define KCP_INFO(args...) printk(KERN_INFO "KCP: " args)
+
+#ifdef RTE_KCP_KO_DEBUG
+#define KCP_DBG(args...) printk(KERN_DEBUG "KCP: " args)
+#else
+#define KCP_DBG(args...)
+#endif
+
+#endif /* _KCP_DEV_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
new file mode 100644
index 0000000..830ad64
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
@@ -0,0 +1,300 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include "kcp_dev.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int kcp_check_if_running(struct net_device *dev)
+{
+	return 0;
+}
+
+static void kcp_get_drvinfo(struct net_device *dev,
+		struct ethtool_drvinfo *info)
+{
+	int ret;
+
+	ret = kcp_nl_exec(info->cmd, dev, NULL, 0,
+			info, sizeof(struct ethtool_drvinfo));
+	if (ret < 0)
+		memset(info, 0, sizeof(struct ethtool_drvinfo));
+}
+
+static int kcp_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, NULL, 0,
+			ecmd, sizeof(struct ethtool_cmd));
+}
+
+static int kcp_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, ecmd, sizeof(struct ethtool_cmd),
+			NULL, 0);
+}
+
+static void kcp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	int ret;
+
+	ret = kcp_nl_exec(wol->cmd, dev, NULL, 0,
+			wol, sizeof(struct ethtool_wolinfo));
+	if (ret < 0)
+		memset(wol, 0, sizeof(struct ethtool_wolinfo));
+}
+
+static int kcp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	return kcp_nl_exec(wol->cmd, dev, wol, sizeof(struct ethtool_wolinfo),
+			NULL, 0);
+}
+
+static int kcp_nway_reset(struct net_device *dev)
+{
+	return kcp_nl_exec(ETHTOOL_NWAY_RST, dev, NULL, 0, NULL, 0);
+}
+
+static unsigned int kcp_get_link(struct net_device *dev)
+{
+	unsigned int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GLINK, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static int kcp_get_eeprom_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GEEPROM_LEN, dev, NULL, 0,
+			&data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static int kcp_get_eeprom(struct net_device *dev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct ethtool_eeprom eeprom_tmp;
+	int ret = 0;
+	int remaining;
+	int offset = 0;
+
+	eeprom_tmp = *eeprom;
+
+	remaining = eeprom_tmp.len;
+	while (remaining > 0 && ret == 0) {
+		eeprom_tmp.len = min(remaining, KCP_ETHTOOL_MSG_LEN);
+
+		ret = kcp_nl_exec(eeprom_tmp.cmd, dev,
+				&eeprom_tmp, sizeof(struct ethtool_eeprom),
+				data + offset, eeprom_tmp.len);
+		eeprom_tmp.offset += eeprom_tmp.len;
+		offset += eeprom_tmp.len;
+		remaining -= eeprom_tmp.len;
+	}
+
+	return ret;
+}
+
+static int kcp_set_eeprom(struct net_device *dev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct ethtool_eeprom *eeprom_tmp;
+	int ret = 0;
+	int remaining;
+	int offset = 0;
+	int payload;
+
+	if (sizeof(struct ethtool_eeprom) > KCP_ETHTOOL_MSG_LEN)
+		return -1;
+
+	eeprom_tmp = kmalloc(KCP_ETHTOOL_MSG_LEN, GFP_KERNEL);
+	payload = KCP_ETHTOOL_MSG_LEN - sizeof(struct ethtool_eeprom);
+
+	*eeprom_tmp = *eeprom;
+	remaining = eeprom->len;
+
+	while (remaining > 0 && ret == 0) {
+		eeprom_tmp->len = min(remaining, payload);
+
+		memcpy(eeprom_tmp->data, data + offset, payload);
+
+		ret = kcp_nl_exec(eeprom->cmd, dev, eeprom,
+				KCP_ETHTOOL_MSG_LEN, NULL, 0);
+
+		eeprom_tmp->offset += eeprom_tmp->len;
+		offset += eeprom_tmp->len;
+		remaining -= eeprom_tmp->len;
+	}
+
+	kfree(eeprom_tmp);
+
+	return ret;
+}
+
+static void kcp_get_ringparam(struct net_device *dev,
+		struct ethtool_ringparam *ring)
+{
+
+	kcp_nl_exec(ring->cmd, dev, NULL, 0,
+			ring, sizeof(struct ethtool_ringparam));
+}
+
+static int kcp_set_ringparam(struct net_device *dev,
+		struct ethtool_ringparam *ring)
+{
+	return kcp_nl_exec(ring->cmd, dev,
+			ring, sizeof(struct ethtool_ringparam),
+			NULL, 0);
+}
+
+static void kcp_get_pauseparam(struct net_device *dev,
+		struct ethtool_pauseparam *pause)
+{
+
+	kcp_nl_exec(pause->cmd, dev, NULL, 0,
+			pause, sizeof(struct ethtool_pauseparam));
+}
+
+static int kcp_set_pauseparam(struct net_device *dev,
+		struct ethtool_pauseparam *pause)
+{
+	return kcp_nl_exec(pause->cmd, dev,
+			pause, sizeof(struct ethtool_pauseparam),
+			NULL, 0);
+}
+
+static u32 kcp_get_msglevel(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GMSGLVL, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_set_msglevel(struct net_device *dev, u32 data)
+{
+
+	kcp_nl_exec(ETHTOOL_SMSGLVL, dev, &data, sizeof(int), NULL, 0);
+}
+
+static int kcp_get_regs_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GREGS_LEN, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+		void *p)
+{
+	struct ethtool_regs regs_tmp;
+	int len = regs->len;
+
+	regs_tmp = *regs;
+
+	if (len > KCP_ETHTOOL_MSG_LEN) {
+		len = KCP_ETHTOOL_MSG_LEN;
+		regs_tmp.len = len;
+	}
+
+	kcp_nl_exec(regs->cmd, dev, &regs_tmp, sizeof(struct ethtool_regs),
+			p, len);
+}
+
+static void kcp_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+
+	kcp_nl_exec(ETHTOOL_GSTRINGS, dev, &stringset, sizeof(u32), data, 0);
+}
+
+static int kcp_get_sset_count(struct net_device *dev, int sset)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GSSET_COUNT, dev, &sset, sizeof(int),
+			&data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_get_ethtool_stats(struct net_device *dev,
+		struct ethtool_stats *stats, u64 *data)
+{
+
+	kcp_nl_exec(stats->cmd, dev, stats, sizeof(struct ethtool_stats),
+			data, stats->n_stats);
+}
+
+static const struct ethtool_ops kcp_ethtool_ops = {
+	.begin			= kcp_check_if_running,
+	.get_drvinfo		= kcp_get_drvinfo,
+	.get_settings		= kcp_get_settings,
+	.set_settings		= kcp_set_settings,
+	.get_regs_len		= kcp_get_regs_len,
+	.get_regs		= kcp_get_regs,
+	.get_wol		= kcp_get_wol,
+	.set_wol		= kcp_set_wol,
+	.nway_reset		= kcp_nway_reset,
+	.get_link		= kcp_get_link,
+	.get_eeprom_len		= kcp_get_eeprom_len,
+	.get_eeprom		= kcp_get_eeprom,
+	.set_eeprom		= kcp_set_eeprom,
+	.get_ringparam		= kcp_get_ringparam,
+	.set_ringparam		= kcp_set_ringparam,
+	.get_pauseparam		= kcp_get_pauseparam,
+	.set_pauseparam		= kcp_set_pauseparam,
+	.get_msglevel		= kcp_get_msglevel,
+	.set_msglevel		= kcp_set_msglevel,
+	.get_strings		= kcp_get_strings,
+	.get_sset_count		= kcp_get_sset_count,
+	.get_ethtool_stats	= kcp_get_ethtool_stats,
+};
+
+void kcp_set_ethtool_ops(struct net_device *netdev)
+{
+	netdev->ethtool_ops = &kcp_ethtool_ops;
+}
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_net.c b/lib/librte_eal/linuxapp/kcp/kcp_net.c
new file mode 100644
index 0000000..16ea153
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_net.c
@@ -0,0 +1,225 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <net/rtnetlink.h>
+
+#include "kcp_dev.h"
+
+static int kcp_net_init(struct net_device *dev)
+{
+	char mac[ETH_ALEN] = {0};
+
+	kcp_nl_exec(RTE_KCP_REQ_GET_MAC, dev, NULL, 0, mac, ETH_ALEN);
+	memcpy(dev->dev_addr, mac, dev->addr_len);
+
+	return 0;
+}
+
+static int kcp_net_open(struct net_device *dev)
+{
+	/* DPDK port already started, stop it first */
+	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+	kcp_nl_exec(RTE_KCP_REQ_START_PORT, dev, NULL, 0, NULL, 0);
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int kcp_net_close(struct net_device *dev)
+{
+	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static int kcp_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static void kcp_net_change_rx_flags(struct net_device *dev, int flags)
+{
+	int on = 1;
+	int off = 0;
+
+	if (flags & IFF_PROMISC)
+		kcp_nl_exec(RTE_KCP_REQ_SET_PROMISC, dev,
+				dev->flags & IFF_PROMISC ?  &on : &off,
+				sizeof(int), NULL, 0);
+
+	if (flags & IFF_ALLMULTI)
+		kcp_nl_exec(RTE_KCP_REQ_SET_ALLMULTI, dev,
+				dev->flags & IFF_ALLMULTI ?  &on : &off,
+				sizeof(int), NULL, 0);
+}
+
+static int kcp_net_set_mac(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	int err = 0;
+
+	if (!is_valid_ether_addr((unsigned char *)(addr->sa_data)))
+		return -EADDRNOTAVAIL;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_SET_MAC, dev, addr->sa_data,
+			dev->addr_len, NULL, 0);
+	if (err < 0)
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	return 0;
+}
+
+static int kcp_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+static int kcp_net_config(struct net_device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	return -EOPNOTSUPP;
+}
+
+static int kcp_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int err = 0;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_CHANGE_MTU, dev, &new_mtu, sizeof(int),
+			NULL, 0);
+
+	if (err == 0)
+		dev->mtu = new_mtu;
+
+	return err;
+}
+
+static struct rtnl_link_stats64 *kcp_net_stats64(struct net_device *dev,
+		struct rtnl_link_stats64 *stats)
+{
+	int err;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_GET_STATS, dev, NULL, 0,
+			stats, sizeof(struct rtnl_link_stats64));
+
+	return stats;
+}
+
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+static int kcp_net_change_carrier(struct net_device *dev, bool new_carrier)
+{
+	if (new_carrier)
+		netif_carrier_on(dev);
+	else
+		netif_carrier_off(dev);
+	return 0;
+}
+#endif
+
+static const struct net_device_ops kcp_net_netdev_ops = {
+	.ndo_init = kcp_net_init,
+	.ndo_open = kcp_net_open,
+	.ndo_stop = kcp_net_close,
+	.ndo_start_xmit = kcp_net_xmit,
+	.ndo_change_rx_flags = kcp_net_change_rx_flags,
+	.ndo_set_mac_address = kcp_net_set_mac,
+	.ndo_do_ioctl = kcp_net_ioctl,
+	.ndo_set_config = kcp_net_config,
+	.ndo_change_mtu = kcp_net_change_mtu,
+	.ndo_get_stats64 = kcp_net_stats64,
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+	.ndo_change_carrier = kcp_net_change_carrier,
+#endif
+};
+
+static void kcp_net_setup(struct net_device *dev)
+{
+	struct kcp_dev *kcp;
+
+	ether_setup(dev);
+	dev->netdev_ops = &kcp_net_netdev_ops;
+
+	kcp = netdev_priv(dev);
+	init_completion(&kcp->msg_received);
+
+	kcp_set_ethtool_ops(dev);
+}
+
+static int kcp_net_newlink(struct net *net, struct net_device *dev,
+		struct nlattr *tb[], struct nlattr *data[])
+{
+	int ret;
+	struct kcp_dev *kcp;
+
+	kcp = netdev_priv(dev);
+
+	if (data && data[IFLA_KCP_PORTID])
+		kcp->port_id = nla_get_u8(data[IFLA_KCP_PORTID]);
+	else
+		kcp->port_id = 0;
+
+	if (data && data[IFLA_KCP_PID])
+		kcp->pid = nla_get_u32(data[IFLA_KCP_PID]);
+	else
+		kcp->pid = 0;
+
+	ret = register_netdevice(dev);
+
+	return ret;
+}
+
+static struct rtnl_link_ops kcp_link_ops __read_mostly = {
+	.kind = KCP_DEVICE,
+	.priv_size = sizeof(struct kcp_dev),
+	.setup = kcp_net_setup,
+	.maxtype = IFLA_KCP_MAX,
+	.newlink = kcp_net_newlink,
+};
+
+static int __init kcp_init(void)
+{
+	kcp_nl_init();
+	return rtnl_link_register(&kcp_link_ops);
+}
+module_init(kcp_init);
+
+static void __exit kcp_exit(void)
+{
+	rtnl_link_unregister(&kcp_link_ops);
+	kcp_nl_release();
+}
+module_exit(kcp_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Kernel Module for managing kcp devices");
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_nl.c b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
new file mode 100644
index 0000000..a4b56aa
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
@@ -0,0 +1,215 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <net/sock.h>
+
+#include "kcp_dev.h"
+
+#define KCP_CMD_TIMEOUT 500 /* ms */
+
+static struct ethtool_input_buffer {
+	int magic;
+	void *buffer;
+	int length;
+	struct completion *msg_received;
+	int *err;
+	int in_use;
+} ethtool_input_buffer;
+
+static struct sock *nl_sock;
+static struct mutex sync_lock;
+
+static int kcp_input_buffer_register(int magic, void *buffer, int length,
+		struct completion *msg_received, int *err)
+{
+	if (ethtool_input_buffer.in_use == 0) {
+		ethtool_input_buffer.magic = magic;
+		ethtool_input_buffer.buffer = buffer;
+		ethtool_input_buffer.length = length;
+		ethtool_input_buffer.msg_received = msg_received;
+		ethtool_input_buffer.err = err;
+		ethtool_input_buffer.in_use = 1;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void kcp_input_buffer_unregister(int magic)
+{
+	if (ethtool_input_buffer.in_use == 1) {
+		if (magic == ethtool_input_buffer.magic) {
+			ethtool_input_buffer.magic = -1;
+			ethtool_input_buffer.buffer = NULL;
+			ethtool_input_buffer.length = 0;
+			ethtool_input_buffer.msg_received = NULL;
+			ethtool_input_buffer.err = NULL;
+			ethtool_input_buffer.in_use = 0;
+		} else {
+			KCP_ERR("Unregister magic mismatch\n");
+		}
+	}
+}
+
+static void nl_recv_user_request(struct kcp_ethtool_msg *ethtool_msg)
+{
+	KCP_DBG("Request from userspace received\n");
+}
+
+static void nl_recv_user_response(struct kcp_ethtool_msg *ethtool_msg)
+{
+	struct completion *msg_received;
+	int recv_len;
+	int expected_len;
+
+	if (ethtool_input_buffer.in_use == 1) {
+		if (ethtool_input_buffer.buffer != NULL) {
+			recv_len = ethtool_msg->output_buffer_len;
+			expected_len = ethtool_input_buffer.length;
+
+			memcpy(ethtool_input_buffer.buffer,
+					ethtool_msg->output_buffer,
+					ethtool_input_buffer.length);
+
+			if (ethtool_msg->err == 0 && recv_len != expected_len)
+				KCP_INFO("Expected and received len not match "
+					"%d - %d\n", recv_len, expected_len);
+		}
+
+		*ethtool_input_buffer.err = ethtool_msg->err;
+		msg_received = ethtool_input_buffer.msg_received;
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		complete(msg_received);
+	}
+}
+
+static void nl_recv(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	nlh = (struct nlmsghdr *)skb->data;
+
+	memcpy(&ethtool_msg, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
+	KCP_DBG("CMD: %d\n", ethtool_msg.cmd_id);
+
+	if (ethtool_msg.flag & KCP_MSG_FLAG_REQUEST) {
+		nl_recv_user_request(&ethtool_msg);
+		return;
+	}
+
+	nl_recv_user_response(&ethtool_msg);
+}
+
+static int kcp_nl_send(int cmd_id, int port_id, unsigned int pid,
+		void *in_data, int in_data_len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	if (pid == 0)
+		return -1;
+
+	memset(&ethtool_msg, 0, sizeof(struct kcp_ethtool_msg));
+	ethtool_msg.cmd_id = cmd_id;
+	ethtool_msg.port_id = port_id;
+
+	if (in_data) {
+		if (in_data_len == 0 || in_data_len > KCP_ETHTOOL_MSG_LEN)
+			return -EINVAL;
+		ethtool_msg.input_buffer_len = in_data_len;
+		memcpy(ethtool_msg.input_buffer, in_data, in_data_len);
+	}
+
+	skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct kcp_ethtool_msg)),
+			GFP_ATOMIC);
+	nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, sizeof(struct kcp_ethtool_msg),
+			0);
+
+	NETLINK_CB(skb).dst_group = 0;
+
+	memcpy(nlmsg_data(nlh), &ethtool_msg, sizeof(struct kcp_ethtool_msg));
+
+	nlmsg_unicast(nl_sock, skb, pid);
+	KCP_DBG("Sent cmd:%d port:%d pid:%u\n", cmd_id, port_id, pid);
+
+	return 0;
+}
+
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data,
+		int in_data_len, void *out_data, int out_data_len)
+{
+	struct kcp_dev *priv = netdev_priv(dev);
+	int err = -EINVAL;
+	int ret;
+
+	if (out_data_len > KCP_ETHTOOL_MSG_LEN) {
+		KCP_ERR("Message is too big to receive:%u\n", out_data_len);
+		return err;
+	}
+
+	mutex_lock(&sync_lock);
+	ret = kcp_input_buffer_register(cmd, out_data, out_data_len,
+			&priv->msg_received, &err);
+	if (ret) {
+		mutex_unlock(&sync_lock);
+		return -EINVAL;
+	}
+
+	ret = kcp_nl_send(cmd, priv->port_id, priv->pid, in_data, in_data_len);
+	if (ret) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		return ret;
+	}
+
+	ret = wait_for_completion_interruptible_timeout(&priv->msg_received,
+			 msecs_to_jiffies(KCP_CMD_TIMEOUT));
+	if (ret == 0 || err < 0) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		priv->nb_timedout_msg++;
+		KCP_INFO("Command timed-out for port:%d cmd:%d (%u)\n",
+				priv->port_id, cmd, priv->nb_timedout_msg);
+		return ret == 0 ? -EINVAL : err;
+	}
+	mutex_unlock(&sync_lock);
+
+	return 0;
+}
+
+static struct netlink_kernel_cfg cfg = {
+	.input = nl_recv,
+};
+
+void kcp_nl_init(void)
+{
+	nl_sock = netlink_kernel_create(&init_net, KCP_NL_GRP, &cfg);
+	mutex_init(&sync_lock);
+}
+
+void kcp_nl_release(void)
+{
+	netlink_kernel_release(nl_sock);
+}
-- 
2.5.0

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

* [PATCH v3 3/4] rte_ctrl_if: add control interface library
  2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  2016-02-26 14:10     ` [PATCH v3 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
  2016-02-26 14:10     ` [PATCH v3 2/4] kcp: add kernel control path kernel module Ferruh Yigit
@ 2016-02-26 14:10     ` Ferruh Yigit
  2016-02-26 14:10     ` [PATCH v3 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
                       ` (2 subsequent siblings)
  5 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-26 14:10 UTC (permalink / raw)
  To: dev

This library gets control messages form kernelspace and forwards them to
librte_ether and returns response back to the kernelspace.

Library does:
1) Trigger Linux virtual interface creation
2) Initialize the netlink socket communication
3) Provides process() API to the application that does processing the
received messages

This library requires corresponding kernel module to be inserted.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---

v3:
* Use librte_ethtool
* Don't create interfaces for virtual PMDs
* Add a new API ...msg_exist() to support port based locking
* Add enable/disable promisc, allmulti support

v2:
* User rtnetlink to create interfaces.
* Add more ethtool support: get/set ringparam, set pauseparam.
* return defined error instead of hardcoded value
---
 MAINTAINERS                                |   1 +
 config/common_linuxapp                     |   3 +-
 doc/api/doxy-api-index.md                  |   1 +
 doc/api/doxy-api.conf                      |   1 +
 doc/guides/prog_guide/ctrl_if_lib.rst      |  52 ++++
 doc/guides/prog_guide/index.rst            |   1 +
 doc/guides/rel_notes/release_16_04.rst     |   9 +
 lib/Makefile                               |   3 +-
 lib/librte_ctrl_if/Makefile                |  58 +++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.c      | 376 +++++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.h      |  54 ++++
 lib/librte_ctrl_if/rte_ctrl_if.c           | 395 +++++++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h           | 129 ++++++++++
 lib/librte_ctrl_if/rte_ctrl_if_version.map |  10 +
 lib/librte_ctrl_if/rte_nl.c                | 313 +++++++++++++++++++++++
 lib/librte_ctrl_if/rte_nl.h                |  50 ++++
 lib/librte_eal/common/include/rte_log.h    |   3 +-
 mk/rte.app.mk                              |   3 +-
 18 files changed, 1458 insertions(+), 4 deletions(-)
 create mode 100644 doc/guides/prog_guide/ctrl_if_lib.rst
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6a77728..24dbfa0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -260,6 +260,7 @@ F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 Linux KCP
 M: Ferruh Yigit <ferruh.yigit@intel.com>
 F: lib/librte_eal/linuxapp/kcp/
+F: lib/librte_ctrl_if/
 
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 0284fae..dc75653 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -506,6 +506,7 @@ CONFIG_RTE_LIBRTE_ETHTOOL=y
 #
 CONFIG_RTE_KCP_KMOD=y
 CONFIG_RTE_KCP_KO_DEBUG=n
+CONFIG_RTE_LIBRTE_CTRL_IF=y
 
 #
 # Compile vhost library
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 4cdd3f5..e34250d 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -151,3 +151,4 @@ There are many libraries, so their headers may be grouped by topics:
   [keepalive]          (@ref rte_keepalive.h),
   [version]            (@ref rte_version.h),
   [ethtool]            (@ref rte_ethtool.h),
+  [control interface]  (@ref rte_ctrl_if.h)
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index c5b8615..1a7999e 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -39,6 +39,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_cmdline \
                           lib/librte_compat \
                           lib/librte_cryptodev \
+                          lib/librte_ctrl_if \
                           lib/librte_distributor \
                           lib/librte_ether \
                           lib/librte_ethtool \
diff --git a/doc/guides/prog_guide/ctrl_if_lib.rst b/doc/guides/prog_guide/ctrl_if_lib.rst
new file mode 100644
index 0000000..36054b9
--- /dev/null
+++ b/doc/guides/prog_guide/ctrl_if_lib.rst
@@ -0,0 +1,52 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+.. _Ctrl_If_Library:
+
+Control Interface Library
+=========================
+
+This Library is to create/destroy control interfaces and process messages
+received by control interface.
+
+Control Interface is Linux network interface and it is possible to call
+various Linux commands to this interface and commands will be forwarded
+to the matching DPDK PMD, and response will be generated by PMD.
+
+Control interface required KCP kernel module to be inserted to function.
+
+Control Interface APIS
+----------------------
+
+
+- ``rte_eth_control_interface_create()``
+- ``rte_eth_control_interface_destroy()``
+- ``rte_eth_control_interface_msg_exist()``
+- ``rte_eth_control_interface_msg_process()``
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index 98f4aca..aadc476 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -52,6 +52,7 @@ Programmer's Guide
     reorder_lib
     ip_fragment_reassembly_lib
     ethtool_lib
+    ctrl_if_lib
     multi_proc_support
     kernel_nic_interface
     thread_safety_dpdk_functions
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 70338f1..5deafdc 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -46,6 +46,14 @@ This section should contain new features added in this release. Sample format:
 
 * **Added vhost-user live migration support.**
 
+* **Control interface support added.**
+
+  To enable controlling DPDK ports by common Linux tools.
+  Following modules added to DPDK:
+
+  * librte_ctrl_if library
+  * librte_eal/linuxapp/kcp kernel module
+
 
 Resolved Issues
 ---------------
@@ -127,6 +135,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_acl.so.2
      librte_cfgfile.so.2
      librte_cmdline.so.1
+   + librte_ctrl_if.so.1
      librte_distributor.so.1
      librte_eal.so.2
    + librte_ethtool.so.1
diff --git a/lib/Makefile b/lib/Makefile
index ce8f0f9..8727454 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -59,6 +59,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
 DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
+DIRS-$(CONFIG_RTE_LIBRTE_CTRL_IF) += librte_ctrl_if
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_ctrl_if/Makefile b/lib/librte_ctrl_if/Makefile
new file mode 100644
index 0000000..fef4e4d
--- /dev/null
+++ b/lib/librte_ctrl_if/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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_ctrl_if.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_ctrl_if_version.map
+
+LIBABIVER := 1
+
+SRCS-y += rte_ctrl_if.c
+SRCS-y += rte_nl.c
+SRCS-y += rte_ctrl_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ctrl_if.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ctrl_if/rte_ctrl_ethtool.c b/lib/librte_ctrl_if/rte_ctrl_ethtool.c
new file mode 100644
index 0000000..fd010db
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_ethtool.c
@@ -0,0 +1,376 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <error.h>
+
+#include <linux/if_link.h>
+
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include <rte_ethtool.h>
+#include "rte_ctrl_ethtool.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int
+get_drvinfo(int port_id, void *data, int *data_len)
+{
+	struct ethtool_drvinfo *info = data;
+	int ret;
+
+	ret = rte_ethtool_get_drvinfo(port_id, info);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_drvinfo);
+
+	return 0;
+}
+
+static int
+get_reg_len(int port_id, void *data, int *data_len)
+{
+	int reg_length = 0;
+
+	reg_length = rte_ethtool_get_regs_len(port_id);
+	if (reg_length < 0)
+		return reg_length;
+
+	*(int *)data = reg_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_reg(int port_id, void *in_data, void *out_data, int *out_data_len)
+{
+	unsigned int reg_length;
+	int reg_length_out_len;
+	struct ethtool_regs *ethtool_regs = in_data;
+	int ret;
+
+	ret = get_reg_len(port_id, &reg_length, &reg_length_out_len);
+
+	/* not enough space in out data buffer */
+	if (ret < 0 || reg_length > ethtool_regs->len)
+		return -1;
+
+	ret = rte_ethtool_get_regs(port_id, ethtool_regs, out_data);
+	if (ret < 0)
+		return ret;
+
+	*out_data_len = reg_length;
+
+	return 0;
+}
+
+static int
+get_link(int port_id, void *data, int *data_len)
+{
+	int ret;
+
+	ret = rte_ethtool_get_link(port_id);
+
+	*(int *)data = ret;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom_length(int port_id, void *data, int *data_len)
+{
+	int eeprom_length = 0;
+
+	eeprom_length = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_length < 0)
+		return eeprom_length;
+
+	*(int *)data = eeprom_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom(int port_id, void *in_data, void *out_data, int *out_data_len)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	int ret;
+
+	ret = rte_ethtool_get_eeprom(port_id, eeprom, out_data);
+	if (ret < 0)
+		return ret;
+
+	*out_data_len = eeprom->len;
+
+	return 0;
+}
+
+static int
+set_eeprom(int port_id, void *in_data)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	int ret;
+
+	ret = rte_ethtool_set_eeprom(port_id, eeprom, eeprom->data);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+get_ringparam(int port_id, void *data, int *data_len)
+{
+	struct ethtool_ringparam *ringparam = data;
+	int ret;
+
+	ret = rte_ethtool_get_ringparam(port_id, ringparam);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_ringparam);
+
+	return 0;
+}
+
+static int
+set_ringparam(int port_id, void *data)
+{
+	struct ethtool_ringparam *ringparam = data;
+	int ret;
+
+	ret = rte_ethtool_set_ringparam(port_id, ringparam);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+get_pauseparam(int port_id, void *data, int *data_len)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+	int ret;
+
+	ret = rte_ethtool_get_pauseparam(port_id, pauseparam);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_pauseparam);
+
+	return 0;
+}
+
+static int
+set_pauseparam(int port_id, void *data)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+
+	return rte_ethtool_set_pauseparam(port_id, pauseparam);
+}
+
+int
+rte_eth_dev_ethtool_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len)
+{
+	int ret = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case ETHTOOL_GDRVINFO:
+		return get_drvinfo(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS_LEN:
+		return get_reg_len(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS:
+		return get_reg(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_GLINK:
+		return get_link(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM_LEN:
+		return get_eeprom_length(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM:
+		return get_eeprom(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_SEEPROM:
+		return set_eeprom(port_id, in_data);
+	case ETHTOOL_GRINGPARAM:
+		return get_ringparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SRINGPARAM:
+		return set_ringparam(port_id, in_data);
+	case ETHTOOL_GPAUSEPARAM:
+		return get_pauseparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SPAUSEPARAM:
+		return set_pauseparam(port_id, in_data);
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+set_mtu(int port_id, void *in_data)
+{
+	int *mtu = in_data;
+
+	return rte_eth_dev_set_mtu(port_id, *mtu);
+}
+
+static int
+get_stats(int port_id, void *data, int *data_len)
+{
+	struct rte_eth_stats stats;
+	struct rtnl_link_stats64 *if_stats = data;
+	int ret;
+
+	ret = rte_eth_stats_get(port_id, &stats);
+	if (ret < 0)
+		return -EOPNOTSUPP;
+
+	if_stats->rx_packets = stats.ipackets;
+	if_stats->tx_packets = stats.opackets;
+	if_stats->rx_bytes = stats.ibytes;
+	if_stats->tx_bytes = stats.obytes;
+	if_stats->rx_errors = stats.ierrors;
+	if_stats->tx_errors = stats.oerrors;
+	if_stats->rx_dropped = stats.imissed;
+	if_stats->multicast = stats.imcasts;
+
+	*data_len = sizeof(struct rtnl_link_stats64);
+
+	return 0;
+}
+
+static int
+get_mac(int port_id, void *data, int *data_len)
+{
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(port_id, &addr);
+	memcpy(data, &addr, sizeof(struct ether_addr));
+
+	*data_len = sizeof(struct ether_addr);
+
+	return 0;
+}
+
+static int
+set_mac(int port_id, void *in_data)
+{
+	struct ether_addr addr;
+
+	memcpy(&addr, in_data, ETHER_ADDR_LEN);
+
+	return rte_eth_dev_default_mac_addr_set(port_id, &addr);
+}
+
+static int
+start_port(int port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return rte_eth_dev_start(port_id);
+}
+
+static int
+stop_port(int port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return 0;
+}
+
+static int
+set_promisc(int port_id, void *in_data)
+{
+	int promisc = *(int *)in_data;
+
+	if (promisc)
+		rte_eth_promiscuous_enable(port_id);
+	else
+		rte_eth_promiscuous_disable(port_id);
+
+	return 0;
+}
+
+static int
+set_allmulti(int port_id, void *in_data)
+{
+	int allmulti = *(int *)in_data;
+
+	if (allmulti)
+		rte_eth_allmulticast_enable(port_id);
+	else
+		rte_eth_allmulticast_disable(port_id);
+
+	return 0;
+}
+
+int
+rte_eth_dev_control_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len)
+{
+	int ret = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case RTE_KCP_REQ_CHANGE_MTU:
+		return set_mtu(port_id, in_data);
+	case RTE_KCP_REQ_GET_STATS:
+		return get_stats(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_GET_MAC:
+		return get_mac(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_SET_MAC:
+		return set_mac(port_id, in_data);
+	case RTE_KCP_REQ_START_PORT:
+		return start_port(port_id);
+	case RTE_KCP_REQ_STOP_PORT:
+		return stop_port(port_id);
+	case RTE_KCP_REQ_SET_PROMISC:
+		return set_promisc(port_id, in_data);
+	case RTE_KCP_REQ_SET_ALLMULTI:
+		return set_allmulti(port_id, in_data);
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_ethtool.h b/lib/librte_ctrl_if/rte_ctrl_ethtool.h
new file mode 100644
index 0000000..1c064e5
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_ethtool.h
@@ -0,0 +1,54 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_CTRL_ETHTOOL_H_
+#define _RTE_CTRL_ETHTOOL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/ethtool.h>
+
+#include <exec-env/rte_kcp_common.h>
+
+int rte_eth_dev_ethtool_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len);
+int rte_eth_dev_control_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_ETHTOOL_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c
new file mode 100644
index 0000000..a8911f6
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.c
@@ -0,0 +1,395 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <rte_ethdev.h>
+#include "rte_ctrl_if.h"
+#include "rte_nl.h"
+
+#define NAMESZ 32
+#define IFNAME "dpdk"
+#define BUFSZ 1024
+
+static int kcp_rtnl_fd = -1;
+static int kcp_fd_ref;
+
+struct kcp_request {
+	struct nlmsghdr nlmsg;
+	char buf[BUFSZ];
+};
+
+static int
+conrol_interface_rtnl_init(void)
+{
+	struct sockaddr_nl src;
+	int ret;
+
+	kcp_rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (kcp_rtnl_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF, "socket for create failed\n");
+		return -1;
+	}
+
+	memset(&src, 0, sizeof(struct sockaddr_nl));
+
+	src.nl_family = AF_NETLINK;
+	src.nl_pid = getpid();
+
+	ret = bind(kcp_rtnl_fd, (struct sockaddr *)&src,
+			sizeof(struct sockaddr_nl));
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Bind for create failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+control_interface_init(void)
+{
+	int ret;
+
+	ret = conrol_interface_rtnl_init();
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize rtnetlink\n");
+		return -1;
+	}
+
+	ret = control_interface_nl_init();
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink\n");
+		close(kcp_rtnl_fd);
+		kcp_rtnl_fd = -1;
+	}
+
+	return ret;
+}
+
+static int
+control_interface_ref_get(void)
+{
+	int ret = 0;
+
+	if (kcp_fd_ref == 0)
+		ret = control_interface_init();
+
+	if (ret == 0)
+		kcp_fd_ref++;
+	else
+		RTE_LOG(ERR, CTRL_IF,
+				"Failed to initialize control interface\n");
+
+	return kcp_fd_ref;
+}
+
+static void
+control_interface_release(void)
+{
+	close(kcp_rtnl_fd);
+	control_interface_nl_release();
+}
+
+static int
+control_interface_ref_put(void)
+{
+	if (kcp_fd_ref == 0)
+		return 0;
+
+	kcp_fd_ref--;
+
+	if (kcp_fd_ref == 0)
+		control_interface_release();
+
+	return kcp_fd_ref;
+}
+
+static int
+add_attr(struct kcp_request *req, unsigned short type, void *buf, size_t len)
+{
+	struct rtattr *rta;
+	int nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(len) > sizeof(struct kcp_request))
+		return -1;
+	rta->rta_type = type;
+	rta->rta_len = RTA_LENGTH(len);
+	memcpy(RTA_DATA(rta), buf, len);
+	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(len);
+
+	return 0;
+}
+
+static struct
+rtattr *add_attr_nested(struct kcp_request *req, unsigned short type)
+{
+	struct rtattr *rta;
+	int nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(0) > sizeof(struct kcp_request))
+		return NULL;
+	rta->rta_type = type;
+	rta->rta_len = nlmsg_len;
+	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(0);
+
+	return rta;
+}
+
+static void
+end_attr_nested(struct kcp_request *req, struct rtattr *rta)
+{
+	rta->rta_len = req->nlmsg.nlmsg_len - rta->rta_len;
+}
+
+static int
+rte_eth_rtnl_create(uint8_t port_id)
+{
+	struct kcp_request req;
+	struct ifinfomsg *info;
+	struct rtattr *rta1;
+	struct rtattr *rta2;
+	unsigned int pid = getpid();
+	char name[NAMESZ];
+	char type[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+	char buf[BUFSZ];
+
+	memset(&req, 0, sizeof(struct kcp_request));
+
+	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
+	req.nlmsg.nlmsg_flags |= NLM_F_ACK;
+	req.nlmsg.nlmsg_type = RTM_NEWLINK;
+
+	info = NLMSG_DATA(&req.nlmsg);
+
+	info->ifi_family = AF_UNSPEC;
+	info->ifi_index = 0;
+
+	snprintf(name, NAMESZ, IFNAME"%u", port_id);
+	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
+	if (ret < 0)
+		return -1;
+
+	rta1 = add_attr_nested(&req, IFLA_LINKINFO);
+	if (rta1 == NULL)
+		return -1;
+
+	snprintf(type, NAMESZ, KCP_DEVICE);
+	ret = add_attr(&req, IFLA_INFO_KIND, type, strlen(type) + 1);
+	if (ret < 0)
+		return -1;
+
+	rta2 = add_attr_nested(&req, IFLA_INFO_DATA);
+	if (rta2 == NULL)
+		return -1;
+
+	ret = add_attr(&req, IFLA_KCP_PORTID, &port_id, sizeof(uint8_t));
+	if (ret < 0)
+		return -1;
+
+	ret = add_attr(&req, IFLA_KCP_PID, &pid, sizeof(unsigned int));
+	if (ret < 0)
+		return -1;
+
+	end_attr_nested(&req, rta2);
+	end_attr_nested(&req, rta1);
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for create failed %d.\n", errno);
+		return -1;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	iov.iov_base = buf;
+	iov.iov_len = sizeof(buf);
+
+	ret = recvmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Recv for create failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+rte_eth_control_interface_create_one(uint8_t port_id)
+{
+	int ret;
+
+	if (control_interface_ref_get() != 0) {
+		ret = rte_eth_rtnl_create(port_id);
+		RTE_LOG(DEBUG, CTRL_IF,
+			"Control interface %s for port:%u\n",
+			ret < 0 ? "failed" : "created", port_id);
+	}
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_create(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			if (rte_eth_devices[i].dev_type == RTE_ETH_DEV_VIRTUAL)
+				continue;
+			ret = rte_eth_control_interface_create_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int
+rte_eth_rtnl_destroy(uint8_t port_id)
+{
+	struct kcp_request req;
+	struct ifinfomsg *info;
+	char name[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+
+	memset(&req, 0, sizeof(struct kcp_request));
+
+	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlmsg.nlmsg_flags = NLM_F_REQUEST;
+	req.nlmsg.nlmsg_type = RTM_DELLINK;
+
+	info = NLMSG_DATA(&req.nlmsg);
+
+	info->ifi_family = AF_UNSPEC;
+	info->ifi_index = 0;
+
+	snprintf(name, NAMESZ, IFNAME"%u", port_id);
+	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
+	if (ret < 0)
+		return -1;
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for destroy failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+rte_eth_control_interface_destroy_one(uint8_t port_id)
+{
+	rte_eth_rtnl_destroy(port_id);
+	control_interface_ref_put();
+	RTE_LOG(DEBUG, CTRL_IF, "Control interface destroyed for port:%u\n",
+			port_id);
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_destroy(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			if (rte_eth_devices[i].dev_type == RTE_ETH_DEV_VIRTUAL)
+				continue;
+			ret = rte_eth_control_interface_destroy_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+int
+rte_eth_control_interface_msg_exist(unsigned int timeout_sec)
+{
+	return control_interface_msg_exist(timeout_sec);
+}
+
+int
+rte_eth_control_interface_msg_process(int flag)
+{
+	return control_interface_msg_process(flag);
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.h b/lib/librte_ctrl_if/rte_ctrl_if.h
new file mode 100644
index 0000000..868a56a
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.h
@@ -0,0 +1,129 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_CTRL_IF_H_
+#define _RTE_CTRL_IF_H_
+
+/**
+ * @file
+ *
+ * Control Interface Library for RTE
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <exec-env/rte_kcp_common.h>
+
+/**
+ * Flags values for rte_eth_control_interface_process_msg() API
+ */
+enum control_interface_process_flag {
+	/**< Process if msg available. */
+	RTE_ETHTOOL_CTRL_IF_PROCESS_MSG,
+
+	/**< Discard msg if available, respond with a error value. */
+	RTE_ETHTOOL_CTRL_IF_DISCARD_MSG,
+};
+
+/**
+ * Creates control interfaces (Linux virtual network interface)for
+ * each existing eal port.
+ *
+ * This API opens device created by supportive kernel module and initializes
+ * kernel communication interface.
+ *
+ * If supportive kernel module is not inserted this API will return
+ * an error.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_create(void);
+
+/**
+ * Destroys control interfaces.
+ *
+ * This API close device created by supportive kernel module and release
+ * underlying communication interface.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_destroy(void);
+
+/**
+ * Check if any msg exist to process.
+ *
+ * This function can be blocking or unblocking according timeout_sec
+ * parameter value. If function will be continuous loop, like can be
+ * called by any forwarding lcore, nonblocking mode should be preferred.
+ * If a separate thread created to handle control messages, blocking
+ * mode can be preferred to save CPU cycles.
+ *
+ * When this function sends a valid port_id, application must call
+ * msg_process() afterwards, to accept new commands.
+ *
+ * @param timeout_sec
+ *  if 0, function is in nonblocking mode.
+ *  if > 0, blocks for given time, if there is no message available,
+ *  sleeps again same amount of time. Value is in seconds.
+ *
+ * @return
+ *  port_id the msg for on success. -1 if no msg waiting.
+ */
+int rte_eth_control_interface_msg_exist(unsigned int timeout_sec);
+
+/**
+ * Process if any received message is available.
+ *
+ * If message exists this function will create a local copy of it and
+ * process or discard the message according flag.
+ *
+ * @param flag
+ *  Defines what to do with message, can be process or discard.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_msg_process(int flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_IF_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if_version.map b/lib/librte_ctrl_if/rte_ctrl_if_version.map
new file mode 100644
index 0000000..0e492cc
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if_version.map
@@ -0,0 +1,10 @@
+DPDK_2.3 {
+	global:
+
+	rte_eth_control_interface_create;
+	rte_eth_control_interface_destroy;
+	rte_eth_control_interface_msg_exist;
+	rte_eth_control_interface_msg_process;
+
+	local: *;
+};
diff --git a/lib/librte_ctrl_if/rte_nl.c b/lib/librte_ctrl_if/rte_nl.c
new file mode 100644
index 0000000..eec8c7c
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.c
@@ -0,0 +1,313 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <rte_spinlock.h>
+#include <rte_ethdev.h>
+#include "rte_ctrl_ethtool.h"
+#include "rte_nl.h"
+#include "rte_ctrl_if.h"
+
+#define MAX_PAYLOAD sizeof(struct kcp_ethtool_msg)
+
+struct ctrl_if_nl {
+	union {
+		struct nlmsghdr nlh;
+		uint8_t nlmsg[NLMSG_SPACE(MAX_PAYLOAD)];
+	};
+	struct msghdr msg;
+	struct iovec iov;
+	struct sockaddr_nl dest_addr;
+};
+
+struct ctrl_if_msg_sync {
+	int kcp_ethtool_msg_count;
+	struct kcp_ethtool_msg msg_storage;
+	pthread_cond_t cond;
+	pthread_mutex_t msg_lock;
+	int pending_process;
+};
+
+static int sock_fd = -1;
+static pthread_t thread_id;
+
+static struct ctrl_if_nl nl_s;
+static struct ctrl_if_nl nl_r;
+
+static struct ctrl_if_msg_sync ctrl_if_sync = {
+	.cond = PTHREAD_COND_INITIALIZER,
+	.msg_lock = PTHREAD_MUTEX_INITIALIZER,
+};
+
+static int
+nl_send(void *buf, size_t len)
+{
+	int ret;
+
+	if (nl_s.nlh.nlmsg_len < len) {
+		RTE_LOG(ERR, CTRL_IF, "Message is too big, len:%zu\n", len);
+		return -1;
+	}
+
+	if (!NLMSG_OK(&nl_s.nlh, NLMSG_SPACE(MAX_PAYLOAD))) {
+		RTE_LOG(ERR, CTRL_IF, "Message is not OK\n");
+		return -1;
+	}
+
+	/* Fill in the netlink message payload */
+	memcpy(NLMSG_DATA(nl_s.nlmsg), buf, len);
+
+	ret = sendmsg(sock_fd, &nl_s.msg, 0);
+
+	if (ret < 0)
+		RTE_LOG(ERR, CTRL_IF, "Failed nl msg send. ret:%d, err:%d\n",
+				ret, errno);
+	return ret;
+}
+
+static int
+nl_ethtool_msg_send(struct kcp_ethtool_msg *msg)
+{
+	return nl_send((void *)msg, sizeof(struct kcp_ethtool_msg));
+}
+
+static void
+process_msg(struct kcp_ethtool_msg *msg)
+{
+	if (msg->cmd_id > RTE_KCP_REQ_UNKNOWN) {
+		msg->err = rte_eth_dev_control_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	} else {
+		msg->err = rte_eth_dev_ethtool_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	}
+
+	if (msg->err)
+		memset(msg->output_buffer, 0, msg->output_buffer_len);
+
+	nl_ethtool_msg_send(msg);
+}
+
+
+int
+control_interface_msg_exist(unsigned int timeout_sec)
+{
+	struct timespec ts;
+	int port_id;
+	int ret = 0;
+
+	if (timeout_sec) {
+		clock_gettime(CLOCK_REALTIME, &ts);
+		ts.tv_sec += timeout_sec;
+	}
+
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+	while (timeout_sec && !ctrl_if_sync.kcp_ethtool_msg_count && !ret)
+		ret = pthread_cond_timedwait(&ctrl_if_sync.cond,
+				&ctrl_if_sync.msg_lock, &ts);
+
+	if (ctrl_if_sync.kcp_ethtool_msg_count == 0) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return -1;
+	}
+
+	ctrl_if_sync.pending_process = 1;
+
+	port_id = ctrl_if_sync.msg_storage.port_id;
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	return port_id;
+}
+
+int
+control_interface_msg_process(int flag)
+{
+	struct kcp_ethtool_msg msg_storage;
+	int ret = 0;
+
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+	if (ctrl_if_sync.kcp_ethtool_msg_count == 0) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return 0;
+	}
+
+	memcpy(&msg_storage, &ctrl_if_sync.msg_storage,
+			sizeof(struct kcp_ethtool_msg));
+	ctrl_if_sync.pending_process = 0;
+	ctrl_if_sync.kcp_ethtool_msg_count = 0;
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	switch (flag) {
+	case RTE_ETHTOOL_CTRL_IF_PROCESS_MSG:
+		process_msg(&msg_storage);
+		break;
+
+	case RTE_ETHTOOL_CTRL_IF_DISCARD_MSG:
+		msg_storage.err = -1;
+		nl_ethtool_msg_send(&msg_storage);
+		break;
+
+	default:
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+msg_add_and_signal(struct nlmsghdr *nlh)
+{
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+
+	if (ctrl_if_sync.pending_process) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return -1;
+	}
+
+	memcpy(&ctrl_if_sync.msg_storage, NLMSG_DATA(nlh),
+			sizeof(struct kcp_ethtool_msg));
+	ctrl_if_sync.kcp_ethtool_msg_count = 1;
+	ctrl_if_sync.msg_storage.flag = KCP_MSG_FLAG_RESPONSE;
+
+	pthread_cond_signal(&ctrl_if_sync.cond);
+
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	return 0;
+}
+
+static void *
+nl_recv(void *arg)
+{
+	int ret;
+
+	for (;;) {
+		ret = recvmsg(sock_fd, &nl_r.msg, 0);
+		if (ret < 0)
+			continue;
+
+		if ((unsigned)ret < sizeof(struct kcp_ethtool_msg)) {
+			RTE_LOG(WARNING, CTRL_IF,
+					"Received %u bytes, payload %lu\n",
+					ret, sizeof(struct kcp_ethtool_msg));
+			continue;
+		}
+
+		msg_add_and_signal(&nl_r.nlh);
+	}
+
+	return arg;
+}
+
+static void
+nl_setup_header(struct ctrl_if_nl *nl)
+{
+	nl->dest_addr.nl_family = AF_NETLINK;
+	nl->dest_addr.nl_pid = 0;   /*  For Linux Kernel */
+	nl->dest_addr.nl_groups = 0;
+
+	memset(nl->nlmsg, 0, NLMSG_SPACE(MAX_PAYLOAD));
+
+	/* Fill the netlink message header */
+	nl->nlh.nlmsg_len = NLMSG_LENGTH(MAX_PAYLOAD);
+	nl->nlh.nlmsg_pid = getpid();  /* self pid */
+	nl->nlh.nlmsg_flags = 0;
+
+	nl->iov.iov_base = (void *)nl->nlmsg;
+	nl->iov.iov_len = nl->nlh.nlmsg_len;
+	memset(&nl->msg, 0, sizeof(struct msghdr));
+	nl->msg.msg_name = (void *)&nl->dest_addr;
+	nl->msg.msg_namelen = sizeof(struct sockaddr_nl);
+	nl->msg.msg_iov = &nl->iov;
+	nl->msg.msg_iovlen = 1;
+}
+
+static int
+nl_socket_init(void)
+{
+	struct sockaddr_nl src_addr;
+	int fd;
+	int ret;
+
+	fd = socket(PF_NETLINK, SOCK_RAW, KCP_NL_GRP);
+	if (fd < 0)
+		return -1;
+
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	ret = bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
+	if (ret) {
+		close(fd);
+		return -1;
+	}
+
+	nl_setup_header(&nl_s);
+	nl_setup_header(&nl_r);
+
+	return fd;
+}
+
+int
+control_interface_nl_init(void)
+{
+	int ret;
+
+	sock_fd = nl_socket_init();
+	if (sock_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink socket\n");
+		return -1;
+	}
+
+	ret = pthread_create(&thread_id, NULL, nl_recv, NULL);
+	if (ret != 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to create receive thread\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void
+control_interface_nl_release(void)
+{
+	pthread_cancel(thread_id);
+	pthread_join(thread_id, NULL);
+	close(sock_fd);
+}
diff --git a/lib/librte_ctrl_if/rte_nl.h b/lib/librte_ctrl_if/rte_nl.h
new file mode 100644
index 0000000..ed4dea7
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.h
@@ -0,0 +1,50 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_NL_H_
+#define _RTE_NL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int control_interface_nl_init(void);
+void control_interface_nl_release(void);
+int control_interface_msg_exist(unsigned int timeout_sec);
+int control_interface_msg_process(int flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_NL_H_ */
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 2e47e7f..a0a2c9f 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
 #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
 #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
 #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#define RTE_LOGTYPE_CTRL_IF 0x00040000 /**< Log related to control interface. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 32f76b1..1b683ef 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -123,6 +123,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF_OFFLOAD)   += -lrte_mbuf_offload
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CTRL_IF)        += -lrte_ctrl_if
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.5.0

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

* [PATCH v3 4/4] examples/ethtool: add control interface support to the application
  2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
                       ` (2 preceding siblings ...)
  2016-02-26 14:10     ` [PATCH v3 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
@ 2016-02-26 14:10     ` Ferruh Yigit
  2016-02-29  9:33     ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Remy Horton
  2016-03-01 15:41     ` [PATCH v4 " Ferruh Yigit
  5 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-26 14:10 UTC (permalink / raw)
  To: dev

Control interface APIs added into the sample application.

To have the support corresponding kernel module (KCP) needs to be inserted.
If kernel module is not there, application will run as it is without
kernel control path support.

When KCP module inserted, running application creates a virtual Linux
network interface (dpdk$) per DPDK port. This interface can be used by
traditional Linux tools.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
---

v3:
* Use blocking mode control interface processing, instead of poll mode

v2:
* No update on sample app
---
 doc/guides/sample_app_ug/ethtool.rst | 41 ++++++++++++++++++++++++++++++++++++
 examples/ethtool/main.c              | 31 +++++++++++++++++++++++++--
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
index 65240ae..af591c2 100644
--- a/doc/guides/sample_app_ug/ethtool.rst
+++ b/doc/guides/sample_app_ug/ethtool.rst
@@ -130,3 +130,44 @@ interface that accepts commands as described in `using the
 application`_. Individual call-back functions handle the detail
 associated with each command, which make use of librte_ethtool
 library.
+
+Control Interface
+~~~~~~~~~~~~~~~~~
+
+If Kernel Control Path (KCP) kernel module (rte_kcp.ko) inserted,
+virtual interfaces created for each DPDK port for control purposes.
+
+Created interfaces are named as dpdk#, like:
+
+.. code-block:: console
+
+        # ifconfig dpdk0; ifconfig dpdk1
+        dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 90:e2:ba:0e:49:b9  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+        dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+Regular Linux commands can be issued on interfaces:
+
+.. code-block:: console
+
+        # ethtool -i dpdk0
+        driver: rte_ixgbe_pmd
+        version: RTE 2.3.0-rc0
+        firmware-version:
+        expansion-rom-version:
+        bus-info: 0000:08:00.1
+        supports-statistics: yes
+        supports-test: no
+        supports-eeprom-access: yes
+        supports-register-dump: yes
+        supports-priv-flags: no
diff --git a/examples/ethtool/main.c b/examples/ethtool/main.c
index 2c655d8..72fbe4c 100644
--- a/examples/ethtool/main.c
+++ b/examples/ethtool/main.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <rte_memory.h>
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
+#include <rte_ctrl_if.h>
 
 #include "ethapp.h"
 
@@ -54,7 +55,6 @@
 #define PKTPOOL_EXTRA_SIZE 512
 #define PKTPOOL_CACHE 32
 
-
 struct txq_port {
 	uint16_t cnt_unsent;
 	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
@@ -259,11 +259,32 @@ static int slave_main(__attribute__((unused)) void *ptr_data)
 	return 0;
 }
 
+static void *
+control_function(__attribute__((unused)) void *arg)
+{
+	int port_id;
+
+	while (1) {
+		/* blocking call with 1 sec timeout */
+		port_id = rte_eth_control_interface_msg_exist(1);
+		if (port_id < 0)
+			continue;
+
+		lock_port(port_id);
+		rte_eth_control_interface_msg_process(
+			RTE_ETHTOOL_CTRL_IF_PROCESS_MSG);
+		unlock_port(port_id);
+	}
+
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	int cnt_args_parsed;
 	uint32_t id_core;
 	uint32_t cnt_ports;
+	pthread_t control_thread;
 
 	/* Init runtime enviornment */
 	cnt_args_parsed = rte_eal_init(argc, argv);
@@ -293,6 +314,9 @@ int main(int argc, char **argv)
 	id_core = rte_get_next_lcore(id_core, 1, 1);
 	rte_eal_remote_launch(slave_main, NULL, id_core);
 
+	pthread_create(&control_thread, NULL, control_function, NULL);
+	rte_eth_control_interface_create();
+
 	ethapp_main();
 
 	app_cfg.exit_now = 1;
@@ -301,5 +325,8 @@ int main(int argc, char **argv)
 			return -1;
 	}
 
+	rte_eth_control_interface_destroy();
+	pthread_cancel(control_thread);
+
 	return 0;
 }
-- 
2.5.0

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-01-27 16:24 ` [PATCH 1/3] kcp: add kernel control path kernel module Ferruh Yigit
  2016-01-28  9:49   ` Remy Horton
@ 2016-02-28 15:34   ` Avi Kivity
  2016-02-28 20:16     ` Ferruh Yigit
  2016-02-29 20:11   ` Stephen Hemminger
  2 siblings, 1 reply; 83+ messages in thread
From: Avi Kivity @ 2016-02-28 15:34 UTC (permalink / raw)
  To: Ferruh Yigit, dev

On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
> This kernel module is based on KNI module, but this one is stripped
> version of it and only for control messages, no data transfer
> functionality provided.
>
> This Linux kernel module helps userspace application create virtual
> interfaces and when a control command issued into that virtual
> interface, module pushes the command to the userspace and gets the
> response back for the caller application.
>
> The Linux tools like ethtool/ifconfig/ip can be used on virtual
> interfaces but not ones for related data, like tcpdump.
>
> In long term this patch intends to replace the KNI and KNI will be
> depreciated.

Instead of adding yet another out-of-tree kernel module, why not extend 
the existing in-tree tap driver?  This will make everyone's life easier.

Since tap also supports data transfer, an application can also forward 
packets not intended to it to the kernel, and forward packets from the 
kernel through the device.

> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> ---
>   config/common_linuxapp                             |   6 +
>   lib/librte_eal/linuxapp/Makefile                   |   5 +-
>   lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
>   .../linuxapp/eal/include/exec-env/rte_kcp_common.h |  86 +++++++
>   lib/librte_eal/linuxapp/kcp/Makefile               |  58 +++++
>   lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  65 +++++
>   lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 261 +++++++++++++++++++
>   lib/librte_eal/linuxapp/kcp/kcp_misc.c             | 282 +++++++++++++++++++++
>   lib/librte_eal/linuxapp/kcp/kcp_net.c              | 209 +++++++++++++++
>   lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 194 ++++++++++++++
>   10 files changed, 1167 insertions(+), 2 deletions(-)
>   create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
>   create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
>   create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
>   create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
>   create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_misc.c
>   create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
>   create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c
>
> diff --git a/config/common_linuxapp b/config/common_linuxapp
> index 74bc515..5d5e3e4 100644
> --- a/config/common_linuxapp
> +++ b/config/common_linuxapp
> @@ -503,6 +503,12 @@ CONFIG_RTE_KNI_VHOST_DEBUG_RX=n
>   CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
>   
>   #
> +# Compile librte_ctrl_if
> +#
> +CONFIG_RTE_KCP_KMOD=y
> +CONFIG_RTE_KCP_KO_DEBUG=n
> +
> +#
>   # Compile vhost library
>   # fuse-devel is needed to run vhost-cuse.
>   # fuse-devel enables user space char driver development
> diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile
> index d9c5233..d1fa3a3 100644
> --- a/lib/librte_eal/linuxapp/Makefile
> +++ b/lib/librte_eal/linuxapp/Makefile
> @@ -1,6 +1,6 @@
>   #   BSD LICENSE
>   #
> -#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
> +#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
>   #   All rights reserved.
>   #
>   #   Redistribution and use in source and binary forms, with or without
> @@ -38,6 +38,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal
>   ifeq ($(CONFIG_RTE_KNI_KMOD),y)
>   DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kni
>   endif
> +ifeq ($(CONFIG_RTE_KCP_KMOD),y)
> +DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kcp
> +endif
>   ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y)
>   DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += xen_dom0
>   endif
> diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
> index 26eced5..dded8cb 100644
> --- a/lib/librte_eal/linuxapp/eal/Makefile
> +++ b/lib/librte_eal/linuxapp/eal/Makefile
> @@ -1,6 +1,6 @@
>   #   BSD LICENSE
>   #
> -#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
> +#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
>   #   All rights reserved.
>   #
>   #   Redistribution and use in source and binary forms, with or without
> @@ -116,6 +116,7 @@ CFLAGS_eal_thread.o += -Wno-return-type
>   endif
>   
>   INC := rte_interrupts.h rte_kni_common.h rte_dom0_common.h
> +INC += rte_kcp_common.h
>   
>   SYMLINK-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP)-include/exec-env := \
>   	$(addprefix include/exec-env/,$(INC))
> diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
> new file mode 100644
> index 0000000..b3a6ee3
> --- /dev/null
> +++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
> @@ -0,0 +1,86 @@
> +/*-
> + *   This file is provided under a dual BSD/LGPLv2 license.  When using or
> + *   redistributing this file, you may do so under either license.
> + *
> + *   GNU LESSER GENERAL PUBLIC LICENSE
> + *
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> + *
> + *   This program is free software; you can redistribute it and/or modify
> + *   it under the terms of version 2.1 of the GNU Lesser General Public License
> + *   as published by the Free Software Foundation.
> + *
> + *   This program is distributed in the hope that it will be useful, but
> + *   WITHOUT ANY WARRANTY; without even the implied warranty of
> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *   Lesser General Public License for more details.
> + *
> + *   You should have received a copy of the GNU Lesser General Public License
> + *   along with this program;
> + *
> + *   Contact Information:
> + *   Intel Corporation
> + *
> + *
> + *   BSD LICENSE
> + *
> + *   Copyright(c) 2016 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_KCP_COMMON_H_
> +#define _RTE_KCP_COMMON_H_
> +
> +#ifdef __KERNEL__
> +#include <linux/if.h>
> +#endif
> +
> +/*
> + * Request id.
> + */
> +enum rte_kcp_req_id {
> +	RTE_KCP_REQ_UNKNOWN = (1 << 16),
> +	RTE_KCP_REQ_CHANGE_MTU,
> +	RTE_KCP_REQ_CFG_NETWORK_IF,
> +	RTE_KCP_REQ_GET_STATS,
> +	RTE_KCP_REQ_GET_MAC,
> +	RTE_KCP_REQ_SET_MAC,
> +	RTE_KCP_REQ_START_PORT,
> +	RTE_KCP_REQ_STOP_PORT,
> +	RTE_KCP_REQ_MAX,
> +};
> +
> +#define KCP_DEVICE "kcp"
> +
> +#define RTE_KCP_IOCTL_TEST    _IOWR(0, 1, int)
> +#define RTE_KCP_IOCTL_CREATE  _IOWR(0, 2, int)
> +#define RTE_KCP_IOCTL_RELEASE _IOWR(0, 3, int)
> +
> +#endif /* _RTE_KCP_COMMON_H_ */
> diff --git a/lib/librte_eal/linuxapp/kcp/Makefile b/lib/librte_eal/linuxapp/kcp/Makefile
> new file mode 100644
> index 0000000..b2c44bd
> --- /dev/null
> +++ b/lib/librte_eal/linuxapp/kcp/Makefile
> @@ -0,0 +1,58 @@
> +#   BSD LICENSE
> +#
> +#   Copyright(c) 2016 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
> +
> +#
> +# module name and path
> +#
> +MODULE = rte_kcp
> +
> +#
> +# CFLAGS
> +#
> +MODULE_CFLAGS += -I$(SRCDIR)
> +MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
> +MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
> +MODULE_CFLAGS += -Wall -Werror
> +
> +# this lib needs main eal
> +DEPDIRS-y += lib/librte_eal/linuxapp/eal
> +
> +#
> +# all source are stored in SRCS-y
> +#
> +SRCS-y += kcp_misc.c
> +SRCS-y += kcp_net.c
> +SRCS-y += kcp_ethtool.c
> +SRCS-y += kcp_nl.c
> +
> +include $(RTE_SDK)/mk/rte.module.mk
> diff --git a/lib/librte_eal/linuxapp/kcp/kcp_dev.h b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
> new file mode 100644
> index 0000000..e537821
> --- /dev/null
> +++ b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
> @@ -0,0 +1,65 @@
> +/*-
> + * GPL LICENSE SUMMARY
> + *
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> + *
> + *   This program is free software; you can redistribute it and/or modify
> + *   it under the terms of version 2 of the GNU General Public License as
> + *   published by the Free Software Foundation.
> + *
> + *   This program is distributed in the hope that it will be useful, but
> + *   WITHOUT ANY WARRANTY; without even the implied warranty of
> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *   General Public License for more details.
> + *
> + *   You should have received a copy of the GNU General Public License
> + *   along with this program;
> + *
> + *   The full GNU General Public License is included in this distribution
> + *   in the file called LICENSE.GPL.
> + *
> + *   Contact Information:
> + *   Intel Corporation
> + */
> +
> +#ifndef _KCP_DEV_H_
> +#define _KCP_DEV_H_
> +
> +#include <linux/netdevice.h>
> +#include <exec-env/rte_kcp_common.h>
> +
> +#define RTE_KCP_NAMESIZE 32
> +
> +struct kcp_dev {
> +	/* kcp list */
> +	struct list_head list;
> +
> +	char name[RTE_KCP_NAMESIZE]; /* Network device name */
> +
> +	/* kcp device */
> +	struct net_device *net_dev;
> +
> +	int port_id;
> +	struct completion msg_received;
> +};
> +
> +void kcp_net_init(struct net_device *dev);
> +
> +void kcp_nl_init(void);
> +void kcp_nl_release(void);
> +int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data, int in_len,
> +		void *out_data, int out_len);
> +
> +void kcp_set_ethtool_ops(struct net_device *netdev);
> +
> +#define KCP_ERR(args...) printk(KERN_ERR "KCP: " args)
> +#define KCP_INFO(args...) printk(KERN_INFO "KCP: " args)
> +#define KCP_PRINT(args...) printk(KERN_DEBUG "KCP: " args)
> +
> +#ifdef RTE_KCP_KO_DEBUG
> +#define KCP_DBG(args...) printk(KERN_DEBUG "KCP: " args)
> +#else
> +#define KCP_DBG(args...)
> +#endif
> +
> +#endif /* _KCP_DEV_H_ */
> diff --git a/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
> new file mode 100644
> index 0000000..3a22dba
> --- /dev/null
> +++ b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
> @@ -0,0 +1,261 @@
> +/*-
> + * GPL LICENSE SUMMARY
> + *
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> + *
> + *   This program is free software; you can redistribute it and/or modify
> + *   it under the terms of version 2 of the GNU General Public License as
> + *   published by the Free Software Foundation.
> + *
> + *   This program is distributed in the hope that it will be useful, but
> + *   WITHOUT ANY WARRANTY; without even the implied warranty of
> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *   General Public License for more details.
> + *
> + *   You should have received a copy of the GNU General Public License
> + *   along with this program;
> + *
> + *   The full GNU General Public License is included in this distribution
> + *   in the file called LICENSE.GPL.
> + *
> + *   Contact Information:
> + *   Intel Corporation
> + */
> +
> +#include "kcp_dev.h"
> +
> +#define ETHTOOL_GEEPROM_LEN 99
> +#define ETHTOOL_GREGS_LEN 98
> +#define ETHTOOL_GSSET_COUNT 97
> +
> +static int
> +kcp_check_if_running(struct net_device *dev)
> +{
> +	return 0;
> +}
> +
> +static void
> +kcp_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
> +{
> +	int ret;
> +
> +	ret = kcp_nl_exec(info->cmd, dev, NULL, 0,
> +			info, sizeof(struct ethtool_drvinfo));
> +	if (ret < 0)
> +		memset(info, 0, sizeof(struct ethtool_drvinfo));
> +}
> +
> +static int
> +kcp_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
> +{
> +	return kcp_nl_exec(ecmd->cmd, dev, NULL, 0,
> +			ecmd, sizeof(struct ethtool_cmd));
> +}
> +
> +static int
> +kcp_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
> +{
> +	return kcp_nl_exec(ecmd->cmd, dev, ecmd, sizeof(struct ethtool_cmd),
> +			NULL, 0);
> +}
> +
> +static void
> +kcp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
> +{
> +	int ret;
> +
> +	ret = kcp_nl_exec(wol->cmd, dev, NULL, 0,
> +			wol, sizeof(struct ethtool_wolinfo));
> +	if (ret < 0)
> +		memset(wol, 0, sizeof(struct ethtool_wolinfo));
> +}
> +
> +static int
> +kcp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
> +{
> +	return kcp_nl_exec(wol->cmd, dev, wol, sizeof(struct ethtool_wolinfo),
> +			NULL, 0);
> +}
> +
> +static int
> +kcp_nway_reset(struct net_device *dev)
> +{
> +	return kcp_nl_exec(ETHTOOL_NWAY_RST, dev, NULL, 0, NULL, 0);
> +}
> +
> +static int
> +kcp_get_eeprom_len(struct net_device *dev)
> +{
> +	int data;
> +	int ret;
> +
> +	ret = kcp_nl_exec(ETHTOOL_GEEPROM_LEN, dev, NULL, 0,
> +			&data, sizeof(int));
> +	if (ret < 0)
> +		return ret;
> +
> +	return data;
> +}
> +
> +static int
> +kcp_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
> +		u8 *bytes)
> +{
> +	int ret;
> +
> +	ret = kcp_nl_exec(eeprom->cmd, dev,
> +			eeprom, sizeof(struct ethtool_eeprom),
> +			bytes, eeprom->len);
> +	*bytes = 0;
> +	return ret;
> +}
> +
> +static int
> +kcp_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
> +		u8 *bytes)
> +{
> +	int ret;
> +
> +	ret = kcp_nl_exec(eeprom->cmd, dev,
> +			eeprom, sizeof(struct ethtool_eeprom),
> +			bytes, eeprom->len);
> +	*bytes = 0;
> +	return ret;
> +}
> +
> +static void
> +kcp_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
> +{
> +
> +	kcp_nl_exec(ring->cmd, dev, NULL, 0,
> +			ring, sizeof(struct ethtool_ringparam));
> +}
> +
> +static int
> +kcp_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
> +{
> +	int ret;
> +
> +	ret = kcp_nl_exec(ring->cmd, dev,
> +			ring, sizeof(struct ethtool_ringparam),
> +			NULL, 0);
> +	return ret;
> +}
> +
> +static void
> +kcp_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
> +{
> +
> +	kcp_nl_exec(pause->cmd, dev, NULL, 0,
> +			pause, sizeof(struct ethtool_pauseparam));
> +}
> +
> +static int
> +kcp_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
> +{
> +	return kcp_nl_exec(pause->cmd, dev,
> +			pause, sizeof(struct ethtool_pauseparam),
> +			NULL, 0);
> +}
> +
> +static u32
> +kcp_get_msglevel(struct net_device *dev)
> +{
> +	int data;
> +	int ret;
> +
> +	ret = kcp_nl_exec(ETHTOOL_GMSGLVL, dev, NULL, 0, &data, sizeof(int));
> +	if (ret < 0)
> +		return ret;
> +
> +	return data;
> +}
> +
> +static void
> +kcp_set_msglevel(struct net_device *dev, u32 data)
> +{
> +
> +	kcp_nl_exec(ETHTOOL_SMSGLVL, dev, &data, sizeof(int), NULL, 0);
> +}
> +
> +static int
> +kcp_get_regs_len(struct net_device *dev)
> +{
> +	int data;
> +	int ret;
> +
> +	ret = kcp_nl_exec(ETHTOOL_GREGS_LEN, dev, NULL, 0, &data, sizeof(int));
> +	if (ret < 0)
> +		return ret;
> +
> +	return data;
> +}
> +
> +static void
> +kcp_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
> +{
> +
> +	kcp_nl_exec(regs->cmd, dev, regs, sizeof(struct ethtool_regs),
> +			p, regs->len);
> +}
> +
> +static void
> +kcp_get_strings(struct net_device *dev, u32 stringset, u8 *data)
> +{
> +
> +	kcp_nl_exec(ETHTOOL_GSTRINGS, dev, &stringset, sizeof(u32), data, 0);
> +}
> +
> +static int
> +kcp_get_sset_count(struct net_device *dev, int sset)
> +{
> +	int data;
> +	int ret;
> +
> +	ret = kcp_nl_exec(ETHTOOL_GSSET_COUNT, dev, &sset, sizeof(int),
> +			&data, sizeof(int));
> +	if (ret < 0)
> +		return ret;
> +
> +	return data;
> +}
> +
> +static void
> +kcp_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats,
> +		u64 *data)
> +{
> +
> +	kcp_nl_exec(stats->cmd, dev, stats, sizeof(struct ethtool_stats),
> +			data, stats->n_stats);
> +}
> +
> +static const struct ethtool_ops kcp_ethtool_ops = {
> +	.begin			= kcp_check_if_running,
> +	.get_drvinfo		= kcp_get_drvinfo,
> +	.get_settings		= kcp_get_settings,
> +	.set_settings		= kcp_set_settings,
> +	.get_regs_len		= kcp_get_regs_len,
> +	.get_regs		= kcp_get_regs,
> +	.get_wol		= kcp_get_wol,
> +	.set_wol		= kcp_set_wol,
> +	.nway_reset		= kcp_nway_reset,
> +	.get_link		= ethtool_op_get_link,
> +	.get_eeprom_len		= kcp_get_eeprom_len,
> +	.get_eeprom		= kcp_get_eeprom,
> +	.set_eeprom		= kcp_set_eeprom,
> +	.get_ringparam		= kcp_get_ringparam,
> +	.set_ringparam		= kcp_set_ringparam,
> +	.get_pauseparam		= kcp_get_pauseparam,
> +	.set_pauseparam		= kcp_set_pauseparam,
> +	.get_msglevel		= kcp_get_msglevel,
> +	.set_msglevel		= kcp_set_msglevel,
> +	.get_strings		= kcp_get_strings,
> +	.get_sset_count		= kcp_get_sset_count,
> +	.get_ethtool_stats	= kcp_get_ethtool_stats,
> +};
> +
> +void
> +kcp_set_ethtool_ops(struct net_device *netdev)
> +{
> +	netdev->ethtool_ops = &kcp_ethtool_ops;
> +}
> diff --git a/lib/librte_eal/linuxapp/kcp/kcp_misc.c b/lib/librte_eal/linuxapp/kcp/kcp_misc.c
> new file mode 100644
> index 0000000..6df0d1b
> --- /dev/null
> +++ b/lib/librte_eal/linuxapp/kcp/kcp_misc.c
> @@ -0,0 +1,282 @@
> +/*-
> + * GPL LICENSE SUMMARY
> + *
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> + *
> + *   This program is free software; you can redistribute it and/or modify
> + *   it under the terms of version 2 of the GNU General Public License as
> + *   published by the Free Software Foundation.
> + *
> + *   This program is distributed in the hope that it will be useful, but
> + *   WITHOUT ANY WARRANTY; without even the implied warranty of
> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *   General Public License for more details.
> + *
> + *   You should have received a copy of the GNU General Public License
> + *   along with this program;
> + *
> + *   The full GNU General Public License is included in this distribution
> + *   in the file called LICENSE.GPL.
> + *
> + *   Contact Information:
> + *   Intel Corporation
> + */
> +
> +#include <linux/module.h>
> +#include <linux/miscdevice.h>
> +
> +#include "kcp_dev.h"
> +
> +#define KCP_DEV_IN_USE_BIT_NUM 0 /* Bit number for device in use */
> +
> +static volatile unsigned long device_in_use; /* device in use flag */
> +
> +/* kcp list lock */
> +static DECLARE_RWSEM(kcp_list_lock);
> +
> +/* kcp list */
> +static struct list_head kcp_list_head = LIST_HEAD_INIT(kcp_list_head);
> +
> +static int
> +kcp_open(struct inode *inode, struct file *file)
> +{
> +	/* kcp device can be opened by one user only, test and set bit */
> +	if (test_and_set_bit(KCP_DEV_IN_USE_BIT_NUM, &device_in_use))
> +		return -EBUSY;
> +
> +	KCP_PRINT("/dev/kcp opened\n");
> +
> +	kcp_nl_init();
> +
> +	return 0;
> +}
> +
> +static int
> +kcp_dev_remove(struct kcp_dev *dev)
> +{
> +	if (!dev)
> +		return -ENODEV;
> +
> +	if (dev->net_dev) {
> +		unregister_netdev(dev->net_dev);
> +		free_netdev(dev->net_dev);
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +kcp_release(struct inode *inode, struct file *file)
> +{
> +	struct kcp_dev *dev, *n;
> +
> +	down_write(&kcp_list_lock);
> +	list_for_each_entry_safe(dev, n, &kcp_list_head, list) {
> +		kcp_dev_remove(dev);
> +		list_del(&dev->list);
> +	}
> +	up_write(&kcp_list_lock);
> +
> +	kcp_nl_release();
> +
> +	/* Clear the bit of device in use */
> +	clear_bit(KCP_DEV_IN_USE_BIT_NUM, &device_in_use);
> +
> +	KCP_PRINT("/dev/kcp closed\n");
> +
> +	return 0;
> +}
> +
> +static int
> +kcp_check_param(struct kcp_dev *kcp, char *name)
> +{
> +	if (!kcp)
> +		return -1;
> +
> +	/* Check if network name has been used */
> +	if (!strncmp(kcp->name, name, RTE_KCP_NAMESIZE)) {
> +		KCP_ERR("KCP interface name %s duplicated\n", name);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +kcp_ioctl_create(unsigned int ioctl_num, unsigned long ioctl_param)
> +{
> +	int ret;
> +	struct net_device *net_dev = NULL;
> +	struct kcp_dev *kcp, *dev, *n;
> +	struct net *net;
> +	char name[RTE_KCP_NAMESIZE];
> +	unsigned int instance = ioctl_param;
> +	char mac[ETH_ALEN];
> +
> +	KCP_PRINT("Creating kcp...\n");
> +
> +	snprintf(name, RTE_KCP_NAMESIZE, "dpdk%u", instance);
> +
> +	/* Check if it has been created */
> +	down_read(&kcp_list_lock);
> +	list_for_each_entry_safe(dev, n, &kcp_list_head, list) {
> +		if (kcp_check_param(dev, name) < 0) {
> +			up_read(&kcp_list_lock);
> +			return -EINVAL;
> +		}
> +	}
> +	up_read(&kcp_list_lock);
> +
> +	net_dev = alloc_netdev(sizeof(struct kcp_dev), name,
> +#ifdef NET_NAME_UNKNOWN
> +							NET_NAME_UNKNOWN,
> +#endif
> +							kcp_net_init);
> +	if (net_dev == NULL) {
> +		KCP_ERR("error allocating device \"%s\"\n", name);
> +		return -EBUSY;
> +	}
> +
> +	net = get_net_ns_by_pid(task_pid_vnr(current));
> +	if (IS_ERR(net)) {
> +		free_netdev(net_dev);
> +		return PTR_ERR(net);
> +	}
> +	dev_net_set(net_dev, net);
> +	put_net(net);
> +
> +	kcp = netdev_priv(net_dev);
> +
> +	kcp->net_dev = net_dev;
> +	kcp->port_id = instance;
> +	init_completion(&kcp->msg_received);
> +	strncpy(kcp->name, name, RTE_KCP_NAMESIZE);
> +
> +	kcp_nl_exec(RTE_KCP_REQ_GET_MAC, net_dev, NULL, 0, mac, ETH_ALEN);
> +	memcpy(net_dev->dev_addr, mac, net_dev->addr_len);
> +
> +	kcp_set_ethtool_ops(net_dev);
> +	ret = register_netdev(net_dev);
> +	if (ret) {
> +		KCP_ERR("error %i registering device \"%s\"\n", ret, name);
> +		kcp_dev_remove(kcp);
> +		return -ENODEV;
> +	}
> +
> +	down_write(&kcp_list_lock);
> +	list_add(&kcp->list, &kcp_list_head);
> +	up_write(&kcp_list_lock);
> +
> +	return 0;
> +}
> +
> +static int
> +kcp_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param)
> +{
> +	int ret = -EINVAL;
> +	struct kcp_dev *dev;
> +	struct kcp_dev *n;
> +	char name[RTE_KCP_NAMESIZE];
> +	unsigned int instance = ioctl_param;
> +
> +	snprintf(name, RTE_KCP_NAMESIZE, "dpdk%u", instance);
> +
> +	down_write(&kcp_list_lock);
> +	list_for_each_entry_safe(dev, n, &kcp_list_head, list) {
> +		if (strncmp(dev->name, name, RTE_KCP_NAMESIZE) != 0)
> +			continue;
> +		kcp_dev_remove(dev);
> +		list_del(&dev->list);
> +		ret = 0;
> +		break;
> +	}
> +	up_write(&kcp_list_lock);
> +	KCP_INFO("%s release kcp named %s\n",
> +		(ret == 0 ? "Successfully" : "Unsuccessfully"), name);
> +
> +	return ret;
> +}
> +
> +static int
> +kcp_ioctl(struct inode *inode, unsigned int ioctl_num,
> +	unsigned long ioctl_param)
> +{
> +	int ret = -EINVAL;
> +
> +	KCP_DBG("IOCTL num=0x%0x param=0x%0lx\n", ioctl_num, ioctl_param);
> +
> +	/*
> +	 * Switch according to the ioctl called
> +	 */
> +	switch (_IOC_NR(ioctl_num)) {
> +	case _IOC_NR(RTE_KCP_IOCTL_TEST):
> +		/* For test only, not used */
> +		break;
> +	case _IOC_NR(RTE_KCP_IOCTL_CREATE):
> +		ret = kcp_ioctl_create(ioctl_num, ioctl_param);
> +		break;
> +	case _IOC_NR(RTE_KCP_IOCTL_RELEASE):
> +		ret = kcp_ioctl_release(ioctl_num, ioctl_param);
> +		break;
> +	default:
> +		KCP_DBG("IOCTL default\n");
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int
> +kcp_compat_ioctl(struct inode *inode, unsigned int ioctl_num,
> +		unsigned long ioctl_param)
> +{
> +	/* 32 bits app on 64 bits OS to be supported later */
> +	KCP_PRINT("Not implemented.\n");
> +
> +	return -EINVAL;
> +}
> +
> +static const struct file_operations kcp_fops = {
> +	.owner = THIS_MODULE,
> +	.open = kcp_open,
> +	.release = kcp_release,
> +	.unlocked_ioctl = (void *)kcp_ioctl,
> +	.compat_ioctl = (void *)kcp_compat_ioctl,
> +};
> +
> +static struct miscdevice kcp_misc = {
> +	.minor = MISC_DYNAMIC_MINOR,
> +	.name = KCP_DEVICE,
> +	.fops = &kcp_fops,
> +};
> +
> +static int __init
> +kcp_init(void)
> +{
> +	KCP_PRINT("DPDK kcp module loading\n");
> +
> +	if (misc_register(&kcp_misc) != 0) {
> +		KCP_ERR("Misc registration failed\n");
> +		return -EPERM;
> +	}
> +
> +	/* Clear the bit of device in use */
> +	clear_bit(KCP_DEV_IN_USE_BIT_NUM, &device_in_use);
> +
> +	KCP_PRINT("DPDK kcp module loaded\n");
> +
> +	return 0;
> +}
> +module_init(kcp_init);
> +
> +static void __exit
> +kcp_exit(void)
> +{
> +	misc_deregister(&kcp_misc);
> +	KCP_PRINT("DPDK kcp module unloaded\n");
> +}
> +module_exit(kcp_exit);
> +
> +MODULE_LICENSE("Dual BSD/GPL");
> +MODULE_AUTHOR("Intel Corporation");
> +MODULE_DESCRIPTION("Kernel Module for managing kcp devices");
> diff --git a/lib/librte_eal/linuxapp/kcp/kcp_net.c b/lib/librte_eal/linuxapp/kcp/kcp_net.c
> new file mode 100644
> index 0000000..9dacaaa
> --- /dev/null
> +++ b/lib/librte_eal/linuxapp/kcp/kcp_net.c
> @@ -0,0 +1,209 @@
> +/*-
> + * GPL LICENSE SUMMARY
> + *
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> + *
> + *   This program is free software; you can redistribute it and/or modify
> + *   it under the terms of version 2 of the GNU General Public License as
> + *   published by the Free Software Foundation.
> + *
> + *   This program is distributed in the hope that it will be useful, but
> + *   WITHOUT ANY WARRANTY; without even the implied warranty of
> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *   General Public License for more details.
> + *
> + *   You should have received a copy of the GNU General Public License
> + *   along with this program;
> + *
> + *   The full GNU General Public License is included in this distribution
> + *   in the file called LICENSE.GPL.
> + *
> + *   Contact Information:
> + *   Intel Corporation
> + */
> +
> +/*
> + * This code is inspired from the book "Linux Device Drivers" by
> + * Alessandro Rubini and Jonathan Corbet, published by O'Reilly & Associates
> + */
> +
> +#include <linux/version.h>
> +#include <linux/etherdevice.h> /* eth_type_trans */
> +
> +#include "kcp_dev.h"
> +
> +/*
> + * Open and close
> + */
> +static int
> +kcp_net_open(struct net_device *dev)
> +{
> +	kcp_nl_exec(RTE_KCP_REQ_START_PORT, dev, NULL, 0, NULL, 0);
> +	netif_start_queue(dev);
> +	return 0;
> +}
> +
> +static int
> +kcp_net_release(struct net_device *dev)
> +{
> +	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
> +	netif_stop_queue(dev); /* can't transmit any more */
> +	return 0;
> +}
> +
> +/*
> + * Configuration changes (passed on by ifconfig)
> + */
> +static int
> +kcp_net_config(struct net_device *dev, struct ifmap *map)
> +{
> +	if (dev->flags & IFF_UP) /* can't act on a running interface */
> +		return -EBUSY;
> +
> +	/* ignore other fields */
> +	return 0;
> +}
> +
> +static int
> +kcp_net_change_mtu(struct net_device *dev, int new_mtu)
> +{
> +	int err;
> +
> +	KCP_DBG("kcp_net_change_mtu new mtu %d to be set\n", new_mtu);
> +	err = kcp_nl_exec(RTE_KCP_REQ_CHANGE_MTU, dev, &new_mtu, sizeof(int),
> +			NULL, 0);
> +
> +	if (err == 0)
> +		dev->mtu = new_mtu;
> +
> +	return err;
> +}
> +
> +/*
> + * Ioctl commands
> + */
> +static int
> +kcp_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
> +{
> +	KCP_DBG("kcp_net_ioctl\n");
> +
> +	return 0;
> +}
> +
> +/*
> + * Return statistics to the caller
> + */
> +static struct  rtnl_link_stats64 *
> +kcp_net_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
> +{
> +	int err;
> +
> +	err = kcp_nl_exec(RTE_KCP_REQ_GET_STATS, dev, NULL, 0,
> +			stats, sizeof(struct rtnl_link_stats64));
> +
> +	return stats;
> +}
> +
> +/**
> + * kcp_net_set_mac - Change the Ethernet Address of the KCP NIC
> + * @netdev: network interface device structure
> + * @p: pointer to an address structure
> + *
> + * Returns 0 on success, negative on failure
> + **/
> +static int
> +kcp_net_set_mac(struct net_device *dev, void *p)
> +{
> +	struct sockaddr *addr = p;
> +	int err;
> +
> +	if (!is_valid_ether_addr((unsigned char *)(addr->sa_data)))
> +		return -EADDRNOTAVAIL;
> +
> +	err = kcp_nl_exec(RTE_KCP_REQ_SET_MAC, dev, addr->sa_data,
> +			dev->addr_len, NULL, 0);
> +	if (err < 0)
> +		return -EADDRNOTAVAIL;
> +
> +	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
> +	return 0;
> +}
> +
> +#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
> +static int
> +kcp_net_change_carrier(struct net_device *dev, bool new_carrier)
> +{
> +	if (new_carrier)
> +		netif_carrier_on(dev);
> +	else
> +		netif_carrier_off(dev);
> +	return 0;
> +}
> +#endif
> +
> +static const struct net_device_ops kcp_net_netdev_ops = {
> +	.ndo_open = kcp_net_open,
> +	.ndo_stop = kcp_net_release,
> +	.ndo_set_config = kcp_net_config,
> +	.ndo_change_mtu = kcp_net_change_mtu,
> +	.ndo_do_ioctl = kcp_net_ioctl,
> +	.ndo_get_stats64 = kcp_net_stats64,
> +	.ndo_set_mac_address = kcp_net_set_mac,
> +#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
> +	.ndo_change_carrier = kcp_net_change_carrier,
> +#endif
> +};
> +
> +/*
> + *  Fill the eth header
> + */
> +static int
> +kcp_net_header(struct sk_buff *skb, struct net_device *dev,
> +		unsigned short type, const void *daddr,
> +		const void *saddr, unsigned int len)
> +{
> +	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
> +
> +	memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len);
> +	memcpy(eth->h_dest,   daddr ? daddr : dev->dev_addr, dev->addr_len);
> +	eth->h_proto = htons(type);
> +
> +	return dev->hard_header_len;
> +}
> +
> +/*
> + * Re-fill the eth header
> + */
> +#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
> +static int
> +kcp_net_rebuild_header(struct sk_buff *skb)
> +{
> +	struct net_device *dev = skb->dev;
> +	struct ethhdr *eth = (struct ethhdr *) skb->data;
> +
> +	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
> +	memcpy(eth->h_dest, dev->dev_addr, dev->addr_len);
> +
> +	return 0;
> +}
> +#endif
> +
> +static const struct header_ops kcp_net_header_ops = {
> +	.create  = kcp_net_header,
> +#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
> +	.rebuild = kcp_net_rebuild_header,
> +#endif
> +	.cache   = NULL,  /* disable caching */
> +};
> +
> +void
> +kcp_net_init(struct net_device *dev)
> +{
> +	KCP_DBG("kcp_net_init\n");
> +
> +	ether_setup(dev); /* assign some of the fields */
> +	dev->netdev_ops      = &kcp_net_netdev_ops;
> +	dev->header_ops      = &kcp_net_header_ops;
> +
> +	dev->flags |= IFF_UP;
> +}
> diff --git a/lib/librte_eal/linuxapp/kcp/kcp_nl.c b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
> new file mode 100644
> index 0000000..e989d2d
> --- /dev/null
> +++ b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
> @@ -0,0 +1,194 @@
> +/*-
> + * GPL LICENSE SUMMARY
> + *
> + *   Copyright(c) 2016 Intel Corporation. All rights reserved.
> + *
> + *   This program is free software; you can redistribute it and/or modify
> + *   it under the terms of version 2 of the GNU General Public License as
> + *   published by the Free Software Foundation.
> + *
> + *   This program is distributed in the hope that it will be useful, but
> + *   WITHOUT ANY WARRANTY; without even the implied warranty of
> + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *   General Public License for more details.
> + *
> + *   You should have received a copy of the GNU General Public License
> + *   along with this program;
> + *   The full GNU General Public License is included in this distribution
> + *   in the file called LICENSE.GPL.
> + *
> + *   Contact Information:
> + *   Intel Corporation
> + */
> +
> +#include <net/sock.h>
> +
> +#include "kcp_dev.h"
> +
> +#define KCP_NL_GRP 31
> +
> +#define KCP_ETHTOOL_MSG_LEN 500
> +struct kcp_ethtool_msg {
> +	int cmd_id;
> +	int port_id;
> +	char input_buffer[KCP_ETHTOOL_MSG_LEN];
> +	char output_buffer[KCP_ETHTOOL_MSG_LEN];
> +	int input_buf_len;
> +	int output_buf_len;
> +	int err;
> +};
> +
> +static struct ethtool_input_buffer {
> +	int magic;
> +	void *buffer;
> +	int length;
> +	struct completion *msg_received;
> +	int *err;
> +} ethtool_input_buffer;
> +
> +static struct sock *nl_sock;
> +static int pid __read_mostly = -1;
> +static struct mutex sync_lock;
> +
> +static int
> +kcp_input_buffer_register(int magic, void *buffer, int length,
> +		struct completion *msg_received, int *err)
> +{
> +	if (ethtool_input_buffer.buffer == NULL) {
> +		ethtool_input_buffer.magic = magic;
> +		ethtool_input_buffer.buffer = buffer;
> +		ethtool_input_buffer.length = length;
> +		ethtool_input_buffer.msg_received = msg_received;
> +		ethtool_input_buffer.err = err;
> +		return 0;
> +	}
> +
> +	return 1;
> +}
> +
> +static void
> +kcp_input_buffer_unregister(int magic)
> +{
> +	if (ethtool_input_buffer.buffer != NULL) {
> +		if (magic == ethtool_input_buffer.magic) {
> +			ethtool_input_buffer.magic = -1;
> +			ethtool_input_buffer.buffer = NULL;
> +			ethtool_input_buffer.length = 0;
> +			ethtool_input_buffer.msg_received = NULL;
> +			ethtool_input_buffer.err = NULL;
> +		}
> +	}
> +}
> +
> +static void
> +nl_recv(struct sk_buff *skb)
> +{
> +	struct nlmsghdr *nlh;
> +	struct kcp_ethtool_msg ethtool_msg;
> +
> +	nlh = (struct nlmsghdr *)skb->data;
> +	if (pid < 0) {
> +		pid = nlh->nlmsg_pid;
> +		KCP_INFO("PID: %d\n", pid);
> +		return;
> +	} else if (pid != nlh->nlmsg_pid) {
> +		KCP_INFO("Message from unexpected peer: %d", nlh->nlmsg_pid);
> +		return;
> +	}
> +
> +	memcpy(&ethtool_msg, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
> +	KCP_DBG("CMD: %d\n", ethtool_msg.cmd_id);
> +
> +	if (ethtool_input_buffer.magic > 0) {
> +		if (ethtool_input_buffer.buffer != NULL) {
> +			memcpy(ethtool_input_buffer.buffer,
> +					&ethtool_msg.output_buffer,
> +					ethtool_input_buffer.length);
> +		}
> +		*ethtool_input_buffer.err = ethtool_msg.err;
> +		complete(ethtool_input_buffer.msg_received);
> +		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
> +	}
> +}
> +
> +static int
> +kcp_nl_send(int cmd_id, int port_id, void *input_buffer, int input_buf_len)
> +{
> +	struct sk_buff *skb;
> +	struct nlmsghdr *nlh;
> +	struct kcp_ethtool_msg ethtool_msg;
> +
> +	memset(&ethtool_msg, 0, sizeof(struct kcp_ethtool_msg));
> +	ethtool_msg.cmd_id = cmd_id;
> +	ethtool_msg.port_id = port_id;
> +
> +	if (input_buffer) {
> +		if (input_buf_len == 0 || input_buf_len > KCP_ETHTOOL_MSG_LEN)
> +			return -EINVAL;
> +		ethtool_msg.input_buf_len = input_buf_len;
> +		memcpy(ethtool_msg.input_buffer, input_buffer, input_buf_len);
> +	}
> +
> +	skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct kcp_ethtool_msg)),
> +			GFP_ATOMIC);
> +	nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, sizeof(struct kcp_ethtool_msg),
> +			0);
> +
> +	NETLINK_CB(skb).dst_group = 0;
> +
> +	memcpy(nlmsg_data(nlh), &ethtool_msg, sizeof(struct kcp_ethtool_msg));
> +
> +	nlmsg_unicast(nl_sock, skb, pid);
> +	KCP_DBG("Sent cmd:%d port:%d\n", cmd_id, port_id);
> +
> +	/*nlmsg_free(skb);*/
> +
> +	return 0;
> +}
> +
> +int
> +kcp_nl_exec(int cmd, struct net_device *dev, void *in_data, int in_len,
> +		void *out_data, int out_len)
> +{
> +	struct kcp_dev *priv = netdev_priv(dev);
> +	int err = -EINVAL;
> +	int ret;
> +
> +	mutex_lock(&sync_lock);
> +	ret = kcp_input_buffer_register(cmd, out_data, out_len,
> +			&priv->msg_received, &err);
> +	if (ret) {
> +		mutex_unlock(&sync_lock);
> +		return -EINVAL;
> +	}
> +
> +	kcp_nl_send(cmd, priv->port_id, in_data, in_len);
> +	ret = wait_for_completion_interruptible_timeout(&priv->msg_received,
> +			 msecs_to_jiffies(10));
> +	if (ret == 0 || err < 0) {
> +		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
> +		mutex_unlock(&sync_lock);
> +		return ret == 0 ? -EINVAL : err;
> +	}
> +	mutex_unlock(&sync_lock);
> +
> +	return 0;
> +}
> +
> +static struct netlink_kernel_cfg cfg = {
> +	.input = nl_recv,
> +};
> +
> +void
> +kcp_nl_init(void)
> +{
> +	nl_sock = netlink_kernel_create(&init_net, KCP_NL_GRP, &cfg);
> +	mutex_init(&sync_lock);
> +}
> +
> +void
> +kcp_nl_release(void)
> +{
> +	netlink_kernel_release(nl_sock);
> +	pid = -1;
> +}

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-28 15:34   ` Avi Kivity
@ 2016-02-28 20:16     ` Ferruh Yigit
  2016-02-29  9:43       ` Avi Kivity
  0 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-28 20:16 UTC (permalink / raw)
  To: Avi Kivity, dev

On 2/28/2016 3:34 PM, Avi Kivity wrote:
> On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
>> This kernel module is based on KNI module, but this one is stripped
>> version of it and only for control messages, no data transfer
>> functionality provided.
>>
>> This Linux kernel module helps userspace application create virtual
>> interfaces and when a control command issued into that virtual
>> interface, module pushes the command to the userspace and gets the
>> response back for the caller application.
>>
>> The Linux tools like ethtool/ifconfig/ip can be used on virtual
>> interfaces but not ones for related data, like tcpdump.
>>
>> In long term this patch intends to replace the KNI and KNI will be
>> depreciated.
> 
> Instead of adding yet another out-of-tree kernel module, why not extend
> the existing in-tree tap driver?  This will make everyone's life easier.
> 
> Since tap also supports data transfer, an application can also forward
> packets not intended to it to the kernel, and forward packets from the
> kernel through the device.
> 
Hi Avi,

KDP (Kernel Data Path) does what you have described, it is implemented
as PMD and it benefits from tap driver to data transfer through the
kernel. It also support custom kernel module for better performance.

For KCP (Kernel Control Path), network driver forwards control commands
to the userspace driver, I doubt this is something wanted for tun/tap
driver, so extending tun/tap driver like this can be hard to upstream.

We are investigating about adding a native support to Linux kernel for
KCP, but there is no task started for this right now, any support is
welcome.

Thanks,
ferruh

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

* Re: [PATCH v3 0/4] Use common Linux tools to control DPDK ports
  2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
                       ` (3 preceding siblings ...)
  2016-02-26 14:10     ` [PATCH v3 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
@ 2016-02-29  9:33     ` Remy Horton
  2016-03-01 15:41     ` [PATCH v4 " Ferruh Yigit
  5 siblings, 0 replies; 83+ messages in thread
From: Remy Horton @ 2016-02-29  9:33 UTC (permalink / raw)
  To: Ferruh Yigit, dev



On 26/02/2016 14:10, Ferruh Yigit wrote:

> Ferruh Yigit (4):
>    lib/librte_ethtool: move librte_ethtool form examples to lib folder
>    kcp: add kernel control path kernel module
>    rte_ctrl_if: add control interface library
>    examples/ethtool: add control interface support to the application

Acked-by: Remy Horton <remy.horton@intel.com>

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-28 20:16     ` Ferruh Yigit
@ 2016-02-29  9:43       ` Avi Kivity
  2016-02-29 10:43         ` Ferruh Yigit
  0 siblings, 1 reply; 83+ messages in thread
From: Avi Kivity @ 2016-02-29  9:43 UTC (permalink / raw)
  To: Ferruh Yigit, dev

On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
> On 2/28/2016 3:34 PM, Avi Kivity wrote:
>> On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
>>> This kernel module is based on KNI module, but this one is stripped
>>> version of it and only for control messages, no data transfer
>>> functionality provided.
>>>
>>> This Linux kernel module helps userspace application create virtual
>>> interfaces and when a control command issued into that virtual
>>> interface, module pushes the command to the userspace and gets the
>>> response back for the caller application.
>>>
>>> The Linux tools like ethtool/ifconfig/ip can be used on virtual
>>> interfaces but not ones for related data, like tcpdump.
>>>
>>> In long term this patch intends to replace the KNI and KNI will be
>>> depreciated.
>> Instead of adding yet another out-of-tree kernel module, why not extend
>> the existing in-tree tap driver?  This will make everyone's life easier.
>>
>> Since tap also supports data transfer, an application can also forward
>> packets not intended to it to the kernel, and forward packets from the
>> kernel through the device.
>>
> Hi Avi,
>
> KDP (Kernel Data Path) does what you have described, it is implemented
> as PMD and it benefits from tap driver to data transfer through the
> kernel. It also support custom kernel module for better performance.
>
> For KCP (Kernel Control Path), network driver forwards control commands
> to the userspace driver, I doubt this is something wanted for tun/tap
> driver, so extending tun/tap driver like this can be hard to upstream.

Have you tried asking?  Maybe if you explain it they will be open to the 
extension.

Certainly it will be better to have KCP and KDP use the same kernel 
interface name; so we'll need to either add data path support to kcp 
(causing duplication with tap), or add control path support to tap. I 
think the latter is preferable.

> We are investigating about adding a native support to Linux kernel for
> KCP, but there is no task started for this right now, any support is
> welcome.
>
>

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29  9:43       ` Avi Kivity
@ 2016-02-29 10:43         ` Ferruh Yigit
  2016-02-29 10:58           ` Avi Kivity
  0 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-29 10:43 UTC (permalink / raw)
  To: Avi Kivity, dev

On 2/29/2016 9:43 AM, Avi Kivity wrote:
> On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
>> On 2/28/2016 3:34 PM, Avi Kivity wrote:
>>> On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
>>>> This kernel module is based on KNI module, but this one is stripped
>>>> version of it and only for control messages, no data transfer
>>>> functionality provided.
>>>>
>>>> This Linux kernel module helps userspace application create virtual
>>>> interfaces and when a control command issued into that virtual
>>>> interface, module pushes the command to the userspace and gets the
>>>> response back for the caller application.
>>>>
>>>> The Linux tools like ethtool/ifconfig/ip can be used on virtual
>>>> interfaces but not ones for related data, like tcpdump.
>>>>
>>>> In long term this patch intends to replace the KNI and KNI will be
>>>> depreciated.
>>> Instead of adding yet another out-of-tree kernel module, why not extend
>>> the existing in-tree tap driver?  This will make everyone's life easier.
>>>
>>> Since tap also supports data transfer, an application can also forward
>>> packets not intended to it to the kernel, and forward packets from the
>>> kernel through the device.
>>>
>> Hi Avi,
>>
>> KDP (Kernel Data Path) does what you have described, it is implemented
>> as PMD and it benefits from tap driver to data transfer through the
>> kernel. It also support custom kernel module for better performance.
>>
>> For KCP (Kernel Control Path), network driver forwards control commands
>> to the userspace driver, I doubt this is something wanted for tun/tap
>> driver, so extending tun/tap driver like this can be hard to upstream.
> 
> Have you tried asking?  Maybe if you explain it they will be open to the
> extension.
> 
Not communicated but tun/tap already doing something different.
For KCP, created interface is map of the DPDK port. All data interface
shows coming from DPDK port. For example if you get stats information
with ifconfig, the values you observe are DPDK port statistics -not
statistics of data between userspace and kernelspace, statistics of data
forwarded between DPDK ports. If you down the interface, DPDK port
stopped, etc...

If you extend the tun/tap, it won't be map of the DPDK port, and if you
get statistics information from that interface, what do you expect to
see, the data transferred between kernel and userspace, or underlying
DPDK port forwarding statistics?

Extending tun/tap in a way we want, forwarding all control commands to
userspace, will break the current tun/tap, this doesn't looks like a
valid option to me.

For data path, using tun/tap is OK and we are already doing it, for the
control path I believe we need a new driver.

> Certainly it will be better to have KCP and KDP use the same kernel
> interface name; so we'll need to either add data path support to kcp
> (causing duplication with tap), or add control path support to tap. I
> think the latter is preferable.
> 
Why it is better to have same interface? Anyone who is not interested
with kernel data path may want to control DPDK ports using common tools,
or want to get some basic information and stats using ethtool or
ifconfig. Why we need to bind two different functionality together?

>> We are investigating about adding a native support to Linux kernel for
>> KCP, but there is no task started for this right now, any support is
>> welcome.
>>
>>
> 

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 10:43         ` Ferruh Yigit
@ 2016-02-29 10:58           ` Avi Kivity
  2016-02-29 11:06             ` Thomas Monjalon
  2016-02-29 11:27             ` Ferruh Yigit
  0 siblings, 2 replies; 83+ messages in thread
From: Avi Kivity @ 2016-02-29 10:58 UTC (permalink / raw)
  To: Ferruh Yigit, dev



On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
> On 2/29/2016 9:43 AM, Avi Kivity wrote:
>> On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
>>> On 2/28/2016 3:34 PM, Avi Kivity wrote:
>>>> On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
>>>>> This kernel module is based on KNI module, but this one is stripped
>>>>> version of it and only for control messages, no data transfer
>>>>> functionality provided.
>>>>>
>>>>> This Linux kernel module helps userspace application create virtual
>>>>> interfaces and when a control command issued into that virtual
>>>>> interface, module pushes the command to the userspace and gets the
>>>>> response back for the caller application.
>>>>>
>>>>> The Linux tools like ethtool/ifconfig/ip can be used on virtual
>>>>> interfaces but not ones for related data, like tcpdump.
>>>>>
>>>>> In long term this patch intends to replace the KNI and KNI will be
>>>>> depreciated.
>>>> Instead of adding yet another out-of-tree kernel module, why not extend
>>>> the existing in-tree tap driver?  This will make everyone's life easier.
>>>>
>>>> Since tap also supports data transfer, an application can also forward
>>>> packets not intended to it to the kernel, and forward packets from the
>>>> kernel through the device.
>>>>
>>> Hi Avi,
>>>
>>> KDP (Kernel Data Path) does what you have described, it is implemented
>>> as PMD and it benefits from tap driver to data transfer through the
>>> kernel. It also support custom kernel module for better performance.
>>>
>>> For KCP (Kernel Control Path), network driver forwards control commands
>>> to the userspace driver, I doubt this is something wanted for tun/tap
>>> driver, so extending tun/tap driver like this can be hard to upstream.
>> Have you tried asking?  Maybe if you explain it they will be open to the
>> extension.
>>
> Not communicated but tun/tap already doing something different.
> For KCP, created interface is map of the DPDK port. All data interface
> shows coming from DPDK port. For example if you get stats information
> with ifconfig, the values you observe are DPDK port statistics -not
> statistics of data between userspace and kernelspace, statistics of data
> forwarded between DPDK ports. If you down the interface, DPDK port
> stopped, etc...
>
> If you extend the tun/tap, it won't be map of the DPDK port, and if you
> get statistics information from that interface, what do you expect to
> see, the data transferred between kernel and userspace, or underlying
> DPDK port forwarding statistics?

Good point.  But you really have to involve netdev on this, or you'll 
live out-of-tree forever.

> Extending tun/tap in a way we want, forwarding all control commands to
> userspace, will break the current tun/tap, this doesn't looks like a
> valid option to me.

It's possible to enhance it while preserving backwards compatibility, by 
enabling a feature flag (statistics from userspace).

> For data path, using tun/tap is OK and we are already doing it, for the
> control path I believe we need a new driver.
>
>> Certainly it will be better to have KCP and KDP use the same kernel
>> interface name; so we'll need to either add data path support to kcp
>> (causing duplication with tap), or add control path support to tap. I
>> think the latter is preferable.
>>
> Why it is better to have same interface? Anyone who is not interested
> with kernel data path may want to control DPDK ports using common tools,
> or want to get some basic information and stats using ethtool or
> ifconfig. Why we need to bind two different functionality together?

Having two interfaces will be confusing for the user.  If I wish to 
firewall data packets coming from the dpdk port, do I set firewall rules 
on dpdk0 or tap0?

I don't think it matters whether you extend tap, or add a data path to 
kcp, but if you want to upstream it, it needs to be blessed by netdev.

>
>>> We are investigating about adding a native support to Linux kernel for
>>> KCP, but there is no task started for this right now, any support is
>>> welcome.
>>>
>>>

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 10:58           ` Avi Kivity
@ 2016-02-29 11:06             ` Thomas Monjalon
  2016-02-29 11:35               ` Ferruh Yigit
  2016-02-29 14:33               ` Jay Rolette
  2016-02-29 11:27             ` Ferruh Yigit
  1 sibling, 2 replies; 83+ messages in thread
From: Thomas Monjalon @ 2016-02-29 11:06 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev, Avi Kivity

Hi,
I totally agree with Avi's comments.
This topic is really important for the future of DPDK.
So I think we must give some time to continue the discussion
and have netdev involved in the choices done.
As a consequence, these series should not be merged in the release 16.04.
Thanks for continuing the work.


2016-02-29 12:58, Avi Kivity:
> On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
> > On 2/29/2016 9:43 AM, Avi Kivity wrote:
> >> On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
> >>> On 2/28/2016 3:34 PM, Avi Kivity wrote:
> >>>> On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
> >>>>> This kernel module is based on KNI module, but this one is stripped
> >>>>> version of it and only for control messages, no data transfer
> >>>>> functionality provided.
> >>>>>
> >>>>> This Linux kernel module helps userspace application create virtual
> >>>>> interfaces and when a control command issued into that virtual
> >>>>> interface, module pushes the command to the userspace and gets the
> >>>>> response back for the caller application.
> >>>>>
> >>>>> The Linux tools like ethtool/ifconfig/ip can be used on virtual
> >>>>> interfaces but not ones for related data, like tcpdump.
> >>>>>
> >>>>> In long term this patch intends to replace the KNI and KNI will be
> >>>>> depreciated.
> >>>> Instead of adding yet another out-of-tree kernel module, why not extend
> >>>> the existing in-tree tap driver?  This will make everyone's life easier.
> >>>>
> >>>> Since tap also supports data transfer, an application can also forward
> >>>> packets not intended to it to the kernel, and forward packets from the
> >>>> kernel through the device.
> >>>>
> >>> Hi Avi,
> >>>
> >>> KDP (Kernel Data Path) does what you have described, it is implemented
> >>> as PMD and it benefits from tap driver to data transfer through the
> >>> kernel. It also support custom kernel module for better performance.
> >>>
> >>> For KCP (Kernel Control Path), network driver forwards control commands
> >>> to the userspace driver, I doubt this is something wanted for tun/tap
> >>> driver, so extending tun/tap driver like this can be hard to upstream.
> >> Have you tried asking?  Maybe if you explain it they will be open to the
> >> extension.
> >>
> > Not communicated but tun/tap already doing something different.
> > For KCP, created interface is map of the DPDK port. All data interface
> > shows coming from DPDK port. For example if you get stats information
> > with ifconfig, the values you observe are DPDK port statistics -not
> > statistics of data between userspace and kernelspace, statistics of data
> > forwarded between DPDK ports. If you down the interface, DPDK port
> > stopped, etc...
> >
> > If you extend the tun/tap, it won't be map of the DPDK port, and if you
> > get statistics information from that interface, what do you expect to
> > see, the data transferred between kernel and userspace, or underlying
> > DPDK port forwarding statistics?
> 
> Good point.  But you really have to involve netdev on this, or you'll 
> live out-of-tree forever.

+1

> > Extending tun/tap in a way we want, forwarding all control commands to
> > userspace, will break the current tun/tap, this doesn't looks like a
> > valid option to me.
> 
> It's possible to enhance it while preserving backwards compatibility, by 
> enabling a feature flag (statistics from userspace).

+1
 
> > For data path, using tun/tap is OK and we are already doing it, for the
> > control path I believe we need a new driver.
> >
> >> Certainly it will be better to have KCP and KDP use the same kernel
> >> interface name; so we'll need to either add data path support to kcp
> >> (causing duplication with tap), or add control path support to tap. I
> >> think the latter is preferable.
> >>
> > Why it is better to have same interface? Anyone who is not interested
> > with kernel data path may want to control DPDK ports using common tools,
> > or want to get some basic information and stats using ethtool or
> > ifconfig. Why we need to bind two different functionality together?
> 
> Having two interfaces will be confusing for the user.  If I wish to 
> firewall data packets coming from the dpdk port, do I set firewall rules 
> on dpdk0 or tap0?

+1
 
> I don't think it matters whether you extend tap, or add a data path to 
> kcp, but if you want to upstream it, it needs to be blessed by netdev.

+1

> >>> We are investigating about adding a native support to Linux kernel for
> >>> KCP, but there is no task started for this right now, any support is
> >>> welcome.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 10:58           ` Avi Kivity
  2016-02-29 11:06             ` Thomas Monjalon
@ 2016-02-29 11:27             ` Ferruh Yigit
  2016-02-29 11:39               ` Avi Kivity
  1 sibling, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-29 11:27 UTC (permalink / raw)
  To: Avi Kivity, dev

On 2/29/2016 10:58 AM, Avi Kivity wrote:
> 
> 
> On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
>> On 2/29/2016 9:43 AM, Avi Kivity wrote:
>>> On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
>>>> On 2/28/2016 3:34 PM, Avi Kivity wrote:
>>>>> On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
>>>>>> This kernel module is based on KNI module, but this one is stripped
>>>>>> version of it and only for control messages, no data transfer
>>>>>> functionality provided.
>>>>>>
>>>>>> This Linux kernel module helps userspace application create virtual
>>>>>> interfaces and when a control command issued into that virtual
>>>>>> interface, module pushes the command to the userspace and gets the
>>>>>> response back for the caller application.
>>>>>>
>>>>>> The Linux tools like ethtool/ifconfig/ip can be used on virtual
>>>>>> interfaces but not ones for related data, like tcpdump.
>>>>>>
>>>>>> In long term this patch intends to replace the KNI and KNI will be
>>>>>> depreciated.
>>>>> Instead of adding yet another out-of-tree kernel module, why not
>>>>> extend
>>>>> the existing in-tree tap driver?  This will make everyone's life
>>>>> easier.
>>>>>
>>>>> Since tap also supports data transfer, an application can also forward
>>>>> packets not intended to it to the kernel, and forward packets from the
>>>>> kernel through the device.
>>>>>
>>>> Hi Avi,
>>>>
>>>> KDP (Kernel Data Path) does what you have described, it is implemented
>>>> as PMD and it benefits from tap driver to data transfer through the
>>>> kernel. It also support custom kernel module for better performance.
>>>>
>>>> For KCP (Kernel Control Path), network driver forwards control commands
>>>> to the userspace driver, I doubt this is something wanted for tun/tap
>>>> driver, so extending tun/tap driver like this can be hard to upstream.
>>> Have you tried asking?  Maybe if you explain it they will be open to the
>>> extension.
>>>
>> Not communicated but tun/tap already doing something different.
>> For KCP, created interface is map of the DPDK port. All data interface
>> shows coming from DPDK port. For example if you get stats information
>> with ifconfig, the values you observe are DPDK port statistics -not
>> statistics of data between userspace and kernelspace, statistics of data
>> forwarded between DPDK ports. If you down the interface, DPDK port
>> stopped, etc...
>>
>> If you extend the tun/tap, it won't be map of the DPDK port, and if you
>> get statistics information from that interface, what do you expect to
>> see, the data transferred between kernel and userspace, or underlying
>> DPDK port forwarding statistics?
> 
> Good point.  But you really have to involve netdev on this, or you'll
> live out-of-tree forever.
> 
Why do we need to touch netdev?

A simple network driver, similar to kcp, can be solution.

This driver implements all net_device_ops and ethtool_ops in a way to
forward everything to the userspace via netlink. All needs to know about
userspace driver is it's unique id. Any userspace application, not only
DPDK drivers, can listen the netlink messages and response to the
requests come to itself.

This kind of driver is not big or complicated, kcp already does %90 of
what described above.

>> Extending tun/tap in a way we want, forwarding all control commands to
>> userspace, will break the current tun/tap, this doesn't looks like a
>> valid option to me.
> 
> It's possible to enhance it while preserving backwards compatibility, by
> enabling a feature flag (statistics from userspace).
> 
>> For data path, using tun/tap is OK and we are already doing it, for the
>> control path I believe we need a new driver.
>>
>>> Certainly it will be better to have KCP and KDP use the same kernel
>>> interface name; so we'll need to either add data path support to kcp
>>> (causing duplication with tap), or add control path support to tap. I
>>> think the latter is preferable.
>>>
>> Why it is better to have same interface? Anyone who is not interested
>> with kernel data path may want to control DPDK ports using common tools,
>> or want to get some basic information and stats using ethtool or
>> ifconfig. Why we need to bind two different functionality together?
> 
> Having two interfaces will be confusing for the user.  If I wish to
> firewall data packets coming from the dpdk port, do I set firewall rules
> on dpdk0 or tap0?
> 
Agreed that it is confusing to have two interfaces.

I think if user wants to use both data and control paths, a way can be
found to end up with single interface, using module params or something
else. Two different drivers for data and control not conflict with each
other and can cooperate.
But to work on this first both KCP and KDP should go in.

> I don't think it matters whether you extend tap, or add a data path to
> kcp, but if you want to upstream it, it needs to be blessed by netdev.
> 
I still think not good idea to merge these two, because they may be used
independently, but we can improve how they work together.

>>
>>>> We are investigating about adding a native support to Linux kernel for
>>>> KCP, but there is no task started for this right now, any support is
>>>> welcome.
>>>>
>>>>
> 

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 11:06             ` Thomas Monjalon
@ 2016-02-29 11:35               ` Ferruh Yigit
  2016-02-29 15:05                 ` Ferruh Yigit
  2016-02-29 15:19                 ` Panu Matilainen
  2016-02-29 14:33               ` Jay Rolette
  1 sibling, 2 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-29 11:35 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Avi Kivity

On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
> Hi,
> I totally agree with Avi's comments.
> This topic is really important for the future of DPDK.
> So I think we must give some time to continue the discussion
> and have netdev involved in the choices done.
> As a consequence, these series should not be merged in the release 16.04.
> Thanks for continuing the work.
> 
Hi Thomas,

It is great to have some discussion and feedbacks.
But I doubt not merging in this release will help to have more discussion.

It is better to have them in this release and let people experiment it,
this gives more chance to better discussion.

These features are replacement of KNI, and KNI is not intended to be
removed in this release, so who are using KNI as solution can continue
to use KNI and can test KCP/KDP, so that we can get more feedbacks.

Thanks,
ferruh

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 11:27             ` Ferruh Yigit
@ 2016-02-29 11:39               ` Avi Kivity
  2016-02-29 14:35                 ` Ferruh Yigit
  0 siblings, 1 reply; 83+ messages in thread
From: Avi Kivity @ 2016-02-29 11:39 UTC (permalink / raw)
  To: Ferruh Yigit, dev



On 02/29/2016 01:27 PM, Ferruh Yigit wrote:
> On 2/29/2016 10:58 AM, Avi Kivity wrote:
>>
>> On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
>>> On 2/29/2016 9:43 AM, Avi Kivity wrote:
>>>> On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
>>>>> On 2/28/2016 3:34 PM, Avi Kivity wrote:
>>>>>> On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
>>>>>>> This kernel module is based on KNI module, but this one is stripped
>>>>>>> version of it and only for control messages, no data transfer
>>>>>>> functionality provided.
>>>>>>>
>>>>>>> This Linux kernel module helps userspace application create virtual
>>>>>>> interfaces and when a control command issued into that virtual
>>>>>>> interface, module pushes the command to the userspace and gets the
>>>>>>> response back for the caller application.
>>>>>>>
>>>>>>> The Linux tools like ethtool/ifconfig/ip can be used on virtual
>>>>>>> interfaces but not ones for related data, like tcpdump.
>>>>>>>
>>>>>>> In long term this patch intends to replace the KNI and KNI will be
>>>>>>> depreciated.
>>>>>> Instead of adding yet another out-of-tree kernel module, why not
>>>>>> extend
>>>>>> the existing in-tree tap driver?  This will make everyone's life
>>>>>> easier.
>>>>>>
>>>>>> Since tap also supports data transfer, an application can also forward
>>>>>> packets not intended to it to the kernel, and forward packets from the
>>>>>> kernel through the device.
>>>>>>
>>>>> Hi Avi,
>>>>>
>>>>> KDP (Kernel Data Path) does what you have described, it is implemented
>>>>> as PMD and it benefits from tap driver to data transfer through the
>>>>> kernel. It also support custom kernel module for better performance.
>>>>>
>>>>> For KCP (Kernel Control Path), network driver forwards control commands
>>>>> to the userspace driver, I doubt this is something wanted for tun/tap
>>>>> driver, so extending tun/tap driver like this can be hard to upstream.
>>>> Have you tried asking?  Maybe if you explain it they will be open to the
>>>> extension.
>>>>
>>> Not communicated but tun/tap already doing something different.
>>> For KCP, created interface is map of the DPDK port. All data interface
>>> shows coming from DPDK port. For example if you get stats information
>>> with ifconfig, the values you observe are DPDK port statistics -not
>>> statistics of data between userspace and kernelspace, statistics of data
>>> forwarded between DPDK ports. If you down the interface, DPDK port
>>> stopped, etc...
>>>
>>> If you extend the tun/tap, it won't be map of the DPDK port, and if you
>>> get statistics information from that interface, what do you expect to
>>> see, the data transferred between kernel and userspace, or underlying
>>> DPDK port forwarding statistics?
>> Good point.  But you really have to involve netdev on this, or you'll
>> live out-of-tree forever.
>>
> Why do we need to touch netdev?

By netdev, I meant the mailing list.  If you don't touch it, your driver 
will remain out-of-tree forever.

> A simple network driver, similar to kcp, can be solution.
>
> This driver implements all net_device_ops and ethtool_ops in a way to
> forward everything to the userspace via netlink. All needs to know about
> userspace driver is it's unique id. Any userspace application, not only
> DPDK drivers, can listen the netlink messages and response to the
> requests come to itself.
>
> This kind of driver is not big or complicated, kcp already does %90 of
> what described above.

I am not arguing against kcp.  It fulfills an important need.  This is 
my argument:

1. having multiple interfaces for the control and data path is bad for 
the user
2. therefore, we need to either add tap functionality to kcp, or add kcp 
functionality to tap
3. netdev@ is more likely (IMO) to accept additional functionality to 
tap than a new driver, but the only way to know is to engage with them

>
>>> Extending tun/tap in a way we want, forwarding all control commands to
>>> userspace, will break the current tun/tap, this doesn't looks like a
>>> valid option to me.
>> It's possible to enhance it while preserving backwards compatibility, by
>> enabling a feature flag (statistics from userspace).
>>
>>> For data path, using tun/tap is OK and we are already doing it, for the
>>> control path I believe we need a new driver.
>>>
>>>> Certainly it will be better to have KCP and KDP use the same kernel
>>>> interface name; so we'll need to either add data path support to kcp
>>>> (causing duplication with tap), or add control path support to tap. I
>>>> think the latter is preferable.
>>>>
>>> Why it is better to have same interface? Anyone who is not interested
>>> with kernel data path may want to control DPDK ports using common tools,
>>> or want to get some basic information and stats using ethtool or
>>> ifconfig. Why we need to bind two different functionality together?
>> Having two interfaces will be confusing for the user.  If I wish to
>> firewall data packets coming from the dpdk port, do I set firewall rules
>> on dpdk0 or tap0?
>>
> Agreed that it is confusing to have two interfaces.
>
> I think if user wants to use both data and control paths, a way can be
> found to end up with single interface, using module params or something
> else. Two different drivers for data and control not conflict with each
> other and can cooperate.

Module parameters are for module-wide options.  A single module can 
support multiple interfaces, so module parameters don't apply.

Let's make it simple for the users, even if it is more complex for us 
(and by us, I mean you, unfortunately).

> But to work on this first both KCP and KDP should go in.

Go in where?  It doesn't help if it goes into dpdk.git and then netdev@ 
rejects it.

>
>> I don't think it matters whether you extend tap, or add a data path to
>> kcp, but if you want to upstream it, it needs to be blessed by netdev.
>>
> I still think not good idea to merge these two, because they may be used
> independently, but we can improve how they work together.
>

 From a developer's perspective, maybe so, but from a user's 
perspective, there should be exactly one interface for the functionality 
exposed by kcp and kdp.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 11:06             ` Thomas Monjalon
  2016-02-29 11:35               ` Ferruh Yigit
@ 2016-02-29 14:33               ` Jay Rolette
  2016-03-01 22:40                 ` Bruce Richardson
  2016-03-02  2:02                 ` Stephen Hemminger
  1 sibling, 2 replies; 83+ messages in thread
From: Jay Rolette @ 2016-02-29 14:33 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: DPDK, Avi Kivity

On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon <thomas.monjalon@6wind.com>
wrote:

> Hi,
> I totally agree with Avi's comments.
> This topic is really important for the future of DPDK.
> So I think we must give some time to continue the discussion
> and have netdev involved in the choices done.
> As a consequence, these series should not be merged in the release 16.04.
> Thanks for continuing the work.
>

I know you guys are very interested in getting rid of the out-of-tree
drivers, but please do not block incremental improvements to DPDK in the
meantime. Ferruh's patch improves the usability of KNI. Don't throw out
good and useful enhancements just because it isn't where you want to be in
the end.

I'd like to see these be merged.

Jay

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 11:39               ` Avi Kivity
@ 2016-02-29 14:35                 ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-29 14:35 UTC (permalink / raw)
  To: Avi Kivity, dev

On 2/29/2016 11:39 AM, Avi Kivity wrote:
> 
> 
> On 02/29/2016 01:27 PM, Ferruh Yigit wrote:
>> On 2/29/2016 10:58 AM, Avi Kivity wrote:
>>>
>>> On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
>>>> On 2/29/2016 9:43 AM, Avi Kivity wrote:
>>>>> On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
>>>>>> On 2/28/2016 3:34 PM, Avi Kivity wrote:
>>>>>>> On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
>>>>>>>> This kernel module is based on KNI module, but this one is stripped
>>>>>>>> version of it and only for control messages, no data transfer
>>>>>>>> functionality provided.
>>>>>>>>
>>>>>>>> This Linux kernel module helps userspace application create virtual
>>>>>>>> interfaces and when a control command issued into that virtual
>>>>>>>> interface, module pushes the command to the userspace and gets the
>>>>>>>> response back for the caller application.
>>>>>>>>
>>>>>>>> The Linux tools like ethtool/ifconfig/ip can be used on virtual
>>>>>>>> interfaces but not ones for related data, like tcpdump.
>>>>>>>>
>>>>>>>> In long term this patch intends to replace the KNI and KNI will be
>>>>>>>> depreciated.
>>>>>>> Instead of adding yet another out-of-tree kernel module, why not
>>>>>>> extend
>>>>>>> the existing in-tree tap driver?  This will make everyone's life
>>>>>>> easier.
>>>>>>>
>>>>>>> Since tap also supports data transfer, an application can also
>>>>>>> forward
>>>>>>> packets not intended to it to the kernel, and forward packets
>>>>>>> from the
>>>>>>> kernel through the device.
>>>>>>>
>>>>>> Hi Avi,
>>>>>>
>>>>>> KDP (Kernel Data Path) does what you have described, it is
>>>>>> implemented
>>>>>> as PMD and it benefits from tap driver to data transfer through the
>>>>>> kernel. It also support custom kernel module for better performance.
>>>>>>
>>>>>> For KCP (Kernel Control Path), network driver forwards control
>>>>>> commands
>>>>>> to the userspace driver, I doubt this is something wanted for tun/tap
>>>>>> driver, so extending tun/tap driver like this can be hard to
>>>>>> upstream.
>>>>> Have you tried asking?  Maybe if you explain it they will be open
>>>>> to the
>>>>> extension.
>>>>>
>>>> Not communicated but tun/tap already doing something different.
>>>> For KCP, created interface is map of the DPDK port. All data interface
>>>> shows coming from DPDK port. For example if you get stats information
>>>> with ifconfig, the values you observe are DPDK port statistics -not
>>>> statistics of data between userspace and kernelspace, statistics of
>>>> data
>>>> forwarded between DPDK ports. If you down the interface, DPDK port
>>>> stopped, etc...
>>>>
>>>> If you extend the tun/tap, it won't be map of the DPDK port, and if you
>>>> get statistics information from that interface, what do you expect to
>>>> see, the data transferred between kernel and userspace, or underlying
>>>> DPDK port forwarding statistics?
>>> Good point.  But you really have to involve netdev on this, or you'll
>>> live out-of-tree forever.
>>>
>> Why do we need to touch netdev?
> 
> By netdev, I meant the mailing list.  If you don't touch it, your driver
> will remain out-of-tree forever.
> 
Sorry, I thought you are suggesting updating netdev (struct net_device)
for this.

>> A simple network driver, similar to kcp, can be solution.
>>
>> This driver implements all net_device_ops and ethtool_ops in a way to
>> forward everything to the userspace via netlink. All needs to know about
>> userspace driver is it's unique id. Any userspace application, not only
>> DPDK drivers, can listen the netlink messages and response to the
>> requests come to itself.
>>
>> This kind of driver is not big or complicated, kcp already does %90 of
>> what described above.
> 
> I am not arguing against kcp.  It fulfills an important need.  This is
> my argument:
> 
> 1. having multiple interfaces for the control and data path is bad for
> the user
> 2. therefore, we need to either add tap functionality to kcp, or add kcp
> functionality to tap
> 3. netdev@ is more likely (IMO) to accept additional functionality to
> tap than a new driver, but the only way to know is to engage with them
> 
Agreed an incremental update to the tap can be easier to get in, but
this is not really working for us, as explained above.

The concern of having two separate interfaces can be solved without
merging data and control path. I believe this is not a showstopper for
the functionality and can be the incremental improvement.

>>
>>>> Extending tun/tap in a way we want, forwarding all control commands to
>>>> userspace, will break the current tun/tap, this doesn't looks like a
>>>> valid option to me.
>>> It's possible to enhance it while preserving backwards compatibility, by
>>> enabling a feature flag (statistics from userspace).
>>>
>>>> For data path, using tun/tap is OK and we are already doing it, for the
>>>> control path I believe we need a new driver.
>>>>
>>>>> Certainly it will be better to have KCP and KDP use the same kernel
>>>>> interface name; so we'll need to either add data path support to kcp
>>>>> (causing duplication with tap), or add control path support to tap. I
>>>>> think the latter is preferable.
>>>>>
>>>> Why it is better to have same interface? Anyone who is not interested
>>>> with kernel data path may want to control DPDK ports using common
>>>> tools,
>>>> or want to get some basic information and stats using ethtool or
>>>> ifconfig. Why we need to bind two different functionality together?
>>> Having two interfaces will be confusing for the user.  If I wish to
>>> firewall data packets coming from the dpdk port, do I set firewall rules
>>> on dpdk0 or tap0?
>>>
>> Agreed that it is confusing to have two interfaces.
>>
>> I think if user wants to use both data and control paths, a way can be
>> found to end up with single interface, using module params or something
>> else. Two different drivers for data and control not conflict with each
>> other and can cooperate.
> 
> Module parameters are for module-wide options.  A single module can
> support multiple interfaces, so module parameters don't apply.
>
> Let's make it simple for the users, even if it is more complex for us
> (and by us, I mean you, unfortunately).

The reason I insist on separate modules is same reason with you,
user/customer rules, not because it is easier. With KCP, DPDK ports
become visible to Linux world, and this has nothing to do with sending
packages to kernel. Decoupling the KCP from data path can give more use
case for KCP, more user can use it.

Also it is possible to make control path more dynamic, you can make them
appear, get some info, set something, and remove them back. This is not
something wanted for slow data path.

This is a design choice to separate responsibilities.

> 
>> But to work on this first both KCP and KDP should go in.
> 
> Go in where?  It doesn't help if it goes into dpdk.git and then netdev@
> rejects it.
> 
Go in to dpdk.git can be good start. It helps on a few things:
1- Get feedback on users, get more requirements
2- In communication with netdev@, helps us showing the existing use case.
3- Linux upstream process is risky and may take long time, DPDK users
may not access these for a long time, and if it makes the Linux kernel,
it may be late for some requirements.

I think it is good to include these in dpdk.org, and in parallel work on
upstreaming. Update the code according comments from both communities.
And if this makes into Linux kernel, we can drop from DPDK.

>>
>>> I don't think it matters whether you extend tap, or add a data path to
>>> kcp, but if you want to upstream it, it needs to be blessed by netdev.
>>>
>> I still think not good idea to merge these two, because they may be used
>> independently, but we can improve how they work together.
>>
> 
> From a developer's perspective, maybe so, but from a user's perspective,
> there should be exactly one interface for the functionality exposed by
> kcp and kdp.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 11:35               ` Ferruh Yigit
@ 2016-02-29 15:05                 ` Ferruh Yigit
  2016-02-29 15:19                 ` Panu Matilainen
  1 sibling, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-02-29 15:05 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Avi Kivity

On 2/29/2016 11:35 AM, Ferruh Yigit wrote:
> On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
>> Hi,
>> I totally agree with Avi's comments.
>> This topic is really important for the future of DPDK.
>> So I think we must give some time to continue the discussion
>> and have netdev involved in the choices done.
>> As a consequence, these series should not be merged in the release 16.04.
>> Thanks for continuing the work.
>>
> Hi Thomas,
> 
> It is great to have some discussion and feedbacks.
> But I doubt not merging in this release will help to have more discussion.
> 
> It is better to have them in this release and let people experiment it,
> this gives more chance to better discussion.
> 
> These features are replacement of KNI, and KNI is not intended to be
> removed in this release, so who are using KNI as solution can continue
> to use KNI and can test KCP/KDP, so that we can get more feedbacks.
> 
One more thing, overall reason of working on KCP/KDP is reduce KNI
maintenance cost, and add more features, not to add more maintenance cost.
The most maintenance cost of KNI is because of Linux network drivers in
it, which KCP removes them, so there is an improvement.

Although it is not as good as removing them completely, KCP/KDP is one
step closer to be upstreamed than existing KNI.

Thanks,
ferruh

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 11:35               ` Ferruh Yigit
  2016-02-29 15:05                 ` Ferruh Yigit
@ 2016-02-29 15:19                 ` Panu Matilainen
  2016-02-29 15:27                   ` Thomas Monjalon
  1 sibling, 1 reply; 83+ messages in thread
From: Panu Matilainen @ 2016-02-29 15:19 UTC (permalink / raw)
  To: Ferruh Yigit, Thomas Monjalon; +Cc: dev, Avi Kivity

On 02/29/2016 01:35 PM, Ferruh Yigit wrote:
> On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
>> Hi,
>> I totally agree with Avi's comments.
>> This topic is really important for the future of DPDK.
>> So I think we must give some time to continue the discussion
>> and have netdev involved in the choices done.
>> As a consequence, these series should not be merged in the release 16.04.
>> Thanks for continuing the work.
>>
> Hi Thomas,
>
> It is great to have some discussion and feedbacks.
> But I doubt not merging in this release will help to have more discussion.
>
> It is better to have them in this release and let people experiment it,
> this gives more chance to better discussion.
>
> These features are replacement of KNI, and KNI is not intended to be
> removed in this release, so who are using KNI as solution can continue
> to use KNI and can test KCP/KDP, so that we can get more feedbacks.

So make the work available from a separate git repo and make it easy for 
people to experiment with it. Code doesn't have to be in a release for 
the sake of experimenting, and removing code is much harder than not 
adding it in the first place, witness KNI.

	- Panu -

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 15:19                 ` Panu Matilainen
@ 2016-02-29 15:27                   ` Thomas Monjalon
  2016-02-29 16:04                     ` Panu Matilainen
  0 siblings, 1 reply; 83+ messages in thread
From: Thomas Monjalon @ 2016-02-29 15:27 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev, Avi Kivity

2016-02-29 17:19, Panu Matilainen:
> On 02/29/2016 01:35 PM, Ferruh Yigit wrote:
> > On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
> >> Hi,
> >> I totally agree with Avi's comments.
> >> This topic is really important for the future of DPDK.
> >> So I think we must give some time to continue the discussion
> >> and have netdev involved in the choices done.
> >> As a consequence, these series should not be merged in the release 16.04.
> >> Thanks for continuing the work.
> >>
> > Hi Thomas,
> >
> > It is great to have some discussion and feedbacks.
> > But I doubt not merging in this release will help to have more discussion.
> >
> > It is better to have them in this release and let people experiment it,
> > this gives more chance to better discussion.
> >
> > These features are replacement of KNI, and KNI is not intended to be
> > removed in this release, so who are using KNI as solution can continue
> > to use KNI and can test KCP/KDP, so that we can get more feedbacks.
> 
> So make the work available from a separate git repo and make it easy for 
> people to experiment with it. Code doesn't have to be in a release for 
> the sake of experimenting, and removing code is much harder than not 
> adding it in the first place, witness KNI.

Good idea.
What about a -next tree to experiment on kernel interactions?

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 15:27                   ` Thomas Monjalon
@ 2016-02-29 16:04                     ` Panu Matilainen
  0 siblings, 0 replies; 83+ messages in thread
From: Panu Matilainen @ 2016-02-29 16:04 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit; +Cc: dev, Avi Kivity

On 02/29/2016 05:27 PM, Thomas Monjalon wrote:
> 2016-02-29 17:19, Panu Matilainen:
>> On 02/29/2016 01:35 PM, Ferruh Yigit wrote:
>>> On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
>>>> Hi,
>>>> I totally agree with Avi's comments.
>>>> This topic is really important for the future of DPDK.
>>>> So I think we must give some time to continue the discussion
>>>> and have netdev involved in the choices done.
>>>> As a consequence, these series should not be merged in the release 16.04.
>>>> Thanks for continuing the work.
>>>>
>>> Hi Thomas,
>>>
>>> It is great to have some discussion and feedbacks.
>>> But I doubt not merging in this release will help to have more discussion.
>>>
>>> It is better to have them in this release and let people experiment it,
>>> this gives more chance to better discussion.
>>>
>>> These features are replacement of KNI, and KNI is not intended to be
>>> removed in this release, so who are using KNI as solution can continue
>>> to use KNI and can test KCP/KDP, so that we can get more feedbacks.
>>
>> So make the work available from a separate git repo and make it easy for
>> people to experiment with it. Code doesn't have to be in a release for
>> the sake of experimenting, and removing code is much harder than not
>> adding it in the first place, witness KNI.
>
> Good idea.
> What about a -next tree to experiment on kernel interactions?

Here's another, related but more radical (and rather unbaked) idea:

Move all the kernel modules and their associated libraries (thinking of 
KNI here) to a separate repo with perhaps more relaxed rules, but OTOH 
require upstream kernel support for any features to be included in dpdk 
itself. Carrot-and-stick of sorts :)

	- Panu -

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-01-27 16:24 ` [PATCH 1/3] kcp: add kernel control path kernel module Ferruh Yigit
  2016-01-28  9:49   ` Remy Horton
  2016-02-28 15:34   ` Avi Kivity
@ 2016-02-29 20:11   ` Stephen Hemminger
  2016-03-01  0:35     ` Ferruh Yigit
  2 siblings, 1 reply; 83+ messages in thread
From: Stephen Hemminger @ 2016-02-29 20:11 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On Wed, 27 Jan 2016 16:24:07 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> +static int
> +kcp_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param)
> +{
> +	int ret = -EINVAL;
> +	struct kcp_dev *dev;
> +	struct kcp_dev *n;
> +	char name[RTE_KCP_NAMESIZE];
> +	unsigned int instance = ioctl_param;
> +
> +	snprintf(name, RTE_KCP_NAMESIZE, "dpdk%u", instance);
> +
> +	down_write(&kcp_list_lock);


Some observations about how acceptable this will to upstream
kernel developers.

ioctl's are the lease favored form of API.

You chose the worst possible mutual exclusion read/write semaphores.
Read/write is slower than simpler primtives, and semaphores were
replaced for almost all usage models by mutexes (about 4 years ago).

Looks like you copied the out of date kernel API's used
by KNI.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 20:11   ` Stephen Hemminger
@ 2016-03-01  0:35     ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-01  0:35 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On 2/29/2016 8:11 PM, Stephen Hemminger wrote:
> On Wed, 27 Jan 2016 16:24:07 +0000
> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> 
>> +static int
>> +kcp_ioctl_release(unsigned int ioctl_num, unsigned long ioctl_param)
>> +{
>> +	int ret = -EINVAL;
>> +	struct kcp_dev *dev;
>> +	struct kcp_dev *n;
>> +	char name[RTE_KCP_NAMESIZE];
>> +	unsigned int instance = ioctl_param;
>> +
>> +	snprintf(name, RTE_KCP_NAMESIZE, "dpdk%u", instance);
>> +
>> +	down_write(&kcp_list_lock);
> 
> 
> Some observations about how acceptable this will to upstream
> kernel developers.
> 
> ioctl's are the lease favored form of API.
>
This is from v1 of patch, v3 is out and it removed ioctl, replacing it
with rtnetlink.

v3:
http://dpdk.org/dev/patchwork/patch/10872/


> You chose the worst possible mutual exclusion read/write semaphores.
> Read/write is slower than simpler primtives, and semaphores were
> replaced for almost all usage models by mutexes (about 4 years ago).
> 
> Looks like you copied the out of date kernel API's used
> by KNI.
> 
But still using same locks, and as you have guessed these are from
legacy code. I will replace them with newer, faster lock APIs happily.

If only problem is using slow lock APIs, it seems code is in pretty good
shape J Please check the v3, it is in better shape now. With more review
from reviewers and after a few more versions, we can have something
upstreamable.

Thanks,
ferruh

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

* Re: [PATCH v3 2/4] kcp: add kernel control path kernel module
  2016-02-26 14:10     ` [PATCH v3 2/4] kcp: add kernel control path kernel module Ferruh Yigit
@ 2016-03-01  1:02       ` Stephen Hemminger
  2016-03-01 15:53         ` Ferruh Yigit
  0 siblings, 1 reply; 83+ messages in thread
From: Stephen Hemminger @ 2016-03-01  1:02 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On Fri, 26 Feb 2016 14:10:39 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> +#define KCP_ERR(args...) printk(KERN_ERR "KCP: " args)
> +#define KCP_INFO(args...) printk(KERN_INFO "KCP: " args)
> +
> +#ifdef RTE_KCP_KO_DEBUG
> +#define KCP_DBG(args...) printk(KERN_DEBUG "KCP: " args)
> +#else
> +#define KCP_DBG(args...)
> +#endif

These macros will not make netdev developers happy.

Use standard printk macros, and if you want prefix, use pr_fmt


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

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

* [PATCH v4 0/4] Use common Linux tools to control DPDK ports
  2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
                       ` (4 preceding siblings ...)
  2016-02-29  9:33     ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Remy Horton
@ 2016-03-01 15:41     ` Ferruh Yigit
  2016-03-01 15:41       ` [PATCH v4 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
                         ` (4 more replies)
  5 siblings, 5 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-01 15:41 UTC (permalink / raw)
  To: dev

This work is to make DPDK ports more visible and to enable using common
Linux tools to configure DPDK ports.

Patch is based on KNI but contains only control functionality of it,
also this patch does not include any Linux kernel network driver as
part of it.

Basically with the help of a kernel module (KCP), virtual Linux network
interfaces named as "dpdk$" are created per DPDK port, control messages
sent to these virtual interfaces are forwarded to DPDK, and response
sent back to Linux application.

Virtual interfaces created when DPDK application started and destroyed
automatically when DPDK application terminated.

Communication between kernel-space and DPDK done using netlink socket.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

v4:
* Kernel side changes:
  * Remove logging helper macros, use pr_fmt
  * Seperate log msg for timeout and error
* Control library changes:
  * Add ethtool_get_settings as dummy

v3:
* Kernel side changes:
  * Devices are not up by default
  * Add enable/disable promisc, allmulti support
  * Increase timeout to 500ms and print log when a command timedout
* Control library changes:
  * Use librte_ethtool
  * Don't create interfaces for virtual PMDs
  * Add a new API ...msg_exist() to support port based locking
  * Add enable/disable promisc, allmulti support
* Example changes:
  * Use blocking mode control interface processing, instead of poll mode

v2:
* Use rtnetlink to create interfaces
* Add more ethtool support: get/set ringparam, set pauseparam.
* fix ethtool get/set eeprom
* lots of minor updates, enhancements in the code


Samples:

$ ifconfig
dpdk0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::92e2:baff:fe0e:49b8  prefixlen 64  scopeid 0x20<link>
        ether 90:e2:ba:0e:49:b8  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

dpdk1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::21b:21ff:fe76:fa20  prefixlen 64  scopeid 0x20<link>
        ether 00:1b:21:76:fa:20  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

After some traffic on port 0:

$ ifconfig
dpdk0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::92e2:baff:fe0e:49b8  prefixlen 64  scopeid 0x20<link>
        ether 90:e2:ba:0e:49:b8  txqueuelen 1000  (Ethernet)
        RX packets 26117404  bytes 1671514264 (1.5 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 27897889  bytes 1785463944 (1.6 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


$ ethtool -i dpdk0
driver: rte_ixgbe_pmd
version: DPDK 16.04.0-rc0
firmware-version: 
expansion-rom-version: 
bus-info: 0000:08:00.0
supports-statistics: no
supports-test: no
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no


$ ethtool -e dpdk0 offset 20 length 10
Offset          Values
------          ------
0x0014:         b7 01 bf 01 c7 01 cf 01 09 02 


$ ip l show dpdk0
44: dpdk0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:b8 brd ff:ff:ff:ff:ff:ff

$ ip l set dpdk0 addr 90:e2:ba:0e:49:b9

$ ip l show dpdk0
44: dpdk0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:b9 brd ff:ff:ff:ff:ff:ff


Ferruh Yigit (4):
  lib/librte_ethtool: move librte_ethtool form examples to lib folder
  kcp: add kernel control path kernel module
  rte_ctrl_if: add control interface library
  examples/ethtool: add control interface support to the application

 MAINTAINERS                                        |   5 +
 config/common_linuxapp                             |  14 +-
 doc/api/doxy-api-index.md                          |   4 +-
 doc/api/doxy-api.conf                              |   2 +
 doc/api/examples.dox                               |   5 +-
 doc/guides/prog_guide/ctrl_if_lib.rst              |  52 ++
 doc/guides/prog_guide/ethtool_lib.rst              |  62 ++
 doc/guides/prog_guide/index.rst                    |   4 +-
 doc/guides/rel_notes/release_16_04.rst             |  10 +
 doc/guides/sample_app_ug/ethtool.rst               |  77 +-
 examples/ethtool/Makefile                          |  24 +-
 examples/ethtool/ethapp.c                          | 873 +++++++++++++++++++++
 examples/ethtool/ethapp.h                          |  41 +
 examples/ethtool/ethtool-app/Makefile              |  54 --
 examples/ethtool/ethtool-app/ethapp.c              | 873 ---------------------
 examples/ethtool/ethtool-app/ethapp.h              |  41 -
 examples/ethtool/ethtool-app/main.c                | 305 -------
 examples/ethtool/lib/Makefile                      |  57 --
 examples/ethtool/lib/rte_ethtool.c                 | 423 ----------
 examples/ethtool/lib/rte_ethtool.h                 | 410 ----------
 examples/ethtool/main.c                            | 332 ++++++++
 lib/Makefile                                       |   4 +-
 lib/librte_ctrl_if/Makefile                        |  58 ++
 lib/librte_ctrl_if/rte_ctrl_ethtool.c              | 390 +++++++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.h              |  54 ++
 lib/librte_ctrl_if/rte_ctrl_if.c                   | 395 ++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h                   | 129 +++
 lib/librte_ctrl_if/rte_ctrl_if_version.map         |  10 +
 lib/librte_ctrl_if/rte_nl.c                        | 313 ++++++++
 lib/librte_ctrl_if/rte_nl.h                        |  50 ++
 lib/librte_eal/common/include/rte_log.h            |   3 +-
 lib/librte_eal/linuxapp/Makefile                   |   5 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h | 109 +++
 lib/librte_eal/linuxapp/kcp/Makefile               |  57 ++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  56 ++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 300 +++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 225 ++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 220 ++++++
 lib/librte_ethtool/Makefile                        |  57 ++
 lib/librte_ethtool/rte_ethtool.c                   | 423 ++++++++++
 lib/librte_ethtool/rte_ethtool.h                   | 413 ++++++++++
 lib/librte_ethtool/rte_ethtool_version.map         |  28 +
 mk/rte.app.mk                                      |   4 +-
 44 files changed, 4759 insertions(+), 2215 deletions(-)
 create mode 100644 doc/guides/prog_guide/ctrl_if_lib.rst
 create mode 100644 doc/guides/prog_guide/ethtool_lib.rst
 create mode 100644 examples/ethtool/ethapp.c
 create mode 100644 examples/ethtool/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/Makefile
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.c
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/main.c
 delete mode 100644 examples/ethtool/lib/Makefile
 delete mode 100644 examples/ethtool/lib/rte_ethtool.c
 delete mode 100644 examples/ethtool/lib/rte_ethtool.h
 create mode 100644 examples/ethtool/main.c
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c
 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.5.0

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

* [PATCH v4 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder
  2016-03-01 15:41     ` [PATCH v4 " Ferruh Yigit
@ 2016-03-01 15:41       ` Ferruh Yigit
  2016-03-01 15:41       ` [PATCH v4 2/4] kcp: add kernel control path kernel module Ferruh Yigit
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-01 15:41 UTC (permalink / raw)
  To: dev

With KCP, examples/ethtool/lib/ethtool has two users, to prevent code
dublication, moving library from examples folder into lib/ folder.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

v4:
* No update
---
 config/common_linuxapp                     |   5 +
 doc/api/doxy-api-index.md                  |   3 +-
 doc/api/doxy-api.conf                      |   1 +
 doc/api/examples.dox                       |   5 +-
 doc/guides/prog_guide/ethtool_lib.rst      |  62 ++
 doc/guides/prog_guide/index.rst            |   3 +-
 doc/guides/rel_notes/release_16_04.rst     |   1 +
 doc/guides/sample_app_ug/ethtool.rst       |  36 +-
 examples/ethtool/Makefile                  |  24 +-
 examples/ethtool/ethapp.c                  | 873 +++++++++++++++++++++++++++++
 examples/ethtool/ethapp.h                  |  41 ++
 examples/ethtool/ethtool-app/Makefile      |  54 --
 examples/ethtool/ethtool-app/ethapp.c      | 873 -----------------------------
 examples/ethtool/ethtool-app/ethapp.h      |  41 --
 examples/ethtool/ethtool-app/main.c        | 305 ----------
 examples/ethtool/lib/Makefile              |  57 --
 examples/ethtool/lib/rte_ethtool.c         | 423 --------------
 examples/ethtool/lib/rte_ethtool.h         | 410 --------------
 examples/ethtool/main.c                    | 305 ++++++++++
 lib/Makefile                               |   1 +
 lib/librte_ethtool/Makefile                |  57 ++
 lib/librte_ethtool/rte_ethtool.c           | 423 ++++++++++++++
 lib/librte_ethtool/rte_ethtool.h           | 413 ++++++++++++++
 lib/librte_ethtool/rte_ethtool_version.map |  28 +
 mk/rte.app.mk                              |   1 +
 25 files changed, 2236 insertions(+), 2209 deletions(-)
 create mode 100644 doc/guides/prog_guide/ethtool_lib.rst
 create mode 100644 examples/ethtool/ethapp.c
 create mode 100644 examples/ethtool/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/Makefile
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.c
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/main.c
 delete mode 100644 examples/ethtool/lib/Makefile
 delete mode 100644 examples/ethtool/lib/rte_ethtool.c
 delete mode 100644 examples/ethtool/lib/rte_ethtool.h
 create mode 100644 examples/ethtool/main.c
 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/config/common_linuxapp b/config/common_linuxapp
index f1638db..960dde4 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -497,6 +497,11 @@ CONFIG_RTE_KNI_VHOST_DEBUG_RX=n
 CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 
 #
+# Compile librte_ethtool
+#
+CONFIG_RTE_LIBRTE_ETHTOOL=y
+
+#
 # Compile vhost library
 # fuse-devel is needed to run vhost-cuse.
 # fuse-devel enables user space char driver development
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 7a91001..4cdd3f5 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -149,4 +149,5 @@ There are many libraries, so their headers may be grouped by topics:
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
   [keepalive]          (@ref rte_keepalive.h),
-  [version]            (@ref rte_version.h)
+  [version]            (@ref rte_version.h),
+  [ethtool]            (@ref rte_ethtool.h),
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index 57e8b5d..c5b8615 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -41,6 +41,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_cryptodev \
                           lib/librte_distributor \
                           lib/librte_ether \
+                          lib/librte_ethtool \
                           lib/librte_hash \
                           lib/librte_ip_frag \
                           lib/librte_ivshmem \
diff --git a/doc/api/examples.dox b/doc/api/examples.dox
index 200af0b..8763d77 100644
--- a/doc/api/examples.dox
+++ b/doc/api/examples.dox
@@ -8,9 +8,8 @@
 @example distributor/main.c
 @example dpdk_qat/crypto.c
 @example dpdk_qat/main.c
-@example ethtool/ethtool-app/ethapp.c
-@example ethtool/ethtool-app/main.c
-@example ethtool/lib/rte_ethtool.c
+@example ethtool/ethapp.c
+@example ethtool/main.c
 @example exception_path/main.c
 @example helloworld/main.c
 @example ip_fragmentation/main.c
diff --git a/doc/guides/prog_guide/ethtool_lib.rst b/doc/guides/prog_guide/ethtool_lib.rst
new file mode 100644
index 0000000..e161cd0
--- /dev/null
+++ b/doc/guides/prog_guide/ethtool_lib.rst
@@ -0,0 +1,62 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+.. _Ethtool_Library:
+
+Ethtool Library
+===============
+
+Ethtool interface
+-----------------
+
+The Ethtool interface is built as a separate library, and implements
+the following functions:
+
+- ``rte_ethtool_get_drvinfo()``
+- ``rte_ethtool_get_regs_len()``
+- ``rte_ethtool_get_regs()``
+- ``rte_ethtool_get_link()``
+- ``rte_ethtool_get_eeprom_len()``
+- ``rte_ethtool_get_eeprom()``
+- ``rte_ethtool_set_eeprom()``
+- ``rte_ethtool_get_pauseparam()``
+- ``rte_ethtool_set_pauseparam()``
+- ``rte_ethtool_net_open()``
+- ``rte_ethtool_net_stop()``
+- ``rte_ethtool_net_get_mac_addr()``
+- ``rte_ethtool_net_set_mac_addr()``
+- ``rte_ethtool_net_validate_addr()``
+- ``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_net_set_rx_mode()``
+- ``rte_ethtool_get_ringparam()``
+- ``rte_ethtool_set_ringparam()``
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index a9404fb..98f4aca 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -1,5 +1,5 @@
 ..  BSD LICENSE
-    Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+    Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
     All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@ Programmer's Guide
     packet_distrib_lib
     reorder_lib
     ip_fragment_reassembly_lib
+    ethtool_lib
     multi_proc_support
     kernel_nic_interface
     thread_safety_dpdk_functions
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index fd7dd1a..082e0b8 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -144,6 +144,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_cmdline.so.1
      librte_distributor.so.1
      librte_eal.so.2
+   + librte_ethtool.so.1
      librte_hash.so.2
      librte_ip_frag.so.1
      librte_ivshmem.so.1
diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
index 4d1697e..65240ae 100644
--- a/doc/guides/sample_app_ug/ethtool.rst
+++ b/doc/guides/sample_app_ug/ethtool.rst
@@ -1,6 +1,6 @@
 
 ..  BSD LICENSE
-    Copyright(c) 2015 Intel Corporation. All rights reserved.
+    Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
     All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
@@ -71,7 +71,7 @@ The only available options are the standard ones for the EAL:
 
 .. code-block:: console
 
-    ./ethtool-app/ethtool-app/${RTE_TARGET}/ethtool [EAL options]
+    ./${RTE_TARGET}/ethtool [EAL options]
 
 Refer to the *DPDK Getting Started Guide* for general information on
 running applications and the Environment Abstraction Layer (EAL)
@@ -128,33 +128,5 @@ Ethtool Shell
 The foreground part of the Ethtool sample is a console-based
 interface that accepts commands as described in `using the
 application`_. Individual call-back functions handle the detail
-associated with each command, which make use of the functions
-defined in the `Ethtool interface`_ to the DPDK functions.
-
-Ethtool interface
------------------
-
-The Ethtool interface is built as a separate library, and implements
-the following functions:
-
-- ``rte_ethtool_get_drvinfo()``
-- ``rte_ethtool_get_regs_len()``
-- ``rte_ethtool_get_regs()``
-- ``rte_ethtool_get_link()``
-- ``rte_ethtool_get_eeprom_len()``
-- ``rte_ethtool_get_eeprom()``
-- ``rte_ethtool_set_eeprom()``
-- ``rte_ethtool_get_pauseparam()``
-- ``rte_ethtool_set_pauseparam()``
-- ``rte_ethtool_net_open()``
-- ``rte_ethtool_net_stop()``
-- ``rte_ethtool_net_get_mac_addr()``
-- ``rte_ethtool_net_set_mac_addr()``
-- ``rte_ethtool_net_validate_addr()``
-- ``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_net_set_rx_mode()``
-- ``rte_ethtool_get_ringparam()``
-- ``rte_ethtool_set_ringparam()``
+associated with each command, which make use of librte_ethtool
+library.
diff --git a/examples/ethtool/Makefile b/examples/ethtool/Makefile
index 995cd25..23a6ffd 100644
--- a/examples/ethtool/Makefile
+++ b/examples/ethtool/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -33,17 +33,23 @@ ifeq ($(RTE_SDK),)
 $(error "Please define RTE_SDK environment variable")
 endif
 
-# Default target, can be overwritten by command line or environment
+# Default target, can be overridden 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")
-$(info This application can only operate in a linuxapp environment, \
-please change the definition of the RTE_TARGET environment variable)
-else
+# binary name
+APP = ethtool
+
+# all source are stored in SRCS-y
+SRCS-y := main.c ethapp.c
+
+#CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#LDLIBS += -L$(subst ethtool-app,lib,$(RTE_OUTPUT))/lib
+#LDLIBS += -lrte_ethtool
 
-DIRS-y += lib ethtool-app
-endif
 
-include $(RTE_SDK)/mk/rte.extsubdir.mk
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/ethtool/ethapp.c b/examples/ethtool/ethapp.c
new file mode 100644
index 0000000..fca602b
--- /dev/null
+++ b/examples/ethtool/ethapp.c
@@ -0,0 +1,873 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015-2016 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 <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "rte_ethtool.h"
+#include "ethapp.h"
+
+#define EEPROM_DUMP_CHUNKSIZE 1024
+
+
+struct pcmd_get_params {
+	cmdline_fixed_string_t cmd;
+};
+struct pcmd_int_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+};
+struct pcmd_intstr_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	cmdline_fixed_string_t opt;
+};
+struct pcmd_intmac_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	struct ether_addr mac;
+};
+struct pcmd_str_params {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t opt;
+};
+struct pcmd_vlan_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	cmdline_fixed_string_t mode;
+	uint16_t vid;
+};
+struct pcmd_intintint_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	uint16_t tx;
+	uint16_t rx;
+};
+
+
+/* Parameter-less commands */
+cmdline_parse_token_string_t pcmd_quit_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "quit");
+cmdline_parse_token_string_t pcmd_stats_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "stats");
+cmdline_parse_token_string_t pcmd_drvinfo_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "drvinfo");
+cmdline_parse_token_string_t pcmd_link_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "link");
+
+/* Commands taking just port id */
+cmdline_parse_token_string_t pcmd_open_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "open");
+cmdline_parse_token_string_t pcmd_stop_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "stop");
+cmdline_parse_token_string_t pcmd_rxmode_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "rxmode");
+cmdline_parse_token_string_t pcmd_portstats_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "portstats");
+cmdline_parse_token_num_t pcmd_int_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_int_params, port, UINT16);
+
+/* Commands taking port id and string */
+cmdline_parse_token_string_t pcmd_eeprom_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "eeprom");
+cmdline_parse_token_string_t pcmd_mtu_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "mtu");
+cmdline_parse_token_string_t pcmd_regs_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "regs");
+
+cmdline_parse_token_num_t pcmd_intstr_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_intstr_token_opt =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, opt, NULL);
+
+/* Commands taking port id and a MAC address string */
+cmdline_parse_token_string_t pcmd_macaddr_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "macaddr");
+cmdline_parse_token_num_t pcmd_intmac_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intmac_params, port, UINT16);
+cmdline_parse_token_etheraddr_t pcmd_intmac_token_mac =
+	TOKEN_ETHERADDR_INITIALIZER(struct pcmd_intmac_params, mac);
+
+/* Command taking just a MAC address */
+cmdline_parse_token_string_t pcmd_validate_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "validate");
+
+
+/* Commands taking port id and two integers */
+cmdline_parse_token_string_t pcmd_ringparam_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intintint_params, cmd,
+		"ringparam");
+cmdline_parse_token_num_t pcmd_intintint_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, port, UINT16);
+cmdline_parse_token_num_t pcmd_intintint_token_tx =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, tx, UINT16);
+cmdline_parse_token_num_t pcmd_intintint_token_rx =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, rx, UINT16);
+
+
+/* Pause commands */
+cmdline_parse_token_string_t pcmd_pause_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "pause");
+cmdline_parse_token_num_t pcmd_pause_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_pause_token_opt =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params,
+		opt, "all#tx#rx#none");
+
+/* VLAN commands */
+cmdline_parse_token_string_t pcmd_vlan_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, cmd, "vlan");
+cmdline_parse_token_num_t pcmd_vlan_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_vlan_token_mode =
+	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, mode, "add#del");
+cmdline_parse_token_num_t pcmd_vlan_token_vid =
+	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, vid, UINT16);
+
+
+static void
+pcmd_quit_callback(__rte_unused void *ptr_params,
+	struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	cmdline_quit(ctx);
+}
+
+
+static void
+pcmd_drvinfo_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct ethtool_drvinfo info;
+	int id_port;
+
+	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
+		if (rte_ethtool_get_drvinfo(id_port, &info)) {
+			printf("Error getting info for port %i\n", id_port);
+			return;
+		}
+		printf("Port %i driver: %s (ver: %s)\n",
+			id_port, info.driver, info.version
+		      );
+	}
+}
+
+
+static void
+pcmd_link_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	int num_ports = rte_eth_dev_count();
+	int id_port, stat_port;
+
+	for (id_port = 0; id_port < num_ports; id_port++) {
+		if (!rte_eth_dev_is_valid_port(id_port))
+			continue;
+		stat_port = rte_ethtool_get_link(id_port);
+		switch (stat_port) {
+		case 0:
+			printf("Port %i: Down\n", id_port);
+			break;
+		case 1:
+			printf("Port %i: Up\n", id_port);
+			break;
+		default:
+			printf("Port %i: Error getting link status\n",
+				id_port
+				);
+			break;
+		}
+	}
+	printf("\n");
+}
+
+
+static void
+pcmd_regs_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int len_regs;
+	struct ethtool_regs regs;
+	unsigned char *buf_data;
+	FILE *fp_regs;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	len_regs = rte_ethtool_get_regs_len(params->port);
+	if (len_regs > 0) {
+		printf("Port %i: %i bytes\n", params->port, len_regs);
+		buf_data = malloc(len_regs);
+		if (buf_data == NULL) {
+			printf("Error allocating %i bytes for buffer\n",
+				len_regs);
+			return;
+		}
+		if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
+			fp_regs = fopen(params->opt, "wb");
+			if (fp_regs == NULL) {
+				printf("Error opening '%s' for writing\n",
+					params->opt);
+			} else {
+				if ((int)fwrite(buf_data,
+						1, len_regs,
+						fp_regs) != len_regs)
+					printf("Error writing '%s'\n",
+						params->opt);
+				fclose(fp_regs);
+			}
+		}
+		free(buf_data);
+	} else if (len_regs == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error getting registers\n", params->port);
+}
+
+
+static void
+pcmd_eeprom_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	struct ethtool_eeprom info_eeprom;
+	int len_eeprom;
+	int pos_eeprom;
+	int stat;
+	unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
+	FILE *fp_eeprom;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	len_eeprom = rte_ethtool_get_eeprom_len(params->port);
+	if (len_eeprom > 0) {
+		fp_eeprom = fopen(params->opt, "wb");
+		if (fp_eeprom == NULL) {
+			printf("Error opening '%s' for writing\n",
+				params->opt);
+			return;
+		}
+		printf("Total EEPROM length: %i bytes\n", len_eeprom);
+		info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
+		for (pos_eeprom = 0;
+				pos_eeprom < len_eeprom;
+				pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
+			info_eeprom.offset = pos_eeprom;
+			if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
+				info_eeprom.len = len_eeprom - pos_eeprom;
+			else
+				info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
+			stat = rte_ethtool_get_eeprom(
+				params->port, &info_eeprom, bytes_eeprom
+				);
+			if (stat != 0) {
+				printf("EEPROM read error %i\n", stat);
+				break;
+			}
+			if (fwrite(bytes_eeprom,
+					1, info_eeprom.len,
+					fp_eeprom) != info_eeprom.len) {
+				printf("Error writing '%s'\n", params->opt);
+				break;
+			}
+		}
+		fclose(fp_eeprom);
+	} else if (len_eeprom == 0)
+		printf("Port %i: Device does not have EEPROM\n", params->port);
+	else if (len_eeprom == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error getting EEPROM\n", params->port);
+}
+
+
+static void
+pcmd_pause_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	struct ethtool_pauseparam info;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data != NULL) {
+		stat = rte_ethtool_get_pauseparam(params->port, &info);
+	} else {
+		memset(&info, 0, sizeof(info));
+		if (strcasecmp("all", params->opt) == 0) {
+			info.tx_pause = 1;
+			info.rx_pause = 1;
+		} else if (strcasecmp("tx", params->opt) == 0) {
+			info.tx_pause = 1;
+			info.rx_pause = 0;
+		} else if (strcasecmp("rx", params->opt) == 0) {
+			info.tx_pause = 0;
+			info.rx_pause = 1;
+		} else {
+			info.tx_pause = 0;
+			info.rx_pause = 0;
+		}
+		/* Assume auto-negotiation wanted */
+		info.autoneg = 1;
+		stat = rte_ethtool_set_pauseparam(params->port, &info);
+	}
+	if (stat == 0) {
+		if (info.rx_pause && info.tx_pause)
+			printf("Port %i: Tx & Rx Paused\n", params->port);
+		else if (info.rx_pause)
+			printf("Port %i: Rx Paused\n", params->port);
+		else if (info.tx_pause)
+			printf("Port %i: Tx Paused\n", params->port);
+		else
+			printf("Port %i: Tx & Rx not paused\n", params->port);
+	} else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error %i\n", params->port, stat);
+}
+
+
+static void
+pcmd_open_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	lock_port(params->port);
+	stat = rte_ethtool_net_open(params->port);
+	mark_port_active(params->port);
+	unlock_port(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error opening device\n", params->port);
+}
+
+static void
+pcmd_stop_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	lock_port(params->port);
+	stat = rte_ethtool_net_stop(params->port);
+	mark_port_inactive(params->port);
+	unlock_port(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error stopping device\n", params->port);
+}
+
+
+static void
+pcmd_rxmode_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_set_rx_mode(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error setting rx mode\n", params->port);
+}
+
+
+static void
+pcmd_macaddr_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intmac_params *params = ptr_params;
+	struct ether_addr mac_addr;
+	int stat;
+
+	stat = 0;
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data != NULL) {
+		lock_port(params->port);
+		stat = rte_ethtool_net_set_mac_addr(params->port,
+			&params->mac);
+		mark_port_newmac(params->port);
+		unlock_port(params->port);
+		if (stat == 0) {
+			printf("MAC address changed\n");
+			return;
+		}
+	} else {
+		stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
+		if (stat == 0) {
+			printf(
+				"Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+				params->port,
+				mac_addr.addr_bytes[0],
+				mac_addr.addr_bytes[1],
+				mac_addr.addr_bytes[2],
+				mac_addr.addr_bytes[3],
+				mac_addr.addr_bytes[4],
+				mac_addr.addr_bytes[5]);
+			return;
+		}
+	}
+
+	printf("Port %i: Error %s\n", params->port,
+	       strerror(-stat));
+}
+
+static void
+pcmd_mtu_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int stat;
+	int new_mtu;
+	char *ptr_parse_end;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	new_mtu = atoi(params->opt);
+	new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
+	if (*ptr_parse_end != '\0' ||
+			new_mtu < ETHER_MIN_MTU ||
+			new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
+		printf("Port %i: Invalid MTU value\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
+	if (stat == 0)
+		printf("Port %i: MTU set to %i\n", params->port, new_mtu);
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error setting MTU\n", params->port);
+}
+
+
+
+static void pcmd_portstats_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	struct rte_eth_stats stat_info;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
+	if (stat == 0) {
+		/* Most of rte_eth_stats is deprecated.. */
+		printf("Port %i stats\n", params->port);
+		printf("   In: %" PRIu64 " (%" PRIu64 " bytes)\n"
+			"  Out: %"PRIu64" (%"PRIu64 " bytes)\n"
+			"  Err: %"PRIu64"\n",
+			stat_info.ipackets,
+			stat_info.ibytes,
+			stat_info.opackets,
+			stat_info.obytes,
+			stat_info.ierrors+stat_info.oerrors
+		      );
+	} else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error fetching statistics\n", params->port);
+}
+
+static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intintint_params *params = ptr_params;
+	struct ethtool_ringparam ring_data;
+	struct ethtool_ringparam ring_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data == NULL) {
+		stat = rte_ethtool_get_ringparam(params->port, &ring_data);
+		if (stat == 0) {
+			printf("Port %i ring parameters\n"
+				"  Rx Pending: %i (%i max)\n"
+				"  Tx Pending: %i (%i max)\n",
+				params->port,
+				ring_data.rx_pending,
+				ring_data.rx_max_pending,
+				ring_data.tx_pending,
+				ring_data.tx_max_pending);
+		}
+	} else {
+		if (params->tx < 1 || params->rx < 1) {
+			printf("Error: Invalid parameters\n");
+			return;
+		}
+		memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
+		ring_params.tx_pending = params->tx;
+		ring_params.rx_pending = params->rx;
+		lock_port(params->port);
+		stat = rte_ethtool_set_ringparam(params->port, &ring_params);
+		unlock_port(params->port);
+	}
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error fetching statistics\n", params->port);
+}
+
+static void pcmd_validate_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intmac_params *params = ptr_params;
+
+	if (rte_ethtool_net_validate_addr(0, &params->mac))
+		printf("Address is unicast\n");
+	else
+		printf("Address is not unicast\n");
+}
+
+
+static void pcmd_vlan_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_vlan_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = 0;
+
+	if (strcasecmp("add", params->mode) == 0) {
+		stat = rte_ethtool_net_vlan_rx_add_vid(
+			params->port, params->vid
+			);
+		if (stat == 0)
+			printf("VLAN vid %i added\n", params->vid);
+
+	} else if (strcasecmp("del", params->mode) == 0) {
+		stat = rte_ethtool_net_vlan_rx_kill_vid(
+			params->port, params->vid
+			);
+		if (stat == 0)
+			printf("VLAN vid %i removed\n", params->vid);
+	} else {
+		/* Should not happen! */
+		printf("Error: Bad mode %s\n", params->mode);
+	}
+	if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else if (stat == -ENOSYS)
+		printf("Port %i: VLAN filtering disabled\n", params->port);
+	else if (stat != 0)
+		printf("Port %i: Error changing VLAN setup (code %i)\n",
+			params->port, -stat);
+}
+
+
+cmdline_parse_inst_t pcmd_quit = {
+	.f = pcmd_quit_callback,
+	.data = NULL,
+	.help_str = "quit\n     Exit program",
+	.tokens = {(void *)&pcmd_quit_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_drvinfo = {
+	.f = pcmd_drvinfo_callback,
+	.data = NULL,
+	.help_str = "drvinfo\n     Print driver info",
+	.tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_link = {
+	.f = pcmd_link_callback,
+	.data = NULL,
+	.help_str = "link\n     Print port link states",
+	.tokens = {(void *)&pcmd_link_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_regs = {
+	.f = pcmd_regs_callback,
+	.data = NULL,
+	.help_str = "regs <port_id> <filename>\n"
+		"     Dump port register(s) to file",
+	.tokens = {
+		(void *)&pcmd_regs_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_eeprom = {
+	.f = pcmd_eeprom_callback,
+	.data = NULL,
+	.help_str = "eeprom <port_id> <filename>\n    Dump EEPROM to file",
+	.tokens = {
+		(void *)&pcmd_eeprom_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_pause_noopt = {
+	.f = pcmd_pause_callback,
+	.data = (void *)0x01,
+	.help_str = "pause <port_id>\n     Print port pause state",
+	.tokens = {
+		(void *)&pcmd_pause_token_cmd,
+		(void *)&pcmd_pause_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_pause = {
+	.f = pcmd_pause_callback,
+	.data = NULL,
+	.help_str =
+		"pause <port_id> <all|tx|rx|none>\n     Pause/unpause port",
+	.tokens = {
+		(void *)&pcmd_pause_token_cmd,
+		(void *)&pcmd_pause_token_port,
+		(void *)&pcmd_pause_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_open = {
+	.f = pcmd_open_callback,
+	.data = NULL,
+	.help_str = "open <port_id>\n     Open port",
+	.tokens = {
+		(void *)&pcmd_open_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_stop = {
+	.f = pcmd_stop_callback,
+	.data = NULL,
+	.help_str = "stop <port_id>\n     Stop port",
+	.tokens = {
+		(void *)&pcmd_stop_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_rxmode = {
+	.f = pcmd_rxmode_callback,
+	.data = NULL,
+	.help_str = "rxmode <port_id>\n     Toggle port Rx mode",
+	.tokens = {
+		(void *)&pcmd_rxmode_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_macaddr_get = {
+	.f = pcmd_macaddr_callback,
+	.data = NULL,
+	.help_str = "macaddr <port_id>\n"
+		"     Get MAC address",
+	.tokens = {
+		(void *)&pcmd_macaddr_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_macaddr = {
+	.f = pcmd_macaddr_callback,
+	.data = (void *)0x01,
+	.help_str =
+		"macaddr <port_id> <mac_addr>\n"
+		"     Set MAC address",
+	.tokens = {
+		(void *)&pcmd_macaddr_token_cmd,
+		(void *)&pcmd_intmac_token_port,
+		(void *)&pcmd_intmac_token_mac,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_mtu = {
+	.f = pcmd_mtu_callback,
+	.data = NULL,
+	.help_str = "mtu <port_id> <mtu_value>\n"
+		"     Change MTU",
+	.tokens = {
+		(void *)&pcmd_mtu_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_portstats = {
+	.f = pcmd_portstats_callback,
+	.data = NULL,
+	.help_str = "portstats <port_id>\n"
+		"     Print port eth statistics",
+	.tokens = {
+		(void *)&pcmd_portstats_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_ringparam = {
+	.f = pcmd_ringparam_callback,
+	.data = NULL,
+	.help_str = "ringparam <port_id>\n"
+		"     Print ring parameters",
+	.tokens = {
+		(void *)&pcmd_ringparam_token_cmd,
+		(void *)&pcmd_intintint_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_ringparam_set = {
+	.f = pcmd_ringparam_callback,
+	.data = (void *)1,
+	.help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
+		"     Set ring parameters",
+	.tokens = {
+		(void *)&pcmd_ringparam_token_cmd,
+		(void *)&pcmd_intintint_token_port,
+		(void *)&pcmd_intintint_token_tx,
+		(void *)&pcmd_intintint_token_rx,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_validate = {
+	.f = pcmd_validate_callback,
+	.data = NULL,
+	.help_str = "validate <mac_addr>\n"
+		"     Check that MAC address is valid unicast address",
+	.tokens = {
+		(void *)&pcmd_validate_token_cmd,
+		(void *)&pcmd_intmac_token_mac,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_vlan = {
+	.f = pcmd_vlan_callback,
+	.data = NULL,
+	.help_str = "vlan <port_id> <add|del> <vlan_id>\n"
+		"     Add/remove VLAN id",
+	.tokens = {
+		(void *)&pcmd_vlan_token_cmd,
+		(void *)&pcmd_vlan_token_port,
+		(void *)&pcmd_vlan_token_mode,
+		(void *)&pcmd_vlan_token_vid,
+		NULL
+	},
+};
+
+
+cmdline_parse_ctx_t list_prompt_commands[] = {
+	(cmdline_parse_inst_t *)&pcmd_drvinfo,
+	(cmdline_parse_inst_t *)&pcmd_eeprom,
+	(cmdline_parse_inst_t *)&pcmd_link,
+	(cmdline_parse_inst_t *)&pcmd_macaddr_get,
+	(cmdline_parse_inst_t *)&pcmd_macaddr,
+	(cmdline_parse_inst_t *)&pcmd_mtu,
+	(cmdline_parse_inst_t *)&pcmd_open,
+	(cmdline_parse_inst_t *)&pcmd_pause_noopt,
+	(cmdline_parse_inst_t *)&pcmd_pause,
+	(cmdline_parse_inst_t *)&pcmd_portstats,
+	(cmdline_parse_inst_t *)&pcmd_regs,
+	(cmdline_parse_inst_t *)&pcmd_ringparam,
+	(cmdline_parse_inst_t *)&pcmd_ringparam_set,
+	(cmdline_parse_inst_t *)&pcmd_rxmode,
+	(cmdline_parse_inst_t *)&pcmd_stop,
+	(cmdline_parse_inst_t *)&pcmd_validate,
+	(cmdline_parse_inst_t *)&pcmd_vlan,
+	(cmdline_parse_inst_t *)&pcmd_quit,
+	NULL
+};
+
+
+void ethapp_main(void)
+{
+	struct cmdline *ctx_cmdline;
+
+	ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
+	cmdline_interact(ctx_cmdline);
+	cmdline_stdin_exit(ctx_cmdline);
+}
diff --git a/examples/ethtool/ethapp.h b/examples/ethtool/ethapp.h
new file mode 100644
index 0000000..bd48c7c
--- /dev/null
+++ b/examples/ethtool/ethapp.h
@@ -0,0 +1,41 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015-2016 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.
+ */
+
+
+void ethapp_main(void);
+void print_stats(void);
+void lock_port(int idx_port);
+void unlock_port(int idx_port);
+void mark_port_inactive(int idx_port);
+void mark_port_active(int idx_port);
+void mark_port_newmac(int idx_port);
diff --git a/examples/ethtool/ethtool-app/Makefile b/examples/ethtool/ethtool-app/Makefile
deleted file mode 100644
index 09c66ad..0000000
--- a/examples/ethtool/ethtool-app/Makefile
+++ /dev/null
@@ -1,54 +0,0 @@
-#   BSD LICENSE
-#
-#   Copyright(c) 2010-2014 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 overridden by command line or environment
-RTE_TARGET ?= x86_64-native-linuxapp-gcc
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-# binary name
-APP = ethtool
-
-# all source are stored in SRCS-y
-SRCS-y := main.c ethapp.c
-
-CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
-CFLAGS += $(WERROR_FLAGS)
-
-LDLIBS += -L$(subst ethtool-app,lib,$(RTE_OUTPUT))/lib
-LDLIBS += -lrte_ethtool
-
-
-include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/ethtool/ethtool-app/ethapp.c b/examples/ethtool/ethtool-app/ethapp.c
deleted file mode 100644
index 2ed4796..0000000
--- a/examples/ethtool/ethtool-app/ethapp.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/*-
- *   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 <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
-#include <cmdline.h>
-
-#include "rte_ethtool.h"
-#include "ethapp.h"
-
-#define EEPROM_DUMP_CHUNKSIZE 1024
-
-
-struct pcmd_get_params {
-	cmdline_fixed_string_t cmd;
-};
-struct pcmd_int_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-};
-struct pcmd_intstr_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	cmdline_fixed_string_t opt;
-};
-struct pcmd_intmac_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	struct ether_addr mac;
-};
-struct pcmd_str_params {
-	cmdline_fixed_string_t cmd;
-	cmdline_fixed_string_t opt;
-};
-struct pcmd_vlan_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	cmdline_fixed_string_t mode;
-	uint16_t vid;
-};
-struct pcmd_intintint_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	uint16_t tx;
-	uint16_t rx;
-};
-
-
-/* Parameter-less commands */
-cmdline_parse_token_string_t pcmd_quit_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "quit");
-cmdline_parse_token_string_t pcmd_stats_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "stats");
-cmdline_parse_token_string_t pcmd_drvinfo_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "drvinfo");
-cmdline_parse_token_string_t pcmd_link_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "link");
-
-/* Commands taking just port id */
-cmdline_parse_token_string_t pcmd_open_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "open");
-cmdline_parse_token_string_t pcmd_stop_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "stop");
-cmdline_parse_token_string_t pcmd_rxmode_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "rxmode");
-cmdline_parse_token_string_t pcmd_portstats_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "portstats");
-cmdline_parse_token_num_t pcmd_int_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_int_params, port, UINT16);
-
-/* Commands taking port id and string */
-cmdline_parse_token_string_t pcmd_eeprom_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "eeprom");
-cmdline_parse_token_string_t pcmd_mtu_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "mtu");
-cmdline_parse_token_string_t pcmd_regs_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "regs");
-
-cmdline_parse_token_num_t pcmd_intstr_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_intstr_token_opt =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, opt, NULL);
-
-/* Commands taking port id and a MAC address string */
-cmdline_parse_token_string_t pcmd_macaddr_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "macaddr");
-cmdline_parse_token_num_t pcmd_intmac_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intmac_params, port, UINT16);
-cmdline_parse_token_etheraddr_t pcmd_intmac_token_mac =
-	TOKEN_ETHERADDR_INITIALIZER(struct pcmd_intmac_params, mac);
-
-/* Command taking just a MAC address */
-cmdline_parse_token_string_t pcmd_validate_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "validate");
-
-
-/* Commands taking port id and two integers */
-cmdline_parse_token_string_t pcmd_ringparam_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intintint_params, cmd,
-		"ringparam");
-cmdline_parse_token_num_t pcmd_intintint_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, port, UINT16);
-cmdline_parse_token_num_t pcmd_intintint_token_tx =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, tx, UINT16);
-cmdline_parse_token_num_t pcmd_intintint_token_rx =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, rx, UINT16);
-
-
-/* Pause commands */
-cmdline_parse_token_string_t pcmd_pause_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "pause");
-cmdline_parse_token_num_t pcmd_pause_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_pause_token_opt =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params,
-		opt, "all#tx#rx#none");
-
-/* VLAN commands */
-cmdline_parse_token_string_t pcmd_vlan_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, cmd, "vlan");
-cmdline_parse_token_num_t pcmd_vlan_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_vlan_token_mode =
-	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, mode, "add#del");
-cmdline_parse_token_num_t pcmd_vlan_token_vid =
-	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, vid, UINT16);
-
-
-static void
-pcmd_quit_callback(__rte_unused void *ptr_params,
-	struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	cmdline_quit(ctx);
-}
-
-
-static void
-pcmd_drvinfo_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct ethtool_drvinfo info;
-	int id_port;
-
-	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
-		if (rte_ethtool_get_drvinfo(id_port, &info)) {
-			printf("Error getting info for port %i\n", id_port);
-			return;
-		}
-		printf("Port %i driver: %s (ver: %s)\n",
-			id_port, info.driver, info.version
-		      );
-	}
-}
-
-
-static void
-pcmd_link_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	int num_ports = rte_eth_dev_count();
-	int id_port, stat_port;
-
-	for (id_port = 0; id_port < num_ports; id_port++) {
-		if (!rte_eth_dev_is_valid_port(id_port))
-			continue;
-		stat_port = rte_ethtool_get_link(id_port);
-		switch (stat_port) {
-		case 0:
-			printf("Port %i: Down\n", id_port);
-			break;
-		case 1:
-			printf("Port %i: Up\n", id_port);
-			break;
-		default:
-			printf("Port %i: Error getting link status\n",
-				id_port
-				);
-			break;
-		}
-	}
-	printf("\n");
-}
-
-
-static void
-pcmd_regs_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int len_regs;
-	struct ethtool_regs regs;
-	unsigned char *buf_data;
-	FILE *fp_regs;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	len_regs = rte_ethtool_get_regs_len(params->port);
-	if (len_regs > 0) {
-		printf("Port %i: %i bytes\n", params->port, len_regs);
-		buf_data = malloc(len_regs);
-		if (buf_data == NULL) {
-			printf("Error allocating %i bytes for buffer\n",
-				len_regs);
-			return;
-		}
-		if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
-			fp_regs = fopen(params->opt, "wb");
-			if (fp_regs == NULL) {
-				printf("Error opening '%s' for writing\n",
-					params->opt);
-			} else {
-				if ((int)fwrite(buf_data,
-						1, len_regs,
-						fp_regs) != len_regs)
-					printf("Error writing '%s'\n",
-						params->opt);
-				fclose(fp_regs);
-			}
-		}
-		free(buf_data);
-	} else if (len_regs == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error getting registers\n", params->port);
-}
-
-
-static void
-pcmd_eeprom_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	struct ethtool_eeprom info_eeprom;
-	int len_eeprom;
-	int pos_eeprom;
-	int stat;
-	unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
-	FILE *fp_eeprom;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	len_eeprom = rte_ethtool_get_eeprom_len(params->port);
-	if (len_eeprom > 0) {
-		fp_eeprom = fopen(params->opt, "wb");
-		if (fp_eeprom == NULL) {
-			printf("Error opening '%s' for writing\n",
-				params->opt);
-			return;
-		}
-		printf("Total EEPROM length: %i bytes\n", len_eeprom);
-		info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
-		for (pos_eeprom = 0;
-				pos_eeprom < len_eeprom;
-				pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
-			info_eeprom.offset = pos_eeprom;
-			if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
-				info_eeprom.len = len_eeprom - pos_eeprom;
-			else
-				info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
-			stat = rte_ethtool_get_eeprom(
-				params->port, &info_eeprom, bytes_eeprom
-				);
-			if (stat != 0) {
-				printf("EEPROM read error %i\n", stat);
-				break;
-			}
-			if (fwrite(bytes_eeprom,
-					1, info_eeprom.len,
-					fp_eeprom) != info_eeprom.len) {
-				printf("Error writing '%s'\n", params->opt);
-				break;
-			}
-		}
-		fclose(fp_eeprom);
-	} else if (len_eeprom == 0)
-		printf("Port %i: Device does not have EEPROM\n", params->port);
-	else if (len_eeprom == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error getting EEPROM\n", params->port);
-}
-
-
-static void
-pcmd_pause_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	struct ethtool_pauseparam info;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data != NULL) {
-		stat = rte_ethtool_get_pauseparam(params->port, &info);
-	} else {
-		memset(&info, 0, sizeof(info));
-		if (strcasecmp("all", params->opt) == 0) {
-			info.tx_pause = 1;
-			info.rx_pause = 1;
-		} else if (strcasecmp("tx", params->opt) == 0) {
-			info.tx_pause = 1;
-			info.rx_pause = 0;
-		} else if (strcasecmp("rx", params->opt) == 0) {
-			info.tx_pause = 0;
-			info.rx_pause = 1;
-		} else {
-			info.tx_pause = 0;
-			info.rx_pause = 0;
-		}
-		/* Assume auto-negotiation wanted */
-		info.autoneg = 1;
-		stat = rte_ethtool_set_pauseparam(params->port, &info);
-	}
-	if (stat == 0) {
-		if (info.rx_pause && info.tx_pause)
-			printf("Port %i: Tx & Rx Paused\n", params->port);
-		else if (info.rx_pause)
-			printf("Port %i: Rx Paused\n", params->port);
-		else if (info.tx_pause)
-			printf("Port %i: Tx Paused\n", params->port);
-		else
-			printf("Port %i: Tx & Rx not paused\n", params->port);
-	} else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error %i\n", params->port, stat);
-}
-
-
-static void
-pcmd_open_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	lock_port(params->port);
-	stat = rte_ethtool_net_open(params->port);
-	mark_port_active(params->port);
-	unlock_port(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error opening device\n", params->port);
-}
-
-static void
-pcmd_stop_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	lock_port(params->port);
-	stat = rte_ethtool_net_stop(params->port);
-	mark_port_inactive(params->port);
-	unlock_port(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error stopping device\n", params->port);
-}
-
-
-static void
-pcmd_rxmode_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_set_rx_mode(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error setting rx mode\n", params->port);
-}
-
-
-static void
-pcmd_macaddr_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intmac_params *params = ptr_params;
-	struct ether_addr mac_addr;
-	int stat;
-
-	stat = 0;
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data != NULL) {
-		lock_port(params->port);
-		stat = rte_ethtool_net_set_mac_addr(params->port,
-			&params->mac);
-		mark_port_newmac(params->port);
-		unlock_port(params->port);
-		if (stat == 0) {
-			printf("MAC address changed\n");
-			return;
-		}
-	} else {
-		stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
-		if (stat == 0) {
-			printf(
-				"Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-				params->port,
-				mac_addr.addr_bytes[0],
-				mac_addr.addr_bytes[1],
-				mac_addr.addr_bytes[2],
-				mac_addr.addr_bytes[3],
-				mac_addr.addr_bytes[4],
-				mac_addr.addr_bytes[5]);
-			return;
-		}
-	}
-
-	printf("Port %i: Error %s\n", params->port,
-	       strerror(-stat));
-}
-
-static void
-pcmd_mtu_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int stat;
-	int new_mtu;
-	char *ptr_parse_end;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	new_mtu = atoi(params->opt);
-	new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
-	if (*ptr_parse_end != '\0' ||
-			new_mtu < ETHER_MIN_MTU ||
-			new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
-		printf("Port %i: Invalid MTU value\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
-	if (stat == 0)
-		printf("Port %i: MTU set to %i\n", params->port, new_mtu);
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error setting MTU\n", params->port);
-}
-
-
-
-static void pcmd_portstats_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	struct rte_eth_stats stat_info;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
-	if (stat == 0) {
-		/* Most of rte_eth_stats is deprecated.. */
-		printf("Port %i stats\n", params->port);
-		printf("   In: %" PRIu64 " (%" PRIu64 " bytes)\n"
-			"  Out: %"PRIu64" (%"PRIu64 " bytes)\n"
-			"  Err: %"PRIu64"\n",
-			stat_info.ipackets,
-			stat_info.ibytes,
-			stat_info.opackets,
-			stat_info.obytes,
-			stat_info.ierrors+stat_info.oerrors
-		      );
-	} else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error fetching statistics\n", params->port);
-}
-
-static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intintint_params *params = ptr_params;
-	struct ethtool_ringparam ring_data;
-	struct ethtool_ringparam ring_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data == NULL) {
-		stat = rte_ethtool_get_ringparam(params->port, &ring_data);
-		if (stat == 0) {
-			printf("Port %i ring parameters\n"
-				"  Rx Pending: %i (%i max)\n"
-				"  Tx Pending: %i (%i max)\n",
-				params->port,
-				ring_data.rx_pending,
-				ring_data.rx_max_pending,
-				ring_data.tx_pending,
-				ring_data.tx_max_pending);
-		}
-	} else {
-		if (params->tx < 1 || params->rx < 1) {
-			printf("Error: Invalid parameters\n");
-			return;
-		}
-		memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
-		ring_params.tx_pending = params->tx;
-		ring_params.rx_pending = params->rx;
-		lock_port(params->port);
-		stat = rte_ethtool_set_ringparam(params->port, &ring_params);
-		unlock_port(params->port);
-	}
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error fetching statistics\n", params->port);
-}
-
-static void pcmd_validate_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intmac_params *params = ptr_params;
-
-	if (rte_ethtool_net_validate_addr(0, &params->mac))
-		printf("Address is unicast\n");
-	else
-		printf("Address is not unicast\n");
-}
-
-
-static void pcmd_vlan_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_vlan_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = 0;
-
-	if (strcasecmp("add", params->mode) == 0) {
-		stat = rte_ethtool_net_vlan_rx_add_vid(
-			params->port, params->vid
-			);
-		if (stat == 0)
-			printf("VLAN vid %i added\n", params->vid);
-
-	} else if (strcasecmp("del", params->mode) == 0) {
-		stat = rte_ethtool_net_vlan_rx_kill_vid(
-			params->port, params->vid
-			);
-		if (stat == 0)
-			printf("VLAN vid %i removed\n", params->vid);
-	} else {
-		/* Should not happen! */
-		printf("Error: Bad mode %s\n", params->mode);
-	}
-	if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else if (stat == -ENOSYS)
-		printf("Port %i: VLAN filtering disabled\n", params->port);
-	else if (stat != 0)
-		printf("Port %i: Error changing VLAN setup (code %i)\n",
-			params->port, -stat);
-}
-
-
-cmdline_parse_inst_t pcmd_quit = {
-	.f = pcmd_quit_callback,
-	.data = NULL,
-	.help_str = "quit\n     Exit program",
-	.tokens = {(void *)&pcmd_quit_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_drvinfo = {
-	.f = pcmd_drvinfo_callback,
-	.data = NULL,
-	.help_str = "drvinfo\n     Print driver info",
-	.tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_link = {
-	.f = pcmd_link_callback,
-	.data = NULL,
-	.help_str = "link\n     Print port link states",
-	.tokens = {(void *)&pcmd_link_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_regs = {
-	.f = pcmd_regs_callback,
-	.data = NULL,
-	.help_str = "regs <port_id> <filename>\n"
-		"     Dump port register(s) to file",
-	.tokens = {
-		(void *)&pcmd_regs_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_eeprom = {
-	.f = pcmd_eeprom_callback,
-	.data = NULL,
-	.help_str = "eeprom <port_id> <filename>\n    Dump EEPROM to file",
-	.tokens = {
-		(void *)&pcmd_eeprom_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_pause_noopt = {
-	.f = pcmd_pause_callback,
-	.data = (void *)0x01,
-	.help_str = "pause <port_id>\n     Print port pause state",
-	.tokens = {
-		(void *)&pcmd_pause_token_cmd,
-		(void *)&pcmd_pause_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_pause = {
-	.f = pcmd_pause_callback,
-	.data = NULL,
-	.help_str =
-		"pause <port_id> <all|tx|rx|none>\n     Pause/unpause port",
-	.tokens = {
-		(void *)&pcmd_pause_token_cmd,
-		(void *)&pcmd_pause_token_port,
-		(void *)&pcmd_pause_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_open = {
-	.f = pcmd_open_callback,
-	.data = NULL,
-	.help_str = "open <port_id>\n     Open port",
-	.tokens = {
-		(void *)&pcmd_open_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_stop = {
-	.f = pcmd_stop_callback,
-	.data = NULL,
-	.help_str = "stop <port_id>\n     Stop port",
-	.tokens = {
-		(void *)&pcmd_stop_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_rxmode = {
-	.f = pcmd_rxmode_callback,
-	.data = NULL,
-	.help_str = "rxmode <port_id>\n     Toggle port Rx mode",
-	.tokens = {
-		(void *)&pcmd_rxmode_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_macaddr_get = {
-	.f = pcmd_macaddr_callback,
-	.data = NULL,
-	.help_str = "macaddr <port_id>\n"
-		"     Get MAC address",
-	.tokens = {
-		(void *)&pcmd_macaddr_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_macaddr = {
-	.f = pcmd_macaddr_callback,
-	.data = (void *)0x01,
-	.help_str =
-		"macaddr <port_id> <mac_addr>\n"
-		"     Set MAC address",
-	.tokens = {
-		(void *)&pcmd_macaddr_token_cmd,
-		(void *)&pcmd_intmac_token_port,
-		(void *)&pcmd_intmac_token_mac,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_mtu = {
-	.f = pcmd_mtu_callback,
-	.data = NULL,
-	.help_str = "mtu <port_id> <mtu_value>\n"
-		"     Change MTU",
-	.tokens = {
-		(void *)&pcmd_mtu_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_portstats = {
-	.f = pcmd_portstats_callback,
-	.data = NULL,
-	.help_str = "portstats <port_id>\n"
-		"     Print port eth statistics",
-	.tokens = {
-		(void *)&pcmd_portstats_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_ringparam = {
-	.f = pcmd_ringparam_callback,
-	.data = NULL,
-	.help_str = "ringparam <port_id>\n"
-		"     Print ring parameters",
-	.tokens = {
-		(void *)&pcmd_ringparam_token_cmd,
-		(void *)&pcmd_intintint_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_ringparam_set = {
-	.f = pcmd_ringparam_callback,
-	.data = (void *)1,
-	.help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
-		"     Set ring parameters",
-	.tokens = {
-		(void *)&pcmd_ringparam_token_cmd,
-		(void *)&pcmd_intintint_token_port,
-		(void *)&pcmd_intintint_token_tx,
-		(void *)&pcmd_intintint_token_rx,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_validate = {
-	.f = pcmd_validate_callback,
-	.data = NULL,
-	.help_str = "validate <mac_addr>\n"
-		"     Check that MAC address is valid unicast address",
-	.tokens = {
-		(void *)&pcmd_validate_token_cmd,
-		(void *)&pcmd_intmac_token_mac,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_vlan = {
-	.f = pcmd_vlan_callback,
-	.data = NULL,
-	.help_str = "vlan <port_id> <add|del> <vlan_id>\n"
-		"     Add/remove VLAN id",
-	.tokens = {
-		(void *)&pcmd_vlan_token_cmd,
-		(void *)&pcmd_vlan_token_port,
-		(void *)&pcmd_vlan_token_mode,
-		(void *)&pcmd_vlan_token_vid,
-		NULL
-	},
-};
-
-
-cmdline_parse_ctx_t list_prompt_commands[] = {
-	(cmdline_parse_inst_t *)&pcmd_drvinfo,
-	(cmdline_parse_inst_t *)&pcmd_eeprom,
-	(cmdline_parse_inst_t *)&pcmd_link,
-	(cmdline_parse_inst_t *)&pcmd_macaddr_get,
-	(cmdline_parse_inst_t *)&pcmd_macaddr,
-	(cmdline_parse_inst_t *)&pcmd_mtu,
-	(cmdline_parse_inst_t *)&pcmd_open,
-	(cmdline_parse_inst_t *)&pcmd_pause_noopt,
-	(cmdline_parse_inst_t *)&pcmd_pause,
-	(cmdline_parse_inst_t *)&pcmd_portstats,
-	(cmdline_parse_inst_t *)&pcmd_regs,
-	(cmdline_parse_inst_t *)&pcmd_ringparam,
-	(cmdline_parse_inst_t *)&pcmd_ringparam_set,
-	(cmdline_parse_inst_t *)&pcmd_rxmode,
-	(cmdline_parse_inst_t *)&pcmd_stop,
-	(cmdline_parse_inst_t *)&pcmd_validate,
-	(cmdline_parse_inst_t *)&pcmd_vlan,
-	(cmdline_parse_inst_t *)&pcmd_quit,
-	NULL
-};
-
-
-void ethapp_main(void)
-{
-	struct cmdline *ctx_cmdline;
-
-	ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
-	cmdline_interact(ctx_cmdline);
-	cmdline_stdin_exit(ctx_cmdline);
-}
diff --git a/examples/ethtool/ethtool-app/ethapp.h b/examples/ethtool/ethtool-app/ethapp.h
deleted file mode 100644
index ba438ee..0000000
--- a/examples/ethtool/ethtool-app/ethapp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*-
- *   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.
- */
-
-
-void ethapp_main(void);
-void print_stats(void);
-void lock_port(int idx_port);
-void unlock_port(int idx_port);
-void mark_port_inactive(int idx_port);
-void mark_port_active(int idx_port);
-void mark_port_newmac(int idx_port);
diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
deleted file mode 100644
index 2c655d8..0000000
--- a/examples/ethtool/ethtool-app/main.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*-
- *   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 <rte_common.h>
-#include <rte_spinlock.h>
-#include <rte_eal.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_memory.h>
-#include <rte_mempool.h>
-#include <rte_mbuf.h>
-
-#include "ethapp.h"
-
-#define MAX_PORTS RTE_MAX_ETHPORTS
-#define MAX_BURST_LENGTH 32
-#define PORT_RX_QUEUE_SIZE 128
-#define PORT_TX_QUEUE_SIZE 256
-#define PKTPOOL_EXTRA_SIZE 512
-#define PKTPOOL_CACHE 32
-
-
-struct txq_port {
-	uint16_t cnt_unsent;
-	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
-};
-
-struct app_port {
-	struct ether_addr mac_addr;
-	struct txq_port txq;
-	rte_spinlock_t lock;
-	int port_active;
-	int port_dirty;
-	int idx_port;
-	struct rte_mempool *pkt_pool;
-};
-
-struct app_config {
-	struct app_port ports[MAX_PORTS];
-	int cnt_ports;
-	int exit_now;
-};
-
-
-struct app_config app_cfg;
-
-
-void lock_port(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	rte_spinlock_lock(&ptr_port->lock);
-}
-
-void unlock_port(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	rte_spinlock_unlock(&ptr_port->lock);
-}
-
-void mark_port_active(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_active = 1;
-}
-
-void mark_port_inactive(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_active = 0;
-}
-
-void mark_port_newmac(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_dirty = 1;
-}
-
-static void setup_ports(struct app_config *app_cfg, int cnt_ports)
-{
-	int idx_port;
-	int size_pktpool;
-	struct rte_eth_conf cfg_port;
-	struct rte_eth_dev_info dev_info;
-	char str_name[16];
-
-	memset(&cfg_port, 0, sizeof(cfg_port));
-	cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
-
-	for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
-		struct app_port *ptr_port = &app_cfg->ports[idx_port];
-
-		rte_eth_dev_info_get(idx_port, &dev_info);
-		size_pktpool = dev_info.rx_desc_lim.nb_max +
-			dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
-
-		snprintf(str_name, 16, "pkt_pool%i", idx_port);
-		ptr_port->pkt_pool = rte_pktmbuf_pool_create(
-			str_name,
-			size_pktpool, PKTPOOL_CACHE,
-			0,
-			RTE_MBUF_DEFAULT_BUF_SIZE,
-			rte_socket_id()
-			);
-		if (ptr_port->pkt_pool == NULL)
-			rte_exit(EXIT_FAILURE,
-				"rte_pktmbuf_pool_create failed"
-				);
-
-		printf("Init port %i..\n", idx_port);
-		ptr_port->port_active = 1;
-		ptr_port->port_dirty = 0;
-		ptr_port->idx_port = idx_port;
-
-		if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_dev_configure failed");
-		if (rte_eth_rx_queue_setup(
-			    idx_port, 0, PORT_RX_QUEUE_SIZE,
-			    rte_eth_dev_socket_id(idx_port), NULL,
-			    ptr_port->pkt_pool) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_rx_queue_setup failed"
-				);
-		if (rte_eth_tx_queue_setup(
-			    idx_port, 0, PORT_TX_QUEUE_SIZE,
-			    rte_eth_dev_socket_id(idx_port), NULL) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_tx_queue_setup failed"
-				);
-		if (rte_eth_dev_start(idx_port) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "%s:%i: rte_eth_dev_start failed",
-				 __FILE__, __LINE__
-				);
-		rte_eth_promiscuous_enable(idx_port);
-		rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
-		rte_spinlock_init(&ptr_port->lock);
-	}
-}
-
-static void process_frame(struct app_port *ptr_port,
-	struct rte_mbuf *ptr_frame)
-{
-	struct ether_hdr *ptr_mac_hdr;
-
-	ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct ether_hdr *);
-	ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
-	ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
-}
-
-static int slave_main(__attribute__((unused)) void *ptr_data)
-{
-	struct app_port *ptr_port;
-	struct rte_mbuf *ptr_frame;
-	struct txq_port *txq;
-
-	uint16_t cnt_recv_frames;
-	uint16_t idx_frame;
-	uint16_t cnt_sent;
-	uint16_t idx_port;
-	uint16_t lock_result;
-
-	while (app_cfg.exit_now == 0) {
-		for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
-			/* Check that port is active and unlocked */
-			ptr_port = &app_cfg.ports[idx_port];
-			lock_result = rte_spinlock_trylock(&ptr_port->lock);
-			if (lock_result == 0)
-				continue;
-			if (ptr_port->port_active == 0) {
-				rte_spinlock_unlock(&ptr_port->lock);
-				continue;
-			}
-			txq = &ptr_port->txq;
-
-			/* MAC address was updated */
-			if (ptr_port->port_dirty == 1) {
-				rte_eth_macaddr_get(ptr_port->idx_port,
-					&ptr_port->mac_addr);
-				ptr_port->port_dirty = 0;
-			}
-
-			/* Incoming frames */
-			cnt_recv_frames = rte_eth_rx_burst(
-				ptr_port->idx_port, 0,
-				&txq->buf_frames[txq->cnt_unsent],
-				RTE_DIM(txq->buf_frames) - txq->cnt_unsent
-				);
-			if (cnt_recv_frames > 0) {
-				for (idx_frame = 0;
-					idx_frame < cnt_recv_frames;
-					idx_frame++) {
-					ptr_frame = txq->buf_frames[
-						idx_frame + txq->cnt_unsent];
-					process_frame(ptr_port, ptr_frame);
-				}
-				txq->cnt_unsent += cnt_recv_frames;
-			}
-
-			/* Outgoing frames */
-			if (txq->cnt_unsent > 0) {
-				cnt_sent = rte_eth_tx_burst(
-					ptr_port->idx_port, 0,
-					txq->buf_frames,
-					txq->cnt_unsent
-					);
-				/* Shuffle up unsent frame pointers */
-				for (idx_frame = cnt_sent;
-					idx_frame < txq->cnt_unsent;
-					idx_frame++)
-					txq->buf_frames[idx_frame - cnt_sent] =
-						txq->buf_frames[idx_frame];
-				txq->cnt_unsent -= cnt_sent;
-			}
-			rte_spinlock_unlock(&ptr_port->lock);
-		} /* end for( idx_port ) */
-	} /* end for(;;) */
-
-	return 0;
-}
-
-int main(int argc, char **argv)
-{
-	int cnt_args_parsed;
-	uint32_t id_core;
-	uint32_t cnt_ports;
-
-	/* Init runtime enviornment */
-	cnt_args_parsed = rte_eal_init(argc, argv);
-	if (cnt_args_parsed < 0)
-		rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
-
-	cnt_ports = rte_eth_dev_count();
-	printf("Number of NICs: %i\n", cnt_ports);
-	if (cnt_ports == 0)
-		rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
-	if (cnt_ports > MAX_PORTS) {
-		printf("Info: Using only %i of %i ports\n",
-			cnt_ports, MAX_PORTS
-			);
-		cnt_ports = MAX_PORTS;
-	}
-
-	setup_ports(&app_cfg, cnt_ports);
-
-	app_cfg.exit_now = 0;
-	app_cfg.cnt_ports = cnt_ports;
-
-	if (rte_lcore_count() < 2)
-		rte_exit(EXIT_FAILURE, "No available slave core!\n");
-	/* Assume there is an available slave.. */
-	id_core = rte_lcore_id();
-	id_core = rte_get_next_lcore(id_core, 1, 1);
-	rte_eal_remote_launch(slave_main, NULL, id_core);
-
-	ethapp_main();
-
-	app_cfg.exit_now = 1;
-	RTE_LCORE_FOREACH_SLAVE(id_core) {
-		if (rte_eal_wait_lcore(id_core) < 0)
-			return -1;
-	}
-
-	return 0;
-}
diff --git a/examples/ethtool/lib/Makefile b/examples/ethtool/lib/Makefile
deleted file mode 100644
index d7ee955..0000000
--- a/examples/ethtool/lib/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-#   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
-
-LIBABIVER := 1
-
-# 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/ethtool/lib/rte_ethtool.c b/examples/ethtool/lib/rte_ethtool.c
deleted file mode 100644
index 42e05f1..0000000
--- a/examples/ethtool/lib/rte_ethtool.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*-
- *   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_ether.h>
-#include "rte_ethtool.h"
-
-#define PKTPOOL_SIZE 512
-#define PKTPOOL_CACHE 32
-
-
-int
-rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
-{
-	struct rte_eth_dev_info dev_info;
-	int n;
-
-	if (drvinfo == NULL)
-		return -EINVAL;
-
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-
-	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)
-{
-	int count_regs;
-
-	count_regs = rte_eth_dev_get_reg_length(port_id);
-	if (count_regs > 0)
-		return count_regs * sizeof(uint32_t);
-	return count_regs;
-}
-
-int
-rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
-{
-	struct rte_dev_reg_info reg_info;
-	int status;
-
-	if (regs == NULL || data == NULL)
-		return -EINVAL;
-
-	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;
-
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	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;
-
-	if (eeprom == NULL || words == NULL)
-		return -EINVAL;
-
-	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;
-
-	if (eeprom == NULL || words == NULL || eeprom->offset >= eeprom->len)
-		return -EINVAL;
-
-	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;
-
-	if (pause_param == NULL)
-		return -EINVAL;
-
-	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_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;
-	default:
-		/* dummy block to avoid compiler warning */
-		break;
-	}
-	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;
-
-	if (pause_param == NULL)
-		return -EINVAL;
-
-	/*
-	 * 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)
-{
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	rte_eth_dev_stop(port_id);
-
-	return 0;
-}
-
-int
-rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
-{
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	if (addr == NULL)
-		return -EINVAL;
-	rte_eth_macaddr_get(port_id, addr);
-
-	return 0;
-}
-
-int
-rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
-{
-	if (addr == NULL)
-		return -EINVAL;
-	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)
-{
-	if (addr == NULL)
-		return -EINVAL;
-	return is_valid_assigned_ether_addr(addr);
-}
-
-int
-rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
-{
-	if (mtu < 0 || mtu > UINT16_MAX)
-		return -EINVAL;
-	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)
-{
-	if (stats == NULL)
-		return -EINVAL;
-	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);
-}
-
-/*
- * The set_rx_mode provides driver-specific rx mode setting.
- * This implementation implements rx mode setting based upon
- * ixgbe/igb drivers. Further improvement is to provide a
- * callback op field over struct rte_eth_dev::dev_ops so each
- * driver can register device-specific implementation
- */
-int
-rte_ethtool_net_set_rx_mode(uint8_t port_id)
-{
-	uint16_t num_vfs;
-	struct rte_eth_dev_info dev_info;
-	uint16_t vf;
-
-	memset(&dev_info, 0, sizeof(dev_info));
-	rte_eth_dev_info_get(port_id, &dev_info);
-	num_vfs = dev_info.max_vfs;
-
-	/* Set VF vf_rx_mode, VF unsupport status is discard */
-	for (vf = 0; vf < num_vfs; vf++)
-		rte_eth_dev_set_vf_rxmode(port_id, vf,
-			ETH_VMDQ_ACCEPT_UNTAG, 0);
-
-	/* Enable Rx vlan filter, VF unspport status is discard */
-	rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
-
-	return 0;
-}
-
-
-int
-rte_ethtool_get_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param)
-{
-	struct rte_eth_dev_info dev_info;
-	struct rte_eth_rxq_info rx_qinfo;
-	struct rte_eth_txq_info tx_qinfo;
-	int stat;
-
-	if (ring_param == NULL)
-		return -EINVAL;
-
-	rte_eth_dev_info_get(port_id, &dev_info);
-
-	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	stat = rte_eth_tx_queue_info_get(port_id, 0, &tx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	memset(ring_param, 0, sizeof(*ring_param));
-	ring_param->rx_pending = rx_qinfo.nb_desc;
-	ring_param->rx_max_pending = dev_info.rx_desc_lim.nb_max;
-	ring_param->tx_pending = tx_qinfo.nb_desc;
-	ring_param->tx_max_pending = dev_info.tx_desc_lim.nb_max;
-
-	return 0;
-}
-
-
-int
-rte_ethtool_set_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param)
-{
-	struct rte_eth_rxq_info rx_qinfo;
-	int stat;
-
-	if (ring_param == NULL)
-		return -EINVAL;
-
-	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	rte_eth_dev_stop(port_id);
-
-	stat = rte_eth_tx_queue_setup(port_id, 0, ring_param->tx_pending,
-		rte_socket_id(), NULL);
-	if (stat != 0)
-		return stat;
-
-	stat = rte_eth_rx_queue_setup(port_id, 0, ring_param->rx_pending,
-		rte_socket_id(), NULL, rx_qinfo.mp);
-	if (stat != 0)
-		return stat;
-
-	return rte_eth_dev_start(port_id);
-}
diff --git a/examples/ethtool/lib/rte_ethtool.h b/examples/ethtool/lib/rte_ethtool.h
deleted file mode 100644
index 2e79d45..0000000
--- a/examples/ethtool/lib/rte_ethtool.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/*-
- *   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_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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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);
-
-/**
- * Getting ring paramaters for Ethernet device.
- *
- * @param port_id
- *   The port identifier of the Ethernet device.
- * @param ring_param
- *   Pointer to struct ethrool_ringparam to receive parameters.
- * @return
- *   - (0) if successful.
- *   - (-ENOTSUP) if hardware doesn't support.
- *   - (-ENODEV) if *port_id* invalid.
- *   - others depends on the specific operations implementation.
- * @note
- *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
- *   are used, and the function only gets parameters for queue 0.
- */
-int rte_ethtool_get_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param);
-
-/**
- * Setting ring paramaters for Ethernet device.
- *
- * @param port_id
- *   The port identifier of the Ethernet device.
- * @param ring_param
- *   Pointer to struct ethrool_ringparam with parameters to set.
- * @return
- *   - (0) if successful.
- *   - (-ENOTSUP) if hardware doesn't support.
- *   - (-ENODEV) if *port_id* invalid.
- *   - others depends on the specific operations implementation.
- * @note
- *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
- *   are used, and the function only sets parameters for queue 0.
- */
-int rte_ethtool_set_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/ethtool/main.c b/examples/ethtool/main.c
new file mode 100644
index 0000000..2c655d8
--- /dev/null
+++ b/examples/ethtool/main.c
@@ -0,0 +1,305 @@
+/*-
+ *   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 <rte_common.h>
+#include <rte_spinlock.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_memory.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+
+#include "ethapp.h"
+
+#define MAX_PORTS RTE_MAX_ETHPORTS
+#define MAX_BURST_LENGTH 32
+#define PORT_RX_QUEUE_SIZE 128
+#define PORT_TX_QUEUE_SIZE 256
+#define PKTPOOL_EXTRA_SIZE 512
+#define PKTPOOL_CACHE 32
+
+
+struct txq_port {
+	uint16_t cnt_unsent;
+	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
+};
+
+struct app_port {
+	struct ether_addr mac_addr;
+	struct txq_port txq;
+	rte_spinlock_t lock;
+	int port_active;
+	int port_dirty;
+	int idx_port;
+	struct rte_mempool *pkt_pool;
+};
+
+struct app_config {
+	struct app_port ports[MAX_PORTS];
+	int cnt_ports;
+	int exit_now;
+};
+
+
+struct app_config app_cfg;
+
+
+void lock_port(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	rte_spinlock_lock(&ptr_port->lock);
+}
+
+void unlock_port(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	rte_spinlock_unlock(&ptr_port->lock);
+}
+
+void mark_port_active(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_active = 1;
+}
+
+void mark_port_inactive(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_active = 0;
+}
+
+void mark_port_newmac(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_dirty = 1;
+}
+
+static void setup_ports(struct app_config *app_cfg, int cnt_ports)
+{
+	int idx_port;
+	int size_pktpool;
+	struct rte_eth_conf cfg_port;
+	struct rte_eth_dev_info dev_info;
+	char str_name[16];
+
+	memset(&cfg_port, 0, sizeof(cfg_port));
+	cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
+
+	for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
+		struct app_port *ptr_port = &app_cfg->ports[idx_port];
+
+		rte_eth_dev_info_get(idx_port, &dev_info);
+		size_pktpool = dev_info.rx_desc_lim.nb_max +
+			dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
+
+		snprintf(str_name, 16, "pkt_pool%i", idx_port);
+		ptr_port->pkt_pool = rte_pktmbuf_pool_create(
+			str_name,
+			size_pktpool, PKTPOOL_CACHE,
+			0,
+			RTE_MBUF_DEFAULT_BUF_SIZE,
+			rte_socket_id()
+			);
+		if (ptr_port->pkt_pool == NULL)
+			rte_exit(EXIT_FAILURE,
+				"rte_pktmbuf_pool_create failed"
+				);
+
+		printf("Init port %i..\n", idx_port);
+		ptr_port->port_active = 1;
+		ptr_port->port_dirty = 0;
+		ptr_port->idx_port = idx_port;
+
+		if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_dev_configure failed");
+		if (rte_eth_rx_queue_setup(
+			    idx_port, 0, PORT_RX_QUEUE_SIZE,
+			    rte_eth_dev_socket_id(idx_port), NULL,
+			    ptr_port->pkt_pool) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_rx_queue_setup failed"
+				);
+		if (rte_eth_tx_queue_setup(
+			    idx_port, 0, PORT_TX_QUEUE_SIZE,
+			    rte_eth_dev_socket_id(idx_port), NULL) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_tx_queue_setup failed"
+				);
+		if (rte_eth_dev_start(idx_port) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "%s:%i: rte_eth_dev_start failed",
+				 __FILE__, __LINE__
+				);
+		rte_eth_promiscuous_enable(idx_port);
+		rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
+		rte_spinlock_init(&ptr_port->lock);
+	}
+}
+
+static void process_frame(struct app_port *ptr_port,
+	struct rte_mbuf *ptr_frame)
+{
+	struct ether_hdr *ptr_mac_hdr;
+
+	ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct ether_hdr *);
+	ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
+	ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
+}
+
+static int slave_main(__attribute__((unused)) void *ptr_data)
+{
+	struct app_port *ptr_port;
+	struct rte_mbuf *ptr_frame;
+	struct txq_port *txq;
+
+	uint16_t cnt_recv_frames;
+	uint16_t idx_frame;
+	uint16_t cnt_sent;
+	uint16_t idx_port;
+	uint16_t lock_result;
+
+	while (app_cfg.exit_now == 0) {
+		for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
+			/* Check that port is active and unlocked */
+			ptr_port = &app_cfg.ports[idx_port];
+			lock_result = rte_spinlock_trylock(&ptr_port->lock);
+			if (lock_result == 0)
+				continue;
+			if (ptr_port->port_active == 0) {
+				rte_spinlock_unlock(&ptr_port->lock);
+				continue;
+			}
+			txq = &ptr_port->txq;
+
+			/* MAC address was updated */
+			if (ptr_port->port_dirty == 1) {
+				rte_eth_macaddr_get(ptr_port->idx_port,
+					&ptr_port->mac_addr);
+				ptr_port->port_dirty = 0;
+			}
+
+			/* Incoming frames */
+			cnt_recv_frames = rte_eth_rx_burst(
+				ptr_port->idx_port, 0,
+				&txq->buf_frames[txq->cnt_unsent],
+				RTE_DIM(txq->buf_frames) - txq->cnt_unsent
+				);
+			if (cnt_recv_frames > 0) {
+				for (idx_frame = 0;
+					idx_frame < cnt_recv_frames;
+					idx_frame++) {
+					ptr_frame = txq->buf_frames[
+						idx_frame + txq->cnt_unsent];
+					process_frame(ptr_port, ptr_frame);
+				}
+				txq->cnt_unsent += cnt_recv_frames;
+			}
+
+			/* Outgoing frames */
+			if (txq->cnt_unsent > 0) {
+				cnt_sent = rte_eth_tx_burst(
+					ptr_port->idx_port, 0,
+					txq->buf_frames,
+					txq->cnt_unsent
+					);
+				/* Shuffle up unsent frame pointers */
+				for (idx_frame = cnt_sent;
+					idx_frame < txq->cnt_unsent;
+					idx_frame++)
+					txq->buf_frames[idx_frame - cnt_sent] =
+						txq->buf_frames[idx_frame];
+				txq->cnt_unsent -= cnt_sent;
+			}
+			rte_spinlock_unlock(&ptr_port->lock);
+		} /* end for( idx_port ) */
+	} /* end for(;;) */
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int cnt_args_parsed;
+	uint32_t id_core;
+	uint32_t cnt_ports;
+
+	/* Init runtime enviornment */
+	cnt_args_parsed = rte_eal_init(argc, argv);
+	if (cnt_args_parsed < 0)
+		rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
+
+	cnt_ports = rte_eth_dev_count();
+	printf("Number of NICs: %i\n", cnt_ports);
+	if (cnt_ports == 0)
+		rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
+	if (cnt_ports > MAX_PORTS) {
+		printf("Info: Using only %i of %i ports\n",
+			cnt_ports, MAX_PORTS
+			);
+		cnt_ports = MAX_PORTS;
+	}
+
+	setup_ports(&app_cfg, cnt_ports);
+
+	app_cfg.exit_now = 0;
+	app_cfg.cnt_ports = cnt_ports;
+
+	if (rte_lcore_count() < 2)
+		rte_exit(EXIT_FAILURE, "No available slave core!\n");
+	/* Assume there is an available slave.. */
+	id_core = rte_lcore_id();
+	id_core = rte_get_next_lcore(id_core, 1, 1);
+	rte_eal_remote_launch(slave_main, NULL, id_core);
+
+	ethapp_main();
+
+	app_cfg.exit_now = 1;
+	RTE_LCORE_FOREACH_SLAVE(id_core) {
+		if (rte_eal_wait_lcore(id_core) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/lib/Makefile b/lib/Makefile
index ef172ea..ce8f0f9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
 DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_ethtool/Makefile b/lib/librte_ethtool/Makefile
new file mode 100644
index 0000000..8be7105
--- /dev/null
+++ b/lib/librte_ethtool/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015-2016 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
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ethtool.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_eal 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..d9c5408
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.c
@@ -0,0 +1,423 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 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_ether.h>
+#include "rte_ethtool.h"
+
+#define PKTPOOL_SIZE 512
+#define PKTPOOL_CACHE 32
+
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	if (drvinfo == NULL)
+		return -EINVAL;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	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)
+{
+	int count_regs;
+
+	count_regs = rte_eth_dev_get_reg_length(port_id);
+	if (count_regs > 0)
+		return count_regs * sizeof(uint32_t);
+	return count_regs;
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	if (regs == NULL || data == NULL)
+		return -EINVAL;
+
+	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;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	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;
+
+	if (eeprom == NULL || words == NULL)
+		return -EINVAL;
+
+	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;
+
+	if (eeprom == NULL || words == NULL || eeprom->offset >= eeprom->len)
+		return -EINVAL;
+
+	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;
+
+	if (pause_param == NULL)
+		return -EINVAL;
+
+	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_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;
+	default:
+		/* dummy block to avoid compiler warning */
+		break;
+	}
+	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;
+
+	if (pause_param == NULL)
+		return -EINVAL;
+
+	/*
+	 * 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)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	if (addr == NULL)
+		return -EINVAL;
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	if (addr == NULL)
+		return -EINVAL;
+	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)
+{
+	if (addr == NULL)
+		return -EINVAL;
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	if (mtu < 0 || mtu > UINT16_MAX)
+		return -EINVAL;
+	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)
+{
+	if (stats == NULL)
+		return -EINVAL;
+	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);
+}
+
+/*
+ * The set_rx_mode provides driver-specific rx mode setting.
+ * This implementation implements rx mode setting based upon
+ * ixgbe/igb drivers. Further improvement is to provide a
+ * callback op field over struct rte_eth_dev::dev_ops so each
+ * driver can register device-specific implementation
+ */
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t num_vfs;
+	struct rte_eth_dev_info dev_info;
+	uint16_t vf;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+	num_vfs = dev_info.max_vfs;
+
+	/* Set VF vf_rx_mode, VF unsupport status is discard */
+	for (vf = 0; vf < num_vfs; vf++)
+		rte_eth_dev_set_vf_rxmode(port_id, vf,
+			ETH_VMDQ_ACCEPT_UNTAG, 0);
+
+	/* Enable Rx vlan filter, VF unspport status is discard */
+	rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
+
+	return 0;
+}
+
+
+int
+rte_ethtool_get_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_eth_dev_info dev_info;
+	struct rte_eth_rxq_info rx_qinfo;
+	struct rte_eth_txq_info tx_qinfo;
+	int stat;
+
+	if (ring_param == NULL)
+		return -EINVAL;
+
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	stat = rte_eth_tx_queue_info_get(port_id, 0, &tx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	memset(ring_param, 0, sizeof(*ring_param));
+	ring_param->rx_pending = rx_qinfo.nb_desc;
+	ring_param->rx_max_pending = dev_info.rx_desc_lim.nb_max;
+	ring_param->tx_pending = tx_qinfo.nb_desc;
+	ring_param->tx_max_pending = dev_info.tx_desc_lim.nb_max;
+
+	return 0;
+}
+
+
+int
+rte_ethtool_set_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_eth_rxq_info rx_qinfo;
+	int stat;
+
+	if (ring_param == NULL)
+		return -EINVAL;
+
+	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	rte_eth_dev_stop(port_id);
+
+	stat = rte_eth_tx_queue_setup(port_id, 0, ring_param->tx_pending,
+		rte_socket_id(), NULL);
+	if (stat != 0)
+		return stat;
+
+	stat = rte_eth_rx_queue_setup(port_id, 0, ring_param->rx_pending,
+		rte_socket_id(), NULL, rx_qinfo.mp);
+	if (stat != 0)
+		return stat;
+
+	return rte_eth_dev_start(port_id);
+}
diff --git a/lib/librte_ethtool/rte_ethtool.h b/lib/librte_ethtool/rte_ethtool.h
new file mode 100644
index 0000000..c60f7bb
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.h
@@ -0,0 +1,413 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 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_
+
+/**
+ * @file
+ *
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_drvinfo:         ethtool_ops::get_driverinfo \n
+ * rte_ethtool_get_link:            ethtool_ops::get_link \n
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len \n
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs \n
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len \n
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom \n
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom \n
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam \n
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam \n
+ * rte_ethtool_get_ringparam:       ethtool_ops::set_ringparam \n
+ * rte_ethtool_set_ringparam:       ethtool_ops::set_ringparam \n
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open \n
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop \n
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address \n
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr \n
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu \n
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64 \n
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid \n
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid \n
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode \n
+ *
+ */
+#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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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 regs
+ *   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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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);
+
+/**
+ * Getting ring paramaters for Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *   Pointer to struct ethrool_ringparam to receive parameters.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ * @note
+ *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
+ *   are used, and the function only gets parameters for queue 0.
+ */
+int rte_ethtool_get_ringparam(uint8_t port_id,
+		struct ethtool_ringparam *ring_param);
+
+/**
+ * Setting ring paramaters for Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *   Pointer to struct ethrool_ringparam with parameters to set.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ * @note
+ *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
+ *   are used, and the function only sets parameters for queue 0.
+ */
+int rte_ethtool_set_ringparam(uint8_t port_id,
+		struct ethtool_ringparam *ring_param);
+
+#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..34183b8
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool_version.map
@@ -0,0 +1,28 @@
+DPDK_16.04 {
+	global:
+
+	rte_ethtool_get_drvinfo;
+	rte_ethtool_get_link;
+	rte_ethtool_get_regs_len;
+	rte_ethtool_get_regs;
+	rte_ethtool_get_eeprom_len;
+	rte_ethtool_get_eeprom;
+	rte_ethtool_set_eeprom;
+	rte_ethtool_get_pauseparam;
+	rte_ethtool_set_pauseparam;
+	rte_ethtool_get_ringparam;
+	rte_ethtool_set_ringparam;
+
+	rte_ethtool_net_open;
+	rte_ethtool_net_stop;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_set_mac_addr;
+	rte_ethtool_net_validate_addr;
+	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_net_set_rx_mode;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8ecab41..32f76b1 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -122,6 +122,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF_OFFLOAD)   += -lrte_mbuf_offload
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.5.0

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

* [PATCH v4 2/4] kcp: add kernel control path kernel module
  2016-03-01 15:41     ` [PATCH v4 " Ferruh Yigit
  2016-03-01 15:41       ` [PATCH v4 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
@ 2016-03-01 15:41       ` Ferruh Yigit
  2016-03-01 23:06         ` Stephen Hemminger
                           ` (2 more replies)
  2016-03-01 15:41       ` [PATCH v4 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
                         ` (2 subsequent siblings)
  4 siblings, 3 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-01 15:41 UTC (permalink / raw)
  To: dev

This kernel module is based on KNI module, but this one is stripped
version of it and only for control messages, no data transfer
functionality provided.

This Linux kernel module helps userspace application create virtual
interfaces and when a control command issued into that virtual
interface, module pushes the command to the userspace and gets the
response back for the caller application.

The Linux tools like ethtool/ifconfig/ip can be used on virtual
interfaces but not ones for related data, like tcpdump.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

v4:
* Remove logging helper macros, use pr_fmt
* Seperate log msg for timeout and error

v3:
* Devices are not up by default
* Add enable/disable promisc, allmulti support
* Increase timeout to 500ms and print log when a command timedout

v2:
* Use rtnetlink to create interfaces
* Fix ethtool get/set eeprom
* Remove commented out code
---
 MAINTAINERS                                        |   4 +
 config/common_linuxapp                             |   6 +
 lib/librte_eal/linuxapp/Makefile                   |   5 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h | 109 ++++++++
 lib/librte_eal/linuxapp/kcp/Makefile               |  57 ++++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  56 ++++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 300 +++++++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 225 ++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 220 +++++++++++++++
 10 files changed, 983 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 628bc05..6a77728 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -257,6 +257,10 @@ F: app/test/test_kni.c
 F: examples/kni/
 F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 
+Linux KCP
+M: Ferruh Yigit <ferruh.yigit@intel.com>
+F: lib/librte_eal/linuxapp/kcp/
+
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
 F: drivers/net/af_packet/
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 960dde4..0284fae 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -502,6 +502,12 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 CONFIG_RTE_LIBRTE_ETHTOOL=y
 
 #
+# Compile librte_ctrl_if
+#
+CONFIG_RTE_KCP_KMOD=y
+CONFIG_RTE_KCP_KO_DEBUG=n
+
+#
 # Compile vhost library
 # fuse-devel is needed to run vhost-cuse.
 # fuse-devel enables user space char driver development
diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile
index d9c5233..d1fa3a3 100644
--- a/lib/librte_eal/linuxapp/Makefile
+++ b/lib/librte_eal/linuxapp/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,9 @@ DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += eal
 ifeq ($(CONFIG_RTE_KNI_KMOD),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kni
 endif
+ifeq ($(CONFIG_RTE_KCP_KMOD),y)
+DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += kcp
+endif
 ifeq ($(CONFIG_RTE_LIBRTE_XEN_DOM0),y)
 DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += xen_dom0
 endif
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 6e26250..f6a3a41 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,7 @@ CFLAGS_eal_thread.o += -Wno-return-type
 endif
 
 INC := rte_interrupts.h rte_kni_common.h rte_dom0_common.h
+INC += rte_kcp_common.h
 
 SYMLINK-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP)-include/exec-env := \
 	$(addprefix include/exec-env/,$(INC))
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
new file mode 100644
index 0000000..988713e
--- /dev/null
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
@@ -0,0 +1,109 @@
+/*-
+ *   This file is provided under a dual BSD/LGPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GNU LESSER GENERAL PUBLIC LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2.1 of the GNU Lesser General Public License
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this program;
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ *
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_KCP_COMMON_H_
+#define _RTE_KCP_COMMON_H_
+
+#define KCP_DEVICE "kcp"
+
+#define KCP_NL_GRP 31
+
+#define KCP_ETHTOOL_MSG_LEN 500
+struct kcp_ethtool_msg {
+	int cmd_id;
+	int port_id;
+	unsigned int flag;
+	char input_buffer[KCP_ETHTOOL_MSG_LEN];
+	char output_buffer[KCP_ETHTOOL_MSG_LEN];
+	int input_buffer_len;
+	int output_buffer_len;
+	int err;
+};
+
+enum kcp_ethtool_msg_flag {
+	KCP_MSG_FLAG_NONE,
+	KCP_MSG_FLAG_REQUEST,
+	KCP_MSG_FLAG_RESPONSE,
+};
+
+enum {
+	IFLA_KCP_UNSPEC,
+	IFLA_KCP_PORTID,
+	IFLA_KCP_PID,
+	__IFLA_KCP_MAX,
+};
+
+#define IFLA_KCP_MAX (__IFLA_KCP_MAX - 1)
+
+/*
+ * Request id.
+ */
+enum rte_kcp_req_id {
+	RTE_KCP_REQ_UNKNOWN = (1 << 16),
+	RTE_KCP_REQ_CHANGE_MTU,
+	RTE_KCP_REQ_CFG_NETWORK_IF,
+	RTE_KCP_REQ_GET_STATS,
+	RTE_KCP_REQ_GET_MAC,
+	RTE_KCP_REQ_SET_MAC,
+	RTE_KCP_REQ_START_PORT,
+	RTE_KCP_REQ_STOP_PORT,
+	RTE_KCP_REQ_SET_PROMISC,
+	RTE_KCP_REQ_SET_ALLMULTI,
+	RTE_KCP_REQ_MAX,
+};
+
+#endif /* _RTE_KCP_COMMON_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/Makefile b/lib/librte_eal/linuxapp/kcp/Makefile
new file mode 100644
index 0000000..46d9dd8
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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
+
+#
+# module name and path
+#
+MODULE = rte_kcp
+
+#
+# CFLAGS
+#
+MODULE_CFLAGS += -I$(SRCDIR)
+MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
+MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
+MODULE_CFLAGS += -Wall -Werror
+
+# this lib needs main eal
+DEPDIRS-y += lib/librte_eal/linuxapp/eal
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y += kcp_net.c
+SRCS-y += kcp_ethtool.c
+SRCS-y += kcp_nl.c
+
+include $(RTE_SDK)/mk/rte.module.mk
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_dev.h b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
new file mode 100644
index 0000000..87577bd
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
@@ -0,0 +1,56 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#ifndef _KCP_DEV_H_
+#define _KCP_DEV_H_
+
+#include <linux/netdevice.h>
+#include <exec-env/rte_kcp_common.h>
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+struct kcp_dev {
+	int port_id;
+	unsigned int pid;
+	struct completion msg_received;
+	unsigned int nb_timedout_msg;
+};
+
+void kcp_nl_init(void);
+void kcp_nl_release(void);
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data, int in_len,
+		void *out_data, int out_len);
+
+void kcp_set_ethtool_ops(struct net_device *netdev);
+
+#ifdef RTE_KCP_KO_DEBUG
+#define KCP_DBG(args...) pr_info(args)
+#else
+#define KCP_DBG(args...)
+#endif
+
+#endif /* _KCP_DEV_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
new file mode 100644
index 0000000..830ad64
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
@@ -0,0 +1,300 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include "kcp_dev.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int kcp_check_if_running(struct net_device *dev)
+{
+	return 0;
+}
+
+static void kcp_get_drvinfo(struct net_device *dev,
+		struct ethtool_drvinfo *info)
+{
+	int ret;
+
+	ret = kcp_nl_exec(info->cmd, dev, NULL, 0,
+			info, sizeof(struct ethtool_drvinfo));
+	if (ret < 0)
+		memset(info, 0, sizeof(struct ethtool_drvinfo));
+}
+
+static int kcp_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, NULL, 0,
+			ecmd, sizeof(struct ethtool_cmd));
+}
+
+static int kcp_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, ecmd, sizeof(struct ethtool_cmd),
+			NULL, 0);
+}
+
+static void kcp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	int ret;
+
+	ret = kcp_nl_exec(wol->cmd, dev, NULL, 0,
+			wol, sizeof(struct ethtool_wolinfo));
+	if (ret < 0)
+		memset(wol, 0, sizeof(struct ethtool_wolinfo));
+}
+
+static int kcp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	return kcp_nl_exec(wol->cmd, dev, wol, sizeof(struct ethtool_wolinfo),
+			NULL, 0);
+}
+
+static int kcp_nway_reset(struct net_device *dev)
+{
+	return kcp_nl_exec(ETHTOOL_NWAY_RST, dev, NULL, 0, NULL, 0);
+}
+
+static unsigned int kcp_get_link(struct net_device *dev)
+{
+	unsigned int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GLINK, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static int kcp_get_eeprom_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GEEPROM_LEN, dev, NULL, 0,
+			&data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static int kcp_get_eeprom(struct net_device *dev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct ethtool_eeprom eeprom_tmp;
+	int ret = 0;
+	int remaining;
+	int offset = 0;
+
+	eeprom_tmp = *eeprom;
+
+	remaining = eeprom_tmp.len;
+	while (remaining > 0 && ret == 0) {
+		eeprom_tmp.len = min(remaining, KCP_ETHTOOL_MSG_LEN);
+
+		ret = kcp_nl_exec(eeprom_tmp.cmd, dev,
+				&eeprom_tmp, sizeof(struct ethtool_eeprom),
+				data + offset, eeprom_tmp.len);
+		eeprom_tmp.offset += eeprom_tmp.len;
+		offset += eeprom_tmp.len;
+		remaining -= eeprom_tmp.len;
+	}
+
+	return ret;
+}
+
+static int kcp_set_eeprom(struct net_device *dev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct ethtool_eeprom *eeprom_tmp;
+	int ret = 0;
+	int remaining;
+	int offset = 0;
+	int payload;
+
+	if (sizeof(struct ethtool_eeprom) > KCP_ETHTOOL_MSG_LEN)
+		return -1;
+
+	eeprom_tmp = kmalloc(KCP_ETHTOOL_MSG_LEN, GFP_KERNEL);
+	payload = KCP_ETHTOOL_MSG_LEN - sizeof(struct ethtool_eeprom);
+
+	*eeprom_tmp = *eeprom;
+	remaining = eeprom->len;
+
+	while (remaining > 0 && ret == 0) {
+		eeprom_tmp->len = min(remaining, payload);
+
+		memcpy(eeprom_tmp->data, data + offset, payload);
+
+		ret = kcp_nl_exec(eeprom->cmd, dev, eeprom,
+				KCP_ETHTOOL_MSG_LEN, NULL, 0);
+
+		eeprom_tmp->offset += eeprom_tmp->len;
+		offset += eeprom_tmp->len;
+		remaining -= eeprom_tmp->len;
+	}
+
+	kfree(eeprom_tmp);
+
+	return ret;
+}
+
+static void kcp_get_ringparam(struct net_device *dev,
+		struct ethtool_ringparam *ring)
+{
+
+	kcp_nl_exec(ring->cmd, dev, NULL, 0,
+			ring, sizeof(struct ethtool_ringparam));
+}
+
+static int kcp_set_ringparam(struct net_device *dev,
+		struct ethtool_ringparam *ring)
+{
+	return kcp_nl_exec(ring->cmd, dev,
+			ring, sizeof(struct ethtool_ringparam),
+			NULL, 0);
+}
+
+static void kcp_get_pauseparam(struct net_device *dev,
+		struct ethtool_pauseparam *pause)
+{
+
+	kcp_nl_exec(pause->cmd, dev, NULL, 0,
+			pause, sizeof(struct ethtool_pauseparam));
+}
+
+static int kcp_set_pauseparam(struct net_device *dev,
+		struct ethtool_pauseparam *pause)
+{
+	return kcp_nl_exec(pause->cmd, dev,
+			pause, sizeof(struct ethtool_pauseparam),
+			NULL, 0);
+}
+
+static u32 kcp_get_msglevel(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GMSGLVL, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_set_msglevel(struct net_device *dev, u32 data)
+{
+
+	kcp_nl_exec(ETHTOOL_SMSGLVL, dev, &data, sizeof(int), NULL, 0);
+}
+
+static int kcp_get_regs_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GREGS_LEN, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+		void *p)
+{
+	struct ethtool_regs regs_tmp;
+	int len = regs->len;
+
+	regs_tmp = *regs;
+
+	if (len > KCP_ETHTOOL_MSG_LEN) {
+		len = KCP_ETHTOOL_MSG_LEN;
+		regs_tmp.len = len;
+	}
+
+	kcp_nl_exec(regs->cmd, dev, &regs_tmp, sizeof(struct ethtool_regs),
+			p, len);
+}
+
+static void kcp_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+
+	kcp_nl_exec(ETHTOOL_GSTRINGS, dev, &stringset, sizeof(u32), data, 0);
+}
+
+static int kcp_get_sset_count(struct net_device *dev, int sset)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GSSET_COUNT, dev, &sset, sizeof(int),
+			&data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_get_ethtool_stats(struct net_device *dev,
+		struct ethtool_stats *stats, u64 *data)
+{
+
+	kcp_nl_exec(stats->cmd, dev, stats, sizeof(struct ethtool_stats),
+			data, stats->n_stats);
+}
+
+static const struct ethtool_ops kcp_ethtool_ops = {
+	.begin			= kcp_check_if_running,
+	.get_drvinfo		= kcp_get_drvinfo,
+	.get_settings		= kcp_get_settings,
+	.set_settings		= kcp_set_settings,
+	.get_regs_len		= kcp_get_regs_len,
+	.get_regs		= kcp_get_regs,
+	.get_wol		= kcp_get_wol,
+	.set_wol		= kcp_set_wol,
+	.nway_reset		= kcp_nway_reset,
+	.get_link		= kcp_get_link,
+	.get_eeprom_len		= kcp_get_eeprom_len,
+	.get_eeprom		= kcp_get_eeprom,
+	.set_eeprom		= kcp_set_eeprom,
+	.get_ringparam		= kcp_get_ringparam,
+	.set_ringparam		= kcp_set_ringparam,
+	.get_pauseparam		= kcp_get_pauseparam,
+	.set_pauseparam		= kcp_set_pauseparam,
+	.get_msglevel		= kcp_get_msglevel,
+	.set_msglevel		= kcp_set_msglevel,
+	.get_strings		= kcp_get_strings,
+	.get_sset_count		= kcp_get_sset_count,
+	.get_ethtool_stats	= kcp_get_ethtool_stats,
+};
+
+void kcp_set_ethtool_ops(struct net_device *netdev)
+{
+	netdev->ethtool_ops = &kcp_ethtool_ops;
+}
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_net.c b/lib/librte_eal/linuxapp/kcp/kcp_net.c
new file mode 100644
index 0000000..16ea153
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_net.c
@@ -0,0 +1,225 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <net/rtnetlink.h>
+
+#include "kcp_dev.h"
+
+static int kcp_net_init(struct net_device *dev)
+{
+	char mac[ETH_ALEN] = {0};
+
+	kcp_nl_exec(RTE_KCP_REQ_GET_MAC, dev, NULL, 0, mac, ETH_ALEN);
+	memcpy(dev->dev_addr, mac, dev->addr_len);
+
+	return 0;
+}
+
+static int kcp_net_open(struct net_device *dev)
+{
+	/* DPDK port already started, stop it first */
+	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+	kcp_nl_exec(RTE_KCP_REQ_START_PORT, dev, NULL, 0, NULL, 0);
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int kcp_net_close(struct net_device *dev)
+{
+	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static int kcp_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static void kcp_net_change_rx_flags(struct net_device *dev, int flags)
+{
+	int on = 1;
+	int off = 0;
+
+	if (flags & IFF_PROMISC)
+		kcp_nl_exec(RTE_KCP_REQ_SET_PROMISC, dev,
+				dev->flags & IFF_PROMISC ?  &on : &off,
+				sizeof(int), NULL, 0);
+
+	if (flags & IFF_ALLMULTI)
+		kcp_nl_exec(RTE_KCP_REQ_SET_ALLMULTI, dev,
+				dev->flags & IFF_ALLMULTI ?  &on : &off,
+				sizeof(int), NULL, 0);
+}
+
+static int kcp_net_set_mac(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	int err = 0;
+
+	if (!is_valid_ether_addr((unsigned char *)(addr->sa_data)))
+		return -EADDRNOTAVAIL;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_SET_MAC, dev, addr->sa_data,
+			dev->addr_len, NULL, 0);
+	if (err < 0)
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	return 0;
+}
+
+static int kcp_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+static int kcp_net_config(struct net_device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	return -EOPNOTSUPP;
+}
+
+static int kcp_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int err = 0;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_CHANGE_MTU, dev, &new_mtu, sizeof(int),
+			NULL, 0);
+
+	if (err == 0)
+		dev->mtu = new_mtu;
+
+	return err;
+}
+
+static struct rtnl_link_stats64 *kcp_net_stats64(struct net_device *dev,
+		struct rtnl_link_stats64 *stats)
+{
+	int err;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_GET_STATS, dev, NULL, 0,
+			stats, sizeof(struct rtnl_link_stats64));
+
+	return stats;
+}
+
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+static int kcp_net_change_carrier(struct net_device *dev, bool new_carrier)
+{
+	if (new_carrier)
+		netif_carrier_on(dev);
+	else
+		netif_carrier_off(dev);
+	return 0;
+}
+#endif
+
+static const struct net_device_ops kcp_net_netdev_ops = {
+	.ndo_init = kcp_net_init,
+	.ndo_open = kcp_net_open,
+	.ndo_stop = kcp_net_close,
+	.ndo_start_xmit = kcp_net_xmit,
+	.ndo_change_rx_flags = kcp_net_change_rx_flags,
+	.ndo_set_mac_address = kcp_net_set_mac,
+	.ndo_do_ioctl = kcp_net_ioctl,
+	.ndo_set_config = kcp_net_config,
+	.ndo_change_mtu = kcp_net_change_mtu,
+	.ndo_get_stats64 = kcp_net_stats64,
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+	.ndo_change_carrier = kcp_net_change_carrier,
+#endif
+};
+
+static void kcp_net_setup(struct net_device *dev)
+{
+	struct kcp_dev *kcp;
+
+	ether_setup(dev);
+	dev->netdev_ops = &kcp_net_netdev_ops;
+
+	kcp = netdev_priv(dev);
+	init_completion(&kcp->msg_received);
+
+	kcp_set_ethtool_ops(dev);
+}
+
+static int kcp_net_newlink(struct net *net, struct net_device *dev,
+		struct nlattr *tb[], struct nlattr *data[])
+{
+	int ret;
+	struct kcp_dev *kcp;
+
+	kcp = netdev_priv(dev);
+
+	if (data && data[IFLA_KCP_PORTID])
+		kcp->port_id = nla_get_u8(data[IFLA_KCP_PORTID]);
+	else
+		kcp->port_id = 0;
+
+	if (data && data[IFLA_KCP_PID])
+		kcp->pid = nla_get_u32(data[IFLA_KCP_PID]);
+	else
+		kcp->pid = 0;
+
+	ret = register_netdevice(dev);
+
+	return ret;
+}
+
+static struct rtnl_link_ops kcp_link_ops __read_mostly = {
+	.kind = KCP_DEVICE,
+	.priv_size = sizeof(struct kcp_dev),
+	.setup = kcp_net_setup,
+	.maxtype = IFLA_KCP_MAX,
+	.newlink = kcp_net_newlink,
+};
+
+static int __init kcp_init(void)
+{
+	kcp_nl_init();
+	return rtnl_link_register(&kcp_link_ops);
+}
+module_init(kcp_init);
+
+static void __exit kcp_exit(void)
+{
+	rtnl_link_unregister(&kcp_link_ops);
+	kcp_nl_release();
+}
+module_exit(kcp_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Kernel Module for managing kcp devices");
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_nl.c b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
new file mode 100644
index 0000000..b34edb9
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
@@ -0,0 +1,220 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <net/sock.h>
+
+#include "kcp_dev.h"
+
+#define KCP_CMD_TIMEOUT 500 /* ms */
+
+static struct ethtool_input_buffer {
+	int magic;
+	void *buffer;
+	int length;
+	struct completion *msg_received;
+	int *err;
+	int in_use;
+} ethtool_input_buffer;
+
+static struct sock *nl_sock;
+static struct mutex sync_lock;
+
+static int kcp_input_buffer_register(int magic, void *buffer, int length,
+		struct completion *msg_received, int *err)
+{
+	if (ethtool_input_buffer.in_use == 0) {
+		ethtool_input_buffer.magic = magic;
+		ethtool_input_buffer.buffer = buffer;
+		ethtool_input_buffer.length = length;
+		ethtool_input_buffer.msg_received = msg_received;
+		ethtool_input_buffer.err = err;
+		ethtool_input_buffer.in_use = 1;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void kcp_input_buffer_unregister(int magic)
+{
+	if (ethtool_input_buffer.in_use == 1) {
+		if (magic == ethtool_input_buffer.magic) {
+			ethtool_input_buffer.magic = -1;
+			ethtool_input_buffer.buffer = NULL;
+			ethtool_input_buffer.length = 0;
+			ethtool_input_buffer.msg_received = NULL;
+			ethtool_input_buffer.err = NULL;
+			ethtool_input_buffer.in_use = 0;
+		} else {
+			pr_err("Unregister magic mismatch\n");
+		}
+	}
+}
+
+static void nl_recv_user_request(struct kcp_ethtool_msg *ethtool_msg)
+{
+	KCP_DBG("Request from userspace received\n");
+}
+
+static void nl_recv_user_response(struct kcp_ethtool_msg *ethtool_msg)
+{
+	struct completion *msg_received;
+	int recv_len;
+	int expected_len;
+
+	if (ethtool_input_buffer.in_use == 1) {
+		if (ethtool_input_buffer.buffer != NULL) {
+			recv_len = ethtool_msg->output_buffer_len;
+			expected_len = ethtool_input_buffer.length;
+
+			memcpy(ethtool_input_buffer.buffer,
+					ethtool_msg->output_buffer,
+					ethtool_input_buffer.length);
+
+			if (ethtool_msg->err == 0 && recv_len != expected_len)
+				pr_info("Expected and received len not match "
+					"%d - %d\n", recv_len, expected_len);
+		}
+
+		*ethtool_input_buffer.err = ethtool_msg->err;
+		msg_received = ethtool_input_buffer.msg_received;
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		complete(msg_received);
+	}
+}
+
+static void nl_recv(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	nlh = (struct nlmsghdr *)skb->data;
+
+	memcpy(&ethtool_msg, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
+	KCP_DBG("CMD: %d\n", ethtool_msg.cmd_id);
+
+	if (ethtool_msg.flag & KCP_MSG_FLAG_REQUEST) {
+		nl_recv_user_request(&ethtool_msg);
+		return;
+	}
+
+	nl_recv_user_response(&ethtool_msg);
+}
+
+static int kcp_nl_send(int cmd_id, int port_id, unsigned int pid,
+		void *in_data, int in_data_len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	if (pid == 0)
+		return -1;
+
+	memset(&ethtool_msg, 0, sizeof(struct kcp_ethtool_msg));
+	ethtool_msg.cmd_id = cmd_id;
+	ethtool_msg.port_id = port_id;
+
+	if (in_data) {
+		if (in_data_len == 0 || in_data_len > KCP_ETHTOOL_MSG_LEN)
+			return -EINVAL;
+		ethtool_msg.input_buffer_len = in_data_len;
+		memcpy(ethtool_msg.input_buffer, in_data, in_data_len);
+	}
+
+	skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct kcp_ethtool_msg)),
+			GFP_ATOMIC);
+	nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, sizeof(struct kcp_ethtool_msg),
+			0);
+
+	NETLINK_CB(skb).dst_group = 0;
+
+	memcpy(nlmsg_data(nlh), &ethtool_msg, sizeof(struct kcp_ethtool_msg));
+
+	nlmsg_unicast(nl_sock, skb, pid);
+	KCP_DBG("Sent cmd:%d port:%d pid:%u\n", cmd_id, port_id, pid);
+
+	return 0;
+}
+
+int kcp_nl_exec(int cmd, struct net_device *dev, void *in_data,
+		int in_data_len, void *out_data, int out_data_len)
+{
+	struct kcp_dev *priv = netdev_priv(dev);
+	int err = -EINVAL;
+	int ret;
+
+	if (out_data_len > KCP_ETHTOOL_MSG_LEN) {
+		pr_err("Message is too big to receive:%u\n", out_data_len);
+		return err;
+	}
+
+	mutex_lock(&sync_lock);
+	ret = kcp_input_buffer_register(cmd, out_data, out_data_len,
+			&priv->msg_received, &err);
+	if (ret) {
+		mutex_unlock(&sync_lock);
+		return -EINVAL;
+	}
+
+	ret = kcp_nl_send(cmd, priv->port_id, priv->pid, in_data, in_data_len);
+	if (ret) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		return ret;
+	}
+
+	ret = wait_for_completion_interruptible_timeout(&priv->msg_received,
+			 msecs_to_jiffies(KCP_CMD_TIMEOUT));
+	if (ret == 0 || err < 0) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		if (ret == 0) { /* timeout */
+			priv->nb_timedout_msg++;
+			pr_info("Command timed-out for port:%d cmd:%d (%u)\n",
+				priv->port_id, cmd, priv->nb_timedout_msg);
+			return -EINVAL;
+		}
+		KCP_DBG("Command return error for port:%d cmd:%d err:%d\n",
+				priv->port_id, cmd, err);
+		return err;
+	}
+	mutex_unlock(&sync_lock);
+
+	return 0;
+}
+
+static struct netlink_kernel_cfg cfg = {
+	.input = nl_recv,
+};
+
+void kcp_nl_init(void)
+{
+	nl_sock = netlink_kernel_create(&init_net, KCP_NL_GRP, &cfg);
+	mutex_init(&sync_lock);
+}
+
+void kcp_nl_release(void)
+{
+	netlink_kernel_release(nl_sock);
+}
-- 
2.5.0

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

* [PATCH v4 3/4] rte_ctrl_if: add control interface library
  2016-03-01 15:41     ` [PATCH v4 " Ferruh Yigit
  2016-03-01 15:41       ` [PATCH v4 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
  2016-03-01 15:41       ` [PATCH v4 2/4] kcp: add kernel control path kernel module Ferruh Yigit
@ 2016-03-01 15:41       ` Ferruh Yigit
  2016-03-01 15:42       ` [PATCH v4 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
  2016-03-09 11:41       ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  4 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-01 15:41 UTC (permalink / raw)
  To: dev

This library gets control messages form kernelspace and forwards them to
librte_ether and returns response back to the kernelspace.

Library does:
1) Trigger Linux virtual interface creation
2) Initialize the netlink socket communication
3) Provides process() API to the application that does processing the
received messages

This library requires corresponding kernel module to be inserted.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

v4:
* Add ethtool_get_settings as dummy

v3:
* Use librte_ethtool
* Don't create interfaces for virtual PMDs
* Add a new API ...msg_exist() to support port based locking
* Add enable/disable promisc, allmulti support

v2:
* User rtnetlink to create interfaces.
* Add more ethtool support: get/set ringparam, set pauseparam.
* return defined error instead of hardcoded value
---
 MAINTAINERS                                |   1 +
 config/common_linuxapp                     |   3 +-
 doc/api/doxy-api-index.md                  |   1 +
 doc/api/doxy-api.conf                      |   1 +
 doc/guides/prog_guide/ctrl_if_lib.rst      |  52 ++++
 doc/guides/prog_guide/index.rst            |   1 +
 doc/guides/rel_notes/release_16_04.rst     |   9 +
 lib/Makefile                               |   3 +-
 lib/librte_ctrl_if/Makefile                |  58 +++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.c      | 390 ++++++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.h      |  54 ++++
 lib/librte_ctrl_if/rte_ctrl_if.c           | 395 +++++++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h           | 129 ++++++++++
 lib/librte_ctrl_if/rte_ctrl_if_version.map |  10 +
 lib/librte_ctrl_if/rte_nl.c                | 313 +++++++++++++++++++++++
 lib/librte_ctrl_if/rte_nl.h                |  50 ++++
 lib/librte_eal/common/include/rte_log.h    |   3 +-
 mk/rte.app.mk                              |   3 +-
 18 files changed, 1472 insertions(+), 4 deletions(-)
 create mode 100644 doc/guides/prog_guide/ctrl_if_lib.rst
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6a77728..24dbfa0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -260,6 +260,7 @@ F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 Linux KCP
 M: Ferruh Yigit <ferruh.yigit@intel.com>
 F: lib/librte_eal/linuxapp/kcp/
+F: lib/librte_ctrl_if/
 
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 0284fae..dc75653 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -506,6 +506,7 @@ CONFIG_RTE_LIBRTE_ETHTOOL=y
 #
 CONFIG_RTE_KCP_KMOD=y
 CONFIG_RTE_KCP_KO_DEBUG=n
+CONFIG_RTE_LIBRTE_CTRL_IF=y
 
 #
 # Compile vhost library
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 4cdd3f5..e34250d 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -151,3 +151,4 @@ There are many libraries, so their headers may be grouped by topics:
   [keepalive]          (@ref rte_keepalive.h),
   [version]            (@ref rte_version.h),
   [ethtool]            (@ref rte_ethtool.h),
+  [control interface]  (@ref rte_ctrl_if.h)
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index c5b8615..1a7999e 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -39,6 +39,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_cmdline \
                           lib/librte_compat \
                           lib/librte_cryptodev \
+                          lib/librte_ctrl_if \
                           lib/librte_distributor \
                           lib/librte_ether \
                           lib/librte_ethtool \
diff --git a/doc/guides/prog_guide/ctrl_if_lib.rst b/doc/guides/prog_guide/ctrl_if_lib.rst
new file mode 100644
index 0000000..36054b9
--- /dev/null
+++ b/doc/guides/prog_guide/ctrl_if_lib.rst
@@ -0,0 +1,52 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+.. _Ctrl_If_Library:
+
+Control Interface Library
+=========================
+
+This Library is to create/destroy control interfaces and process messages
+received by control interface.
+
+Control Interface is Linux network interface and it is possible to call
+various Linux commands to this interface and commands will be forwarded
+to the matching DPDK PMD, and response will be generated by PMD.
+
+Control interface required KCP kernel module to be inserted to function.
+
+Control Interface APIS
+----------------------
+
+
+- ``rte_eth_control_interface_create()``
+- ``rte_eth_control_interface_destroy()``
+- ``rte_eth_control_interface_msg_exist()``
+- ``rte_eth_control_interface_msg_process()``
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index 98f4aca..aadc476 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -52,6 +52,7 @@ Programmer's Guide
     reorder_lib
     ip_fragment_reassembly_lib
     ethtool_lib
+    ctrl_if_lib
     multi_proc_support
     kernel_nic_interface
     thread_safety_dpdk_functions
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 082e0b8..792b09d 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -51,6 +51,14 @@ This section should contain new features added in this release. Sample format:
 
 * **Added vhost-user live migration support.**
 
+* **Control interface support added.**
+
+  To enable controlling DPDK ports by common Linux tools.
+  Following modules added to DPDK:
+
+  * librte_ctrl_if library
+  * librte_eal/linuxapp/kcp kernel module
+
 
 Resolved Issues
 ---------------
@@ -142,6 +150,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_acl.so.2
      librte_cfgfile.so.2
      librte_cmdline.so.1
+   + librte_ctrl_if.so.1
      librte_distributor.so.1
      librte_eal.so.2
    + librte_ethtool.so.1
diff --git a/lib/Makefile b/lib/Makefile
index ce8f0f9..8727454 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -59,6 +59,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
 DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
+DIRS-$(CONFIG_RTE_LIBRTE_CTRL_IF) += librte_ctrl_if
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_ctrl_if/Makefile b/lib/librte_ctrl_if/Makefile
new file mode 100644
index 0000000..fef4e4d
--- /dev/null
+++ b/lib/librte_ctrl_if/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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_ctrl_if.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_ctrl_if_version.map
+
+LIBABIVER := 1
+
+SRCS-y += rte_ctrl_if.c
+SRCS-y += rte_nl.c
+SRCS-y += rte_ctrl_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ctrl_if.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ctrl_if/rte_ctrl_ethtool.c b/lib/librte_ctrl_if/rte_ctrl_ethtool.c
new file mode 100644
index 0000000..3204879
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_ethtool.c
@@ -0,0 +1,390 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <error.h>
+
+#include <linux/if_link.h>
+
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include <rte_ethtool.h>
+#include "rte_ctrl_ethtool.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int
+get_settings(int port_id __rte_unused, void *data, int *data_len)
+{
+	struct ethtool_cmd *ecmd = data;
+
+	/* No PMD equivalent, added to make get pauseparam work */
+	memset(ecmd, 0, sizeof(struct ethtool_cmd));
+
+	*data_len = sizeof(struct ethtool_cmd);
+	return 0;
+}
+
+static int
+get_drvinfo(int port_id, void *data, int *data_len)
+{
+	struct ethtool_drvinfo *info = data;
+	int ret;
+
+	ret = rte_ethtool_get_drvinfo(port_id, info);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_drvinfo);
+
+	return 0;
+}
+
+static int
+get_reg_len(int port_id, void *data, int *data_len)
+{
+	int reg_length = 0;
+
+	reg_length = rte_ethtool_get_regs_len(port_id);
+	if (reg_length < 0)
+		return reg_length;
+
+	*(int *)data = reg_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_reg(int port_id, void *in_data, void *out_data, int *out_data_len)
+{
+	unsigned int reg_length;
+	int reg_length_out_len;
+	struct ethtool_regs *ethtool_regs = in_data;
+	int ret;
+
+	ret = get_reg_len(port_id, &reg_length, &reg_length_out_len);
+
+	/* not enough space in out data buffer */
+	if (ret < 0 || reg_length > ethtool_regs->len)
+		return -1;
+
+	ret = rte_ethtool_get_regs(port_id, ethtool_regs, out_data);
+	if (ret < 0)
+		return ret;
+
+	*out_data_len = reg_length;
+
+	return 0;
+}
+
+static int
+get_link(int port_id, void *data, int *data_len)
+{
+	int ret;
+
+	ret = rte_ethtool_get_link(port_id);
+
+	*(int *)data = ret;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom_length(int port_id, void *data, int *data_len)
+{
+	int eeprom_length = 0;
+
+	eeprom_length = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_length < 0)
+		return eeprom_length;
+
+	*(int *)data = eeprom_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom(int port_id, void *in_data, void *out_data, int *out_data_len)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	int ret;
+
+	ret = rte_ethtool_get_eeprom(port_id, eeprom, out_data);
+	if (ret < 0)
+		return ret;
+
+	*out_data_len = eeprom->len;
+
+	return 0;
+}
+
+static int
+set_eeprom(int port_id, void *in_data)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	int ret;
+
+	ret = rte_ethtool_set_eeprom(port_id, eeprom, eeprom->data);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+get_ringparam(int port_id, void *data, int *data_len)
+{
+	struct ethtool_ringparam *ringparam = data;
+	int ret;
+
+	ret = rte_ethtool_get_ringparam(port_id, ringparam);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_ringparam);
+
+	return 0;
+}
+
+static int
+set_ringparam(int port_id, void *data)
+{
+	struct ethtool_ringparam *ringparam = data;
+	int ret;
+
+	ret = rte_ethtool_set_ringparam(port_id, ringparam);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+get_pauseparam(int port_id, void *data, int *data_len)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+	int ret;
+
+	ret = rte_ethtool_get_pauseparam(port_id, pauseparam);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_pauseparam);
+
+	return 0;
+}
+
+static int
+set_pauseparam(int port_id, void *data)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+
+	return rte_ethtool_set_pauseparam(port_id, pauseparam);
+}
+
+int
+rte_eth_dev_ethtool_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len)
+{
+	int ret = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case ETHTOOL_GSET:
+		return get_settings(port_id, out_data, out_data_len);
+	case ETHTOOL_GDRVINFO:
+		return get_drvinfo(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS_LEN:
+		return get_reg_len(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS:
+		return get_reg(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_GLINK:
+		return get_link(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM_LEN:
+		return get_eeprom_length(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM:
+		return get_eeprom(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_SEEPROM:
+		return set_eeprom(port_id, in_data);
+	case ETHTOOL_GRINGPARAM:
+		return get_ringparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SRINGPARAM:
+		return set_ringparam(port_id, in_data);
+	case ETHTOOL_GPAUSEPARAM:
+		return get_pauseparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SPAUSEPARAM:
+		return set_pauseparam(port_id, in_data);
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+set_mtu(int port_id, void *in_data)
+{
+	int *mtu = in_data;
+
+	return rte_eth_dev_set_mtu(port_id, *mtu);
+}
+
+static int
+get_stats(int port_id, void *data, int *data_len)
+{
+	struct rte_eth_stats stats;
+	struct rtnl_link_stats64 *if_stats = data;
+	int ret;
+
+	ret = rte_eth_stats_get(port_id, &stats);
+	if (ret < 0)
+		return -EOPNOTSUPP;
+
+	if_stats->rx_packets = stats.ipackets;
+	if_stats->tx_packets = stats.opackets;
+	if_stats->rx_bytes = stats.ibytes;
+	if_stats->tx_bytes = stats.obytes;
+	if_stats->rx_errors = stats.ierrors;
+	if_stats->tx_errors = stats.oerrors;
+	if_stats->rx_dropped = stats.imissed;
+	if_stats->multicast = stats.imcasts;
+
+	*data_len = sizeof(struct rtnl_link_stats64);
+
+	return 0;
+}
+
+static int
+get_mac(int port_id, void *data, int *data_len)
+{
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(port_id, &addr);
+	memcpy(data, &addr, sizeof(struct ether_addr));
+
+	*data_len = sizeof(struct ether_addr);
+
+	return 0;
+}
+
+static int
+set_mac(int port_id, void *in_data)
+{
+	struct ether_addr addr;
+
+	memcpy(&addr, in_data, ETHER_ADDR_LEN);
+
+	return rte_eth_dev_default_mac_addr_set(port_id, &addr);
+}
+
+static int
+start_port(int port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return rte_eth_dev_start(port_id);
+}
+
+static int
+stop_port(int port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return 0;
+}
+
+static int
+set_promisc(int port_id, void *in_data)
+{
+	int promisc = *(int *)in_data;
+
+	if (promisc)
+		rte_eth_promiscuous_enable(port_id);
+	else
+		rte_eth_promiscuous_disable(port_id);
+
+	return 0;
+}
+
+static int
+set_allmulti(int port_id, void *in_data)
+{
+	int allmulti = *(int *)in_data;
+
+	if (allmulti)
+		rte_eth_allmulticast_enable(port_id);
+	else
+		rte_eth_allmulticast_disable(port_id);
+
+	return 0;
+}
+
+int
+rte_eth_dev_control_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len)
+{
+	int ret = 0;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case RTE_KCP_REQ_CHANGE_MTU:
+		return set_mtu(port_id, in_data);
+	case RTE_KCP_REQ_GET_STATS:
+		return get_stats(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_GET_MAC:
+		return get_mac(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_SET_MAC:
+		return set_mac(port_id, in_data);
+	case RTE_KCP_REQ_START_PORT:
+		return start_port(port_id);
+	case RTE_KCP_REQ_STOP_PORT:
+		return stop_port(port_id);
+	case RTE_KCP_REQ_SET_PROMISC:
+		return set_promisc(port_id, in_data);
+	case RTE_KCP_REQ_SET_ALLMULTI:
+		return set_allmulti(port_id, in_data);
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+	return ret;
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_ethtool.h b/lib/librte_ctrl_if/rte_ctrl_ethtool.h
new file mode 100644
index 0000000..1c064e5
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_ethtool.h
@@ -0,0 +1,54 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_CTRL_ETHTOOL_H_
+#define _RTE_CTRL_ETHTOOL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/ethtool.h>
+
+#include <exec-env/rte_kcp_common.h>
+
+int rte_eth_dev_ethtool_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len);
+int rte_eth_dev_control_process(int cmd_id, int port_id, void *in_data,
+		void *out_data, int *out_data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_ETHTOOL_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c
new file mode 100644
index 0000000..a8911f6
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.c
@@ -0,0 +1,395 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <rte_ethdev.h>
+#include "rte_ctrl_if.h"
+#include "rte_nl.h"
+
+#define NAMESZ 32
+#define IFNAME "dpdk"
+#define BUFSZ 1024
+
+static int kcp_rtnl_fd = -1;
+static int kcp_fd_ref;
+
+struct kcp_request {
+	struct nlmsghdr nlmsg;
+	char buf[BUFSZ];
+};
+
+static int
+conrol_interface_rtnl_init(void)
+{
+	struct sockaddr_nl src;
+	int ret;
+
+	kcp_rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (kcp_rtnl_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF, "socket for create failed\n");
+		return -1;
+	}
+
+	memset(&src, 0, sizeof(struct sockaddr_nl));
+
+	src.nl_family = AF_NETLINK;
+	src.nl_pid = getpid();
+
+	ret = bind(kcp_rtnl_fd, (struct sockaddr *)&src,
+			sizeof(struct sockaddr_nl));
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Bind for create failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+control_interface_init(void)
+{
+	int ret;
+
+	ret = conrol_interface_rtnl_init();
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize rtnetlink\n");
+		return -1;
+	}
+
+	ret = control_interface_nl_init();
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink\n");
+		close(kcp_rtnl_fd);
+		kcp_rtnl_fd = -1;
+	}
+
+	return ret;
+}
+
+static int
+control_interface_ref_get(void)
+{
+	int ret = 0;
+
+	if (kcp_fd_ref == 0)
+		ret = control_interface_init();
+
+	if (ret == 0)
+		kcp_fd_ref++;
+	else
+		RTE_LOG(ERR, CTRL_IF,
+				"Failed to initialize control interface\n");
+
+	return kcp_fd_ref;
+}
+
+static void
+control_interface_release(void)
+{
+	close(kcp_rtnl_fd);
+	control_interface_nl_release();
+}
+
+static int
+control_interface_ref_put(void)
+{
+	if (kcp_fd_ref == 0)
+		return 0;
+
+	kcp_fd_ref--;
+
+	if (kcp_fd_ref == 0)
+		control_interface_release();
+
+	return kcp_fd_ref;
+}
+
+static int
+add_attr(struct kcp_request *req, unsigned short type, void *buf, size_t len)
+{
+	struct rtattr *rta;
+	int nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(len) > sizeof(struct kcp_request))
+		return -1;
+	rta->rta_type = type;
+	rta->rta_len = RTA_LENGTH(len);
+	memcpy(RTA_DATA(rta), buf, len);
+	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(len);
+
+	return 0;
+}
+
+static struct
+rtattr *add_attr_nested(struct kcp_request *req, unsigned short type)
+{
+	struct rtattr *rta;
+	int nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(0) > sizeof(struct kcp_request))
+		return NULL;
+	rta->rta_type = type;
+	rta->rta_len = nlmsg_len;
+	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(0);
+
+	return rta;
+}
+
+static void
+end_attr_nested(struct kcp_request *req, struct rtattr *rta)
+{
+	rta->rta_len = req->nlmsg.nlmsg_len - rta->rta_len;
+}
+
+static int
+rte_eth_rtnl_create(uint8_t port_id)
+{
+	struct kcp_request req;
+	struct ifinfomsg *info;
+	struct rtattr *rta1;
+	struct rtattr *rta2;
+	unsigned int pid = getpid();
+	char name[NAMESZ];
+	char type[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+	char buf[BUFSZ];
+
+	memset(&req, 0, sizeof(struct kcp_request));
+
+	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
+	req.nlmsg.nlmsg_flags |= NLM_F_ACK;
+	req.nlmsg.nlmsg_type = RTM_NEWLINK;
+
+	info = NLMSG_DATA(&req.nlmsg);
+
+	info->ifi_family = AF_UNSPEC;
+	info->ifi_index = 0;
+
+	snprintf(name, NAMESZ, IFNAME"%u", port_id);
+	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
+	if (ret < 0)
+		return -1;
+
+	rta1 = add_attr_nested(&req, IFLA_LINKINFO);
+	if (rta1 == NULL)
+		return -1;
+
+	snprintf(type, NAMESZ, KCP_DEVICE);
+	ret = add_attr(&req, IFLA_INFO_KIND, type, strlen(type) + 1);
+	if (ret < 0)
+		return -1;
+
+	rta2 = add_attr_nested(&req, IFLA_INFO_DATA);
+	if (rta2 == NULL)
+		return -1;
+
+	ret = add_attr(&req, IFLA_KCP_PORTID, &port_id, sizeof(uint8_t));
+	if (ret < 0)
+		return -1;
+
+	ret = add_attr(&req, IFLA_KCP_PID, &pid, sizeof(unsigned int));
+	if (ret < 0)
+		return -1;
+
+	end_attr_nested(&req, rta2);
+	end_attr_nested(&req, rta1);
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for create failed %d.\n", errno);
+		return -1;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	iov.iov_base = buf;
+	iov.iov_len = sizeof(buf);
+
+	ret = recvmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Recv for create failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+rte_eth_control_interface_create_one(uint8_t port_id)
+{
+	int ret;
+
+	if (control_interface_ref_get() != 0) {
+		ret = rte_eth_rtnl_create(port_id);
+		RTE_LOG(DEBUG, CTRL_IF,
+			"Control interface %s for port:%u\n",
+			ret < 0 ? "failed" : "created", port_id);
+	}
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_create(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			if (rte_eth_devices[i].dev_type == RTE_ETH_DEV_VIRTUAL)
+				continue;
+			ret = rte_eth_control_interface_create_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int
+rte_eth_rtnl_destroy(uint8_t port_id)
+{
+	struct kcp_request req;
+	struct ifinfomsg *info;
+	char name[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+
+	memset(&req, 0, sizeof(struct kcp_request));
+
+	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlmsg.nlmsg_flags = NLM_F_REQUEST;
+	req.nlmsg.nlmsg_type = RTM_DELLINK;
+
+	info = NLMSG_DATA(&req.nlmsg);
+
+	info->ifi_family = AF_UNSPEC;
+	info->ifi_index = 0;
+
+	snprintf(name, NAMESZ, IFNAME"%u", port_id);
+	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
+	if (ret < 0)
+		return -1;
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for destroy failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+rte_eth_control_interface_destroy_one(uint8_t port_id)
+{
+	rte_eth_rtnl_destroy(port_id);
+	control_interface_ref_put();
+	RTE_LOG(DEBUG, CTRL_IF, "Control interface destroyed for port:%u\n",
+			port_id);
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_destroy(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			if (rte_eth_devices[i].dev_type == RTE_ETH_DEV_VIRTUAL)
+				continue;
+			ret = rte_eth_control_interface_destroy_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+int
+rte_eth_control_interface_msg_exist(unsigned int timeout_sec)
+{
+	return control_interface_msg_exist(timeout_sec);
+}
+
+int
+rte_eth_control_interface_msg_process(int flag)
+{
+	return control_interface_msg_process(flag);
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.h b/lib/librte_ctrl_if/rte_ctrl_if.h
new file mode 100644
index 0000000..868a56a
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.h
@@ -0,0 +1,129 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_CTRL_IF_H_
+#define _RTE_CTRL_IF_H_
+
+/**
+ * @file
+ *
+ * Control Interface Library for RTE
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <exec-env/rte_kcp_common.h>
+
+/**
+ * Flags values for rte_eth_control_interface_process_msg() API
+ */
+enum control_interface_process_flag {
+	/**< Process if msg available. */
+	RTE_ETHTOOL_CTRL_IF_PROCESS_MSG,
+
+	/**< Discard msg if available, respond with a error value. */
+	RTE_ETHTOOL_CTRL_IF_DISCARD_MSG,
+};
+
+/**
+ * Creates control interfaces (Linux virtual network interface)for
+ * each existing eal port.
+ *
+ * This API opens device created by supportive kernel module and initializes
+ * kernel communication interface.
+ *
+ * If supportive kernel module is not inserted this API will return
+ * an error.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_create(void);
+
+/**
+ * Destroys control interfaces.
+ *
+ * This API close device created by supportive kernel module and release
+ * underlying communication interface.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_destroy(void);
+
+/**
+ * Check if any msg exist to process.
+ *
+ * This function can be blocking or unblocking according timeout_sec
+ * parameter value. If function will be continuous loop, like can be
+ * called by any forwarding lcore, nonblocking mode should be preferred.
+ * If a separate thread created to handle control messages, blocking
+ * mode can be preferred to save CPU cycles.
+ *
+ * When this function sends a valid port_id, application must call
+ * msg_process() afterwards, to accept new commands.
+ *
+ * @param timeout_sec
+ *  if 0, function is in nonblocking mode.
+ *  if > 0, blocks for given time, if there is no message available,
+ *  sleeps again same amount of time. Value is in seconds.
+ *
+ * @return
+ *  port_id the msg for on success. -1 if no msg waiting.
+ */
+int rte_eth_control_interface_msg_exist(unsigned int timeout_sec);
+
+/**
+ * Process if any received message is available.
+ *
+ * If message exists this function will create a local copy of it and
+ * process or discard the message according flag.
+ *
+ * @param flag
+ *  Defines what to do with message, can be process or discard.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_msg_process(int flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_IF_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if_version.map b/lib/librte_ctrl_if/rte_ctrl_if_version.map
new file mode 100644
index 0000000..c3a91ab
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if_version.map
@@ -0,0 +1,10 @@
+DPDK_16.04 {
+	global:
+
+	rte_eth_control_interface_create;
+	rte_eth_control_interface_destroy;
+	rte_eth_control_interface_msg_exist;
+	rte_eth_control_interface_msg_process;
+
+	local: *;
+};
diff --git a/lib/librte_ctrl_if/rte_nl.c b/lib/librte_ctrl_if/rte_nl.c
new file mode 100644
index 0000000..eec8c7c
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.c
@@ -0,0 +1,313 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <rte_spinlock.h>
+#include <rte_ethdev.h>
+#include "rte_ctrl_ethtool.h"
+#include "rte_nl.h"
+#include "rte_ctrl_if.h"
+
+#define MAX_PAYLOAD sizeof(struct kcp_ethtool_msg)
+
+struct ctrl_if_nl {
+	union {
+		struct nlmsghdr nlh;
+		uint8_t nlmsg[NLMSG_SPACE(MAX_PAYLOAD)];
+	};
+	struct msghdr msg;
+	struct iovec iov;
+	struct sockaddr_nl dest_addr;
+};
+
+struct ctrl_if_msg_sync {
+	int kcp_ethtool_msg_count;
+	struct kcp_ethtool_msg msg_storage;
+	pthread_cond_t cond;
+	pthread_mutex_t msg_lock;
+	int pending_process;
+};
+
+static int sock_fd = -1;
+static pthread_t thread_id;
+
+static struct ctrl_if_nl nl_s;
+static struct ctrl_if_nl nl_r;
+
+static struct ctrl_if_msg_sync ctrl_if_sync = {
+	.cond = PTHREAD_COND_INITIALIZER,
+	.msg_lock = PTHREAD_MUTEX_INITIALIZER,
+};
+
+static int
+nl_send(void *buf, size_t len)
+{
+	int ret;
+
+	if (nl_s.nlh.nlmsg_len < len) {
+		RTE_LOG(ERR, CTRL_IF, "Message is too big, len:%zu\n", len);
+		return -1;
+	}
+
+	if (!NLMSG_OK(&nl_s.nlh, NLMSG_SPACE(MAX_PAYLOAD))) {
+		RTE_LOG(ERR, CTRL_IF, "Message is not OK\n");
+		return -1;
+	}
+
+	/* Fill in the netlink message payload */
+	memcpy(NLMSG_DATA(nl_s.nlmsg), buf, len);
+
+	ret = sendmsg(sock_fd, &nl_s.msg, 0);
+
+	if (ret < 0)
+		RTE_LOG(ERR, CTRL_IF, "Failed nl msg send. ret:%d, err:%d\n",
+				ret, errno);
+	return ret;
+}
+
+static int
+nl_ethtool_msg_send(struct kcp_ethtool_msg *msg)
+{
+	return nl_send((void *)msg, sizeof(struct kcp_ethtool_msg));
+}
+
+static void
+process_msg(struct kcp_ethtool_msg *msg)
+{
+	if (msg->cmd_id > RTE_KCP_REQ_UNKNOWN) {
+		msg->err = rte_eth_dev_control_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	} else {
+		msg->err = rte_eth_dev_ethtool_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	}
+
+	if (msg->err)
+		memset(msg->output_buffer, 0, msg->output_buffer_len);
+
+	nl_ethtool_msg_send(msg);
+}
+
+
+int
+control_interface_msg_exist(unsigned int timeout_sec)
+{
+	struct timespec ts;
+	int port_id;
+	int ret = 0;
+
+	if (timeout_sec) {
+		clock_gettime(CLOCK_REALTIME, &ts);
+		ts.tv_sec += timeout_sec;
+	}
+
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+	while (timeout_sec && !ctrl_if_sync.kcp_ethtool_msg_count && !ret)
+		ret = pthread_cond_timedwait(&ctrl_if_sync.cond,
+				&ctrl_if_sync.msg_lock, &ts);
+
+	if (ctrl_if_sync.kcp_ethtool_msg_count == 0) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return -1;
+	}
+
+	ctrl_if_sync.pending_process = 1;
+
+	port_id = ctrl_if_sync.msg_storage.port_id;
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	return port_id;
+}
+
+int
+control_interface_msg_process(int flag)
+{
+	struct kcp_ethtool_msg msg_storage;
+	int ret = 0;
+
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+	if (ctrl_if_sync.kcp_ethtool_msg_count == 0) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return 0;
+	}
+
+	memcpy(&msg_storage, &ctrl_if_sync.msg_storage,
+			sizeof(struct kcp_ethtool_msg));
+	ctrl_if_sync.pending_process = 0;
+	ctrl_if_sync.kcp_ethtool_msg_count = 0;
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	switch (flag) {
+	case RTE_ETHTOOL_CTRL_IF_PROCESS_MSG:
+		process_msg(&msg_storage);
+		break;
+
+	case RTE_ETHTOOL_CTRL_IF_DISCARD_MSG:
+		msg_storage.err = -1;
+		nl_ethtool_msg_send(&msg_storage);
+		break;
+
+	default:
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+msg_add_and_signal(struct nlmsghdr *nlh)
+{
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+
+	if (ctrl_if_sync.pending_process) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return -1;
+	}
+
+	memcpy(&ctrl_if_sync.msg_storage, NLMSG_DATA(nlh),
+			sizeof(struct kcp_ethtool_msg));
+	ctrl_if_sync.kcp_ethtool_msg_count = 1;
+	ctrl_if_sync.msg_storage.flag = KCP_MSG_FLAG_RESPONSE;
+
+	pthread_cond_signal(&ctrl_if_sync.cond);
+
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	return 0;
+}
+
+static void *
+nl_recv(void *arg)
+{
+	int ret;
+
+	for (;;) {
+		ret = recvmsg(sock_fd, &nl_r.msg, 0);
+		if (ret < 0)
+			continue;
+
+		if ((unsigned)ret < sizeof(struct kcp_ethtool_msg)) {
+			RTE_LOG(WARNING, CTRL_IF,
+					"Received %u bytes, payload %lu\n",
+					ret, sizeof(struct kcp_ethtool_msg));
+			continue;
+		}
+
+		msg_add_and_signal(&nl_r.nlh);
+	}
+
+	return arg;
+}
+
+static void
+nl_setup_header(struct ctrl_if_nl *nl)
+{
+	nl->dest_addr.nl_family = AF_NETLINK;
+	nl->dest_addr.nl_pid = 0;   /*  For Linux Kernel */
+	nl->dest_addr.nl_groups = 0;
+
+	memset(nl->nlmsg, 0, NLMSG_SPACE(MAX_PAYLOAD));
+
+	/* Fill the netlink message header */
+	nl->nlh.nlmsg_len = NLMSG_LENGTH(MAX_PAYLOAD);
+	nl->nlh.nlmsg_pid = getpid();  /* self pid */
+	nl->nlh.nlmsg_flags = 0;
+
+	nl->iov.iov_base = (void *)nl->nlmsg;
+	nl->iov.iov_len = nl->nlh.nlmsg_len;
+	memset(&nl->msg, 0, sizeof(struct msghdr));
+	nl->msg.msg_name = (void *)&nl->dest_addr;
+	nl->msg.msg_namelen = sizeof(struct sockaddr_nl);
+	nl->msg.msg_iov = &nl->iov;
+	nl->msg.msg_iovlen = 1;
+}
+
+static int
+nl_socket_init(void)
+{
+	struct sockaddr_nl src_addr;
+	int fd;
+	int ret;
+
+	fd = socket(PF_NETLINK, SOCK_RAW, KCP_NL_GRP);
+	if (fd < 0)
+		return -1;
+
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	ret = bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
+	if (ret) {
+		close(fd);
+		return -1;
+	}
+
+	nl_setup_header(&nl_s);
+	nl_setup_header(&nl_r);
+
+	return fd;
+}
+
+int
+control_interface_nl_init(void)
+{
+	int ret;
+
+	sock_fd = nl_socket_init();
+	if (sock_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink socket\n");
+		return -1;
+	}
+
+	ret = pthread_create(&thread_id, NULL, nl_recv, NULL);
+	if (ret != 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to create receive thread\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void
+control_interface_nl_release(void)
+{
+	pthread_cancel(thread_id);
+	pthread_join(thread_id, NULL);
+	close(sock_fd);
+}
diff --git a/lib/librte_ctrl_if/rte_nl.h b/lib/librte_ctrl_if/rte_nl.h
new file mode 100644
index 0000000..ed4dea7
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.h
@@ -0,0 +1,50 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_NL_H_
+#define _RTE_NL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int control_interface_nl_init(void);
+void control_interface_nl_release(void);
+int control_interface_msg_exist(unsigned int timeout_sec);
+int control_interface_msg_process(int flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_NL_H_ */
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 2e47e7f..a0a2c9f 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
 #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
 #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
 #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#define RTE_LOGTYPE_CTRL_IF 0x00040000 /**< Log related to control interface. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 32f76b1..1b683ef 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -123,6 +123,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF_OFFLOAD)   += -lrte_mbuf_offload
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CTRL_IF)        += -lrte_ctrl_if
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.5.0

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

* [PATCH v4 4/4] examples/ethtool: add control interface support to the application
  2016-03-01 15:41     ` [PATCH v4 " Ferruh Yigit
                         ` (2 preceding siblings ...)
  2016-03-01 15:41       ` [PATCH v4 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
@ 2016-03-01 15:42       ` Ferruh Yigit
  2016-03-09 11:41       ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  4 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-01 15:42 UTC (permalink / raw)
  To: dev

Control interface APIs added into the sample application.

To have the support corresponding kernel module (KCP) needs to be inserted.
If kernel module is not there, application will run as it is without
kernel control path support.

When KCP module inserted, running application creates a virtual Linux
network interface (dpdk$) per DPDK port. This interface can be used by
traditional Linux tools.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

v4:
* No update

v3:
* Use blocking mode control interface processing, instead of poll mode

v2:
* No update on sample app
---
 doc/guides/sample_app_ug/ethtool.rst | 41 ++++++++++++++++++++++++++++++++++++
 examples/ethtool/main.c              | 31 +++++++++++++++++++++++++--
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
index 65240ae..af591c2 100644
--- a/doc/guides/sample_app_ug/ethtool.rst
+++ b/doc/guides/sample_app_ug/ethtool.rst
@@ -130,3 +130,44 @@ interface that accepts commands as described in `using the
 application`_. Individual call-back functions handle the detail
 associated with each command, which make use of librte_ethtool
 library.
+
+Control Interface
+~~~~~~~~~~~~~~~~~
+
+If Kernel Control Path (KCP) kernel module (rte_kcp.ko) inserted,
+virtual interfaces created for each DPDK port for control purposes.
+
+Created interfaces are named as dpdk#, like:
+
+.. code-block:: console
+
+        # ifconfig dpdk0; ifconfig dpdk1
+        dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 90:e2:ba:0e:49:b9  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+        dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+Regular Linux commands can be issued on interfaces:
+
+.. code-block:: console
+
+        # ethtool -i dpdk0
+        driver: rte_ixgbe_pmd
+        version: RTE 2.3.0-rc0
+        firmware-version:
+        expansion-rom-version:
+        bus-info: 0000:08:00.1
+        supports-statistics: yes
+        supports-test: no
+        supports-eeprom-access: yes
+        supports-register-dump: yes
+        supports-priv-flags: no
diff --git a/examples/ethtool/main.c b/examples/ethtool/main.c
index 2c655d8..72fbe4c 100644
--- a/examples/ethtool/main.c
+++ b/examples/ethtool/main.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <rte_memory.h>
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
+#include <rte_ctrl_if.h>
 
 #include "ethapp.h"
 
@@ -54,7 +55,6 @@
 #define PKTPOOL_EXTRA_SIZE 512
 #define PKTPOOL_CACHE 32
 
-
 struct txq_port {
 	uint16_t cnt_unsent;
 	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
@@ -259,11 +259,32 @@ static int slave_main(__attribute__((unused)) void *ptr_data)
 	return 0;
 }
 
+static void *
+control_function(__attribute__((unused)) void *arg)
+{
+	int port_id;
+
+	while (1) {
+		/* blocking call with 1 sec timeout */
+		port_id = rte_eth_control_interface_msg_exist(1);
+		if (port_id < 0)
+			continue;
+
+		lock_port(port_id);
+		rte_eth_control_interface_msg_process(
+			RTE_ETHTOOL_CTRL_IF_PROCESS_MSG);
+		unlock_port(port_id);
+	}
+
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	int cnt_args_parsed;
 	uint32_t id_core;
 	uint32_t cnt_ports;
+	pthread_t control_thread;
 
 	/* Init runtime enviornment */
 	cnt_args_parsed = rte_eal_init(argc, argv);
@@ -293,6 +314,9 @@ int main(int argc, char **argv)
 	id_core = rte_get_next_lcore(id_core, 1, 1);
 	rte_eal_remote_launch(slave_main, NULL, id_core);
 
+	pthread_create(&control_thread, NULL, control_function, NULL);
+	rte_eth_control_interface_create();
+
 	ethapp_main();
 
 	app_cfg.exit_now = 1;
@@ -301,5 +325,8 @@ int main(int argc, char **argv)
 			return -1;
 	}
 
+	rte_eth_control_interface_destroy();
+	pthread_cancel(control_thread);
+
 	return 0;
 }
-- 
2.5.0

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

* Re: [PATCH v3 2/4] kcp: add kernel control path kernel module
  2016-03-01  1:02       ` Stephen Hemminger
@ 2016-03-01 15:53         ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-01 15:53 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On 3/1/2016 1:02 AM, Stephen Hemminger wrote:
> On Fri, 26 Feb 2016 14:10:39 +0000
> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> 
>> +#define KCP_ERR(args...) printk(KERN_ERR "KCP: " args)
>> +#define KCP_INFO(args...) printk(KERN_INFO "KCP: " args)
>> +
>> +#ifdef RTE_KCP_KO_DEBUG
>> +#define KCP_DBG(args...) printk(KERN_DEBUG "KCP: " args)
>> +#else
>> +#define KCP_DBG(args...)
>> +#endif
> 
> These macros will not make netdev developers happy.
> 
> Use standard printk macros, and if you want prefix, use pr_fmt
> 
> 
> #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> 
Hi Stephen,

I removed the macros and send a new version of patch set.

v4:
http://dpdk.org/dev/patchwork/patch/10950/

Thanks,
ferruh

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 14:33               ` Jay Rolette
@ 2016-03-01 22:40                 ` Bruce Richardson
  2016-03-02  2:02                 ` Stephen Hemminger
  1 sibling, 0 replies; 83+ messages in thread
From: Bruce Richardson @ 2016-03-01 22:40 UTC (permalink / raw)
  To: Jay Rolette; +Cc: DPDK, Avi Kivity

On Mon, Feb 29, 2016 at 08:33:25AM -0600, Jay Rolette wrote:
> On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon <thomas.monjalon@6wind.com>
> wrote:
> 
> > Hi,
> > I totally agree with Avi's comments.
> > This topic is really important for the future of DPDK.
> > So I think we must give some time to continue the discussion
> > and have netdev involved in the choices done.
> > As a consequence, these series should not be merged in the release 16.04.
> > Thanks for continuing the work.
> >
> 
> I know you guys are very interested in getting rid of the out-of-tree
> drivers, but please do not block incremental improvements to DPDK in the
> meantime. Ferruh's patch improves the usability of KNI. Don't throw out
> good and useful enhancements just because it isn't where you want to be in
> the end.
> 
> I'd like to see these be merged.
> 
> Jay

+1 to this. While this may not eliminate out of tree kernel modules, and solve
all problems, I think taking in kcp and kdp and removing KNI will leave DPDK in
a better state than it was.

Also, with regards to having the kernel data path, and the port control part
inside the same module, our experience with KNI has led us to explicitly
separating them out. The path from user to kernel space should be completely
separated from the netdevs which back dpdk ports. Consider stats reporting alone:
netdevs backed by dpdk ports can report out packet rx/tx counts for the hw ports
while the user-kernel path can report out packet rx/tx from kernel.

	Regards,
	/Bruce

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

* Re: [PATCH v4 2/4] kcp: add kernel control path kernel module
  2016-03-01 15:41       ` [PATCH v4 2/4] kcp: add kernel control path kernel module Ferruh Yigit
@ 2016-03-01 23:06         ` Stephen Hemminger
  2016-03-02 11:05           ` Ferruh Yigit
  2016-03-01 23:09         ` Stephen Hemminger
  2016-03-01 23:10         ` Stephen Hemminger
  2 siblings, 1 reply; 83+ messages in thread
From: Stephen Hemminger @ 2016-03-01 23:06 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On Tue,  1 Mar 2016 15:41:58 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> +#ifdef RTE_KCP_KO_DEBUG
> +#define KCP_DBG(args...) pr_info(args)
> +#else
> +#define KCP_DBG(args...)
> +#en

Why not use pr_debug() which is compile enabled already and supports dynamic
enabling as well.

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

* Re: [PATCH v4 2/4] kcp: add kernel control path kernel module
  2016-03-01 15:41       ` [PATCH v4 2/4] kcp: add kernel control path kernel module Ferruh Yigit
  2016-03-01 23:06         ` Stephen Hemminger
@ 2016-03-01 23:09         ` Stephen Hemminger
  2016-03-01 23:10         ` Stephen Hemminger
  2 siblings, 0 replies; 83+ messages in thread
From: Stephen Hemminger @ 2016-03-01 23:09 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On Tue,  1 Mar 2016 15:41:58 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> +
> +static int kcp_net_set_mac(struct net_device *dev, void *p)
> +{
> +	struct sockaddr *addr = p;
> +	int err = 0;

Unnecessary assignment.

> +
> +	if (!is_valid_ether_addr((unsigned char *)(addr->sa_data)))
No cast needed:
	if (!is_valid_ether_addr(addr->sa_data))
		return -EADDRNOTAVAIL;

> +		return -EADDRNOTAVAIL;
> +

Don't you want to validate that dev->addr_len == ETHER_ADDR_LEN?

> +	err = kcp_nl_exec(RTE_KCP_REQ_SET_MAC, dev, addr->sa_data,
> +			dev->addr_len, NULL, 0);
> +	if (err < 0)
> +		return -EADDRNOTAVAIL;
> +
> +	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
> +
> +	return 0;
> +}
> +

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

* Re: [PATCH v4 2/4] kcp: add kernel control path kernel module
  2016-03-01 15:41       ` [PATCH v4 2/4] kcp: add kernel control path kernel module Ferruh Yigit
  2016-03-01 23:06         ` Stephen Hemminger
  2016-03-01 23:09         ` Stephen Hemminger
@ 2016-03-01 23:10         ` Stephen Hemminger
  2016-03-02 11:06           ` Ferruh Yigit
  2 siblings, 1 reply; 83+ messages in thread
From: Stephen Hemminger @ 2016-03-01 23:10 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev

On Tue,  1 Mar 2016 15:41:58 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> +struct kcp_ethtool_msg {
> +	int cmd_id;
> +	int port_id;
> +	unsigned int flag;
> +	char input_buffer[KCP_ETHTOOL_MSG_LEN];
> +	char output_buffer[KCP_ETHTOOL_MSG_LEN];
> +	int input_buffer_len;
> +	int output_buffer_len;
> +	int err;
> +};
> +

In general try and use unsigned where ever it is possible.
Having int and char types was the C style back in Unix, but now
most code use size_t, uint32_t and uint8_t.


You seem to be trying to force ethtool into netlink.
There are some others doing that already, so following their work
would be good.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-02-29 14:33               ` Jay Rolette
  2016-03-01 22:40                 ` Bruce Richardson
@ 2016-03-02  2:02                 ` Stephen Hemminger
  2016-03-02  8:27                   ` Panu Matilainen
  2016-03-02 22:18                   ` Jay Rolette
  1 sibling, 2 replies; 83+ messages in thread
From: Stephen Hemminger @ 2016-03-02  2:02 UTC (permalink / raw)
  To: Jay Rolette; +Cc: DPDK, Avi Kivity

On Mon, 29 Feb 2016 08:33:25 -0600
Jay Rolette <rolette@infiniteio.com> wrote:

> On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon <thomas.monjalon@6wind.com>
> wrote:
> 
> > Hi,
> > I totally agree with Avi's comments.
> > This topic is really important for the future of DPDK.
> > So I think we must give some time to continue the discussion
> > and have netdev involved in the choices done.
> > As a consequence, these series should not be merged in the release 16.04.
> > Thanks for continuing the work.
> >
> 
> I know you guys are very interested in getting rid of the out-of-tree
> drivers, but please do not block incremental improvements to DPDK in the
> meantime. Ferruh's patch improves the usability of KNI. Don't throw out
> good and useful enhancements just because it isn't where you want to be in
> the end.
> 
> I'd like to see these be merged.
> 
> Jay

The code is really not ready. I am okay with cooperative development
but the current code needs to go into a staging type tree.
No compatibility, no ABI guarantees, more of an RFC.
Don't want vendors building products with it then screaming when it
gets rebuilt/reworked/scrapped.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02  2:02                 ` Stephen Hemminger
@ 2016-03-02  8:27                   ` Panu Matilainen
  2016-03-02 10:47                     ` Vincent JARDIN
  2016-03-02 22:18                   ` Jay Rolette
  1 sibling, 1 reply; 83+ messages in thread
From: Panu Matilainen @ 2016-03-02  8:27 UTC (permalink / raw)
  To: Stephen Hemminger, Jay Rolette; +Cc: DPDK, Avi Kivity

On 03/02/2016 04:02 AM, Stephen Hemminger wrote:
> On Mon, 29 Feb 2016 08:33:25 -0600
> Jay Rolette <rolette@infiniteio.com> wrote:
>
>> On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon <thomas.monjalon@6wind.com>
>> wrote:
>>
>>> Hi,
>>> I totally agree with Avi's comments.
>>> This topic is really important for the future of DPDK.
>>> So I think we must give some time to continue the discussion
>>> and have netdev involved in the choices done.
>>> As a consequence, these series should not be merged in the release 16.04.
>>> Thanks for continuing the work.
>>>
>>
>> I know you guys are very interested in getting rid of the out-of-tree
>> drivers, but please do not block incremental improvements to DPDK in the
>> meantime. Ferruh's patch improves the usability of KNI. Don't throw out
>> good and useful enhancements just because it isn't where you want to be in
>> the end.
>>
>> I'd like to see these be merged.
>>
>> Jay
>
> The code is really not ready. I am okay with cooperative development
> but the current code needs to go into a staging type tree.
> No compatibility, no ABI guarantees, more of an RFC.
> Don't want vendors building products with it then screaming when it
> gets rebuilt/reworked/scrapped.
>

Exactly.

If a venturous vendor wants to go and build a product based on something 
in a staging tree there's nothing stopping them from doing that, but at 
least it should set the expectations straight.

	- Panu -

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02  8:27                   ` Panu Matilainen
@ 2016-03-02 10:47                     ` Vincent JARDIN
  2016-03-02 10:51                       ` Jim Thompson
  2016-03-02 11:21                       ` Thomas Monjalon
  0 siblings, 2 replies; 83+ messages in thread
From: Vincent JARDIN @ 2016-03-02 10:47 UTC (permalink / raw)
  To: Panu Matilainen, Stephen Hemminger, Jay Rolette, thomas.monjalon
  Cc: DPDK, Avi Kivity

Le 02/03/2016 09:27, Panu Matilainen a écrit :
>>> I'd like to see these be merged.
>>>
>>> Jay
>>
>> The code is really not ready. I am okay with cooperative development
>> but the current code needs to go into a staging type tree.
>> No compatibility, no ABI guarantees, more of an RFC.
>> Don't want vendors building products with it then screaming when it
>> gets rebuilt/reworked/scrapped.
>>
>
> Exactly.

+1 too

We need to build on this innovation while there is a path for kernel 
mainstream. The logic of using a staging is a good one.

Thomas,

can we open a staging folder into the DPDK like it is done into the kernel?

Thank you,
   Vincent

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02 10:47                     ` Vincent JARDIN
@ 2016-03-02 10:51                       ` Jim Thompson
  2016-03-02 12:03                         ` Vincent JARDIN
  2016-03-02 11:21                       ` Thomas Monjalon
  1 sibling, 1 reply; 83+ messages in thread
From: Jim Thompson @ 2016-03-02 10:51 UTC (permalink / raw)
  To: Vincent JARDIN; +Cc: Avi Kivity, DPDK


> On Mar 2, 2016, at 4:47 AM, Vincent JARDIN <vincent.jardin@6wind.com> wrote:
> 
> Le 02/03/2016 09:27, Panu Matilainen a écrit :
>>>> I'd like to see these be merged.
>>>> 
>>>> Jay
>>> 
>>> The code is really not ready. I am okay with cooperative development
>>> but the current code needs to go into a staging type tree.
>>> No compatibility, no ABI guarantees, more of an RFC.
>>> Don't want vendors building products with it then screaming when it
>>> gets rebuilt/reworked/scrapped.
>>> 
>> 
>> Exactly.
> 
> +1 too
> 
> We need to build on this innovation while there is a path for kernel mainstream. The logic of using a staging is a good one.
> 
> Thomas,
> 
> can we open a staging folder into the DPDK like it is done into the kernel?

Can we take it as a requirement to support FreeBSD this time around?

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

* Re: [PATCH v4 2/4] kcp: add kernel control path kernel module
  2016-03-01 23:06         ` Stephen Hemminger
@ 2016-03-02 11:05           ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-02 11:05 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On 3/1/2016 11:06 PM, Stephen Hemminger wrote:
> On Tue,  1 Mar 2016 15:41:58 +0000
> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> 
>> +#ifdef RTE_KCP_KO_DEBUG
>> +#define KCP_DBG(args...) pr_info(args)
>> +#else
>> +#define KCP_DBG(args...)
>> +#en
> 
> Why not use pr_debug() which is compile enabled already and supports dynamic
> enabling as well.
> 
Because of dynamic debug control, it is more complex and less known.
But I will update it to pr_debug.

Thanks,
ferruh

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

* Re: [PATCH v4 2/4] kcp: add kernel control path kernel module
  2016-03-01 23:10         ` Stephen Hemminger
@ 2016-03-02 11:06           ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-02 11:06 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: dev

On 3/1/2016 11:10 PM, Stephen Hemminger wrote:
> On Tue,  1 Mar 2016 15:41:58 +0000
> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> 
>> +struct kcp_ethtool_msg {
>> +	int cmd_id;
>> +	int port_id;
>> +	unsigned int flag;
>> +	char input_buffer[KCP_ETHTOOL_MSG_LEN];
>> +	char output_buffer[KCP_ETHTOOL_MSG_LEN];
>> +	int input_buffer_len;
>> +	int output_buffer_len;
>> +	int err;
>> +};
>> +
> 
> In general try and use unsigned where ever it is possible.
> Having int and char types was the C style back in Unix, but now
> most code use size_t, uint32_t and uint8_t.
> 
Thanks for the comments, this and previous ones, I will update accordingly.

> 
> You seem to be trying to force ethtool into netlink.
> There are some others doing that already, so following their work
> would be good.
> 
Sure I would like to check them, where can I find them? inside the kernel?

Thanks,
ferruh

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02 10:47                     ` Vincent JARDIN
  2016-03-02 10:51                       ` Jim Thompson
@ 2016-03-02 11:21                       ` Thomas Monjalon
  2016-03-02 22:35                         ` Thomas Monjalon
  1 sibling, 1 reply; 83+ messages in thread
From: Thomas Monjalon @ 2016-03-02 11:21 UTC (permalink / raw)
  To: Vincent JARDIN, Stephen Hemminger, Jay Rolette; +Cc: dev, Avi Kivity

2016-03-02 11:47, Vincent JARDIN:
> Le 02/03/2016 09:27, Panu Matilainen a écrit :
> >>> I'd like to see these be merged.
> >>>
> >>> Jay
> >>
> >> The code is really not ready. I am okay with cooperative development
> >> but the current code needs to go into a staging type tree.
> >> No compatibility, no ABI guarantees, more of an RFC.
> >> Don't want vendors building products with it then screaming when it
> >> gets rebuilt/reworked/scrapped.
> >>
> >
> > Exactly.
> 
> +1 too
> 
> We need to build on this innovation while there is a path for kernel 
> mainstream. The logic of using a staging is a good one.
> 
> Thomas,
> 
> can we open a staging folder into the DPDK like it is done into the kernel?

It's possible to create a staging directory if everybody agree.
It is important to state in a README file or in the doc/ that
there will be no guarantee (no stable ABI, no validation and can be dropped)
and that it is a work in progress, a suggestion to discuss with the kernel
community.

The kernel modules must clearly target an upstream integration.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02 10:51                       ` Jim Thompson
@ 2016-03-02 12:03                         ` Vincent JARDIN
  2016-03-02 22:51                           ` Jim Thompson
  0 siblings, 1 reply; 83+ messages in thread
From: Vincent JARDIN @ 2016-03-02 12:03 UTC (permalink / raw)
  To: Jim Thompson; +Cc: Avi Kivity, DPDK

Le 02/03/2016 11:51, Jim Thompson a écrit :
> Can we take it as a requirement to support FreeBSD this time around?

Of course, all OS should be on the loop, but I guess, it would be per 
kernel specific. What is ethtool on FreeBSD? Or can you start porting 
ethtool on FreeBSD?

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02  2:02                 ` Stephen Hemminger
  2016-03-02  8:27                   ` Panu Matilainen
@ 2016-03-02 22:18                   ` Jay Rolette
  2016-03-03 10:11                     ` Ferruh Yigit
  1 sibling, 1 reply; 83+ messages in thread
From: Jay Rolette @ 2016-03-02 22:18 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: DPDK, Avi Kivity

On Tue, Mar 1, 2016 at 8:02 PM, Stephen Hemminger <
stephen@networkplumber.org> wrote:

> On Mon, 29 Feb 2016 08:33:25 -0600
> Jay Rolette <rolette@infiniteio.com> wrote:
>
> > On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon <
> thomas.monjalon@6wind.com>
> > wrote:
> >
> > > Hi,
> > > I totally agree with Avi's comments.
> > > This topic is really important for the future of DPDK.
> > > So I think we must give some time to continue the discussion
> > > and have netdev involved in the choices done.
> > > As a consequence, these series should not be merged in the release
> 16.04.
> > > Thanks for continuing the work.
> > >
> >
> > I know you guys are very interested in getting rid of the out-of-tree
> > drivers, but please do not block incremental improvements to DPDK in the
> > meantime. Ferruh's patch improves the usability of KNI. Don't throw out
> > good and useful enhancements just because it isn't where you want to be
> in
> > the end.
> >
> > I'd like to see these be merged.
> >
> > Jay
>
> The code is really not ready. I am okay with cooperative development
> but the current code needs to go into a staging type tree.
> No compatibility, no ABI guarantees, more of an RFC.
> Don't want vendors building products with it then screaming when it
> gets rebuilt/reworked/scrapped.
>

That's fair. To be clear, it wasn't my intent for code that wasn't baked
yet to be merged.

The main point of my comment was that I think it is important not to halt
incremental improvements to existing capabilities (KNI in this case) just
because there are philosophical or directional changes that the community
would like to make longer-term.

Bird in the hand vs. two in the bush...

Jay

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02 11:21                       ` Thomas Monjalon
@ 2016-03-02 22:35                         ` Thomas Monjalon
  2016-03-03  8:31                           ` Panu Matilainen
  2016-03-10  0:04                           ` Thomas Monjalon
  0 siblings, 2 replies; 83+ messages in thread
From: Thomas Monjalon @ 2016-03-02 22:35 UTC (permalink / raw)
  To: Vincent JARDIN; +Cc: dev, Avi Kivity

2016-03-02 12:21, Thomas Monjalon:
> 2016-03-02 11:47, Vincent JARDIN:
> > Le 02/03/2016 09:27, Panu Matilainen a écrit :
> > >>> I'd like to see these be merged.
> > >>>
> > >>> Jay
> > >>
> > >> The code is really not ready. I am okay with cooperative development
> > >> but the current code needs to go into a staging type tree.
> > >> No compatibility, no ABI guarantees, more of an RFC.
> > >> Don't want vendors building products with it then screaming when it
> > >> gets rebuilt/reworked/scrapped.
> > >>
> > >
> > > Exactly.
> > 
> > +1 too
> > 
> > We need to build on this innovation while there is a path for kernel 
> > mainstream. The logic of using a staging is a good one.
> > 
> > Thomas,
> > 
> > can we open a staging folder into the DPDK like it is done into the kernel?
> 
> It's possible to create a staging directory if everybody agree.
> It is important to state in a README file or in the doc/ that
> there will be no guarantee (no stable ABI, no validation and can be dropped)
> and that it is a work in progress, a suggestion to discuss with the kernel
> community.
> 
> The kernel modules must clearly target an upstream integration.

Actually the examples directory has been used as a staging for ethtool and
lthread. We also have the crypto API which is still experimental.
So I think we must decide among these 3 solutions:
	- no special directory, just mark and document an experimental state
	- put only kcp/kdp in the staging directory
	- put kcp/kdp in staging and move other experimental libs here

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02 12:03                         ` Vincent JARDIN
@ 2016-03-02 22:51                           ` Jim Thompson
  0 siblings, 0 replies; 83+ messages in thread
From: Jim Thompson @ 2016-03-02 22:51 UTC (permalink / raw)
  To: Vincent JARDIN; +Cc: Avi Kivity, DPDK


> On Mar 2, 2016, at 6:03 AM, Vincent JARDIN <vincent.jardin@6wind.com> wrote:
> 
> Le 02/03/2016 11:51, Jim Thompson a écrit :
>> Can we take it as a requirement to support FreeBSD this time around?
> 
> Of course, all OS should be on the loop, but I guess, it would be per kernel specific. What is ethtool on FreeBSD?

Ifconfig

> Or can you start porting ethtool on FreeBSD?

With netlink?  Hmm. 

I'm more interested in what kni (or its replacement) provides for an interface in/out  of the kernel stack ("slow path") on FreeBSD. 

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02 22:35                         ` Thomas Monjalon
@ 2016-03-03  8:31                           ` Panu Matilainen
  2016-03-03 10:05                             ` Ferruh Yigit
  2016-03-10  0:04                           ` Thomas Monjalon
  1 sibling, 1 reply; 83+ messages in thread
From: Panu Matilainen @ 2016-03-03  8:31 UTC (permalink / raw)
  To: Thomas Monjalon, Vincent JARDIN; +Cc: dev, Avi Kivity

On 03/03/2016 12:35 AM, Thomas Monjalon wrote:
> 2016-03-02 12:21, Thomas Monjalon:
>> 2016-03-02 11:47, Vincent JARDIN:
>>> Le 02/03/2016 09:27, Panu Matilainen a écrit :
>>>>>> I'd like to see these be merged.
>>>>>>
>>>>>> Jay
>>>>>
>>>>> The code is really not ready. I am okay with cooperative development
>>>>> but the current code needs to go into a staging type tree.
>>>>> No compatibility, no ABI guarantees, more of an RFC.
>>>>> Don't want vendors building products with it then screaming when it
>>>>> gets rebuilt/reworked/scrapped.
>>>>>
>>>>
>>>> Exactly.
>>>
>>> +1 too
>>>
>>> We need to build on this innovation while there is a path for kernel
>>> mainstream. The logic of using a staging is a good one.
>>>
>>> Thomas,
>>>
>>> can we open a staging folder into the DPDK like it is done into the kernel?
>>
>> It's possible to create a staging directory if everybody agree.
>> It is important to state in a README file or in the doc/ that
>> there will be no guarantee (no stable ABI, no validation and can be dropped)
>> and that it is a work in progress, a suggestion to discuss with the kernel
>> community.
>>
>> The kernel modules must clearly target an upstream integration.
>
> Actually the examples directory has been used as a staging for ethtool and
> lthread. We also have the crypto API which is still experimental.
> So I think we must decide among these 3 solutions:
> 	- no special directory, just mark and document an experimental state
> 	- put only kcp/kdp in the staging directory
> 	- put kcp/kdp in staging and move other experimental libs here

To answer this, I think we need to start by clarifying the kernel module 
situation. Quoting your from 
http://dpdk.org/ml/archives/dev/2016-January/032263.html:

> Sorry the kernel module party is over.
> One day, igb_uio will be removed.
> I suggest to make a first version without interrupt support
> and work with Linux community to fix your issues.

This to me reads "no more out-of-tree kernel modules, period" but here 
we are discussing the fate of another one.

If the policy truly is "no more kernel modules" (which I would fully 
back and applaud) then I think there's little to discuss - if the 
destination is kernel upstream then why should the modules pass through 
the dpdk codebase? Put it in another repo on dpdk.org, advertise it, 
make testing it as easy as possible and all (like have it integrate with 
dpdk makefiles if needed) instead.

The difference with crypto API and ethtool is different in that the 
destination for them clearly is dpdk itself. I would like to see 
experimental code moved to a separate (staging or whatever) directory 
(or a repo/git submodule) to make the situation absolutely clear. Or a 
repo/git submodule or such. I also still think experimental features 
should not be enabled by default in the configs, no other project that I 
know of does that, but that's another discussion.

	- Panu -

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-03  8:31                           ` Panu Matilainen
@ 2016-03-03 10:05                             ` Ferruh Yigit
  2016-03-03 10:11                               ` Thomas Monjalon
  2016-03-03 10:51                               ` Panu Matilainen
  0 siblings, 2 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-03 10:05 UTC (permalink / raw)
  To: Panu Matilainen, Thomas Monjalon, Vincent JARDIN; +Cc: dev, Avi Kivity

On 3/3/2016 8:31 AM, Panu Matilainen wrote:
> On 03/03/2016 12:35 AM, Thomas Monjalon wrote:
>> 2016-03-02 12:21, Thomas Monjalon:
>>> 2016-03-02 11:47, Vincent JARDIN:
>>>> Le 02/03/2016 09:27, Panu Matilainen a écrit :
>>>>>>> I'd like to see these be merged.
>>>>>>>
>>>>>>> Jay
>>>>>>
>>>>>> The code is really not ready. I am okay with cooperative development
>>>>>> but the current code needs to go into a staging type tree.
>>>>>> No compatibility, no ABI guarantees, more of an RFC.
>>>>>> Don't want vendors building products with it then screaming when it
>>>>>> gets rebuilt/reworked/scrapped.
>>>>>>
>>>>>
>>>>> Exactly.
>>>>
>>>> +1 too
>>>>
>>>> We need to build on this innovation while there is a path for kernel
>>>> mainstream. The logic of using a staging is a good one.
>>>>
>>>> Thomas,
>>>>
>>>> can we open a staging folder into the DPDK like it is done into the
>>>> kernel?
>>>
>>> It's possible to create a staging directory if everybody agree.
>>> It is important to state in a README file or in the doc/ that
>>> there will be no guarantee (no stable ABI, no validation and can be
>>> dropped)
>>> and that it is a work in progress, a suggestion to discuss with the
>>> kernel
>>> community.
>>>
>>> The kernel modules must clearly target an upstream integration.
>>
>> Actually the examples directory has been used as a staging for ethtool
>> and
>> lthread. We also have the crypto API which is still experimental.
>> So I think we must decide among these 3 solutions:
>>     - no special directory, just mark and document an experimental state
>>     - put only kcp/kdp in the staging directory
>>     - put kcp/kdp in staging and move other experimental libs here
> 
> To answer this, I think we need to start by clarifying the kernel module
> situation. Quoting your from
> http://dpdk.org/ml/archives/dev/2016-January/032263.html:
> 
>> Sorry the kernel module party is over.
>> One day, igb_uio will be removed.
>> I suggest to make a first version without interrupt support
>> and work with Linux community to fix your issues.
> 
> This to me reads "no more out-of-tree kernel modules, period" but here
> we are discussing the fate of another one.
> 
> If the policy truly is "no more kernel modules" (which I would fully
> back and applaud) then I think there's little to discuss - if the
> destination is kernel upstream then why should the modules pass through
> the dpdk codebase? Put it in another repo on dpdk.org, advertise it,
> make testing it as easy as possible and all (like have it integrate with
> dpdk makefiles if needed) instead.
> 
Hi Panu,

I just want to remind that these modules are to replace existing KNI
kernel module, and to reduce it's maintenance cost.
We are not adding new kernel modules for new features.

I believe replacing KNI module with new code in DPDK is a required
improvement step. But to replace, KNI users should verify the new codes.

Going directly from KNI to Linux upstream, if possible, is not easy.
Upstreaming should be done in incremental steps.

How about following steps:
1- Add KCP/KDP with an EXPERIMENTAL flag.
2- When they are mature enough, remove KNI, remove EXPERIMENTAL from
KCP/KDP.
3- Work on upstreaming

Thanks,
ferruh

> The difference with crypto API and ethtool is different in that the
> destination for them clearly is dpdk itself. I would like to see
> experimental code moved to a separate (staging or whatever) directory
> (or a repo/git submodule) to make the situation absolutely clear. Or a
> repo/git submodule or such. I also still think experimental features
> should not be enabled by default in the configs, no other project that I
> know of does that, but that's another discussion.
> 
>     - Panu -

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-03 10:05                             ` Ferruh Yigit
@ 2016-03-03 10:11                               ` Thomas Monjalon
  2016-03-03 10:51                               ` Panu Matilainen
  1 sibling, 0 replies; 83+ messages in thread
From: Thomas Monjalon @ 2016-03-03 10:11 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: dev, Avi Kivity

2016-03-03 10:05, Ferruh Yigit:
> On 3/3/2016 8:31 AM, Panu Matilainen wrote:
> > On 03/03/2016 12:35 AM, Thomas Monjalon wrote:
> >> 2016-03-02 12:21, Thomas Monjalon:
> >>> 2016-03-02 11:47, Vincent JARDIN:
> >>>> Le 02/03/2016 09:27, Panu Matilainen a écrit :
> >>>>>>> I'd like to see these be merged.
> >>>>>>>
> >>>>>>> Jay
> >>>>>>
> >>>>>> The code is really not ready. I am okay with cooperative development
> >>>>>> but the current code needs to go into a staging type tree.
> >>>>>> No compatibility, no ABI guarantees, more of an RFC.
> >>>>>> Don't want vendors building products with it then screaming when it
> >>>>>> gets rebuilt/reworked/scrapped.
> >>>>>>
> >>>>>
> >>>>> Exactly.
> >>>>
> >>>> +1 too
> >>>>
> >>>> We need to build on this innovation while there is a path for kernel
> >>>> mainstream. The logic of using a staging is a good one.
> >>>>
> >>>> Thomas,
> >>>>
> >>>> can we open a staging folder into the DPDK like it is done into the
> >>>> kernel?
> >>>
> >>> It's possible to create a staging directory if everybody agree.
> >>> It is important to state in a README file or in the doc/ that
> >>> there will be no guarantee (no stable ABI, no validation and can be
> >>> dropped)
> >>> and that it is a work in progress, a suggestion to discuss with the
> >>> kernel
> >>> community.
> >>>
> >>> The kernel modules must clearly target an upstream integration.
> >>
> >> Actually the examples directory has been used as a staging for ethtool
> >> and
> >> lthread. We also have the crypto API which is still experimental.
> >> So I think we must decide among these 3 solutions:
> >>     - no special directory, just mark and document an experimental state
> >>     - put only kcp/kdp in the staging directory
> >>     - put kcp/kdp in staging and move other experimental libs here
> > 
> > To answer this, I think we need to start by clarifying the kernel module
> > situation. Quoting your from
> > http://dpdk.org/ml/archives/dev/2016-January/032263.html:
> > 
> >> Sorry the kernel module party is over.
> >> One day, igb_uio will be removed.
> >> I suggest to make a first version without interrupt support
> >> and work with Linux community to fix your issues.
> > 
> > This to me reads "no more out-of-tree kernel modules, period" but here
> > we are discussing the fate of another one.
> > 
> > If the policy truly is "no more kernel modules" (which I would fully
> > back and applaud) then I think there's little to discuss - if the
> > destination is kernel upstream then why should the modules pass through
> > the dpdk codebase? Put it in another repo on dpdk.org, advertise it,
> > make testing it as easy as possible and all (like have it integrate with
> > dpdk makefiles if needed) instead.
> > 
> Hi Panu,
> 
> I just want to remind that these modules are to replace existing KNI
> kernel module, and to reduce it's maintenance cost.
> We are not adding new kernel modules for new features.
> 
> I believe replacing KNI module with new code in DPDK is a required
> improvement step. But to replace, KNI users should verify the new codes.
> 
> Going directly from KNI to Linux upstream, if possible, is not easy.
> Upstreaming should be done in incremental steps.
> 
> How about following steps:
> 1- Add KCP/KDP with an EXPERIMENTAL flag.
> 2- When they are mature enough, remove KNI, remove EXPERIMENTAL from
> KCP/KDP.
> 3- Work on upstreaming

What about working with upstream early (step 3 before 2)?
KNI is not so nice but it was advertised and used.
If we want to advertise a replacement, it must be approved by upstream.
We need some stable and widely adopted interfaces to bring more confidence
in the project.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02 22:18                   ` Jay Rolette
@ 2016-03-03 10:11                     ` Ferruh Yigit
  2016-03-03 16:59                       ` Stephen Hemminger
  0 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-03 10:11 UTC (permalink / raw)
  To: Jay Rolette, Stephen Hemminger; +Cc: DPDK, Avi Kivity

On 3/2/2016 10:18 PM, Jay Rolette wrote:
> 
> On Tue, Mar 1, 2016 at 8:02 PM, Stephen Hemminger
> <stephen@networkplumber.org <mailto:stephen@networkplumber.org>> wrote:
> 
>     On Mon, 29 Feb 2016 08:33:25 -0600
>     Jay Rolette <rolette@infiniteio.com <mailto:rolette@infiniteio.com>>
>     wrote:
> 
>     > On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon
>     <thomas.monjalon@6wind.com <mailto:thomas.monjalon@6wind.com>>
>     > wrote:
>     >
>     > > Hi,
>     > > I totally agree with Avi's comments.
>     > > This topic is really important for the future of DPDK.
>     > > So I think we must give some time to continue the discussion
>     > > and have netdev involved in the choices done.
>     > > As a consequence, these series should not be merged in the
>     release 16.04.
>     > > Thanks for continuing the work.
>     > >
>     >
>     > I know you guys are very interested in getting rid of the out-of-tree
>     > drivers, but please do not block incremental improvements to DPDK
>     in the
>     > meantime. Ferruh's patch improves the usability of KNI. Don't
>     throw out
>     > good and useful enhancements just because it isn't where you want
>     to be in
>     > the end.
>     >
>     > I'd like to see these be merged.
>     >
>     > Jay
> 
>     The code is really not ready. I am okay with cooperative development
>     but the current code needs to go into a staging type tree.
>     No compatibility, no ABI guarantees, more of an RFC.
>     Don't want vendors building products with it then screaming when it
>     gets rebuilt/reworked/scrapped.
> 
> 
> That's fair. To be clear, it wasn't my intent for code that wasn't baked
> yet to be merged. 
> 
> The main point of my comment was that I think it is important not to
> halt incremental improvements to existing capabilities (KNI in this
> case) just because there are philosophical or directional changes that
> the community would like to make longer-term.
> 
> Bird in the hand vs. two in the bush...
> 

There are two different statements, first, code being not ready, I agree
a fair point (although there is no argument to that statement, it makes
hard to discuss this, I will put aside this), this implies when code is
ready it can go in to repo.

But not having kernel module, independent from their state against what
they are trying to replace is something else. And this won't help on KNI
related problems.

Thanks,
ferruh

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-03 10:05                             ` Ferruh Yigit
  2016-03-03 10:11                               ` Thomas Monjalon
@ 2016-03-03 10:51                               ` Panu Matilainen
  1 sibling, 0 replies; 83+ messages in thread
From: Panu Matilainen @ 2016-03-03 10:51 UTC (permalink / raw)
  To: Ferruh Yigit, Thomas Monjalon, Vincent JARDIN; +Cc: dev, Avi Kivity

On 03/03/2016 12:05 PM, Ferruh Yigit wrote:
> On 3/3/2016 8:31 AM, Panu Matilainen wrote:
>> On 03/03/2016 12:35 AM, Thomas Monjalon wrote:
>>> 2016-03-02 12:21, Thomas Monjalon:
>>>> 2016-03-02 11:47, Vincent JARDIN:
>>>>> Le 02/03/2016 09:27, Panu Matilainen a écrit :
>>>>>>>> I'd like to see these be merged.
>>>>>>>>
>>>>>>>> Jay
>>>>>>>
>>>>>>> The code is really not ready. I am okay with cooperative development
>>>>>>> but the current code needs to go into a staging type tree.
>>>>>>> No compatibility, no ABI guarantees, more of an RFC.
>>>>>>> Don't want vendors building products with it then screaming when it
>>>>>>> gets rebuilt/reworked/scrapped.
>>>>>>>
>>>>>>
>>>>>> Exactly.
>>>>>
>>>>> +1 too
>>>>>
>>>>> We need to build on this innovation while there is a path for kernel
>>>>> mainstream. The logic of using a staging is a good one.
>>>>>
>>>>> Thomas,
>>>>>
>>>>> can we open a staging folder into the DPDK like it is done into the
>>>>> kernel?
>>>>
>>>> It's possible to create a staging directory if everybody agree.
>>>> It is important to state in a README file or in the doc/ that
>>>> there will be no guarantee (no stable ABI, no validation and can be
>>>> dropped)
>>>> and that it is a work in progress, a suggestion to discuss with the
>>>> kernel
>>>> community.
>>>>
>>>> The kernel modules must clearly target an upstream integration.
>>>
>>> Actually the examples directory has been used as a staging for ethtool
>>> and
>>> lthread. We also have the crypto API which is still experimental.
>>> So I think we must decide among these 3 solutions:
>>>      - no special directory, just mark and document an experimental state
>>>      - put only kcp/kdp in the staging directory
>>>      - put kcp/kdp in staging and move other experimental libs here
>>
>> To answer this, I think we need to start by clarifying the kernel module
>> situation. Quoting your from
>> http://dpdk.org/ml/archives/dev/2016-January/032263.html:
>>
>>> Sorry the kernel module party is over.
>>> One day, igb_uio will be removed.
>>> I suggest to make a first version without interrupt support
>>> and work with Linux community to fix your issues.
>>
>> This to me reads "no more out-of-tree kernel modules, period" but here
>> we are discussing the fate of another one.
>>
>> If the policy truly is "no more kernel modules" (which I would fully
>> back and applaud) then I think there's little to discuss - if the
>> destination is kernel upstream then why should the modules pass through
>> the dpdk codebase? Put it in another repo on dpdk.org, advertise it,
>> make testing it as easy as possible and all (like have it integrate with
>> dpdk makefiles if needed) instead.
>>
> Hi Panu,
>
> I just want to remind that these modules are to replace existing KNI
> kernel module, and to reduce it's maintenance cost.
> We are not adding new kernel modules for new features.
>
> I believe replacing KNI module with new code in DPDK is a required
> improvement step. But to replace, KNI users should verify the new codes.
>
> Going directly from KNI to Linux upstream, if possible, is not easy.
> Upstreaming should be done in incremental steps.
>
> How about following steps:
> 1- Add KCP/KDP with an EXPERIMENTAL flag.
> 2- When they are mature enough, remove KNI, remove EXPERIMENTAL from
> KCP/KDP.
> 3- Work on upstreaming

And if upstream says no, as they just as well might? You're one step 
forward, two steps back.

You need to engage upstream NOW, as has been suggested in this thread 
several times already.

	- Panu -

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-03 10:11                     ` Ferruh Yigit
@ 2016-03-03 16:59                       ` Stephen Hemminger
  2016-03-03 18:18                         ` Ferruh Yigit
  0 siblings, 1 reply; 83+ messages in thread
From: Stephen Hemminger @ 2016-03-03 16:59 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: DPDK, Avi Kivity

On Thu, 3 Mar 2016 10:11:57 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> On 3/2/2016 10:18 PM, Jay Rolette wrote:
> > 
> > On Tue, Mar 1, 2016 at 8:02 PM, Stephen Hemminger
> > <stephen@networkplumber.org <mailto:stephen@networkplumber.org>> wrote:
> > 
> >     On Mon, 29 Feb 2016 08:33:25 -0600
> >     Jay Rolette <rolette@infiniteio.com <mailto:rolette@infiniteio.com>>
> >     wrote:
> > 
> >     > On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon
> >     <thomas.monjalon@6wind.com <mailto:thomas.monjalon@6wind.com>>
> >     > wrote:
> >     >
> >     > > Hi,
> >     > > I totally agree with Avi's comments.
> >     > > This topic is really important for the future of DPDK.
> >     > > So I think we must give some time to continue the discussion
> >     > > and have netdev involved in the choices done.
> >     > > As a consequence, these series should not be merged in the
> >     release 16.04.
> >     > > Thanks for continuing the work.
> >     > >
> >     >
> >     > I know you guys are very interested in getting rid of the out-of-tree
> >     > drivers, but please do not block incremental improvements to DPDK
> >     in the
> >     > meantime. Ferruh's patch improves the usability of KNI. Don't
> >     throw out
> >     > good and useful enhancements just because it isn't where you want
> >     to be in
> >     > the end.
> >     >
> >     > I'd like to see these be merged.
> >     >
> >     > Jay
> > 
> >     The code is really not ready. I am okay with cooperative development
> >     but the current code needs to go into a staging type tree.
> >     No compatibility, no ABI guarantees, more of an RFC.
> >     Don't want vendors building products with it then screaming when it
> >     gets rebuilt/reworked/scrapped.
> > 
> > 
> > That's fair. To be clear, it wasn't my intent for code that wasn't baked
> > yet to be merged. 
> > 
> > The main point of my comment was that I think it is important not to
> > halt incremental improvements to existing capabilities (KNI in this
> > case) just because there are philosophical or directional changes that
> > the community would like to make longer-term.
> > 
> > Bird in the hand vs. two in the bush...
> > 
> 
> There are two different statements, first, code being not ready, I agree
> a fair point (although there is no argument to that statement, it makes
> hard to discuss this, I will put aside this), this implies when code is
> ready it can go in to repo.
> 
> But not having kernel module, independent from their state against what
> they are trying to replace is something else. And this won't help on KNI
> related problems.
> 
> Thanks,
> ferruh
> 

Why not re-submit patches but put in lib/librte_eal/staging or similar path
and make sure that it does not get build by normal build process.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-03 16:59                       ` Stephen Hemminger
@ 2016-03-03 18:18                         ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-03 18:18 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: DPDK, Avi Kivity

On 3/3/2016 4:59 PM, Stephen Hemminger wrote:
> On Thu, 3 Mar 2016 10:11:57 +0000
> Ferruh Yigit <ferruh.yigit@intel.com> wrote:
> 
>> On 3/2/2016 10:18 PM, Jay Rolette wrote:
>>>
>>> On Tue, Mar 1, 2016 at 8:02 PM, Stephen Hemminger
>>> <stephen@networkplumber.org <mailto:stephen@networkplumber.org>> wrote:
>>>
>>>     On Mon, 29 Feb 2016 08:33:25 -0600
>>>     Jay Rolette <rolette@infiniteio.com <mailto:rolette@infiniteio.com>>
>>>     wrote:
>>>
>>>     > On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon
>>>     <thomas.monjalon@6wind.com <mailto:thomas.monjalon@6wind.com>>
>>>     > wrote:
>>>     >
>>>     > > Hi,
>>>     > > I totally agree with Avi's comments.
>>>     > > This topic is really important for the future of DPDK.
>>>     > > So I think we must give some time to continue the discussion
>>>     > > and have netdev involved in the choices done.
>>>     > > As a consequence, these series should not be merged in the
>>>     release 16.04.
>>>     > > Thanks for continuing the work.
>>>     > >
>>>     >
>>>     > I know you guys are very interested in getting rid of the out-of-tree
>>>     > drivers, but please do not block incremental improvements to DPDK
>>>     in the
>>>     > meantime. Ferruh's patch improves the usability of KNI. Don't
>>>     throw out
>>>     > good and useful enhancements just because it isn't where you want
>>>     to be in
>>>     > the end.
>>>     >
>>>     > I'd like to see these be merged.
>>>     >
>>>     > Jay
>>>
>>>     The code is really not ready. I am okay with cooperative development
>>>     but the current code needs to go into a staging type tree.
>>>     No compatibility, no ABI guarantees, more of an RFC.
>>>     Don't want vendors building products with it then screaming when it
>>>     gets rebuilt/reworked/scrapped.
>>>
>>>
>>> That's fair. To be clear, it wasn't my intent for code that wasn't baked
>>> yet to be merged. 
>>>
>>> The main point of my comment was that I think it is important not to
>>> halt incremental improvements to existing capabilities (KNI in this
>>> case) just because there are philosophical or directional changes that
>>> the community would like to make longer-term.
>>>
>>> Bird in the hand vs. two in the bush...
>>>
>>
>> There are two different statements, first, code being not ready, I agree
>> a fair point (although there is no argument to that statement, it makes
>> hard to discuss this, I will put aside this), this implies when code is
>> ready it can go in to repo.
>>
>> But not having kernel module, independent from their state against what
>> they are trying to replace is something else. And this won't help on KNI
>> related problems.
>>
>> Thanks,
>> ferruh
>>
> 
> Why not re-submit patches but put in lib/librte_eal/staging or similar path
> and make sure that it does not get build by normal build process.
> 
I will do when staging is ready/defined.

Also will start working on upstreaming modules.

Thanks,
ferruh

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

* [PATCH v5 0/4] Use common Linux tools to control DPDK ports
  2016-03-01 15:41     ` [PATCH v4 " Ferruh Yigit
                         ` (3 preceding siblings ...)
  2016-03-01 15:42       ` [PATCH v4 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
@ 2016-03-09 11:41       ` Ferruh Yigit
  2016-03-09 11:41         ` [PATCH v5 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
                           ` (4 more replies)
  4 siblings, 5 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-09 11:41 UTC (permalink / raw)
  To: dev

This patch sent to keep record of latest status of the work.


This work is to make DPDK ports more visible and to enable using common
Linux tools to configure DPDK ports.

Patch is based on KNI but contains only control functionality of it,
also this patch does not include any Linux kernel network driver as
part of it.

Basically with the help of a kernel module (KCP), virtual Linux network
interfaces named as "dpdk$" are created per DPDK port, control messages
sent to these virtual interfaces are forwarded to DPDK, and response
sent back to Linux application.

Virtual interfaces created when DPDK application started and destroyed
automatically when DPDK application terminated.

Communication between kernel-space and DPDK done using netlink socket.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

v5:
* Use unsigned primitive types as possible

v4:
* Kernel side changes:
  * Remove logging helper macros, use pr_fmt
  * Seperate log msg for timeout and error
* Control library changes:
  * Add ethtool_get_settings as dummy

v3:
* Kernel side changes:
  * Devices are not up by default
  * Add enable/disable promisc, allmulti support
  * Increase timeout to 500ms and print log when a command timedout
* Control library changes:
  * Use librte_ethtool
  * Don't create interfaces for virtual PMDs
  * Add a new API ...msg_exist() to support port based locking
  * Add enable/disable promisc, allmulti support
* Example changes:
  * Use blocking mode control interface processing, instead of poll mode

v2:
* Use rtnetlink to create interfaces
* Add more ethtool support: get/set ringparam, set pauseparam.
* fix ethtool get/set eeprom
* lots of minor updates, enhancements in the code


Samples:

$ ifconfig
dpdk0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::92e2:baff:fe0e:49b8  prefixlen 64  scopeid 0x20<link>
        ether 90:e2:ba:0e:49:b8  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

dpdk1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::21b:21ff:fe76:fa20  prefixlen 64  scopeid 0x20<link>
        ether 00:1b:21:76:fa:20  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

After some traffic on port 0:

$ ifconfig
dpdk0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::92e2:baff:fe0e:49b8  prefixlen 64  scopeid 0x20<link>
        ether 90:e2:ba:0e:49:b8  txqueuelen 1000  (Ethernet)
        RX packets 26117404  bytes 1671514264 (1.5 GiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 27897889  bytes 1785463944 (1.6 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


$ ethtool -i dpdk0
driver: rte_ixgbe_pmd
version: DPDK 16.04.0-rc0
firmware-version: 
expansion-rom-version: 
bus-info: 0000:08:00.0
supports-statistics: no
supports-test: no
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no


$ ethtool -e dpdk0 offset 20 length 10
Offset          Values
------          ------
0x0014:         b7 01 bf 01 c7 01 cf 01 09 02 


$ ip l show dpdk0
44: dpdk0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:b8 brd ff:ff:ff:ff:ff:ff

$ ip l set dpdk0 addr 90:e2:ba:0e:49:b9

$ ip l show dpdk0
44: dpdk0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 90:e2:ba:0e:49:b9 brd ff:ff:ff:ff:ff:ff


Ferruh Yigit (4):
  lib/librte_ethtool: move librte_ethtool form examples to lib folder
  kcp: add kernel control path kernel module
  rte_ctrl_if: add control interface library
  examples/ethtool: add control interface support to the application

 MAINTAINERS                                        |   5 +
 config/common_base                                 |  12 +
 config/common_linuxapp                             |   3 +
 doc/api/doxy-api-index.md                          |   4 +-
 doc/api/doxy-api.conf                              |   2 +
 doc/api/examples.dox                               |   5 +-
 doc/guides/prog_guide/ctrl_if_lib.rst              |  52 ++
 doc/guides/prog_guide/ethtool_lib.rst              |  62 ++
 doc/guides/prog_guide/index.rst                    |   4 +-
 doc/guides/rel_notes/release_16_04.rst             |   9 +
 doc/guides/sample_app_ug/ethtool.rst               |  77 +-
 examples/ethtool/Makefile                          |  24 +-
 examples/ethtool/ethapp.c                          | 873 +++++++++++++++++++++
 examples/ethtool/ethapp.h                          |  41 +
 examples/ethtool/ethtool-app/Makefile              |  54 --
 examples/ethtool/ethtool-app/ethapp.c              | 873 ---------------------
 examples/ethtool/ethtool-app/ethapp.h              |  41 -
 examples/ethtool/ethtool-app/main.c                | 305 -------
 examples/ethtool/lib/Makefile                      |  57 --
 examples/ethtool/lib/rte_ethtool.c                 | 423 ----------
 examples/ethtool/lib/rte_ethtool.h                 | 410 ----------
 examples/ethtool/main.c                            | 332 ++++++++
 lib/Makefile                                       |   4 +-
 lib/librte_ctrl_if/Makefile                        |  58 ++
 lib/librte_ctrl_if/rte_ctrl_ethtool.c              | 391 +++++++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.h              |  54 ++
 lib/librte_ctrl_if/rte_ctrl_if.c                   | 395 ++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h                   | 129 +++
 lib/librte_ctrl_if/rte_ctrl_if_version.map         |  10 +
 lib/librte_ctrl_if/rte_nl.c                        | 313 ++++++++
 lib/librte_ctrl_if/rte_nl.h                        |  50 ++
 lib/librte_eal/common/include/rte_log.h            |   3 +-
 lib/librte_eal/linuxapp/Makefile                   |   3 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h | 109 +++
 lib/librte_eal/linuxapp/kcp/Makefile               |  57 ++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  56 ++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 293 +++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 219 ++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 220 ++++++
 lib/librte_ethtool/Makefile                        |  57 ++
 lib/librte_ethtool/rte_ethtool.c                   | 423 ++++++++++
 lib/librte_ethtool/rte_ethtool.h                   | 413 ++++++++++
 lib/librte_ethtool/rte_ethtool_version.map         |  28 +
 mk/rte.app.mk                                      |   4 +-
 45 files changed, 4746 insertions(+), 2214 deletions(-)
 create mode 100644 doc/guides/prog_guide/ctrl_if_lib.rst
 create mode 100644 doc/guides/prog_guide/ethtool_lib.rst
 create mode 100644 examples/ethtool/ethapp.c
 create mode 100644 examples/ethtool/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/Makefile
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.c
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/main.c
 delete mode 100644 examples/ethtool/lib/Makefile
 delete mode 100644 examples/ethtool/lib/rte_ethtool.c
 delete mode 100644 examples/ethtool/lib/rte_ethtool.h
 create mode 100644 examples/ethtool/main.c
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c
 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.5.0

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

* [PATCH v5 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder
  2016-03-09 11:41       ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
@ 2016-03-09 11:41         ` Ferruh Yigit
  2016-03-09 11:41         ` [PATCH v5 2/4] kcp: add kernel control path kernel module Ferruh Yigit
                           ` (3 subsequent siblings)
  4 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-09 11:41 UTC (permalink / raw)
  To: dev

With KCP, examples/ethtool/lib/ethtool has two users, to prevent code
dublication, moving library from examples folder into lib/ folder.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

v4, v5:
* No update
---
 config/common_base                         |   5 +
 config/common_linuxapp                     |   1 +
 doc/api/doxy-api-index.md                  |   3 +-
 doc/api/doxy-api.conf                      |   1 +
 doc/api/examples.dox                       |   5 +-
 doc/guides/prog_guide/ethtool_lib.rst      |  62 ++
 doc/guides/prog_guide/index.rst            |   3 +-
 doc/guides/rel_notes/release_16_04.rst     |   1 +
 doc/guides/sample_app_ug/ethtool.rst       |  36 +-
 examples/ethtool/Makefile                  |  24 +-
 examples/ethtool/ethapp.c                  | 873 +++++++++++++++++++++++++++++
 examples/ethtool/ethapp.h                  |  41 ++
 examples/ethtool/ethtool-app/Makefile      |  54 --
 examples/ethtool/ethtool-app/ethapp.c      | 873 -----------------------------
 examples/ethtool/ethtool-app/ethapp.h      |  41 --
 examples/ethtool/ethtool-app/main.c        | 305 ----------
 examples/ethtool/lib/Makefile              |  57 --
 examples/ethtool/lib/rte_ethtool.c         | 423 --------------
 examples/ethtool/lib/rte_ethtool.h         | 410 --------------
 examples/ethtool/main.c                    | 305 ++++++++++
 lib/Makefile                               |   1 +
 lib/librte_ethtool/Makefile                |  57 ++
 lib/librte_ethtool/rte_ethtool.c           | 423 ++++++++++++++
 lib/librte_ethtool/rte_ethtool.h           | 413 ++++++++++++++
 lib/librte_ethtool/rte_ethtool_version.map |  28 +
 mk/rte.app.mk                              |   1 +
 26 files changed, 2237 insertions(+), 2209 deletions(-)
 create mode 100644 doc/guides/prog_guide/ethtool_lib.rst
 create mode 100644 examples/ethtool/ethapp.c
 create mode 100644 examples/ethtool/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/Makefile
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.c
 delete mode 100644 examples/ethtool/ethtool-app/ethapp.h
 delete mode 100644 examples/ethtool/ethtool-app/main.c
 delete mode 100644 examples/ethtool/lib/Makefile
 delete mode 100644 examples/ethtool/lib/rte_ethtool.c
 delete mode 100644 examples/ethtool/lib/rte_ethtool.h
 create mode 100644 examples/ethtool/main.c
 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/config/common_base b/config/common_base
index c73f71a..70343ae 100644
--- a/config/common_base
+++ b/config/common_base
@@ -485,6 +485,11 @@ CONFIG_RTE_KNI_VHOST_DEBUG_RX=n
 CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 
 #
+# Compile librte_ethtool
+#
+CONFIG_RTE_LIBRTE_ETHTOOL=n
+
+#
 # Compile vhost library
 # fuse-devel is needed to run vhost-cuse.
 # fuse-devel enables user space char driver development
diff --git a/config/common_linuxapp b/config/common_linuxapp
index ffbe260..6d42070 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -39,6 +39,7 @@ CONFIG_RTE_EAL_IGB_UIO=y
 CONFIG_RTE_EAL_VFIO=y
 CONFIG_RTE_KNI_KMOD=y
 CONFIG_RTE_LIBRTE_KNI=y
+CONFIG_RTE_LIBRTE_ETHTOOL=y
 CONFIG_RTE_LIBRTE_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_POWER=y
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 7a91001..4cdd3f5 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -149,4 +149,5 @@ There are many libraries, so their headers may be grouped by topics:
   [common]             (@ref rte_common.h),
   [ABI compat]         (@ref rte_compat.h),
   [keepalive]          (@ref rte_keepalive.h),
-  [version]            (@ref rte_version.h)
+  [version]            (@ref rte_version.h),
+  [ethtool]            (@ref rte_ethtool.h),
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index 57e8b5d..c5b8615 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -41,6 +41,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_cryptodev \
                           lib/librte_distributor \
                           lib/librte_ether \
+                          lib/librte_ethtool \
                           lib/librte_hash \
                           lib/librte_ip_frag \
                           lib/librte_ivshmem \
diff --git a/doc/api/examples.dox b/doc/api/examples.dox
index 200af0b..8763d77 100644
--- a/doc/api/examples.dox
+++ b/doc/api/examples.dox
@@ -8,9 +8,8 @@
 @example distributor/main.c
 @example dpdk_qat/crypto.c
 @example dpdk_qat/main.c
-@example ethtool/ethtool-app/ethapp.c
-@example ethtool/ethtool-app/main.c
-@example ethtool/lib/rte_ethtool.c
+@example ethtool/ethapp.c
+@example ethtool/main.c
 @example exception_path/main.c
 @example helloworld/main.c
 @example ip_fragmentation/main.c
diff --git a/doc/guides/prog_guide/ethtool_lib.rst b/doc/guides/prog_guide/ethtool_lib.rst
new file mode 100644
index 0000000..e161cd0
--- /dev/null
+++ b/doc/guides/prog_guide/ethtool_lib.rst
@@ -0,0 +1,62 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+.. _Ethtool_Library:
+
+Ethtool Library
+===============
+
+Ethtool interface
+-----------------
+
+The Ethtool interface is built as a separate library, and implements
+the following functions:
+
+- ``rte_ethtool_get_drvinfo()``
+- ``rte_ethtool_get_regs_len()``
+- ``rte_ethtool_get_regs()``
+- ``rte_ethtool_get_link()``
+- ``rte_ethtool_get_eeprom_len()``
+- ``rte_ethtool_get_eeprom()``
+- ``rte_ethtool_set_eeprom()``
+- ``rte_ethtool_get_pauseparam()``
+- ``rte_ethtool_set_pauseparam()``
+- ``rte_ethtool_net_open()``
+- ``rte_ethtool_net_stop()``
+- ``rte_ethtool_net_get_mac_addr()``
+- ``rte_ethtool_net_set_mac_addr()``
+- ``rte_ethtool_net_validate_addr()``
+- ``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_net_set_rx_mode()``
+- ``rte_ethtool_get_ringparam()``
+- ``rte_ethtool_set_ringparam()``
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index a9404fb..98f4aca 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -1,5 +1,5 @@
 ..  BSD LICENSE
-    Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+    Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
     All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,7 @@ Programmer's Guide
     packet_distrib_lib
     reorder_lib
     ip_fragment_reassembly_lib
+    ethtool_lib
     multi_proc_support
     kernel_nic_interface
     thread_safety_dpdk_functions
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 96f144e..a07c292 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -164,6 +164,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_cmdline.so.1
      librte_distributor.so.1
      librte_eal.so.2
+   + librte_ethtool.so.1
      librte_hash.so.2
      librte_ip_frag.so.1
      librte_ivshmem.so.1
diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
index 4d1697e..65240ae 100644
--- a/doc/guides/sample_app_ug/ethtool.rst
+++ b/doc/guides/sample_app_ug/ethtool.rst
@@ -1,6 +1,6 @@
 
 ..  BSD LICENSE
-    Copyright(c) 2015 Intel Corporation. All rights reserved.
+    Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
     All rights reserved.
 
     Redistribution and use in source and binary forms, with or without
@@ -71,7 +71,7 @@ The only available options are the standard ones for the EAL:
 
 .. code-block:: console
 
-    ./ethtool-app/ethtool-app/${RTE_TARGET}/ethtool [EAL options]
+    ./${RTE_TARGET}/ethtool [EAL options]
 
 Refer to the *DPDK Getting Started Guide* for general information on
 running applications and the Environment Abstraction Layer (EAL)
@@ -128,33 +128,5 @@ Ethtool Shell
 The foreground part of the Ethtool sample is a console-based
 interface that accepts commands as described in `using the
 application`_. Individual call-back functions handle the detail
-associated with each command, which make use of the functions
-defined in the `Ethtool interface`_ to the DPDK functions.
-
-Ethtool interface
------------------
-
-The Ethtool interface is built as a separate library, and implements
-the following functions:
-
-- ``rte_ethtool_get_drvinfo()``
-- ``rte_ethtool_get_regs_len()``
-- ``rte_ethtool_get_regs()``
-- ``rte_ethtool_get_link()``
-- ``rte_ethtool_get_eeprom_len()``
-- ``rte_ethtool_get_eeprom()``
-- ``rte_ethtool_set_eeprom()``
-- ``rte_ethtool_get_pauseparam()``
-- ``rte_ethtool_set_pauseparam()``
-- ``rte_ethtool_net_open()``
-- ``rte_ethtool_net_stop()``
-- ``rte_ethtool_net_get_mac_addr()``
-- ``rte_ethtool_net_set_mac_addr()``
-- ``rte_ethtool_net_validate_addr()``
-- ``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_net_set_rx_mode()``
-- ``rte_ethtool_get_ringparam()``
-- ``rte_ethtool_set_ringparam()``
+associated with each command, which make use of librte_ethtool
+library.
diff --git a/examples/ethtool/Makefile b/examples/ethtool/Makefile
index 995cd25..23a6ffd 100644
--- a/examples/ethtool/Makefile
+++ b/examples/ethtool/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -33,17 +33,23 @@ ifeq ($(RTE_SDK),)
 $(error "Please define RTE_SDK environment variable")
 endif
 
-# Default target, can be overwritten by command line or environment
+# Default target, can be overridden 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")
-$(info This application can only operate in a linuxapp environment, \
-please change the definition of the RTE_TARGET environment variable)
-else
+# binary name
+APP = ethtool
+
+# all source are stored in SRCS-y
+SRCS-y := main.c ethapp.c
+
+#CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#LDLIBS += -L$(subst ethtool-app,lib,$(RTE_OUTPUT))/lib
+#LDLIBS += -lrte_ethtool
 
-DIRS-y += lib ethtool-app
-endif
 
-include $(RTE_SDK)/mk/rte.extsubdir.mk
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/ethtool/ethapp.c b/examples/ethtool/ethapp.c
new file mode 100644
index 0000000..fca602b
--- /dev/null
+++ b/examples/ethtool/ethapp.c
@@ -0,0 +1,873 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015-2016 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 <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_etheraddr.h>
+#include <cmdline_socket.h>
+#include <cmdline.h>
+
+#include "rte_ethtool.h"
+#include "ethapp.h"
+
+#define EEPROM_DUMP_CHUNKSIZE 1024
+
+
+struct pcmd_get_params {
+	cmdline_fixed_string_t cmd;
+};
+struct pcmd_int_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+};
+struct pcmd_intstr_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	cmdline_fixed_string_t opt;
+};
+struct pcmd_intmac_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	struct ether_addr mac;
+};
+struct pcmd_str_params {
+	cmdline_fixed_string_t cmd;
+	cmdline_fixed_string_t opt;
+};
+struct pcmd_vlan_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	cmdline_fixed_string_t mode;
+	uint16_t vid;
+};
+struct pcmd_intintint_params {
+	cmdline_fixed_string_t cmd;
+	uint16_t port;
+	uint16_t tx;
+	uint16_t rx;
+};
+
+
+/* Parameter-less commands */
+cmdline_parse_token_string_t pcmd_quit_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "quit");
+cmdline_parse_token_string_t pcmd_stats_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "stats");
+cmdline_parse_token_string_t pcmd_drvinfo_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "drvinfo");
+cmdline_parse_token_string_t pcmd_link_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "link");
+
+/* Commands taking just port id */
+cmdline_parse_token_string_t pcmd_open_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "open");
+cmdline_parse_token_string_t pcmd_stop_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "stop");
+cmdline_parse_token_string_t pcmd_rxmode_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "rxmode");
+cmdline_parse_token_string_t pcmd_portstats_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "portstats");
+cmdline_parse_token_num_t pcmd_int_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_int_params, port, UINT16);
+
+/* Commands taking port id and string */
+cmdline_parse_token_string_t pcmd_eeprom_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "eeprom");
+cmdline_parse_token_string_t pcmd_mtu_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "mtu");
+cmdline_parse_token_string_t pcmd_regs_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "regs");
+
+cmdline_parse_token_num_t pcmd_intstr_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_intstr_token_opt =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, opt, NULL);
+
+/* Commands taking port id and a MAC address string */
+cmdline_parse_token_string_t pcmd_macaddr_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "macaddr");
+cmdline_parse_token_num_t pcmd_intmac_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intmac_params, port, UINT16);
+cmdline_parse_token_etheraddr_t pcmd_intmac_token_mac =
+	TOKEN_ETHERADDR_INITIALIZER(struct pcmd_intmac_params, mac);
+
+/* Command taking just a MAC address */
+cmdline_parse_token_string_t pcmd_validate_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "validate");
+
+
+/* Commands taking port id and two integers */
+cmdline_parse_token_string_t pcmd_ringparam_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intintint_params, cmd,
+		"ringparam");
+cmdline_parse_token_num_t pcmd_intintint_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, port, UINT16);
+cmdline_parse_token_num_t pcmd_intintint_token_tx =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, tx, UINT16);
+cmdline_parse_token_num_t pcmd_intintint_token_rx =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, rx, UINT16);
+
+
+/* Pause commands */
+cmdline_parse_token_string_t pcmd_pause_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "pause");
+cmdline_parse_token_num_t pcmd_pause_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_pause_token_opt =
+	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params,
+		opt, "all#tx#rx#none");
+
+/* VLAN commands */
+cmdline_parse_token_string_t pcmd_vlan_token_cmd =
+	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, cmd, "vlan");
+cmdline_parse_token_num_t pcmd_vlan_token_port =
+	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, port, UINT16);
+cmdline_parse_token_string_t pcmd_vlan_token_mode =
+	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, mode, "add#del");
+cmdline_parse_token_num_t pcmd_vlan_token_vid =
+	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, vid, UINT16);
+
+
+static void
+pcmd_quit_callback(__rte_unused void *ptr_params,
+	struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	cmdline_quit(ctx);
+}
+
+
+static void
+pcmd_drvinfo_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct ethtool_drvinfo info;
+	int id_port;
+
+	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
+		if (rte_ethtool_get_drvinfo(id_port, &info)) {
+			printf("Error getting info for port %i\n", id_port);
+			return;
+		}
+		printf("Port %i driver: %s (ver: %s)\n",
+			id_port, info.driver, info.version
+		      );
+	}
+}
+
+
+static void
+pcmd_link_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	int num_ports = rte_eth_dev_count();
+	int id_port, stat_port;
+
+	for (id_port = 0; id_port < num_ports; id_port++) {
+		if (!rte_eth_dev_is_valid_port(id_port))
+			continue;
+		stat_port = rte_ethtool_get_link(id_port);
+		switch (stat_port) {
+		case 0:
+			printf("Port %i: Down\n", id_port);
+			break;
+		case 1:
+			printf("Port %i: Up\n", id_port);
+			break;
+		default:
+			printf("Port %i: Error getting link status\n",
+				id_port
+				);
+			break;
+		}
+	}
+	printf("\n");
+}
+
+
+static void
+pcmd_regs_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int len_regs;
+	struct ethtool_regs regs;
+	unsigned char *buf_data;
+	FILE *fp_regs;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	len_regs = rte_ethtool_get_regs_len(params->port);
+	if (len_regs > 0) {
+		printf("Port %i: %i bytes\n", params->port, len_regs);
+		buf_data = malloc(len_regs);
+		if (buf_data == NULL) {
+			printf("Error allocating %i bytes for buffer\n",
+				len_regs);
+			return;
+		}
+		if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
+			fp_regs = fopen(params->opt, "wb");
+			if (fp_regs == NULL) {
+				printf("Error opening '%s' for writing\n",
+					params->opt);
+			} else {
+				if ((int)fwrite(buf_data,
+						1, len_regs,
+						fp_regs) != len_regs)
+					printf("Error writing '%s'\n",
+						params->opt);
+				fclose(fp_regs);
+			}
+		}
+		free(buf_data);
+	} else if (len_regs == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error getting registers\n", params->port);
+}
+
+
+static void
+pcmd_eeprom_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	struct ethtool_eeprom info_eeprom;
+	int len_eeprom;
+	int pos_eeprom;
+	int stat;
+	unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
+	FILE *fp_eeprom;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	len_eeprom = rte_ethtool_get_eeprom_len(params->port);
+	if (len_eeprom > 0) {
+		fp_eeprom = fopen(params->opt, "wb");
+		if (fp_eeprom == NULL) {
+			printf("Error opening '%s' for writing\n",
+				params->opt);
+			return;
+		}
+		printf("Total EEPROM length: %i bytes\n", len_eeprom);
+		info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
+		for (pos_eeprom = 0;
+				pos_eeprom < len_eeprom;
+				pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
+			info_eeprom.offset = pos_eeprom;
+			if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
+				info_eeprom.len = len_eeprom - pos_eeprom;
+			else
+				info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
+			stat = rte_ethtool_get_eeprom(
+				params->port, &info_eeprom, bytes_eeprom
+				);
+			if (stat != 0) {
+				printf("EEPROM read error %i\n", stat);
+				break;
+			}
+			if (fwrite(bytes_eeprom,
+					1, info_eeprom.len,
+					fp_eeprom) != info_eeprom.len) {
+				printf("Error writing '%s'\n", params->opt);
+				break;
+			}
+		}
+		fclose(fp_eeprom);
+	} else if (len_eeprom == 0)
+		printf("Port %i: Device does not have EEPROM\n", params->port);
+	else if (len_eeprom == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error getting EEPROM\n", params->port);
+}
+
+
+static void
+pcmd_pause_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	struct ethtool_pauseparam info;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data != NULL) {
+		stat = rte_ethtool_get_pauseparam(params->port, &info);
+	} else {
+		memset(&info, 0, sizeof(info));
+		if (strcasecmp("all", params->opt) == 0) {
+			info.tx_pause = 1;
+			info.rx_pause = 1;
+		} else if (strcasecmp("tx", params->opt) == 0) {
+			info.tx_pause = 1;
+			info.rx_pause = 0;
+		} else if (strcasecmp("rx", params->opt) == 0) {
+			info.tx_pause = 0;
+			info.rx_pause = 1;
+		} else {
+			info.tx_pause = 0;
+			info.rx_pause = 0;
+		}
+		/* Assume auto-negotiation wanted */
+		info.autoneg = 1;
+		stat = rte_ethtool_set_pauseparam(params->port, &info);
+	}
+	if (stat == 0) {
+		if (info.rx_pause && info.tx_pause)
+			printf("Port %i: Tx & Rx Paused\n", params->port);
+		else if (info.rx_pause)
+			printf("Port %i: Rx Paused\n", params->port);
+		else if (info.tx_pause)
+			printf("Port %i: Tx Paused\n", params->port);
+		else
+			printf("Port %i: Tx & Rx not paused\n", params->port);
+	} else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error %i\n", params->port, stat);
+}
+
+
+static void
+pcmd_open_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	lock_port(params->port);
+	stat = rte_ethtool_net_open(params->port);
+	mark_port_active(params->port);
+	unlock_port(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error opening device\n", params->port);
+}
+
+static void
+pcmd_stop_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	lock_port(params->port);
+	stat = rte_ethtool_net_stop(params->port);
+	mark_port_inactive(params->port);
+	unlock_port(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error stopping device\n", params->port);
+}
+
+
+static void
+pcmd_rxmode_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_set_rx_mode(params->port);
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error setting rx mode\n", params->port);
+}
+
+
+static void
+pcmd_macaddr_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intmac_params *params = ptr_params;
+	struct ether_addr mac_addr;
+	int stat;
+
+	stat = 0;
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data != NULL) {
+		lock_port(params->port);
+		stat = rte_ethtool_net_set_mac_addr(params->port,
+			&params->mac);
+		mark_port_newmac(params->port);
+		unlock_port(params->port);
+		if (stat == 0) {
+			printf("MAC address changed\n");
+			return;
+		}
+	} else {
+		stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
+		if (stat == 0) {
+			printf(
+				"Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+				params->port,
+				mac_addr.addr_bytes[0],
+				mac_addr.addr_bytes[1],
+				mac_addr.addr_bytes[2],
+				mac_addr.addr_bytes[3],
+				mac_addr.addr_bytes[4],
+				mac_addr.addr_bytes[5]);
+			return;
+		}
+	}
+
+	printf("Port %i: Error %s\n", params->port,
+	       strerror(-stat));
+}
+
+static void
+pcmd_mtu_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intstr_params *params = ptr_params;
+	int stat;
+	int new_mtu;
+	char *ptr_parse_end;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	new_mtu = atoi(params->opt);
+	new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
+	if (*ptr_parse_end != '\0' ||
+			new_mtu < ETHER_MIN_MTU ||
+			new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
+		printf("Port %i: Invalid MTU value\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
+	if (stat == 0)
+		printf("Port %i: MTU set to %i\n", params->port, new_mtu);
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error setting MTU\n", params->port);
+}
+
+
+
+static void pcmd_portstats_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_int_params *params = ptr_params;
+	struct rte_eth_stats stat_info;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
+	if (stat == 0) {
+		/* Most of rte_eth_stats is deprecated.. */
+		printf("Port %i stats\n", params->port);
+		printf("   In: %" PRIu64 " (%" PRIu64 " bytes)\n"
+			"  Out: %"PRIu64" (%"PRIu64 " bytes)\n"
+			"  Err: %"PRIu64"\n",
+			stat_info.ipackets,
+			stat_info.ibytes,
+			stat_info.opackets,
+			stat_info.obytes,
+			stat_info.ierrors+stat_info.oerrors
+		      );
+	} else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error fetching statistics\n", params->port);
+}
+
+static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	void *ptr_data)
+{
+	struct pcmd_intintint_params *params = ptr_params;
+	struct ethtool_ringparam ring_data;
+	struct ethtool_ringparam ring_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	if (ptr_data == NULL) {
+		stat = rte_ethtool_get_ringparam(params->port, &ring_data);
+		if (stat == 0) {
+			printf("Port %i ring parameters\n"
+				"  Rx Pending: %i (%i max)\n"
+				"  Tx Pending: %i (%i max)\n",
+				params->port,
+				ring_data.rx_pending,
+				ring_data.rx_max_pending,
+				ring_data.tx_pending,
+				ring_data.tx_max_pending);
+		}
+	} else {
+		if (params->tx < 1 || params->rx < 1) {
+			printf("Error: Invalid parameters\n");
+			return;
+		}
+		memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
+		ring_params.tx_pending = params->tx;
+		ring_params.rx_pending = params->rx;
+		lock_port(params->port);
+		stat = rte_ethtool_set_ringparam(params->port, &ring_params);
+		unlock_port(params->port);
+	}
+	if (stat == 0)
+		return;
+	else if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else
+		printf("Port %i: Error fetching statistics\n", params->port);
+}
+
+static void pcmd_validate_callback(void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_intmac_params *params = ptr_params;
+
+	if (rte_ethtool_net_validate_addr(0, &params->mac))
+		printf("Address is unicast\n");
+	else
+		printf("Address is not unicast\n");
+}
+
+
+static void pcmd_vlan_callback(__rte_unused void *ptr_params,
+	__rte_unused struct cmdline *ctx,
+	__rte_unused void *ptr_data)
+{
+	struct pcmd_vlan_params *params = ptr_params;
+	int stat;
+
+	if (!rte_eth_dev_is_valid_port(params->port)) {
+		printf("Error: Invalid port number %i\n", params->port);
+		return;
+	}
+	stat = 0;
+
+	if (strcasecmp("add", params->mode) == 0) {
+		stat = rte_ethtool_net_vlan_rx_add_vid(
+			params->port, params->vid
+			);
+		if (stat == 0)
+			printf("VLAN vid %i added\n", params->vid);
+
+	} else if (strcasecmp("del", params->mode) == 0) {
+		stat = rte_ethtool_net_vlan_rx_kill_vid(
+			params->port, params->vid
+			);
+		if (stat == 0)
+			printf("VLAN vid %i removed\n", params->vid);
+	} else {
+		/* Should not happen! */
+		printf("Error: Bad mode %s\n", params->mode);
+	}
+	if (stat == -ENOTSUP)
+		printf("Port %i: Operation not supported\n", params->port);
+	else if (stat == -ENOSYS)
+		printf("Port %i: VLAN filtering disabled\n", params->port);
+	else if (stat != 0)
+		printf("Port %i: Error changing VLAN setup (code %i)\n",
+			params->port, -stat);
+}
+
+
+cmdline_parse_inst_t pcmd_quit = {
+	.f = pcmd_quit_callback,
+	.data = NULL,
+	.help_str = "quit\n     Exit program",
+	.tokens = {(void *)&pcmd_quit_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_drvinfo = {
+	.f = pcmd_drvinfo_callback,
+	.data = NULL,
+	.help_str = "drvinfo\n     Print driver info",
+	.tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_link = {
+	.f = pcmd_link_callback,
+	.data = NULL,
+	.help_str = "link\n     Print port link states",
+	.tokens = {(void *)&pcmd_link_token_cmd, NULL},
+};
+cmdline_parse_inst_t pcmd_regs = {
+	.f = pcmd_regs_callback,
+	.data = NULL,
+	.help_str = "regs <port_id> <filename>\n"
+		"     Dump port register(s) to file",
+	.tokens = {
+		(void *)&pcmd_regs_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_eeprom = {
+	.f = pcmd_eeprom_callback,
+	.data = NULL,
+	.help_str = "eeprom <port_id> <filename>\n    Dump EEPROM to file",
+	.tokens = {
+		(void *)&pcmd_eeprom_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_pause_noopt = {
+	.f = pcmd_pause_callback,
+	.data = (void *)0x01,
+	.help_str = "pause <port_id>\n     Print port pause state",
+	.tokens = {
+		(void *)&pcmd_pause_token_cmd,
+		(void *)&pcmd_pause_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_pause = {
+	.f = pcmd_pause_callback,
+	.data = NULL,
+	.help_str =
+		"pause <port_id> <all|tx|rx|none>\n     Pause/unpause port",
+	.tokens = {
+		(void *)&pcmd_pause_token_cmd,
+		(void *)&pcmd_pause_token_port,
+		(void *)&pcmd_pause_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_open = {
+	.f = pcmd_open_callback,
+	.data = NULL,
+	.help_str = "open <port_id>\n     Open port",
+	.tokens = {
+		(void *)&pcmd_open_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_stop = {
+	.f = pcmd_stop_callback,
+	.data = NULL,
+	.help_str = "stop <port_id>\n     Stop port",
+	.tokens = {
+		(void *)&pcmd_stop_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_rxmode = {
+	.f = pcmd_rxmode_callback,
+	.data = NULL,
+	.help_str = "rxmode <port_id>\n     Toggle port Rx mode",
+	.tokens = {
+		(void *)&pcmd_rxmode_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_macaddr_get = {
+	.f = pcmd_macaddr_callback,
+	.data = NULL,
+	.help_str = "macaddr <port_id>\n"
+		"     Get MAC address",
+	.tokens = {
+		(void *)&pcmd_macaddr_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_macaddr = {
+	.f = pcmd_macaddr_callback,
+	.data = (void *)0x01,
+	.help_str =
+		"macaddr <port_id> <mac_addr>\n"
+		"     Set MAC address",
+	.tokens = {
+		(void *)&pcmd_macaddr_token_cmd,
+		(void *)&pcmd_intmac_token_port,
+		(void *)&pcmd_intmac_token_mac,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_mtu = {
+	.f = pcmd_mtu_callback,
+	.data = NULL,
+	.help_str = "mtu <port_id> <mtu_value>\n"
+		"     Change MTU",
+	.tokens = {
+		(void *)&pcmd_mtu_token_cmd,
+		(void *)&pcmd_intstr_token_port,
+		(void *)&pcmd_intstr_token_opt,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_portstats = {
+	.f = pcmd_portstats_callback,
+	.data = NULL,
+	.help_str = "portstats <port_id>\n"
+		"     Print port eth statistics",
+	.tokens = {
+		(void *)&pcmd_portstats_token_cmd,
+		(void *)&pcmd_int_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_ringparam = {
+	.f = pcmd_ringparam_callback,
+	.data = NULL,
+	.help_str = "ringparam <port_id>\n"
+		"     Print ring parameters",
+	.tokens = {
+		(void *)&pcmd_ringparam_token_cmd,
+		(void *)&pcmd_intintint_token_port,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_ringparam_set = {
+	.f = pcmd_ringparam_callback,
+	.data = (void *)1,
+	.help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
+		"     Set ring parameters",
+	.tokens = {
+		(void *)&pcmd_ringparam_token_cmd,
+		(void *)&pcmd_intintint_token_port,
+		(void *)&pcmd_intintint_token_tx,
+		(void *)&pcmd_intintint_token_rx,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_validate = {
+	.f = pcmd_validate_callback,
+	.data = NULL,
+	.help_str = "validate <mac_addr>\n"
+		"     Check that MAC address is valid unicast address",
+	.tokens = {
+		(void *)&pcmd_validate_token_cmd,
+		(void *)&pcmd_intmac_token_mac,
+		NULL
+	},
+};
+cmdline_parse_inst_t pcmd_vlan = {
+	.f = pcmd_vlan_callback,
+	.data = NULL,
+	.help_str = "vlan <port_id> <add|del> <vlan_id>\n"
+		"     Add/remove VLAN id",
+	.tokens = {
+		(void *)&pcmd_vlan_token_cmd,
+		(void *)&pcmd_vlan_token_port,
+		(void *)&pcmd_vlan_token_mode,
+		(void *)&pcmd_vlan_token_vid,
+		NULL
+	},
+};
+
+
+cmdline_parse_ctx_t list_prompt_commands[] = {
+	(cmdline_parse_inst_t *)&pcmd_drvinfo,
+	(cmdline_parse_inst_t *)&pcmd_eeprom,
+	(cmdline_parse_inst_t *)&pcmd_link,
+	(cmdline_parse_inst_t *)&pcmd_macaddr_get,
+	(cmdline_parse_inst_t *)&pcmd_macaddr,
+	(cmdline_parse_inst_t *)&pcmd_mtu,
+	(cmdline_parse_inst_t *)&pcmd_open,
+	(cmdline_parse_inst_t *)&pcmd_pause_noopt,
+	(cmdline_parse_inst_t *)&pcmd_pause,
+	(cmdline_parse_inst_t *)&pcmd_portstats,
+	(cmdline_parse_inst_t *)&pcmd_regs,
+	(cmdline_parse_inst_t *)&pcmd_ringparam,
+	(cmdline_parse_inst_t *)&pcmd_ringparam_set,
+	(cmdline_parse_inst_t *)&pcmd_rxmode,
+	(cmdline_parse_inst_t *)&pcmd_stop,
+	(cmdline_parse_inst_t *)&pcmd_validate,
+	(cmdline_parse_inst_t *)&pcmd_vlan,
+	(cmdline_parse_inst_t *)&pcmd_quit,
+	NULL
+};
+
+
+void ethapp_main(void)
+{
+	struct cmdline *ctx_cmdline;
+
+	ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
+	cmdline_interact(ctx_cmdline);
+	cmdline_stdin_exit(ctx_cmdline);
+}
diff --git a/examples/ethtool/ethapp.h b/examples/ethtool/ethapp.h
new file mode 100644
index 0000000..bd48c7c
--- /dev/null
+++ b/examples/ethtool/ethapp.h
@@ -0,0 +1,41 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2015-2016 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.
+ */
+
+
+void ethapp_main(void);
+void print_stats(void);
+void lock_port(int idx_port);
+void unlock_port(int idx_port);
+void mark_port_inactive(int idx_port);
+void mark_port_active(int idx_port);
+void mark_port_newmac(int idx_port);
diff --git a/examples/ethtool/ethtool-app/Makefile b/examples/ethtool/ethtool-app/Makefile
deleted file mode 100644
index 09c66ad..0000000
--- a/examples/ethtool/ethtool-app/Makefile
+++ /dev/null
@@ -1,54 +0,0 @@
-#   BSD LICENSE
-#
-#   Copyright(c) 2010-2014 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 overridden by command line or environment
-RTE_TARGET ?= x86_64-native-linuxapp-gcc
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-# binary name
-APP = ethtool
-
-# all source are stored in SRCS-y
-SRCS-y := main.c ethapp.c
-
-CFLAGS += -O3 -D_GNU_SOURCE -pthread -I$(SRCDIR)/../lib
-CFLAGS += $(WERROR_FLAGS)
-
-LDLIBS += -L$(subst ethtool-app,lib,$(RTE_OUTPUT))/lib
-LDLIBS += -lrte_ethtool
-
-
-include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/ethtool/ethtool-app/ethapp.c b/examples/ethtool/ethtool-app/ethapp.c
deleted file mode 100644
index 2ed4796..0000000
--- a/examples/ethtool/ethtool-app/ethapp.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/*-
- *   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 <cmdline_parse.h>
-#include <cmdline_parse_num.h>
-#include <cmdline_parse_string.h>
-#include <cmdline_parse_etheraddr.h>
-#include <cmdline_socket.h>
-#include <cmdline.h>
-
-#include "rte_ethtool.h"
-#include "ethapp.h"
-
-#define EEPROM_DUMP_CHUNKSIZE 1024
-
-
-struct pcmd_get_params {
-	cmdline_fixed_string_t cmd;
-};
-struct pcmd_int_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-};
-struct pcmd_intstr_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	cmdline_fixed_string_t opt;
-};
-struct pcmd_intmac_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	struct ether_addr mac;
-};
-struct pcmd_str_params {
-	cmdline_fixed_string_t cmd;
-	cmdline_fixed_string_t opt;
-};
-struct pcmd_vlan_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	cmdline_fixed_string_t mode;
-	uint16_t vid;
-};
-struct pcmd_intintint_params {
-	cmdline_fixed_string_t cmd;
-	uint16_t port;
-	uint16_t tx;
-	uint16_t rx;
-};
-
-
-/* Parameter-less commands */
-cmdline_parse_token_string_t pcmd_quit_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "quit");
-cmdline_parse_token_string_t pcmd_stats_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "stats");
-cmdline_parse_token_string_t pcmd_drvinfo_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "drvinfo");
-cmdline_parse_token_string_t pcmd_link_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_get_params, cmd, "link");
-
-/* Commands taking just port id */
-cmdline_parse_token_string_t pcmd_open_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "open");
-cmdline_parse_token_string_t pcmd_stop_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "stop");
-cmdline_parse_token_string_t pcmd_rxmode_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "rxmode");
-cmdline_parse_token_string_t pcmd_portstats_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_int_params, cmd, "portstats");
-cmdline_parse_token_num_t pcmd_int_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_int_params, port, UINT16);
-
-/* Commands taking port id and string */
-cmdline_parse_token_string_t pcmd_eeprom_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "eeprom");
-cmdline_parse_token_string_t pcmd_mtu_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "mtu");
-cmdline_parse_token_string_t pcmd_regs_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "regs");
-
-cmdline_parse_token_num_t pcmd_intstr_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_intstr_token_opt =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, opt, NULL);
-
-/* Commands taking port id and a MAC address string */
-cmdline_parse_token_string_t pcmd_macaddr_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "macaddr");
-cmdline_parse_token_num_t pcmd_intmac_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intmac_params, port, UINT16);
-cmdline_parse_token_etheraddr_t pcmd_intmac_token_mac =
-	TOKEN_ETHERADDR_INITIALIZER(struct pcmd_intmac_params, mac);
-
-/* Command taking just a MAC address */
-cmdline_parse_token_string_t pcmd_validate_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intmac_params, cmd, "validate");
-
-
-/* Commands taking port id and two integers */
-cmdline_parse_token_string_t pcmd_ringparam_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intintint_params, cmd,
-		"ringparam");
-cmdline_parse_token_num_t pcmd_intintint_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, port, UINT16);
-cmdline_parse_token_num_t pcmd_intintint_token_tx =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, tx, UINT16);
-cmdline_parse_token_num_t pcmd_intintint_token_rx =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intintint_params, rx, UINT16);
-
-
-/* Pause commands */
-cmdline_parse_token_string_t pcmd_pause_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params, cmd, "pause");
-cmdline_parse_token_num_t pcmd_pause_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_intstr_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_pause_token_opt =
-	TOKEN_STRING_INITIALIZER(struct pcmd_intstr_params,
-		opt, "all#tx#rx#none");
-
-/* VLAN commands */
-cmdline_parse_token_string_t pcmd_vlan_token_cmd =
-	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, cmd, "vlan");
-cmdline_parse_token_num_t pcmd_vlan_token_port =
-	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, port, UINT16);
-cmdline_parse_token_string_t pcmd_vlan_token_mode =
-	TOKEN_STRING_INITIALIZER(struct pcmd_vlan_params, mode, "add#del");
-cmdline_parse_token_num_t pcmd_vlan_token_vid =
-	TOKEN_NUM_INITIALIZER(struct pcmd_vlan_params, vid, UINT16);
-
-
-static void
-pcmd_quit_callback(__rte_unused void *ptr_params,
-	struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	cmdline_quit(ctx);
-}
-
-
-static void
-pcmd_drvinfo_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct ethtool_drvinfo info;
-	int id_port;
-
-	for (id_port = 0; id_port < rte_eth_dev_count(); id_port++) {
-		if (rte_ethtool_get_drvinfo(id_port, &info)) {
-			printf("Error getting info for port %i\n", id_port);
-			return;
-		}
-		printf("Port %i driver: %s (ver: %s)\n",
-			id_port, info.driver, info.version
-		      );
-	}
-}
-
-
-static void
-pcmd_link_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	int num_ports = rte_eth_dev_count();
-	int id_port, stat_port;
-
-	for (id_port = 0; id_port < num_ports; id_port++) {
-		if (!rte_eth_dev_is_valid_port(id_port))
-			continue;
-		stat_port = rte_ethtool_get_link(id_port);
-		switch (stat_port) {
-		case 0:
-			printf("Port %i: Down\n", id_port);
-			break;
-		case 1:
-			printf("Port %i: Up\n", id_port);
-			break;
-		default:
-			printf("Port %i: Error getting link status\n",
-				id_port
-				);
-			break;
-		}
-	}
-	printf("\n");
-}
-
-
-static void
-pcmd_regs_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int len_regs;
-	struct ethtool_regs regs;
-	unsigned char *buf_data;
-	FILE *fp_regs;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	len_regs = rte_ethtool_get_regs_len(params->port);
-	if (len_regs > 0) {
-		printf("Port %i: %i bytes\n", params->port, len_regs);
-		buf_data = malloc(len_regs);
-		if (buf_data == NULL) {
-			printf("Error allocating %i bytes for buffer\n",
-				len_regs);
-			return;
-		}
-		if (!rte_ethtool_get_regs(params->port, &regs, buf_data)) {
-			fp_regs = fopen(params->opt, "wb");
-			if (fp_regs == NULL) {
-				printf("Error opening '%s' for writing\n",
-					params->opt);
-			} else {
-				if ((int)fwrite(buf_data,
-						1, len_regs,
-						fp_regs) != len_regs)
-					printf("Error writing '%s'\n",
-						params->opt);
-				fclose(fp_regs);
-			}
-		}
-		free(buf_data);
-	} else if (len_regs == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error getting registers\n", params->port);
-}
-
-
-static void
-pcmd_eeprom_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	struct ethtool_eeprom info_eeprom;
-	int len_eeprom;
-	int pos_eeprom;
-	int stat;
-	unsigned char bytes_eeprom[EEPROM_DUMP_CHUNKSIZE];
-	FILE *fp_eeprom;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	len_eeprom = rte_ethtool_get_eeprom_len(params->port);
-	if (len_eeprom > 0) {
-		fp_eeprom = fopen(params->opt, "wb");
-		if (fp_eeprom == NULL) {
-			printf("Error opening '%s' for writing\n",
-				params->opt);
-			return;
-		}
-		printf("Total EEPROM length: %i bytes\n", len_eeprom);
-		info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
-		for (pos_eeprom = 0;
-				pos_eeprom < len_eeprom;
-				pos_eeprom += EEPROM_DUMP_CHUNKSIZE) {
-			info_eeprom.offset = pos_eeprom;
-			if (pos_eeprom + EEPROM_DUMP_CHUNKSIZE > len_eeprom)
-				info_eeprom.len = len_eeprom - pos_eeprom;
-			else
-				info_eeprom.len = EEPROM_DUMP_CHUNKSIZE;
-			stat = rte_ethtool_get_eeprom(
-				params->port, &info_eeprom, bytes_eeprom
-				);
-			if (stat != 0) {
-				printf("EEPROM read error %i\n", stat);
-				break;
-			}
-			if (fwrite(bytes_eeprom,
-					1, info_eeprom.len,
-					fp_eeprom) != info_eeprom.len) {
-				printf("Error writing '%s'\n", params->opt);
-				break;
-			}
-		}
-		fclose(fp_eeprom);
-	} else if (len_eeprom == 0)
-		printf("Port %i: Device does not have EEPROM\n", params->port);
-	else if (len_eeprom == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error getting EEPROM\n", params->port);
-}
-
-
-static void
-pcmd_pause_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	struct ethtool_pauseparam info;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data != NULL) {
-		stat = rte_ethtool_get_pauseparam(params->port, &info);
-	} else {
-		memset(&info, 0, sizeof(info));
-		if (strcasecmp("all", params->opt) == 0) {
-			info.tx_pause = 1;
-			info.rx_pause = 1;
-		} else if (strcasecmp("tx", params->opt) == 0) {
-			info.tx_pause = 1;
-			info.rx_pause = 0;
-		} else if (strcasecmp("rx", params->opt) == 0) {
-			info.tx_pause = 0;
-			info.rx_pause = 1;
-		} else {
-			info.tx_pause = 0;
-			info.rx_pause = 0;
-		}
-		/* Assume auto-negotiation wanted */
-		info.autoneg = 1;
-		stat = rte_ethtool_set_pauseparam(params->port, &info);
-	}
-	if (stat == 0) {
-		if (info.rx_pause && info.tx_pause)
-			printf("Port %i: Tx & Rx Paused\n", params->port);
-		else if (info.rx_pause)
-			printf("Port %i: Rx Paused\n", params->port);
-		else if (info.tx_pause)
-			printf("Port %i: Tx Paused\n", params->port);
-		else
-			printf("Port %i: Tx & Rx not paused\n", params->port);
-	} else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error %i\n", params->port, stat);
-}
-
-
-static void
-pcmd_open_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	lock_port(params->port);
-	stat = rte_ethtool_net_open(params->port);
-	mark_port_active(params->port);
-	unlock_port(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error opening device\n", params->port);
-}
-
-static void
-pcmd_stop_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	lock_port(params->port);
-	stat = rte_ethtool_net_stop(params->port);
-	mark_port_inactive(params->port);
-	unlock_port(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error stopping device\n", params->port);
-}
-
-
-static void
-pcmd_rxmode_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_set_rx_mode(params->port);
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error setting rx mode\n", params->port);
-}
-
-
-static void
-pcmd_macaddr_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intmac_params *params = ptr_params;
-	struct ether_addr mac_addr;
-	int stat;
-
-	stat = 0;
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data != NULL) {
-		lock_port(params->port);
-		stat = rte_ethtool_net_set_mac_addr(params->port,
-			&params->mac);
-		mark_port_newmac(params->port);
-		unlock_port(params->port);
-		if (stat == 0) {
-			printf("MAC address changed\n");
-			return;
-		}
-	} else {
-		stat = rte_ethtool_net_get_mac_addr(params->port, &mac_addr);
-		if (stat == 0) {
-			printf(
-				"Port %i MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-				params->port,
-				mac_addr.addr_bytes[0],
-				mac_addr.addr_bytes[1],
-				mac_addr.addr_bytes[2],
-				mac_addr.addr_bytes[3],
-				mac_addr.addr_bytes[4],
-				mac_addr.addr_bytes[5]);
-			return;
-		}
-	}
-
-	printf("Port %i: Error %s\n", params->port,
-	       strerror(-stat));
-}
-
-static void
-pcmd_mtu_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intstr_params *params = ptr_params;
-	int stat;
-	int new_mtu;
-	char *ptr_parse_end;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	new_mtu = atoi(params->opt);
-	new_mtu = strtoul(params->opt, &ptr_parse_end, 10);
-	if (*ptr_parse_end != '\0' ||
-			new_mtu < ETHER_MIN_MTU ||
-			new_mtu > ETHER_MAX_JUMBO_FRAME_LEN) {
-		printf("Port %i: Invalid MTU value\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_change_mtu(params->port, new_mtu);
-	if (stat == 0)
-		printf("Port %i: MTU set to %i\n", params->port, new_mtu);
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error setting MTU\n", params->port);
-}
-
-
-
-static void pcmd_portstats_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_int_params *params = ptr_params;
-	struct rte_eth_stats stat_info;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = rte_ethtool_net_get_stats64(params->port, &stat_info);
-	if (stat == 0) {
-		/* Most of rte_eth_stats is deprecated.. */
-		printf("Port %i stats\n", params->port);
-		printf("   In: %" PRIu64 " (%" PRIu64 " bytes)\n"
-			"  Out: %"PRIu64" (%"PRIu64 " bytes)\n"
-			"  Err: %"PRIu64"\n",
-			stat_info.ipackets,
-			stat_info.ibytes,
-			stat_info.opackets,
-			stat_info.obytes,
-			stat_info.ierrors+stat_info.oerrors
-		      );
-	} else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error fetching statistics\n", params->port);
-}
-
-static void pcmd_ringparam_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	void *ptr_data)
-{
-	struct pcmd_intintint_params *params = ptr_params;
-	struct ethtool_ringparam ring_data;
-	struct ethtool_ringparam ring_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	if (ptr_data == NULL) {
-		stat = rte_ethtool_get_ringparam(params->port, &ring_data);
-		if (stat == 0) {
-			printf("Port %i ring parameters\n"
-				"  Rx Pending: %i (%i max)\n"
-				"  Tx Pending: %i (%i max)\n",
-				params->port,
-				ring_data.rx_pending,
-				ring_data.rx_max_pending,
-				ring_data.tx_pending,
-				ring_data.tx_max_pending);
-		}
-	} else {
-		if (params->tx < 1 || params->rx < 1) {
-			printf("Error: Invalid parameters\n");
-			return;
-		}
-		memset(&ring_params, 0, sizeof(struct ethtool_ringparam));
-		ring_params.tx_pending = params->tx;
-		ring_params.rx_pending = params->rx;
-		lock_port(params->port);
-		stat = rte_ethtool_set_ringparam(params->port, &ring_params);
-		unlock_port(params->port);
-	}
-	if (stat == 0)
-		return;
-	else if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else
-		printf("Port %i: Error fetching statistics\n", params->port);
-}
-
-static void pcmd_validate_callback(void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_intmac_params *params = ptr_params;
-
-	if (rte_ethtool_net_validate_addr(0, &params->mac))
-		printf("Address is unicast\n");
-	else
-		printf("Address is not unicast\n");
-}
-
-
-static void pcmd_vlan_callback(__rte_unused void *ptr_params,
-	__rte_unused struct cmdline *ctx,
-	__rte_unused void *ptr_data)
-{
-	struct pcmd_vlan_params *params = ptr_params;
-	int stat;
-
-	if (!rte_eth_dev_is_valid_port(params->port)) {
-		printf("Error: Invalid port number %i\n", params->port);
-		return;
-	}
-	stat = 0;
-
-	if (strcasecmp("add", params->mode) == 0) {
-		stat = rte_ethtool_net_vlan_rx_add_vid(
-			params->port, params->vid
-			);
-		if (stat == 0)
-			printf("VLAN vid %i added\n", params->vid);
-
-	} else if (strcasecmp("del", params->mode) == 0) {
-		stat = rte_ethtool_net_vlan_rx_kill_vid(
-			params->port, params->vid
-			);
-		if (stat == 0)
-			printf("VLAN vid %i removed\n", params->vid);
-	} else {
-		/* Should not happen! */
-		printf("Error: Bad mode %s\n", params->mode);
-	}
-	if (stat == -ENOTSUP)
-		printf("Port %i: Operation not supported\n", params->port);
-	else if (stat == -ENOSYS)
-		printf("Port %i: VLAN filtering disabled\n", params->port);
-	else if (stat != 0)
-		printf("Port %i: Error changing VLAN setup (code %i)\n",
-			params->port, -stat);
-}
-
-
-cmdline_parse_inst_t pcmd_quit = {
-	.f = pcmd_quit_callback,
-	.data = NULL,
-	.help_str = "quit\n     Exit program",
-	.tokens = {(void *)&pcmd_quit_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_drvinfo = {
-	.f = pcmd_drvinfo_callback,
-	.data = NULL,
-	.help_str = "drvinfo\n     Print driver info",
-	.tokens = {(void *)&pcmd_drvinfo_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_link = {
-	.f = pcmd_link_callback,
-	.data = NULL,
-	.help_str = "link\n     Print port link states",
-	.tokens = {(void *)&pcmd_link_token_cmd, NULL},
-};
-cmdline_parse_inst_t pcmd_regs = {
-	.f = pcmd_regs_callback,
-	.data = NULL,
-	.help_str = "regs <port_id> <filename>\n"
-		"     Dump port register(s) to file",
-	.tokens = {
-		(void *)&pcmd_regs_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_eeprom = {
-	.f = pcmd_eeprom_callback,
-	.data = NULL,
-	.help_str = "eeprom <port_id> <filename>\n    Dump EEPROM to file",
-	.tokens = {
-		(void *)&pcmd_eeprom_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_pause_noopt = {
-	.f = pcmd_pause_callback,
-	.data = (void *)0x01,
-	.help_str = "pause <port_id>\n     Print port pause state",
-	.tokens = {
-		(void *)&pcmd_pause_token_cmd,
-		(void *)&pcmd_pause_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_pause = {
-	.f = pcmd_pause_callback,
-	.data = NULL,
-	.help_str =
-		"pause <port_id> <all|tx|rx|none>\n     Pause/unpause port",
-	.tokens = {
-		(void *)&pcmd_pause_token_cmd,
-		(void *)&pcmd_pause_token_port,
-		(void *)&pcmd_pause_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_open = {
-	.f = pcmd_open_callback,
-	.data = NULL,
-	.help_str = "open <port_id>\n     Open port",
-	.tokens = {
-		(void *)&pcmd_open_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_stop = {
-	.f = pcmd_stop_callback,
-	.data = NULL,
-	.help_str = "stop <port_id>\n     Stop port",
-	.tokens = {
-		(void *)&pcmd_stop_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_rxmode = {
-	.f = pcmd_rxmode_callback,
-	.data = NULL,
-	.help_str = "rxmode <port_id>\n     Toggle port Rx mode",
-	.tokens = {
-		(void *)&pcmd_rxmode_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_macaddr_get = {
-	.f = pcmd_macaddr_callback,
-	.data = NULL,
-	.help_str = "macaddr <port_id>\n"
-		"     Get MAC address",
-	.tokens = {
-		(void *)&pcmd_macaddr_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_macaddr = {
-	.f = pcmd_macaddr_callback,
-	.data = (void *)0x01,
-	.help_str =
-		"macaddr <port_id> <mac_addr>\n"
-		"     Set MAC address",
-	.tokens = {
-		(void *)&pcmd_macaddr_token_cmd,
-		(void *)&pcmd_intmac_token_port,
-		(void *)&pcmd_intmac_token_mac,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_mtu = {
-	.f = pcmd_mtu_callback,
-	.data = NULL,
-	.help_str = "mtu <port_id> <mtu_value>\n"
-		"     Change MTU",
-	.tokens = {
-		(void *)&pcmd_mtu_token_cmd,
-		(void *)&pcmd_intstr_token_port,
-		(void *)&pcmd_intstr_token_opt,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_portstats = {
-	.f = pcmd_portstats_callback,
-	.data = NULL,
-	.help_str = "portstats <port_id>\n"
-		"     Print port eth statistics",
-	.tokens = {
-		(void *)&pcmd_portstats_token_cmd,
-		(void *)&pcmd_int_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_ringparam = {
-	.f = pcmd_ringparam_callback,
-	.data = NULL,
-	.help_str = "ringparam <port_id>\n"
-		"     Print ring parameters",
-	.tokens = {
-		(void *)&pcmd_ringparam_token_cmd,
-		(void *)&pcmd_intintint_token_port,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_ringparam_set = {
-	.f = pcmd_ringparam_callback,
-	.data = (void *)1,
-	.help_str = "ringparam <port_id> <tx_param> <rx_param>\n"
-		"     Set ring parameters",
-	.tokens = {
-		(void *)&pcmd_ringparam_token_cmd,
-		(void *)&pcmd_intintint_token_port,
-		(void *)&pcmd_intintint_token_tx,
-		(void *)&pcmd_intintint_token_rx,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_validate = {
-	.f = pcmd_validate_callback,
-	.data = NULL,
-	.help_str = "validate <mac_addr>\n"
-		"     Check that MAC address is valid unicast address",
-	.tokens = {
-		(void *)&pcmd_validate_token_cmd,
-		(void *)&pcmd_intmac_token_mac,
-		NULL
-	},
-};
-cmdline_parse_inst_t pcmd_vlan = {
-	.f = pcmd_vlan_callback,
-	.data = NULL,
-	.help_str = "vlan <port_id> <add|del> <vlan_id>\n"
-		"     Add/remove VLAN id",
-	.tokens = {
-		(void *)&pcmd_vlan_token_cmd,
-		(void *)&pcmd_vlan_token_port,
-		(void *)&pcmd_vlan_token_mode,
-		(void *)&pcmd_vlan_token_vid,
-		NULL
-	},
-};
-
-
-cmdline_parse_ctx_t list_prompt_commands[] = {
-	(cmdline_parse_inst_t *)&pcmd_drvinfo,
-	(cmdline_parse_inst_t *)&pcmd_eeprom,
-	(cmdline_parse_inst_t *)&pcmd_link,
-	(cmdline_parse_inst_t *)&pcmd_macaddr_get,
-	(cmdline_parse_inst_t *)&pcmd_macaddr,
-	(cmdline_parse_inst_t *)&pcmd_mtu,
-	(cmdline_parse_inst_t *)&pcmd_open,
-	(cmdline_parse_inst_t *)&pcmd_pause_noopt,
-	(cmdline_parse_inst_t *)&pcmd_pause,
-	(cmdline_parse_inst_t *)&pcmd_portstats,
-	(cmdline_parse_inst_t *)&pcmd_regs,
-	(cmdline_parse_inst_t *)&pcmd_ringparam,
-	(cmdline_parse_inst_t *)&pcmd_ringparam_set,
-	(cmdline_parse_inst_t *)&pcmd_rxmode,
-	(cmdline_parse_inst_t *)&pcmd_stop,
-	(cmdline_parse_inst_t *)&pcmd_validate,
-	(cmdline_parse_inst_t *)&pcmd_vlan,
-	(cmdline_parse_inst_t *)&pcmd_quit,
-	NULL
-};
-
-
-void ethapp_main(void)
-{
-	struct cmdline *ctx_cmdline;
-
-	ctx_cmdline = cmdline_stdin_new(list_prompt_commands, "EthApp> ");
-	cmdline_interact(ctx_cmdline);
-	cmdline_stdin_exit(ctx_cmdline);
-}
diff --git a/examples/ethtool/ethtool-app/ethapp.h b/examples/ethtool/ethtool-app/ethapp.h
deleted file mode 100644
index ba438ee..0000000
--- a/examples/ethtool/ethtool-app/ethapp.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*-
- *   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.
- */
-
-
-void ethapp_main(void);
-void print_stats(void);
-void lock_port(int idx_port);
-void unlock_port(int idx_port);
-void mark_port_inactive(int idx_port);
-void mark_port_active(int idx_port);
-void mark_port_newmac(int idx_port);
diff --git a/examples/ethtool/ethtool-app/main.c b/examples/ethtool/ethtool-app/main.c
deleted file mode 100644
index 2c655d8..0000000
--- a/examples/ethtool/ethtool-app/main.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*-
- *   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 <rte_common.h>
-#include <rte_spinlock.h>
-#include <rte_eal.h>
-#include <rte_ethdev.h>
-#include <rte_ether.h>
-#include <rte_ip.h>
-#include <rte_memory.h>
-#include <rte_mempool.h>
-#include <rte_mbuf.h>
-
-#include "ethapp.h"
-
-#define MAX_PORTS RTE_MAX_ETHPORTS
-#define MAX_BURST_LENGTH 32
-#define PORT_RX_QUEUE_SIZE 128
-#define PORT_TX_QUEUE_SIZE 256
-#define PKTPOOL_EXTRA_SIZE 512
-#define PKTPOOL_CACHE 32
-
-
-struct txq_port {
-	uint16_t cnt_unsent;
-	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
-};
-
-struct app_port {
-	struct ether_addr mac_addr;
-	struct txq_port txq;
-	rte_spinlock_t lock;
-	int port_active;
-	int port_dirty;
-	int idx_port;
-	struct rte_mempool *pkt_pool;
-};
-
-struct app_config {
-	struct app_port ports[MAX_PORTS];
-	int cnt_ports;
-	int exit_now;
-};
-
-
-struct app_config app_cfg;
-
-
-void lock_port(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	rte_spinlock_lock(&ptr_port->lock);
-}
-
-void unlock_port(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	rte_spinlock_unlock(&ptr_port->lock);
-}
-
-void mark_port_active(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_active = 1;
-}
-
-void mark_port_inactive(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_active = 0;
-}
-
-void mark_port_newmac(int idx_port)
-{
-	struct app_port *ptr_port = &app_cfg.ports[idx_port];
-
-	ptr_port->port_dirty = 1;
-}
-
-static void setup_ports(struct app_config *app_cfg, int cnt_ports)
-{
-	int idx_port;
-	int size_pktpool;
-	struct rte_eth_conf cfg_port;
-	struct rte_eth_dev_info dev_info;
-	char str_name[16];
-
-	memset(&cfg_port, 0, sizeof(cfg_port));
-	cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
-
-	for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
-		struct app_port *ptr_port = &app_cfg->ports[idx_port];
-
-		rte_eth_dev_info_get(idx_port, &dev_info);
-		size_pktpool = dev_info.rx_desc_lim.nb_max +
-			dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
-
-		snprintf(str_name, 16, "pkt_pool%i", idx_port);
-		ptr_port->pkt_pool = rte_pktmbuf_pool_create(
-			str_name,
-			size_pktpool, PKTPOOL_CACHE,
-			0,
-			RTE_MBUF_DEFAULT_BUF_SIZE,
-			rte_socket_id()
-			);
-		if (ptr_port->pkt_pool == NULL)
-			rte_exit(EXIT_FAILURE,
-				"rte_pktmbuf_pool_create failed"
-				);
-
-		printf("Init port %i..\n", idx_port);
-		ptr_port->port_active = 1;
-		ptr_port->port_dirty = 0;
-		ptr_port->idx_port = idx_port;
-
-		if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_dev_configure failed");
-		if (rte_eth_rx_queue_setup(
-			    idx_port, 0, PORT_RX_QUEUE_SIZE,
-			    rte_eth_dev_socket_id(idx_port), NULL,
-			    ptr_port->pkt_pool) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_rx_queue_setup failed"
-				);
-		if (rte_eth_tx_queue_setup(
-			    idx_port, 0, PORT_TX_QUEUE_SIZE,
-			    rte_eth_dev_socket_id(idx_port), NULL) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "rte_eth_tx_queue_setup failed"
-				);
-		if (rte_eth_dev_start(idx_port) < 0)
-			rte_exit(EXIT_FAILURE,
-				 "%s:%i: rte_eth_dev_start failed",
-				 __FILE__, __LINE__
-				);
-		rte_eth_promiscuous_enable(idx_port);
-		rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
-		rte_spinlock_init(&ptr_port->lock);
-	}
-}
-
-static void process_frame(struct app_port *ptr_port,
-	struct rte_mbuf *ptr_frame)
-{
-	struct ether_hdr *ptr_mac_hdr;
-
-	ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct ether_hdr *);
-	ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
-	ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
-}
-
-static int slave_main(__attribute__((unused)) void *ptr_data)
-{
-	struct app_port *ptr_port;
-	struct rte_mbuf *ptr_frame;
-	struct txq_port *txq;
-
-	uint16_t cnt_recv_frames;
-	uint16_t idx_frame;
-	uint16_t cnt_sent;
-	uint16_t idx_port;
-	uint16_t lock_result;
-
-	while (app_cfg.exit_now == 0) {
-		for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
-			/* Check that port is active and unlocked */
-			ptr_port = &app_cfg.ports[idx_port];
-			lock_result = rte_spinlock_trylock(&ptr_port->lock);
-			if (lock_result == 0)
-				continue;
-			if (ptr_port->port_active == 0) {
-				rte_spinlock_unlock(&ptr_port->lock);
-				continue;
-			}
-			txq = &ptr_port->txq;
-
-			/* MAC address was updated */
-			if (ptr_port->port_dirty == 1) {
-				rte_eth_macaddr_get(ptr_port->idx_port,
-					&ptr_port->mac_addr);
-				ptr_port->port_dirty = 0;
-			}
-
-			/* Incoming frames */
-			cnt_recv_frames = rte_eth_rx_burst(
-				ptr_port->idx_port, 0,
-				&txq->buf_frames[txq->cnt_unsent],
-				RTE_DIM(txq->buf_frames) - txq->cnt_unsent
-				);
-			if (cnt_recv_frames > 0) {
-				for (idx_frame = 0;
-					idx_frame < cnt_recv_frames;
-					idx_frame++) {
-					ptr_frame = txq->buf_frames[
-						idx_frame + txq->cnt_unsent];
-					process_frame(ptr_port, ptr_frame);
-				}
-				txq->cnt_unsent += cnt_recv_frames;
-			}
-
-			/* Outgoing frames */
-			if (txq->cnt_unsent > 0) {
-				cnt_sent = rte_eth_tx_burst(
-					ptr_port->idx_port, 0,
-					txq->buf_frames,
-					txq->cnt_unsent
-					);
-				/* Shuffle up unsent frame pointers */
-				for (idx_frame = cnt_sent;
-					idx_frame < txq->cnt_unsent;
-					idx_frame++)
-					txq->buf_frames[idx_frame - cnt_sent] =
-						txq->buf_frames[idx_frame];
-				txq->cnt_unsent -= cnt_sent;
-			}
-			rte_spinlock_unlock(&ptr_port->lock);
-		} /* end for( idx_port ) */
-	} /* end for(;;) */
-
-	return 0;
-}
-
-int main(int argc, char **argv)
-{
-	int cnt_args_parsed;
-	uint32_t id_core;
-	uint32_t cnt_ports;
-
-	/* Init runtime enviornment */
-	cnt_args_parsed = rte_eal_init(argc, argv);
-	if (cnt_args_parsed < 0)
-		rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
-
-	cnt_ports = rte_eth_dev_count();
-	printf("Number of NICs: %i\n", cnt_ports);
-	if (cnt_ports == 0)
-		rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
-	if (cnt_ports > MAX_PORTS) {
-		printf("Info: Using only %i of %i ports\n",
-			cnt_ports, MAX_PORTS
-			);
-		cnt_ports = MAX_PORTS;
-	}
-
-	setup_ports(&app_cfg, cnt_ports);
-
-	app_cfg.exit_now = 0;
-	app_cfg.cnt_ports = cnt_ports;
-
-	if (rte_lcore_count() < 2)
-		rte_exit(EXIT_FAILURE, "No available slave core!\n");
-	/* Assume there is an available slave.. */
-	id_core = rte_lcore_id();
-	id_core = rte_get_next_lcore(id_core, 1, 1);
-	rte_eal_remote_launch(slave_main, NULL, id_core);
-
-	ethapp_main();
-
-	app_cfg.exit_now = 1;
-	RTE_LCORE_FOREACH_SLAVE(id_core) {
-		if (rte_eal_wait_lcore(id_core) < 0)
-			return -1;
-	}
-
-	return 0;
-}
diff --git a/examples/ethtool/lib/Makefile b/examples/ethtool/lib/Makefile
deleted file mode 100644
index d7ee955..0000000
--- a/examples/ethtool/lib/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-#   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
-
-LIBABIVER := 1
-
-# 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/ethtool/lib/rte_ethtool.c b/examples/ethtool/lib/rte_ethtool.c
deleted file mode 100644
index 42e05f1..0000000
--- a/examples/ethtool/lib/rte_ethtool.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*-
- *   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_ether.h>
-#include "rte_ethtool.h"
-
-#define PKTPOOL_SIZE 512
-#define PKTPOOL_CACHE 32
-
-
-int
-rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
-{
-	struct rte_eth_dev_info dev_info;
-	int n;
-
-	if (drvinfo == NULL)
-		return -EINVAL;
-
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-
-	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)
-{
-	int count_regs;
-
-	count_regs = rte_eth_dev_get_reg_length(port_id);
-	if (count_regs > 0)
-		return count_regs * sizeof(uint32_t);
-	return count_regs;
-}
-
-int
-rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
-{
-	struct rte_dev_reg_info reg_info;
-	int status;
-
-	if (regs == NULL || data == NULL)
-		return -EINVAL;
-
-	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;
-
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	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;
-
-	if (eeprom == NULL || words == NULL)
-		return -EINVAL;
-
-	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;
-
-	if (eeprom == NULL || words == NULL || eeprom->offset >= eeprom->len)
-		return -EINVAL;
-
-	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;
-
-	if (pause_param == NULL)
-		return -EINVAL;
-
-	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_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;
-	default:
-		/* dummy block to avoid compiler warning */
-		break;
-	}
-	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;
-
-	if (pause_param == NULL)
-		return -EINVAL;
-
-	/*
-	 * 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)
-{
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	rte_eth_dev_stop(port_id);
-
-	return 0;
-}
-
-int
-rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
-{
-	if (!rte_eth_dev_is_valid_port(port_id))
-		return -ENODEV;
-	if (addr == NULL)
-		return -EINVAL;
-	rte_eth_macaddr_get(port_id, addr);
-
-	return 0;
-}
-
-int
-rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
-{
-	if (addr == NULL)
-		return -EINVAL;
-	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)
-{
-	if (addr == NULL)
-		return -EINVAL;
-	return is_valid_assigned_ether_addr(addr);
-}
-
-int
-rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
-{
-	if (mtu < 0 || mtu > UINT16_MAX)
-		return -EINVAL;
-	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)
-{
-	if (stats == NULL)
-		return -EINVAL;
-	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);
-}
-
-/*
- * The set_rx_mode provides driver-specific rx mode setting.
- * This implementation implements rx mode setting based upon
- * ixgbe/igb drivers. Further improvement is to provide a
- * callback op field over struct rte_eth_dev::dev_ops so each
- * driver can register device-specific implementation
- */
-int
-rte_ethtool_net_set_rx_mode(uint8_t port_id)
-{
-	uint16_t num_vfs;
-	struct rte_eth_dev_info dev_info;
-	uint16_t vf;
-
-	memset(&dev_info, 0, sizeof(dev_info));
-	rte_eth_dev_info_get(port_id, &dev_info);
-	num_vfs = dev_info.max_vfs;
-
-	/* Set VF vf_rx_mode, VF unsupport status is discard */
-	for (vf = 0; vf < num_vfs; vf++)
-		rte_eth_dev_set_vf_rxmode(port_id, vf,
-			ETH_VMDQ_ACCEPT_UNTAG, 0);
-
-	/* Enable Rx vlan filter, VF unspport status is discard */
-	rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
-
-	return 0;
-}
-
-
-int
-rte_ethtool_get_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param)
-{
-	struct rte_eth_dev_info dev_info;
-	struct rte_eth_rxq_info rx_qinfo;
-	struct rte_eth_txq_info tx_qinfo;
-	int stat;
-
-	if (ring_param == NULL)
-		return -EINVAL;
-
-	rte_eth_dev_info_get(port_id, &dev_info);
-
-	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	stat = rte_eth_tx_queue_info_get(port_id, 0, &tx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	memset(ring_param, 0, sizeof(*ring_param));
-	ring_param->rx_pending = rx_qinfo.nb_desc;
-	ring_param->rx_max_pending = dev_info.rx_desc_lim.nb_max;
-	ring_param->tx_pending = tx_qinfo.nb_desc;
-	ring_param->tx_max_pending = dev_info.tx_desc_lim.nb_max;
-
-	return 0;
-}
-
-
-int
-rte_ethtool_set_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param)
-{
-	struct rte_eth_rxq_info rx_qinfo;
-	int stat;
-
-	if (ring_param == NULL)
-		return -EINVAL;
-
-	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
-	if (stat != 0)
-		return stat;
-
-	rte_eth_dev_stop(port_id);
-
-	stat = rte_eth_tx_queue_setup(port_id, 0, ring_param->tx_pending,
-		rte_socket_id(), NULL);
-	if (stat != 0)
-		return stat;
-
-	stat = rte_eth_rx_queue_setup(port_id, 0, ring_param->rx_pending,
-		rte_socket_id(), NULL, rx_qinfo.mp);
-	if (stat != 0)
-		return stat;
-
-	return rte_eth_dev_start(port_id);
-}
diff --git a/examples/ethtool/lib/rte_ethtool.h b/examples/ethtool/lib/rte_ethtool.h
deleted file mode 100644
index 2e79d45..0000000
--- a/examples/ethtool/lib/rte_ethtool.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/*-
- *   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_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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-ENODEV) if *port_id* invalid.
- */
-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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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 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.
- *   - (-EINVAL) if parameters 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.
- *   - (-EINVAL) if parameters 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);
-
-/**
- * Getting ring paramaters for Ethernet device.
- *
- * @param port_id
- *   The port identifier of the Ethernet device.
- * @param ring_param
- *   Pointer to struct ethrool_ringparam to receive parameters.
- * @return
- *   - (0) if successful.
- *   - (-ENOTSUP) if hardware doesn't support.
- *   - (-ENODEV) if *port_id* invalid.
- *   - others depends on the specific operations implementation.
- * @note
- *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
- *   are used, and the function only gets parameters for queue 0.
- */
-int rte_ethtool_get_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param);
-
-/**
- * Setting ring paramaters for Ethernet device.
- *
- * @param port_id
- *   The port identifier of the Ethernet device.
- * @param ring_param
- *   Pointer to struct ethrool_ringparam with parameters to set.
- * @return
- *   - (0) if successful.
- *   - (-ENOTSUP) if hardware doesn't support.
- *   - (-ENODEV) if *port_id* invalid.
- *   - others depends on the specific operations implementation.
- * @note
- *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
- *   are used, and the function only sets parameters for queue 0.
- */
-int rte_ethtool_set_ringparam(uint8_t port_id,
-	struct ethtool_ringparam *ring_param);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _RTE_ETHTOOL_H_ */
diff --git a/examples/ethtool/main.c b/examples/ethtool/main.c
new file mode 100644
index 0000000..2c655d8
--- /dev/null
+++ b/examples/ethtool/main.c
@@ -0,0 +1,305 @@
+/*-
+ *   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 <rte_common.h>
+#include <rte_spinlock.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_memory.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+
+#include "ethapp.h"
+
+#define MAX_PORTS RTE_MAX_ETHPORTS
+#define MAX_BURST_LENGTH 32
+#define PORT_RX_QUEUE_SIZE 128
+#define PORT_TX_QUEUE_SIZE 256
+#define PKTPOOL_EXTRA_SIZE 512
+#define PKTPOOL_CACHE 32
+
+
+struct txq_port {
+	uint16_t cnt_unsent;
+	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
+};
+
+struct app_port {
+	struct ether_addr mac_addr;
+	struct txq_port txq;
+	rte_spinlock_t lock;
+	int port_active;
+	int port_dirty;
+	int idx_port;
+	struct rte_mempool *pkt_pool;
+};
+
+struct app_config {
+	struct app_port ports[MAX_PORTS];
+	int cnt_ports;
+	int exit_now;
+};
+
+
+struct app_config app_cfg;
+
+
+void lock_port(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	rte_spinlock_lock(&ptr_port->lock);
+}
+
+void unlock_port(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	rte_spinlock_unlock(&ptr_port->lock);
+}
+
+void mark_port_active(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_active = 1;
+}
+
+void mark_port_inactive(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_active = 0;
+}
+
+void mark_port_newmac(int idx_port)
+{
+	struct app_port *ptr_port = &app_cfg.ports[idx_port];
+
+	ptr_port->port_dirty = 1;
+}
+
+static void setup_ports(struct app_config *app_cfg, int cnt_ports)
+{
+	int idx_port;
+	int size_pktpool;
+	struct rte_eth_conf cfg_port;
+	struct rte_eth_dev_info dev_info;
+	char str_name[16];
+
+	memset(&cfg_port, 0, sizeof(cfg_port));
+	cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
+
+	for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
+		struct app_port *ptr_port = &app_cfg->ports[idx_port];
+
+		rte_eth_dev_info_get(idx_port, &dev_info);
+		size_pktpool = dev_info.rx_desc_lim.nb_max +
+			dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
+
+		snprintf(str_name, 16, "pkt_pool%i", idx_port);
+		ptr_port->pkt_pool = rte_pktmbuf_pool_create(
+			str_name,
+			size_pktpool, PKTPOOL_CACHE,
+			0,
+			RTE_MBUF_DEFAULT_BUF_SIZE,
+			rte_socket_id()
+			);
+		if (ptr_port->pkt_pool == NULL)
+			rte_exit(EXIT_FAILURE,
+				"rte_pktmbuf_pool_create failed"
+				);
+
+		printf("Init port %i..\n", idx_port);
+		ptr_port->port_active = 1;
+		ptr_port->port_dirty = 0;
+		ptr_port->idx_port = idx_port;
+
+		if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_dev_configure failed");
+		if (rte_eth_rx_queue_setup(
+			    idx_port, 0, PORT_RX_QUEUE_SIZE,
+			    rte_eth_dev_socket_id(idx_port), NULL,
+			    ptr_port->pkt_pool) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_rx_queue_setup failed"
+				);
+		if (rte_eth_tx_queue_setup(
+			    idx_port, 0, PORT_TX_QUEUE_SIZE,
+			    rte_eth_dev_socket_id(idx_port), NULL) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "rte_eth_tx_queue_setup failed"
+				);
+		if (rte_eth_dev_start(idx_port) < 0)
+			rte_exit(EXIT_FAILURE,
+				 "%s:%i: rte_eth_dev_start failed",
+				 __FILE__, __LINE__
+				);
+		rte_eth_promiscuous_enable(idx_port);
+		rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
+		rte_spinlock_init(&ptr_port->lock);
+	}
+}
+
+static void process_frame(struct app_port *ptr_port,
+	struct rte_mbuf *ptr_frame)
+{
+	struct ether_hdr *ptr_mac_hdr;
+
+	ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct ether_hdr *);
+	ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
+	ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
+}
+
+static int slave_main(__attribute__((unused)) void *ptr_data)
+{
+	struct app_port *ptr_port;
+	struct rte_mbuf *ptr_frame;
+	struct txq_port *txq;
+
+	uint16_t cnt_recv_frames;
+	uint16_t idx_frame;
+	uint16_t cnt_sent;
+	uint16_t idx_port;
+	uint16_t lock_result;
+
+	while (app_cfg.exit_now == 0) {
+		for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
+			/* Check that port is active and unlocked */
+			ptr_port = &app_cfg.ports[idx_port];
+			lock_result = rte_spinlock_trylock(&ptr_port->lock);
+			if (lock_result == 0)
+				continue;
+			if (ptr_port->port_active == 0) {
+				rte_spinlock_unlock(&ptr_port->lock);
+				continue;
+			}
+			txq = &ptr_port->txq;
+
+			/* MAC address was updated */
+			if (ptr_port->port_dirty == 1) {
+				rte_eth_macaddr_get(ptr_port->idx_port,
+					&ptr_port->mac_addr);
+				ptr_port->port_dirty = 0;
+			}
+
+			/* Incoming frames */
+			cnt_recv_frames = rte_eth_rx_burst(
+				ptr_port->idx_port, 0,
+				&txq->buf_frames[txq->cnt_unsent],
+				RTE_DIM(txq->buf_frames) - txq->cnt_unsent
+				);
+			if (cnt_recv_frames > 0) {
+				for (idx_frame = 0;
+					idx_frame < cnt_recv_frames;
+					idx_frame++) {
+					ptr_frame = txq->buf_frames[
+						idx_frame + txq->cnt_unsent];
+					process_frame(ptr_port, ptr_frame);
+				}
+				txq->cnt_unsent += cnt_recv_frames;
+			}
+
+			/* Outgoing frames */
+			if (txq->cnt_unsent > 0) {
+				cnt_sent = rte_eth_tx_burst(
+					ptr_port->idx_port, 0,
+					txq->buf_frames,
+					txq->cnt_unsent
+					);
+				/* Shuffle up unsent frame pointers */
+				for (idx_frame = cnt_sent;
+					idx_frame < txq->cnt_unsent;
+					idx_frame++)
+					txq->buf_frames[idx_frame - cnt_sent] =
+						txq->buf_frames[idx_frame];
+				txq->cnt_unsent -= cnt_sent;
+			}
+			rte_spinlock_unlock(&ptr_port->lock);
+		} /* end for( idx_port ) */
+	} /* end for(;;) */
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int cnt_args_parsed;
+	uint32_t id_core;
+	uint32_t cnt_ports;
+
+	/* Init runtime enviornment */
+	cnt_args_parsed = rte_eal_init(argc, argv);
+	if (cnt_args_parsed < 0)
+		rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
+
+	cnt_ports = rte_eth_dev_count();
+	printf("Number of NICs: %i\n", cnt_ports);
+	if (cnt_ports == 0)
+		rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
+	if (cnt_ports > MAX_PORTS) {
+		printf("Info: Using only %i of %i ports\n",
+			cnt_ports, MAX_PORTS
+			);
+		cnt_ports = MAX_PORTS;
+	}
+
+	setup_ports(&app_cfg, cnt_ports);
+
+	app_cfg.exit_now = 0;
+	app_cfg.cnt_ports = cnt_ports;
+
+	if (rte_lcore_count() < 2)
+		rte_exit(EXIT_FAILURE, "No available slave core!\n");
+	/* Assume there is an available slave.. */
+	id_core = rte_lcore_id();
+	id_core = rte_get_next_lcore(id_core, 1, 1);
+	rte_eal_remote_launch(slave_main, NULL, id_core);
+
+	ethapp_main();
+
+	app_cfg.exit_now = 1;
+	RTE_LCORE_FOREACH_SLAVE(id_core) {
+		if (rte_eal_wait_lcore(id_core) < 0)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/lib/Makefile b/lib/Makefile
index 6840f87..57b66c6 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -58,6 +58,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
 DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_ethtool/Makefile b/lib/librte_ethtool/Makefile
new file mode 100644
index 0000000..8be7105
--- /dev/null
+++ b/lib/librte_ethtool/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2015-2016 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
+
+# all source are stored in SRC-Y
+SRCS-y := rte_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ethtool.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_eal 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..d9c5408
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.c
@@ -0,0 +1,423 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 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_ether.h>
+#include "rte_ethtool.h"
+
+#define PKTPOOL_SIZE 512
+#define PKTPOOL_CACHE 32
+
+
+int
+rte_ethtool_get_drvinfo(uint8_t port_id, struct ethtool_drvinfo *drvinfo)
+{
+	struct rte_eth_dev_info dev_info;
+	int n;
+
+	if (drvinfo == NULL)
+		return -EINVAL;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	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)
+{
+	int count_regs;
+
+	count_regs = rte_eth_dev_get_reg_length(port_id);
+	if (count_regs > 0)
+		return count_regs * sizeof(uint32_t);
+	return count_regs;
+}
+
+int
+rte_ethtool_get_regs(uint8_t port_id, struct ethtool_regs *regs, void *data)
+{
+	struct rte_dev_reg_info reg_info;
+	int status;
+
+	if (regs == NULL || data == NULL)
+		return -EINVAL;
+
+	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;
+
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	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;
+
+	if (eeprom == NULL || words == NULL)
+		return -EINVAL;
+
+	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;
+
+	if (eeprom == NULL || words == NULL || eeprom->offset >= eeprom->len)
+		return -EINVAL;
+
+	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;
+
+	if (pause_param == NULL)
+		return -EINVAL;
+
+	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_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;
+	default:
+		/* dummy block to avoid compiler warning */
+		break;
+	}
+	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;
+
+	if (pause_param == NULL)
+		return -EINVAL;
+
+	/*
+	 * 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)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	rte_eth_dev_stop(port_id);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_get_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+	if (addr == NULL)
+		return -EINVAL;
+	rte_eth_macaddr_get(port_id, addr);
+
+	return 0;
+}
+
+int
+rte_ethtool_net_set_mac_addr(uint8_t port_id, struct ether_addr *addr)
+{
+	if (addr == NULL)
+		return -EINVAL;
+	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)
+{
+	if (addr == NULL)
+		return -EINVAL;
+	return is_valid_assigned_ether_addr(addr);
+}
+
+int
+rte_ethtool_net_change_mtu(uint8_t port_id, int mtu)
+{
+	if (mtu < 0 || mtu > UINT16_MAX)
+		return -EINVAL;
+	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)
+{
+	if (stats == NULL)
+		return -EINVAL;
+	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);
+}
+
+/*
+ * The set_rx_mode provides driver-specific rx mode setting.
+ * This implementation implements rx mode setting based upon
+ * ixgbe/igb drivers. Further improvement is to provide a
+ * callback op field over struct rte_eth_dev::dev_ops so each
+ * driver can register device-specific implementation
+ */
+int
+rte_ethtool_net_set_rx_mode(uint8_t port_id)
+{
+	uint16_t num_vfs;
+	struct rte_eth_dev_info dev_info;
+	uint16_t vf;
+
+	memset(&dev_info, 0, sizeof(dev_info));
+	rte_eth_dev_info_get(port_id, &dev_info);
+	num_vfs = dev_info.max_vfs;
+
+	/* Set VF vf_rx_mode, VF unsupport status is discard */
+	for (vf = 0; vf < num_vfs; vf++)
+		rte_eth_dev_set_vf_rxmode(port_id, vf,
+			ETH_VMDQ_ACCEPT_UNTAG, 0);
+
+	/* Enable Rx vlan filter, VF unspport status is discard */
+	rte_eth_dev_set_vlan_offload(port_id, ETH_VLAN_FILTER_MASK);
+
+	return 0;
+}
+
+
+int
+rte_ethtool_get_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_eth_dev_info dev_info;
+	struct rte_eth_rxq_info rx_qinfo;
+	struct rte_eth_txq_info tx_qinfo;
+	int stat;
+
+	if (ring_param == NULL)
+		return -EINVAL;
+
+	rte_eth_dev_info_get(port_id, &dev_info);
+
+	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	stat = rte_eth_tx_queue_info_get(port_id, 0, &tx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	memset(ring_param, 0, sizeof(*ring_param));
+	ring_param->rx_pending = rx_qinfo.nb_desc;
+	ring_param->rx_max_pending = dev_info.rx_desc_lim.nb_max;
+	ring_param->tx_pending = tx_qinfo.nb_desc;
+	ring_param->tx_max_pending = dev_info.tx_desc_lim.nb_max;
+
+	return 0;
+}
+
+
+int
+rte_ethtool_set_ringparam(uint8_t port_id,
+	struct ethtool_ringparam *ring_param)
+{
+	struct rte_eth_rxq_info rx_qinfo;
+	int stat;
+
+	if (ring_param == NULL)
+		return -EINVAL;
+
+	stat = rte_eth_rx_queue_info_get(port_id, 0, &rx_qinfo);
+	if (stat != 0)
+		return stat;
+
+	rte_eth_dev_stop(port_id);
+
+	stat = rte_eth_tx_queue_setup(port_id, 0, ring_param->tx_pending,
+		rte_socket_id(), NULL);
+	if (stat != 0)
+		return stat;
+
+	stat = rte_eth_rx_queue_setup(port_id, 0, ring_param->rx_pending,
+		rte_socket_id(), NULL, rx_qinfo.mp);
+	if (stat != 0)
+		return stat;
+
+	return rte_eth_dev_start(port_id);
+}
diff --git a/lib/librte_ethtool/rte_ethtool.h b/lib/librte_ethtool/rte_ethtool.h
new file mode 100644
index 0000000..c60f7bb
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool.h
@@ -0,0 +1,413 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2016 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_
+
+/**
+ * @file
+ *
+ * This new interface is designed to provide a user-space shim layer for
+ * Ethtool and Netdevice op API.
+ *
+ * rte_ethtool_get_drvinfo:         ethtool_ops::get_driverinfo \n
+ * rte_ethtool_get_link:            ethtool_ops::get_link \n
+ * rte_ethtool_get_regs_len:        ethtool_ops::get_regs_len \n
+ * rte_ethtool_get_regs:            ethtool_ops::get_regs \n
+ * rte_ethtool_get_eeprom_len:      ethtool_ops::get_eeprom_len \n
+ * rte_ethtool_get_eeprom:          ethtool_ops::get_eeprom \n
+ * rte_ethtool_set_eeprom:          ethtool_ops::set_eeprom \n
+ * rte_ethtool_get_pauseparam:      ethtool_ops::get_pauseparam \n
+ * rte_ethtool_set_pauseparam:      ethtool_ops::set_pauseparam \n
+ * rte_ethtool_get_ringparam:       ethtool_ops::set_ringparam \n
+ * rte_ethtool_set_ringparam:       ethtool_ops::set_ringparam \n
+ *
+ * rte_ethtool_net_open:            net_device_ops::ndo_open \n
+ * rte_ethtool_net_stop:            net_device_ops::ndo_stop \n
+ * rte_ethtool_net_set_mac_addr:    net_device_ops::ndo_set_mac_address \n
+ * rte_ethtool_net_validate_addr:   net_device_ops::ndo_validate_addr \n
+ * rte_ethtool_net_change_mtu:      net_device_ops::rte_net_change_mtu \n
+ * rte_ethtool_net_get_stats64:     net_device_ops::ndo_get_stats64 \n
+ * rte_ethtool_net_vlan_rx_add_vid  net_device_ops::ndo_vlan_rx_add_vid \n
+ * rte_ethtool_net_vlan_rx_kill_vid net_device_ops::ndo_vlan_rx_kill_vid \n
+ * rte_ethtool_net_set_rx_mode      net_device_ops::ndo_set_rx_mode \n
+ *
+ */
+#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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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 regs
+ *   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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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 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.
+ *   - (-EINVAL) if parameters 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.
+ *   - (-EINVAL) if parameters 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);
+
+/**
+ * Getting ring paramaters for Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *   Pointer to struct ethrool_ringparam to receive parameters.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ * @note
+ *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
+ *   are used, and the function only gets parameters for queue 0.
+ */
+int rte_ethtool_get_ringparam(uint8_t port_id,
+		struct ethtool_ringparam *ring_param);
+
+/**
+ * Setting ring paramaters for Ethernet device.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param ring_param
+ *   Pointer to struct ethrool_ringparam with parameters to set.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ * @note
+ *   Only the tx_pending and rx_pending fields of struct ethtool_ringparam
+ *   are used, and the function only sets parameters for queue 0.
+ */
+int rte_ethtool_set_ringparam(uint8_t port_id,
+		struct ethtool_ringparam *ring_param);
+
+#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..34183b8
--- /dev/null
+++ b/lib/librte_ethtool/rte_ethtool_version.map
@@ -0,0 +1,28 @@
+DPDK_16.04 {
+	global:
+
+	rte_ethtool_get_drvinfo;
+	rte_ethtool_get_link;
+	rte_ethtool_get_regs_len;
+	rte_ethtool_get_regs;
+	rte_ethtool_get_eeprom_len;
+	rte_ethtool_get_eeprom;
+	rte_ethtool_set_eeprom;
+	rte_ethtool_get_pauseparam;
+	rte_ethtool_set_pauseparam;
+	rte_ethtool_get_ringparam;
+	rte_ethtool_set_ringparam;
+
+	rte_ethtool_net_open;
+	rte_ethtool_net_stop;
+	rte_ethtool_net_get_mac_addr;
+	rte_ethtool_net_set_mac_addr;
+	rte_ethtool_net_validate_addr;
+	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_net_set_rx_mode;
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index daac09f..d94da7a 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -113,6 +113,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF_OFFLOAD)   += -lrte_mbuf_offload
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.5.0

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

* [PATCH v5 2/4] kcp: add kernel control path kernel module
  2016-03-09 11:41       ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  2016-03-09 11:41         ` [PATCH v5 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
@ 2016-03-09 11:41         ` Ferruh Yigit
  2016-03-09 11:41         ` [PATCH v5 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
                           ` (2 subsequent siblings)
  4 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-09 11:41 UTC (permalink / raw)
  To: dev

This kernel module is based on KNI module, but this one is stripped
version of it and only for control messages, no data transfer
functionality provided.

This Linux kernel module helps userspace application create virtual
interfaces and when a control command issued into that virtual
interface, module pushes the command to the userspace and gets the
response back for the caller application.

The Linux tools like ethtool/ifconfig/ip can be used on virtual
interfaces but not ones for related data, like tcpdump.

In long term this patch intends to replace the KNI and KNI will be
depreciated.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

v5:
* Use unsigned primitive types as possible

v4:
* Remove logging helper macros, use pr_fmt
* Seperate log msg for timeout and error

v3:
* Devices are not up by default
* Add enable/disable promisc, allmulti support
* Increase timeout to 500ms and print log when a command timedout

v2:
* Use rtnetlink to create interfaces
* Fix ethtool get/set eeprom
* Remove commented out code
---
 MAINTAINERS                                        |   4 +
 config/common_base                                 |   6 +
 config/common_linuxapp                             |   1 +
 lib/librte_eal/linuxapp/Makefile                   |   3 +-
 lib/librte_eal/linuxapp/eal/Makefile               |   3 +-
 .../linuxapp/eal/include/exec-env/rte_kcp_common.h | 109 ++++++++
 lib/librte_eal/linuxapp/kcp/Makefile               |  57 ++++
 lib/librte_eal/linuxapp/kcp/kcp_dev.h              |  56 ++++
 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c          | 293 +++++++++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_net.c              | 219 +++++++++++++++
 lib/librte_eal/linuxapp/kcp/kcp_nl.c               | 220 ++++++++++++++++
 11 files changed, 969 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/Makefile
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_dev.h
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_net.c
 create mode 100644 lib/librte_eal/linuxapp/kcp/kcp_nl.c

diff --git a/MAINTAINERS b/MAINTAINERS
index e253bf7..b461b77 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -258,6 +258,10 @@ F: app/test/test_kni.c
 F: examples/kni/
 F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 
+Linux KCP
+M: Ferruh Yigit <ferruh.yigit@intel.com>
+F: lib/librte_eal/linuxapp/kcp/
+
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
 F: drivers/net/af_packet/
diff --git a/config/common_base b/config/common_base
index 70343ae..86815d6 100644
--- a/config/common_base
+++ b/config/common_base
@@ -490,6 +490,12 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 CONFIG_RTE_LIBRTE_ETHTOOL=n
 
 #
+# Compile librte_ctrl_if
+#
+CONFIG_RTE_KCP_KMOD=n
+CONFIG_RTE_KCP_KO_DEBUG=n
+
+#
 # Compile vhost library
 # fuse-devel is needed to run vhost-cuse.
 # fuse-devel enables user space char driver development
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 6d42070..e67a546 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -40,6 +40,7 @@ CONFIG_RTE_EAL_VFIO=y
 CONFIG_RTE_KNI_KMOD=y
 CONFIG_RTE_LIBRTE_KNI=y
 CONFIG_RTE_LIBRTE_ETHTOOL=y
+CONFIG_RTE_KCP_KMOD=y
 CONFIG_RTE_LIBRTE_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_POWER=y
diff --git a/lib/librte_eal/linuxapp/Makefile b/lib/librte_eal/linuxapp/Makefile
index 20d2a91..2b30aeb 100644
--- a/lib/librte_eal/linuxapp/Makefile
+++ b/lib/librte_eal/linuxapp/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal
 DIRS-$(CONFIG_RTE_EAL_IGB_UIO) += igb_uio
 DIRS-$(CONFIG_RTE_KNI_KMOD) += kni
+DIRS-$(CONFIG_RTE_KCP_KMOD) += kcp
 DIRS-$(CONFIG_RTE_LIBRTE_XEN_DOM0) += xen_dom0
 
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index c5490e4..0036b60 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,7 @@ CFLAGS_eal_thread.o += -Wno-return-type
 endif
 
 INC := rte_interrupts.h rte_kni_common.h rte_dom0_common.h
+INC += rte_kcp_common.h
 
 SYMLINK-$(CONFIG_RTE_EXEC_ENV_LINUXAPP)-include/exec-env := \
 	$(addprefix include/exec-env/,$(INC))
diff --git a/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
new file mode 100644
index 0000000..c17e447
--- /dev/null
+++ b/lib/librte_eal/linuxapp/eal/include/exec-env/rte_kcp_common.h
@@ -0,0 +1,109 @@
+/*-
+ *   This file is provided under a dual BSD/LGPLv2 license.  When using or
+ *   redistributing this file, you may do so under either license.
+ *
+ *   GNU LESSER GENERAL PUBLIC LICENSE
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2.1 of the GNU Lesser General Public License
+ *   as published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this program;
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ *
+ *
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_KCP_COMMON_H_
+#define _RTE_KCP_COMMON_H_
+
+#define KCP_DEVICE "kcp"
+
+#define KCP_NL_GRP 31
+
+#define KCP_ETHTOOL_MSG_LEN 500
+struct kcp_ethtool_msg {
+	uint32_t cmd_id;
+	uint8_t port_id;
+	uint32_t flag;
+	uint8_t input_buffer[KCP_ETHTOOL_MSG_LEN];
+	uint8_t output_buffer[KCP_ETHTOOL_MSG_LEN];
+	size_t input_buffer_len;
+	size_t output_buffer_len;
+	int err;
+};
+
+enum kcp_ethtool_msg_flag {
+	KCP_MSG_FLAG_NONE,
+	KCP_MSG_FLAG_REQUEST,
+	KCP_MSG_FLAG_RESPONSE,
+};
+
+enum {
+	IFLA_KCP_UNSPEC,
+	IFLA_KCP_PORTID,
+	IFLA_KCP_PID,
+	__IFLA_KCP_MAX,
+};
+
+#define IFLA_KCP_MAX (__IFLA_KCP_MAX - 1)
+
+/*
+ * Request id.
+ */
+enum rte_kcp_req_id {
+	RTE_KCP_REQ_UNKNOWN = (1 << 16),
+	RTE_KCP_REQ_CHANGE_MTU,
+	RTE_KCP_REQ_CFG_NETWORK_IF,
+	RTE_KCP_REQ_GET_STATS,
+	RTE_KCP_REQ_GET_MAC,
+	RTE_KCP_REQ_SET_MAC,
+	RTE_KCP_REQ_START_PORT,
+	RTE_KCP_REQ_STOP_PORT,
+	RTE_KCP_REQ_SET_PROMISC,
+	RTE_KCP_REQ_SET_ALLMULTI,
+	RTE_KCP_REQ_MAX,
+};
+
+#endif /* _RTE_KCP_COMMON_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/Makefile b/lib/librte_eal/linuxapp/kcp/Makefile
new file mode 100644
index 0000000..46d9dd8
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/Makefile
@@ -0,0 +1,57 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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
+
+#
+# module name and path
+#
+MODULE = rte_kcp
+
+#
+# CFLAGS
+#
+MODULE_CFLAGS += -I$(SRCDIR)
+MODULE_CFLAGS += -I$(RTE_OUTPUT)/include
+MODULE_CFLAGS += -include $(RTE_OUTPUT)/include/rte_config.h
+MODULE_CFLAGS += -Wall -Werror
+
+# this lib needs main eal
+DEPDIRS-y += lib/librte_eal/linuxapp/eal
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-y += kcp_net.c
+SRCS-y += kcp_ethtool.c
+SRCS-y += kcp_nl.c
+
+include $(RTE_SDK)/mk/rte.module.mk
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_dev.h b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
new file mode 100644
index 0000000..a518de6
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
@@ -0,0 +1,56 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#ifndef _KCP_DEV_H_
+#define _KCP_DEV_H_
+
+#include <linux/netdevice.h>
+#include <exec-env/rte_kcp_common.h>
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+struct kcp_dev {
+	u8 port_id;
+	u32 pid;
+	struct completion msg_received;
+	u32 nb_timedout_msg;
+};
+
+void kcp_nl_init(void);
+void kcp_nl_release(void);
+int kcp_nl_exec(u32 cmd, struct net_device *dev, void *in_data,
+		size_t in_len, void *out_data, size_t out_len);
+
+void kcp_set_ethtool_ops(struct net_device *netdev);
+
+#ifdef RTE_KCP_KO_DEBUG
+#define KCP_DBG(args...) pr_debug(args)
+#else
+#define KCP_DBG(args...)
+#endif
+
+#endif /* _KCP_DEV_H_ */
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
new file mode 100644
index 0000000..71fb5e9
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
@@ -0,0 +1,293 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include "kcp_dev.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int kcp_check_if_running(struct net_device *dev)
+{
+	return 0;
+}
+
+static void kcp_get_drvinfo(struct net_device *dev,
+		struct ethtool_drvinfo *info)
+{
+	int ret;
+
+	ret = kcp_nl_exec(info->cmd, dev, NULL, 0,
+			info, sizeof(struct ethtool_drvinfo));
+	if (ret < 0)
+		memset(info, 0, sizeof(struct ethtool_drvinfo));
+}
+
+static int kcp_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, NULL, 0,
+			ecmd, sizeof(struct ethtool_cmd));
+}
+
+static int kcp_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	return kcp_nl_exec(ecmd->cmd, dev, ecmd, sizeof(struct ethtool_cmd),
+			NULL, 0);
+}
+
+static void kcp_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	int ret;
+
+	ret = kcp_nl_exec(wol->cmd, dev, NULL, 0,
+			wol, sizeof(struct ethtool_wolinfo));
+	if (ret < 0)
+		memset(wol, 0, sizeof(struct ethtool_wolinfo));
+}
+
+static int kcp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	return kcp_nl_exec(wol->cmd, dev, wol, sizeof(struct ethtool_wolinfo),
+			NULL, 0);
+}
+
+static int kcp_nway_reset(struct net_device *dev)
+{
+	return kcp_nl_exec(ETHTOOL_NWAY_RST, dev, NULL, 0, NULL, 0);
+}
+
+static u32 kcp_get_link(struct net_device *dev)
+{
+	u32 data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GLINK, dev, NULL, 0, &data, sizeof(u32));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static int kcp_get_eeprom_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GEEPROM_LEN, dev, NULL, 0,
+			&data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static int kcp_get_eeprom(struct net_device *dev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct ethtool_eeprom eeprom_tmp;
+	int ret = 0;
+	int remaining;
+	u32 offset = 0;
+
+	eeprom_tmp = *eeprom;
+
+	remaining = eeprom_tmp.len;
+	while (remaining > 0 && ret == 0) {
+		eeprom_tmp.len = min(remaining, KCP_ETHTOOL_MSG_LEN);
+
+		ret = kcp_nl_exec(eeprom_tmp.cmd, dev,
+				&eeprom_tmp, sizeof(struct ethtool_eeprom),
+				data + offset, eeprom_tmp.len);
+		eeprom_tmp.offset += eeprom_tmp.len;
+		offset += eeprom_tmp.len;
+		remaining -= eeprom_tmp.len;
+	}
+
+	return ret;
+}
+
+static int kcp_set_eeprom(struct net_device *dev,
+		struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct ethtool_eeprom *eeprom_tmp;
+	int ret = 0;
+	u32 remaining;
+	u32 offset = 0;
+	u32 payload;
+
+	if (sizeof(struct ethtool_eeprom) > KCP_ETHTOOL_MSG_LEN)
+		return -1;
+
+	eeprom_tmp = kmalloc(KCP_ETHTOOL_MSG_LEN, GFP_KERNEL);
+	payload = KCP_ETHTOOL_MSG_LEN - sizeof(struct ethtool_eeprom);
+
+	*eeprom_tmp = *eeprom;
+	remaining = eeprom->len;
+
+	while (remaining > 0 && ret == 0) {
+		eeprom_tmp->len = min(remaining, payload);
+
+		memcpy(eeprom_tmp->data, data + offset, payload);
+
+		ret = kcp_nl_exec(eeprom->cmd, dev, eeprom,
+				KCP_ETHTOOL_MSG_LEN, NULL, 0);
+
+		eeprom_tmp->offset += eeprom_tmp->len;
+		offset += eeprom_tmp->len;
+		remaining -= eeprom_tmp->len;
+	}
+
+	kfree(eeprom_tmp);
+
+	return ret;
+}
+
+static void kcp_get_ringparam(struct net_device *dev,
+		struct ethtool_ringparam *ring)
+{
+	kcp_nl_exec(ring->cmd, dev, NULL, 0,
+			ring, sizeof(struct ethtool_ringparam));
+}
+
+static int kcp_set_ringparam(struct net_device *dev,
+		struct ethtool_ringparam *ring)
+{
+	return kcp_nl_exec(ring->cmd, dev, ring,
+			sizeof(struct ethtool_ringparam), NULL, 0);
+}
+
+static void kcp_get_pauseparam(struct net_device *dev,
+		struct ethtool_pauseparam *pause)
+{
+	kcp_nl_exec(pause->cmd, dev, NULL, 0,
+			pause, sizeof(struct ethtool_pauseparam));
+}
+
+static int kcp_set_pauseparam(struct net_device *dev,
+		struct ethtool_pauseparam *pause)
+{
+	return kcp_nl_exec(pause->cmd, dev, pause,
+			sizeof(struct ethtool_pauseparam), NULL, 0);
+}
+
+static u32 kcp_get_msglevel(struct net_device *dev)
+{
+	u32 data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GMSGLVL, dev, NULL, 0, &data, sizeof(u32));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_set_msglevel(struct net_device *dev, u32 data)
+{
+	kcp_nl_exec(ETHTOOL_SMSGLVL, dev, &data, sizeof(u32), NULL, 0);
+}
+
+static int kcp_get_regs_len(struct net_device *dev)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GREGS_LEN, dev, NULL, 0, &data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+		void *p)
+{
+	struct ethtool_regs regs_tmp;
+	u32 len = regs->len;
+
+	regs_tmp = *regs;
+
+	if (len > KCP_ETHTOOL_MSG_LEN) {
+		len = KCP_ETHTOOL_MSG_LEN;
+		regs_tmp.len = len;
+	}
+
+	kcp_nl_exec(regs->cmd, dev, &regs_tmp, sizeof(struct ethtool_regs),
+			p, len);
+}
+
+static void kcp_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	kcp_nl_exec(ETHTOOL_GSTRINGS, dev, &stringset, sizeof(u32), data, 0);
+}
+
+static int kcp_get_sset_count(struct net_device *dev, int sset)
+{
+	int data;
+	int ret;
+
+	ret = kcp_nl_exec(ETHTOOL_GSSET_COUNT, dev, &sset, sizeof(int),
+			&data, sizeof(int));
+	if (ret < 0)
+		return 0;
+
+	return data;
+}
+
+static void kcp_get_ethtool_stats(struct net_device *dev,
+		struct ethtool_stats *stats, u64 *data)
+{
+	kcp_nl_exec(stats->cmd, dev, stats, sizeof(struct ethtool_stats),
+			data, stats->n_stats);
+}
+
+static const struct ethtool_ops kcp_ethtool_ops = {
+	.begin			= kcp_check_if_running,
+	.get_drvinfo		= kcp_get_drvinfo,
+	.get_settings		= kcp_get_settings,
+	.set_settings		= kcp_set_settings,
+	.get_regs_len		= kcp_get_regs_len,
+	.get_regs		= kcp_get_regs,
+	.get_wol		= kcp_get_wol,
+	.set_wol		= kcp_set_wol,
+	.nway_reset		= kcp_nway_reset,
+	.get_link		= kcp_get_link,
+	.get_eeprom_len		= kcp_get_eeprom_len,
+	.get_eeprom		= kcp_get_eeprom,
+	.set_eeprom		= kcp_set_eeprom,
+	.get_ringparam		= kcp_get_ringparam,
+	.set_ringparam		= kcp_set_ringparam,
+	.get_pauseparam		= kcp_get_pauseparam,
+	.set_pauseparam		= kcp_set_pauseparam,
+	.get_msglevel		= kcp_get_msglevel,
+	.set_msglevel		= kcp_set_msglevel,
+	.get_strings		= kcp_get_strings,
+	.get_sset_count		= kcp_get_sset_count,
+	.get_ethtool_stats	= kcp_get_ethtool_stats,
+};
+
+void kcp_set_ethtool_ops(struct net_device *netdev)
+{
+	netdev->ethtool_ops = &kcp_ethtool_ops;
+}
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_net.c b/lib/librte_eal/linuxapp/kcp/kcp_net.c
new file mode 100644
index 0000000..99a11d2
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_net.c
@@ -0,0 +1,219 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <net/rtnetlink.h>
+
+#include "kcp_dev.h"
+
+static int kcp_net_init(struct net_device *dev)
+{
+	u8 mac[ETH_ALEN] = {0};
+
+	kcp_nl_exec(RTE_KCP_REQ_GET_MAC, dev, NULL, 0, mac, ETH_ALEN);
+	memcpy(dev->dev_addr, mac, dev->addr_len);
+	return 0;
+}
+
+static int kcp_net_open(struct net_device *dev)
+{
+	/* DPDK port already started, stop it first */
+	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+	kcp_nl_exec(RTE_KCP_REQ_START_PORT, dev, NULL, 0, NULL, 0);
+	netif_start_queue(dev);
+	return 0;
+}
+
+static int kcp_net_close(struct net_device *dev)
+{
+	kcp_nl_exec(RTE_KCP_REQ_STOP_PORT, dev, NULL, 0, NULL, 0);
+	netif_stop_queue(dev);
+	return 0;
+}
+
+static int kcp_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static void kcp_net_change_rx_flags(struct net_device *dev, int flags)
+{
+	u32 on = 1;
+	u32 off = 0;
+
+	if (flags & IFF_PROMISC)
+		kcp_nl_exec(RTE_KCP_REQ_SET_PROMISC, dev,
+				dev->flags & IFF_PROMISC ?  &on : &off,
+				sizeof(u32), NULL, 0);
+
+	if (flags & IFF_ALLMULTI)
+		kcp_nl_exec(RTE_KCP_REQ_SET_ALLMULTI, dev,
+				dev->flags & IFF_ALLMULTI ?  &on : &off,
+				sizeof(u32), NULL, 0);
+}
+
+static int kcp_net_set_mac(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	int err;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_SET_MAC, dev, addr->sa_data,
+			dev->addr_len, NULL, 0);
+	if (err < 0)
+		return -EADDRNOTAVAIL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	return 0;
+}
+
+static int kcp_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+static int kcp_net_config(struct net_device *dev, struct ifmap *map)
+{
+	if (dev->flags & IFF_UP)
+		return -EBUSY;
+
+	return -EOPNOTSUPP;
+}
+
+static int kcp_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	int err = 0;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_CHANGE_MTU, dev, &new_mtu, sizeof(int),
+			NULL, 0);
+
+	if (err == 0)
+		dev->mtu = new_mtu;
+
+	return err;
+}
+
+static struct rtnl_link_stats64 *kcp_net_stats64(struct net_device *dev,
+		struct rtnl_link_stats64 *stats)
+{
+	int err;
+
+	err = kcp_nl_exec(RTE_KCP_REQ_GET_STATS, dev, NULL, 0,
+			stats, sizeof(struct rtnl_link_stats64));
+
+	return stats;
+}
+
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+static int kcp_net_change_carrier(struct net_device *dev, bool new_carrier)
+{
+	if (new_carrier)
+		netif_carrier_on(dev);
+	else
+		netif_carrier_off(dev);
+	return 0;
+}
+#endif
+
+static const struct net_device_ops kcp_net_netdev_ops = {
+	.ndo_init = kcp_net_init,
+	.ndo_open = kcp_net_open,
+	.ndo_stop = kcp_net_close,
+	.ndo_start_xmit = kcp_net_xmit,
+	.ndo_change_rx_flags = kcp_net_change_rx_flags,
+	.ndo_set_mac_address = kcp_net_set_mac,
+	.ndo_do_ioctl = kcp_net_ioctl,
+	.ndo_set_config = kcp_net_config,
+	.ndo_change_mtu = kcp_net_change_mtu,
+	.ndo_get_stats64 = kcp_net_stats64,
+#if (KERNEL_VERSION(3, 9, 0) <= LINUX_VERSION_CODE)
+	.ndo_change_carrier = kcp_net_change_carrier,
+#endif
+};
+
+static void kcp_net_setup(struct net_device *dev)
+{
+	struct kcp_dev *kcp;
+
+	ether_setup(dev);
+	dev->netdev_ops = &kcp_net_netdev_ops;
+
+	kcp = netdev_priv(dev);
+	init_completion(&kcp->msg_received);
+
+	kcp_set_ethtool_ops(dev);
+}
+
+static int kcp_net_newlink(struct net *net, struct net_device *dev,
+		struct nlattr *tb[], struct nlattr *data[])
+{
+	struct kcp_dev *kcp = netdev_priv(dev);
+
+	if (data && data[IFLA_KCP_PORTID])
+		kcp->port_id = nla_get_u8(data[IFLA_KCP_PORTID]);
+	else
+		kcp->port_id = 0;
+
+	if (data && data[IFLA_KCP_PID])
+		kcp->pid = nla_get_u32(data[IFLA_KCP_PID]);
+	else
+		kcp->pid = 0;
+
+	return register_netdevice(dev);
+}
+
+static struct rtnl_link_ops kcp_link_ops __read_mostly = {
+	.kind = KCP_DEVICE,
+	.priv_size = sizeof(struct kcp_dev),
+	.setup = kcp_net_setup,
+	.maxtype = IFLA_KCP_MAX,
+	.newlink = kcp_net_newlink,
+};
+
+static int __init kcp_init(void)
+{
+	kcp_nl_init();
+	return rtnl_link_register(&kcp_link_ops);
+}
+module_init(kcp_init);
+
+static void __exit kcp_exit(void)
+{
+	rtnl_link_unregister(&kcp_link_ops);
+	kcp_nl_release();
+}
+module_exit(kcp_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Kernel Module for managing kcp devices");
diff --git a/lib/librte_eal/linuxapp/kcp/kcp_nl.c b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
new file mode 100644
index 0000000..ec62f53
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
@@ -0,0 +1,220 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of version 2 of the GNU General Public License as
+ *   published by the Free Software Foundation.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *   General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;
+ *   The full GNU General Public License is included in this distribution
+ *   in the file called LICENSE.GPL.
+ *
+ *   Contact Information:
+ *   Intel Corporation
+ */
+
+#include <net/sock.h>
+
+#include "kcp_dev.h"
+
+#define KCP_CMD_TIMEOUT 500 /* ms */
+
+static struct ethtool_input_buffer {
+	int magic;
+	void *buffer;
+	size_t length;
+	struct completion *msg_received;
+	int *err;
+	u32 in_use;
+} ethtool_input_buffer;
+
+static struct sock *nl_sock;
+static struct mutex sync_lock;
+
+static int kcp_input_buffer_register(int magic, void *buffer, size_t length,
+		struct completion *msg_received, int *err)
+{
+	if (!ethtool_input_buffer.in_use) {
+		ethtool_input_buffer.magic = magic;
+		ethtool_input_buffer.buffer = buffer;
+		ethtool_input_buffer.length = length;
+		ethtool_input_buffer.msg_received = msg_received;
+		ethtool_input_buffer.err = err;
+		ethtool_input_buffer.in_use = 1;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void kcp_input_buffer_unregister(int magic)
+{
+	if (ethtool_input_buffer.in_use) {
+		if (magic == ethtool_input_buffer.magic) {
+			ethtool_input_buffer.magic = -1;
+			ethtool_input_buffer.buffer = NULL;
+			ethtool_input_buffer.length = 0;
+			ethtool_input_buffer.msg_received = NULL;
+			ethtool_input_buffer.err = NULL;
+			ethtool_input_buffer.in_use = 0;
+		} else {
+			pr_err("Unregister magic mismatch\n");
+		}
+	}
+}
+
+static void nl_recv_user_request(struct kcp_ethtool_msg *ethtool_msg)
+{
+	KCP_DBG("Request from userspace received\n");
+}
+
+static void nl_recv_user_response(struct kcp_ethtool_msg *ethtool_msg)
+{
+	struct completion *msg_received;
+	size_t recv_len;
+	size_t expected_len;
+
+	if (ethtool_input_buffer.in_use) {
+		if (ethtool_input_buffer.buffer != NULL) {
+			recv_len = ethtool_msg->output_buffer_len;
+			expected_len = ethtool_input_buffer.length;
+
+			memcpy(ethtool_input_buffer.buffer,
+					ethtool_msg->output_buffer,
+					ethtool_input_buffer.length);
+
+			if (ethtool_msg->err == 0 && recv_len != expected_len)
+				pr_info("Expected and received len not match "
+					"%zu - %zu\n", recv_len, expected_len);
+		}
+
+		*ethtool_input_buffer.err = ethtool_msg->err;
+		msg_received = ethtool_input_buffer.msg_received;
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		complete(msg_received);
+	}
+}
+
+static void nl_recv(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	nlh = (struct nlmsghdr *)skb->data;
+
+	memcpy(&ethtool_msg, NLMSG_DATA(nlh), sizeof(struct kcp_ethtool_msg));
+	KCP_DBG("CMD: %u\n", ethtool_msg.cmd_id);
+
+	if (ethtool_msg.flag & KCP_MSG_FLAG_REQUEST) {
+		nl_recv_user_request(&ethtool_msg);
+		return;
+	}
+
+	nl_recv_user_response(&ethtool_msg);
+}
+
+static int kcp_nl_send(u32 cmd_id, u8 port_id, u32 pid, void *in_data,
+		size_t in_data_len)
+{
+	struct sk_buff *skb;
+	struct nlmsghdr *nlh;
+	struct kcp_ethtool_msg ethtool_msg;
+
+	if (pid == 0)
+		return -1;
+
+	memset(&ethtool_msg, 0, sizeof(struct kcp_ethtool_msg));
+	ethtool_msg.cmd_id = cmd_id;
+	ethtool_msg.port_id = port_id;
+
+	if (in_data) {
+		if (in_data_len == 0 || in_data_len > KCP_ETHTOOL_MSG_LEN)
+			return -EINVAL;
+		ethtool_msg.input_buffer_len = in_data_len;
+		memcpy(ethtool_msg.input_buffer, in_data, in_data_len);
+	}
+
+	skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct kcp_ethtool_msg)),
+			GFP_ATOMIC);
+	nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, sizeof(struct kcp_ethtool_msg),
+			0);
+
+	NETLINK_CB(skb).dst_group = 0;
+
+	memcpy(nlmsg_data(nlh), &ethtool_msg, sizeof(struct kcp_ethtool_msg));
+
+	nlmsg_unicast(nl_sock, skb, pid);
+	KCP_DBG("Sent cmd:%u port:%u pid:%u\n", cmd_id, port_id, pid);
+
+	return 0;
+}
+
+int kcp_nl_exec(u32 cmd, struct net_device *dev, void *in_data,
+		size_t in_data_len, void *out_data, size_t out_data_len)
+{
+	struct kcp_dev *kcp = netdev_priv(dev);
+	int err = -EINVAL;
+	int ret;
+
+	if (out_data_len > KCP_ETHTOOL_MSG_LEN) {
+		pr_err("Message is too big to receive:%zu\n", out_data_len);
+		return err;
+	}
+
+	mutex_lock(&sync_lock);
+	ret = kcp_input_buffer_register(cmd, out_data, out_data_len,
+			&kcp->msg_received, &err);
+	if (ret) {
+		mutex_unlock(&sync_lock);
+		return -EINVAL;
+	}
+
+	ret = kcp_nl_send(cmd, kcp->port_id, kcp->pid, in_data, in_data_len);
+	if (ret) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		return ret;
+	}
+
+	ret = wait_for_completion_interruptible_timeout(&kcp->msg_received,
+			 msecs_to_jiffies(KCP_CMD_TIMEOUT));
+	if (ret == 0 || err < 0) {
+		kcp_input_buffer_unregister(ethtool_input_buffer.magic);
+		mutex_unlock(&sync_lock);
+		if (ret == 0) { /* timeout */
+			kcp->nb_timedout_msg++;
+			pr_info("Command timed-out for port:%u cmd:%u (%u)\n",
+				kcp->port_id, cmd, kcp->nb_timedout_msg);
+			return -EINVAL;
+		}
+		KCP_DBG("Command return error for port:%d cmd:%d err:%d\n",
+				kcp->port_id, cmd, err);
+		return err;
+	}
+	mutex_unlock(&sync_lock);
+
+	return 0;
+}
+
+static struct netlink_kernel_cfg cfg = {
+	.input = nl_recv,
+};
+
+void kcp_nl_init(void)
+{
+	nl_sock = netlink_kernel_create(&init_net, KCP_NL_GRP, &cfg);
+	mutex_init(&sync_lock);
+}
+
+void kcp_nl_release(void)
+{
+	netlink_kernel_release(nl_sock);
+}
-- 
2.5.0

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

* [PATCH v5 3/4] rte_ctrl_if: add control interface library
  2016-03-09 11:41       ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  2016-03-09 11:41         ` [PATCH v5 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
  2016-03-09 11:41         ` [PATCH v5 2/4] kcp: add kernel control path kernel module Ferruh Yigit
@ 2016-03-09 11:41         ` Ferruh Yigit
  2016-03-09 11:41         ` [PATCH v5 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
  2016-03-14 15:31         ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  4 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-09 11:41 UTC (permalink / raw)
  To: dev

This library gets control messages form kernelspace and forwards them to
librte_ether and returns response back to the kernelspace.

Library does:
1) Trigger Linux virtual interface creation
2) Initialize the netlink socket communication
3) Provides process() API to the application that does processing the
received messages

This library requires corresponding kernel module to be inserted.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

v5:
* Use unsigned primitive types as possible

v4:
* Add ethtool_get_settings as dummy

v3:
* Use librte_ethtool
* Don't create interfaces for virtual PMDs
* Add a new API ...msg_exist() to support port based locking
* Add enable/disable promisc, allmulti support

v2:
* User rtnetlink to create interfaces.
* Add more ethtool support: get/set ringparam, set pauseparam.
* return defined error instead of hardcoded value
---
 MAINTAINERS                                |   1 +
 config/common_base                         |   1 +
 config/common_linuxapp                     |   1 +
 doc/api/doxy-api-index.md                  |   1 +
 doc/api/doxy-api.conf                      |   1 +
 doc/guides/prog_guide/ctrl_if_lib.rst      |  52 ++++
 doc/guides/prog_guide/index.rst            |   1 +
 doc/guides/rel_notes/release_16_04.rst     |   8 +
 lib/Makefile                               |   3 +-
 lib/librte_ctrl_if/Makefile                |  58 +++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.c      | 391 ++++++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ctrl_ethtool.h      |  54 ++++
 lib/librte_ctrl_if/rte_ctrl_if.c           | 395 +++++++++++++++++++++++++++++
 lib/librte_ctrl_if/rte_ctrl_if.h           | 129 ++++++++++
 lib/librte_ctrl_if/rte_ctrl_if_version.map |  10 +
 lib/librte_ctrl_if/rte_nl.c                | 313 +++++++++++++++++++++++
 lib/librte_ctrl_if/rte_nl.h                |  50 ++++
 lib/librte_eal/common/include/rte_log.h    |   3 +-
 mk/rte.app.mk                              |   3 +-
 19 files changed, 1472 insertions(+), 3 deletions(-)
 create mode 100644 doc/guides/prog_guide/ctrl_if_lib.rst
 create mode 100644 lib/librte_ctrl_if/Makefile
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_ethtool.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.c
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if.h
 create mode 100644 lib/librte_ctrl_if/rte_ctrl_if_version.map
 create mode 100644 lib/librte_ctrl_if/rte_nl.c
 create mode 100644 lib/librte_ctrl_if/rte_nl.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b461b77..dd73cc5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -261,6 +261,7 @@ F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 Linux KCP
 M: Ferruh Yigit <ferruh.yigit@intel.com>
 F: lib/librte_eal/linuxapp/kcp/
+F: lib/librte_ctrl_if/
 
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
diff --git a/config/common_base b/config/common_base
index 86815d6..1c138d7 100644
--- a/config/common_base
+++ b/config/common_base
@@ -494,6 +494,7 @@ CONFIG_RTE_LIBRTE_ETHTOOL=n
 #
 CONFIG_RTE_KCP_KMOD=n
 CONFIG_RTE_KCP_KO_DEBUG=n
+CONFIG_RTE_LIBRTE_CTRL_IF=n
 
 #
 # Compile vhost library
diff --git a/config/common_linuxapp b/config/common_linuxapp
index e67a546..86bfe3c 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -41,6 +41,7 @@ CONFIG_RTE_KNI_KMOD=y
 CONFIG_RTE_LIBRTE_KNI=y
 CONFIG_RTE_LIBRTE_ETHTOOL=y
 CONFIG_RTE_KCP_KMOD=y
+CONFIG_RTE_LIBRTE_CTRL_IF=y
 CONFIG_RTE_LIBRTE_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
 CONFIG_RTE_LIBRTE_POWER=y
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 4cdd3f5..e34250d 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -151,3 +151,4 @@ There are many libraries, so their headers may be grouped by topics:
   [keepalive]          (@ref rte_keepalive.h),
   [version]            (@ref rte_version.h),
   [ethtool]            (@ref rte_ethtool.h),
+  [control interface]  (@ref rte_ctrl_if.h)
diff --git a/doc/api/doxy-api.conf b/doc/api/doxy-api.conf
index c5b8615..1a7999e 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -39,6 +39,7 @@ INPUT                   = doc/api/doxy-api-index.md \
                           lib/librte_cmdline \
                           lib/librte_compat \
                           lib/librte_cryptodev \
+                          lib/librte_ctrl_if \
                           lib/librte_distributor \
                           lib/librte_ether \
                           lib/librte_ethtool \
diff --git a/doc/guides/prog_guide/ctrl_if_lib.rst b/doc/guides/prog_guide/ctrl_if_lib.rst
new file mode 100644
index 0000000..36054b9
--- /dev/null
+++ b/doc/guides/prog_guide/ctrl_if_lib.rst
@@ -0,0 +1,52 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+.. _Ctrl_If_Library:
+
+Control Interface Library
+=========================
+
+This Library is to create/destroy control interfaces and process messages
+received by control interface.
+
+Control Interface is Linux network interface and it is possible to call
+various Linux commands to this interface and commands will be forwarded
+to the matching DPDK PMD, and response will be generated by PMD.
+
+Control interface required KCP kernel module to be inserted to function.
+
+Control Interface APIS
+----------------------
+
+
+- ``rte_eth_control_interface_create()``
+- ``rte_eth_control_interface_destroy()``
+- ``rte_eth_control_interface_msg_exist()``
+- ``rte_eth_control_interface_msg_process()``
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index 98f4aca..aadc476 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -52,6 +52,7 @@ Programmer's Guide
     reorder_lib
     ip_fragment_reassembly_lib
     ethtool_lib
+    ctrl_if_lib
     multi_proc_support
     kernel_nic_interface
     thread_safety_dpdk_functions
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index a07c292..0a9e188 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -63,6 +63,13 @@ This section should contain new features added in this release. Sample format:
   space bytes, to boost the performance. In the meanwhile, it deprecated the
   legacy way via reading/writing sysfile supported by kernel module igb_uio.
 
+* **Control interface support added.**
+
+  To enable controlling DPDK ports by common Linux tools.
+  Following modules added to DPDK:
+
+  * librte_ctrl_if library
+  * librte_eal/linuxapp/kcp kernel module
 
 Resolved Issues
 ---------------
@@ -162,6 +169,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_acl.so.2
      librte_cfgfile.so.2
      librte_cmdline.so.1
+   + librte_ctrl_if.so.1
      librte_distributor.so.1
      librte_eal.so.2
    + librte_ethtool.so.1
diff --git a/lib/Makefile b/lib/Makefile
index 57b66c6..646fee8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -59,6 +59,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
 DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
 DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
 DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
+DIRS-$(CONFIG_RTE_LIBRTE_CTRL_IF) += librte_ctrl_if
 
 ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
 DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_ctrl_if/Makefile b/lib/librte_ctrl_if/Makefile
new file mode 100644
index 0000000..fbb418b
--- /dev/null
+++ b/lib/librte_ctrl_if/Makefile
@@ -0,0 +1,58 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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_ctrl_if.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+EXPORT_MAP := rte_ctrl_if_version.map
+
+LIBABIVER := 1
+
+SRCS-y += rte_ctrl_if.c
+SRCS-y += rte_nl.c
+SRCS-y += rte_ctrl_ethtool.c
+
+#
+# Export include files
+#
+SYMLINK-y-include += rte_ctrl_if.h
+
+# this lib depends upon:
+DEPDIRS-y += lib/librte_ether lib/librte_ethtool
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_ctrl_if/rte_ctrl_ethtool.c b/lib/librte_ctrl_if/rte_ctrl_ethtool.c
new file mode 100644
index 0000000..4f9b54e
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_ethtool.c
@@ -0,0 +1,391 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <error.h>
+
+#include <linux/if_link.h>
+
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include <rte_ethtool.h>
+#include "rte_ctrl_ethtool.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int
+get_settings(uint8_t port_id __rte_unused, void *data, size_t *data_len)
+{
+	struct ethtool_cmd *ecmd = data;
+
+	/* No PMD equivalent, added to make get pauseparam work */
+	memset(ecmd, 0, sizeof(struct ethtool_cmd));
+
+	*data_len = sizeof(struct ethtool_cmd);
+	return 0;
+}
+
+static int
+get_drvinfo(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct ethtool_drvinfo *info = data;
+	int ret;
+
+	ret = rte_ethtool_get_drvinfo(port_id, info);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_drvinfo);
+
+	return 0;
+}
+
+static int
+get_reg_len(uint8_t port_id, void *data, size_t *data_len)
+{
+	int reg_length = 0;
+
+	reg_length = rte_ethtool_get_regs_len(port_id);
+	if (reg_length < 0)
+		return reg_length;
+
+	*(int *)data = reg_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_reg_len_internal(uint8_t port_id, size_t *reg_length)
+{
+	size_t reg_length_out_len;
+
+	return get_reg_len(port_id, reg_length, &reg_length_out_len);
+}
+
+static int
+get_reg(uint8_t port_id, void *in_data, void *out_data, size_t *out_data_len)
+{
+	size_t reg_length;
+	struct ethtool_regs *ethtool_regs = in_data;
+	int ret;
+
+	ret = get_reg_len_internal(port_id, &reg_length);
+	/* not enough space in out data buffer */
+	if (ret < 0 || reg_length > ethtool_regs->len)
+		return -1;
+
+	ret = rte_ethtool_get_regs(port_id, ethtool_regs, out_data);
+	if (ret < 0)
+		return ret;
+
+	*out_data_len = reg_length;
+
+	return 0;
+}
+
+static int
+get_link(uint8_t port_id, void *data, size_t *data_len)
+{
+	int ret;
+
+	ret = rte_ethtool_get_link(port_id);
+
+	*(int *)data = ret;
+	*data_len = sizeof(size_t);
+
+	return 0;
+}
+
+static int
+get_eeprom_length(uint8_t port_id, void *data, size_t *data_len)
+{
+	int eeprom_length = 0;
+
+	eeprom_length = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_length < 0)
+		return eeprom_length;
+
+	*(int *)data = eeprom_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom(uint8_t port_id, void *in_data, void *out_data,
+		size_t *out_data_len)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	int ret;
+
+	ret = rte_ethtool_get_eeprom(port_id, eeprom, out_data);
+	if (ret < 0)
+		return ret;
+
+	*out_data_len = eeprom->len;
+
+	return 0;
+}
+
+static int
+set_eeprom(uint8_t port_id, void *in_data)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	int ret;
+
+	ret = rte_ethtool_set_eeprom(port_id, eeprom, eeprom->data);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+get_ringparam(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct ethtool_ringparam *ringparam = data;
+	int ret;
+
+	ret = rte_ethtool_get_ringparam(port_id, ringparam);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_ringparam);
+
+	return 0;
+}
+
+static int
+set_ringparam(uint8_t port_id, void *data)
+{
+	struct ethtool_ringparam *ringparam = data;
+	int ret;
+
+	ret = rte_ethtool_set_ringparam(port_id, ringparam);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+get_pauseparam(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+	int ret;
+
+	ret = rte_ethtool_get_pauseparam(port_id, pauseparam);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_pauseparam);
+
+	return 0;
+}
+
+static int
+set_pauseparam(uint8_t port_id, void *data)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+
+	return rte_ethtool_set_pauseparam(port_id, pauseparam);
+}
+
+int
+rte_eth_dev_ethtool_process(uint32_t cmd_id, uint8_t port_id, void *in_data,
+		void *out_data, size_t *out_data_len)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case ETHTOOL_GSET:
+		return get_settings(port_id, out_data, out_data_len);
+	case ETHTOOL_GDRVINFO:
+		return get_drvinfo(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS_LEN:
+		return get_reg_len(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS:
+		return get_reg(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_GLINK:
+		return get_link(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM_LEN:
+		return get_eeprom_length(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM:
+		return get_eeprom(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_SEEPROM:
+		return set_eeprom(port_id, in_data);
+	case ETHTOOL_GRINGPARAM:
+		return get_ringparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SRINGPARAM:
+		return set_ringparam(port_id, in_data);
+	case ETHTOOL_GPAUSEPARAM:
+		return get_pauseparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SPAUSEPARAM:
+		return set_pauseparam(port_id, in_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int
+set_mtu(uint8_t port_id, void *in_data)
+{
+	int *mtu = in_data;
+
+	return rte_eth_dev_set_mtu(port_id, *mtu);
+}
+
+static int
+get_stats(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct rte_eth_stats stats;
+	struct rtnl_link_stats64 *if_stats = data;
+	int ret;
+
+	ret = rte_eth_stats_get(port_id, &stats);
+	if (ret < 0)
+		return -EOPNOTSUPP;
+
+	if_stats->rx_packets = stats.ipackets;
+	if_stats->tx_packets = stats.opackets;
+	if_stats->rx_bytes = stats.ibytes;
+	if_stats->tx_bytes = stats.obytes;
+	if_stats->rx_errors = stats.ierrors;
+	if_stats->tx_errors = stats.oerrors;
+	if_stats->rx_dropped = stats.imissed;
+	if_stats->multicast = stats.imcasts;
+
+	*data_len = sizeof(struct rtnl_link_stats64);
+
+	return 0;
+}
+
+static int
+get_mac(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(port_id, &addr);
+	memcpy(data, &addr, sizeof(struct ether_addr));
+
+	*data_len = sizeof(struct ether_addr);
+
+	return 0;
+}
+
+static int
+set_mac(uint8_t port_id, void *in_data)
+{
+	struct ether_addr addr;
+
+	memcpy(&addr, in_data, ETHER_ADDR_LEN);
+
+	return rte_eth_dev_default_mac_addr_set(port_id, &addr);
+}
+
+static int
+start_port(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return rte_eth_dev_start(port_id);
+}
+
+static int
+stop_port(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return 0;
+}
+
+static int
+set_promisc(uint8_t port_id, void *in_data)
+{
+	int *promisc = in_data;
+
+	if (*promisc)
+		rte_eth_promiscuous_enable(port_id);
+	else
+		rte_eth_promiscuous_disable(port_id);
+
+	return 0;
+}
+
+static int
+set_allmulti(uint8_t port_id, void *in_data)
+{
+	int *allmulti = in_data;
+
+	if (*allmulti)
+		rte_eth_allmulticast_enable(port_id);
+	else
+		rte_eth_allmulticast_disable(port_id);
+
+	return 0;
+}
+
+int
+rte_eth_dev_control_process(uint32_t cmd_id, uint8_t port_id, void *in_data,
+		void *out_data, size_t *out_data_len)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case RTE_KCP_REQ_CHANGE_MTU:
+		return set_mtu(port_id, in_data);
+	case RTE_KCP_REQ_GET_STATS:
+		return get_stats(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_GET_MAC:
+		return get_mac(port_id, out_data, out_data_len);
+	case RTE_KCP_REQ_SET_MAC:
+		return set_mac(port_id, in_data);
+	case RTE_KCP_REQ_START_PORT:
+		return start_port(port_id);
+	case RTE_KCP_REQ_STOP_PORT:
+		return stop_port(port_id);
+	case RTE_KCP_REQ_SET_PROMISC:
+		return set_promisc(port_id, in_data);
+	case RTE_KCP_REQ_SET_ALLMULTI:
+		return set_allmulti(port_id, in_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_ethtool.h b/lib/librte_ctrl_if/rte_ctrl_ethtool.h
new file mode 100644
index 0000000..26efb43
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_ethtool.h
@@ -0,0 +1,54 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_CTRL_ETHTOOL_H_
+#define _RTE_CTRL_ETHTOOL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <linux/ethtool.h>
+
+#include <exec-env/rte_kcp_common.h>
+
+int rte_eth_dev_ethtool_process(uint32_t cmd_id, uint8_t port_id, void *in_data,
+		void *out_data, size_t *out_data_len);
+int rte_eth_dev_control_process(uint32_t cmd_id, uint8_t port_id, void *in_data,
+		void *out_data, size_t *out_data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_ETHTOOL_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c
new file mode 100644
index 0000000..eedfed7
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.c
@@ -0,0 +1,395 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <rte_ethdev.h>
+#include "rte_ctrl_if.h"
+#include "rte_nl.h"
+
+#define NAMESZ 32
+#define IFNAME "dpdk"
+#define BUFSZ 1024
+
+static int kcp_rtnl_fd = -1;
+static uint32_t kcp_fd_ref;
+
+struct kcp_request {
+	struct nlmsghdr nlmsg;
+	uint8_t buf[BUFSZ];
+};
+
+static int
+conrol_interface_rtnl_init(void)
+{
+	struct sockaddr_nl src;
+	int ret;
+
+	kcp_rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (kcp_rtnl_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Socket for create failed\n");
+		return -1;
+	}
+
+	memset(&src, 0, sizeof(struct sockaddr_nl));
+
+	src.nl_family = AF_NETLINK;
+	src.nl_pid = getpid();
+
+	ret = bind(kcp_rtnl_fd, (struct sockaddr *)&src,
+			sizeof(struct sockaddr_nl));
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Bind for create failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+control_interface_init(void)
+{
+	int ret;
+
+	ret = conrol_interface_rtnl_init();
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize rtnetlink\n");
+		return -1;
+	}
+
+	ret = control_interface_nl_init();
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink\n");
+		close(kcp_rtnl_fd);
+		kcp_rtnl_fd = -1;
+	}
+
+	return ret;
+}
+
+static int
+control_interface_ref_get(void)
+{
+	int ret = 0;
+
+	if (kcp_fd_ref == 0)
+		ret = control_interface_init();
+
+	if (ret == 0)
+		kcp_fd_ref++;
+	else
+		RTE_LOG(ERR, CTRL_IF,
+				"Failed to initialize control interface\n");
+
+	return kcp_fd_ref;
+}
+
+static void
+control_interface_release(void)
+{
+	close(kcp_rtnl_fd);
+	control_interface_nl_release();
+}
+
+static int
+control_interface_ref_put(void)
+{
+	if (kcp_fd_ref == 0)
+		return 0;
+
+	kcp_fd_ref--;
+
+	if (kcp_fd_ref == 0)
+		control_interface_release();
+
+	return kcp_fd_ref;
+}
+
+static int
+add_attr(struct kcp_request *req, uint16_t type, void *buf, size_t len)
+{
+	struct rtattr *rta;
+	int nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(len) > sizeof(struct kcp_request))
+		return -1;
+	rta->rta_type = type;
+	rta->rta_len = RTA_LENGTH(len);
+	memcpy(RTA_DATA(rta), buf, len);
+	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(len);
+
+	return 0;
+}
+
+static struct
+rtattr *add_attr_nested(struct kcp_request *req, unsigned short type)
+{
+	struct rtattr *rta;
+	uint32_t nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((uint8_t *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(0) > sizeof(struct kcp_request))
+		return NULL;
+	rta->rta_type = type;
+	rta->rta_len = nlmsg_len;
+	req->nlmsg.nlmsg_len = nlmsg_len + RTA_LENGTH(0);
+
+	return rta;
+}
+
+static void
+end_attr_nested(struct kcp_request *req, struct rtattr *rta)
+{
+	rta->rta_len = req->nlmsg.nlmsg_len - rta->rta_len;
+}
+
+static int
+rte_eth_rtnl_create(uint8_t port_id)
+{
+	struct kcp_request req;
+	struct ifinfomsg *info;
+	struct rtattr *rta1;
+	struct rtattr *rta2;
+	uint32_t pid = getpid();
+	char name[NAMESZ];
+	char type[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+	uint8_t buf[BUFSZ];
+
+	memset(&req, 0, sizeof(struct kcp_request));
+
+	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlmsg.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
+	req.nlmsg.nlmsg_flags |= NLM_F_ACK;
+	req.nlmsg.nlmsg_type = RTM_NEWLINK;
+
+	info = NLMSG_DATA(&req.nlmsg);
+
+	info->ifi_family = AF_UNSPEC;
+	info->ifi_index = 0;
+
+	snprintf(name, NAMESZ, IFNAME"%u", port_id);
+	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
+	if (ret < 0)
+		return -1;
+
+	rta1 = add_attr_nested(&req, IFLA_LINKINFO);
+	if (rta1 == NULL)
+		return -1;
+
+	snprintf(type, NAMESZ, KCP_DEVICE);
+	ret = add_attr(&req, IFLA_INFO_KIND, type, strlen(type) + 1);
+	if (ret < 0)
+		return -1;
+
+	rta2 = add_attr_nested(&req, IFLA_INFO_DATA);
+	if (rta2 == NULL)
+		return -1;
+
+	ret = add_attr(&req, IFLA_KCP_PORTID, &port_id, sizeof(uint8_t));
+	if (ret < 0)
+		return -1;
+
+	ret = add_attr(&req, IFLA_KCP_PID, &pid, sizeof(uint32_t));
+	if (ret < 0)
+		return -1;
+
+	end_attr_nested(&req, rta2);
+	end_attr_nested(&req, rta1);
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for create failed %d.\n", errno);
+		return -1;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	iov.iov_base = buf;
+	iov.iov_len = sizeof(buf);
+
+	ret = recvmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Recv for create failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+rte_eth_control_interface_create_one(uint8_t port_id)
+{
+	int ret;
+
+	if (control_interface_ref_get() != 0) {
+		ret = rte_eth_rtnl_create(port_id);
+		RTE_LOG(DEBUG, CTRL_IF,
+			"Control interface %s for port:%u\n",
+			ret < 0 ? "failed" : "created", port_id);
+	}
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_create(void)
+{
+	uint8_t i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			if (rte_eth_devices[i].dev_type == RTE_ETH_DEV_VIRTUAL)
+				continue;
+			ret = rte_eth_control_interface_create_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int
+rte_eth_rtnl_destroy(uint8_t port_id)
+{
+	struct kcp_request req;
+	struct ifinfomsg *info;
+	char name[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+
+	memset(&req, 0, sizeof(struct kcp_request));
+
+	req.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.nlmsg.nlmsg_flags = NLM_F_REQUEST;
+	req.nlmsg.nlmsg_type = RTM_DELLINK;
+
+	info = NLMSG_DATA(&req.nlmsg);
+
+	info->ifi_family = AF_UNSPEC;
+	info->ifi_index = 0;
+
+	snprintf(name, NAMESZ, IFNAME"%u", port_id);
+	ret = add_attr(&req, IFLA_IFNAME, name, strlen(name) + 1);
+	if (ret < 0)
+		return -1;
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(kcp_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for destroy failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+rte_eth_control_interface_destroy_one(uint8_t port_id)
+{
+	rte_eth_rtnl_destroy(port_id);
+	control_interface_ref_put();
+	RTE_LOG(DEBUG, CTRL_IF, "Control interface destroyed for port:%u\n",
+			port_id);
+
+	return 0;
+}
+
+int
+rte_eth_control_interface_destroy(void)
+{
+	uint8_t i;
+	int ret = 0;
+
+	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+		if (rte_eth_dev_is_valid_port(i)) {
+			if (rte_eth_devices[i].dev_type == RTE_ETH_DEV_VIRTUAL)
+				continue;
+			ret = rte_eth_control_interface_destroy_one(i);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return ret;
+}
+
+uint8_t
+rte_eth_control_interface_msg_exist(uint32_t timeout_sec)
+{
+	return control_interface_msg_exist(timeout_sec);
+}
+
+int
+rte_eth_control_interface_msg_process(uint32_t flag)
+{
+	return control_interface_msg_process(flag);
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.h b/lib/librte_ctrl_if/rte_ctrl_if.h
new file mode 100644
index 0000000..22b0386
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.h
@@ -0,0 +1,129 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_CTRL_IF_H_
+#define _RTE_CTRL_IF_H_
+
+/**
+ * @file
+ *
+ * Control Interface Library for RTE
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <exec-env/rte_kcp_common.h>
+
+/**
+ * Flags values for rte_eth_control_interface_process_msg() API
+ */
+enum control_interface_process_flag {
+	/**< Process if msg available. */
+	RTE_ETHTOOL_CTRL_IF_PROCESS_MSG,
+
+	/**< Discard msg if available, respond with a error value. */
+	RTE_ETHTOOL_CTRL_IF_DISCARD_MSG,
+};
+
+/**
+ * Creates control interfaces (Linux virtual network interface)for
+ * each existing eal port.
+ *
+ * This API opens device created by supportive kernel module and initializes
+ * kernel communication interface.
+ *
+ * If supportive kernel module is not inserted this API will return
+ * an error.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_create(void);
+
+/**
+ * Destroys control interfaces.
+ *
+ * This API close device created by supportive kernel module and release
+ * underlying communication interface.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_destroy(void);
+
+/**
+ * Check if any msg exist to process.
+ *
+ * This function can be blocking or unblocking according timeout_sec
+ * parameter value. If function will be continuous loop, like can be
+ * called by any forwarding lcore, nonblocking mode should be preferred.
+ * If a separate thread created to handle control messages, blocking
+ * mode can be preferred to save CPU cycles.
+ *
+ * When this function sends a valid port_id, application must call
+ * msg_process() afterwards, to accept new commands.
+ *
+ * @param timeout_sec
+ *  if 0, function is in nonblocking mode.
+ *  if > 0, blocks for given time, if there is no message available,
+ *  sleeps again same amount of time. Value is in seconds.
+ *
+ * @return
+ *  port_id the msg for on success. -1 if no msg waiting.
+ */
+uint8_t rte_eth_control_interface_msg_exist(uint32_t timeout_sec);
+
+/**
+ * Process if any received message is available.
+ *
+ * If message exists this function will create a local copy of it and
+ * process or discard the message according flag.
+ *
+ * @param flag
+ *  Defines what to do with message, can be process or discard.
+ *
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_msg_process(uint32_t flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_IF_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if_version.map b/lib/librte_ctrl_if/rte_ctrl_if_version.map
new file mode 100644
index 0000000..c3a91ab
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if_version.map
@@ -0,0 +1,10 @@
+DPDK_16.04 {
+	global:
+
+	rte_eth_control_interface_create;
+	rte_eth_control_interface_destroy;
+	rte_eth_control_interface_msg_exist;
+	rte_eth_control_interface_msg_process;
+
+	local: *;
+};
diff --git a/lib/librte_ctrl_if/rte_nl.c b/lib/librte_ctrl_if/rte_nl.c
new file mode 100644
index 0000000..b883d0f
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.c
@@ -0,0 +1,313 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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 <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <rte_spinlock.h>
+#include <rte_ethdev.h>
+#include "rte_ctrl_ethtool.h"
+#include "rte_nl.h"
+#include "rte_ctrl_if.h"
+
+#define MAX_PAYLOAD sizeof(struct kcp_ethtool_msg)
+
+struct ctrl_if_nl {
+	union {
+		struct nlmsghdr nlh;
+		uint8_t nlmsg[NLMSG_SPACE(MAX_PAYLOAD)];
+	};
+	struct msghdr msg;
+	struct iovec iov;
+	struct sockaddr_nl dest_addr;
+};
+
+struct ctrl_if_msg_sync {
+	size_t kcp_ethtool_msg_count;
+	struct kcp_ethtool_msg msg_storage;
+	pthread_cond_t cond;
+	pthread_mutex_t msg_lock;
+	uint32_t pending_process;
+};
+
+static int sock_fd = -1;
+static pthread_t thread_id;
+
+static struct ctrl_if_nl nl_s;
+static struct ctrl_if_nl nl_r;
+
+static struct ctrl_if_msg_sync ctrl_if_sync = {
+	.cond = PTHREAD_COND_INITIALIZER,
+	.msg_lock = PTHREAD_MUTEX_INITIALIZER,
+};
+
+static int
+nl_send(void *buf, size_t len)
+{
+	int ret;
+
+	if (nl_s.nlh.nlmsg_len < len) {
+		RTE_LOG(ERR, CTRL_IF, "Message is too big, len:%zu\n", len);
+		return -1;
+	}
+
+	if (!NLMSG_OK(&nl_s.nlh, NLMSG_SPACE(MAX_PAYLOAD))) {
+		RTE_LOG(ERR, CTRL_IF, "Message is not OK\n");
+		return -1;
+	}
+
+	/* Fill in the netlink message payload */
+	memcpy(NLMSG_DATA(nl_s.nlmsg), buf, len);
+
+	ret = sendmsg(sock_fd, &nl_s.msg, 0);
+
+	if (ret < 0)
+		RTE_LOG(ERR, CTRL_IF, "Failed nl msg send. ret:%d, err:%d\n",
+				ret, errno);
+	return ret;
+}
+
+static int
+nl_ethtool_msg_send(struct kcp_ethtool_msg *msg)
+{
+	return nl_send((void *)msg, sizeof(struct kcp_ethtool_msg));
+}
+
+static void
+process_msg(struct kcp_ethtool_msg *msg)
+{
+	if (msg->cmd_id > RTE_KCP_REQ_UNKNOWN) {
+		msg->err = rte_eth_dev_control_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	} else {
+		msg->err = rte_eth_dev_ethtool_process(msg->cmd_id,
+				msg->port_id, msg->input_buffer,
+				msg->output_buffer, &msg->output_buffer_len);
+	}
+
+	if (msg->err)
+		memset(msg->output_buffer, 0, msg->output_buffer_len);
+
+	nl_ethtool_msg_send(msg);
+}
+
+
+uint8_t
+control_interface_msg_exist(uint32_t timeout_sec)
+{
+	struct timespec ts;
+	uint8_t port_id;
+	int ret = 0;
+
+	if (timeout_sec) {
+		clock_gettime(CLOCK_REALTIME, &ts);
+		ts.tv_sec += timeout_sec;
+	}
+
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+	while (timeout_sec && !ctrl_if_sync.kcp_ethtool_msg_count && !ret)
+		ret = pthread_cond_timedwait(&ctrl_if_sync.cond,
+				&ctrl_if_sync.msg_lock, &ts);
+
+	if (ctrl_if_sync.kcp_ethtool_msg_count == 0) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return -1;
+	}
+
+	ctrl_if_sync.pending_process = 1;
+
+	port_id = ctrl_if_sync.msg_storage.port_id;
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	return port_id;
+}
+
+int
+control_interface_msg_process(uint32_t flag)
+{
+	struct kcp_ethtool_msg msg_storage;
+	int ret = 0;
+
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+	if (ctrl_if_sync.kcp_ethtool_msg_count == 0) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return 0;
+	}
+
+	memcpy(&msg_storage, &ctrl_if_sync.msg_storage,
+			sizeof(struct kcp_ethtool_msg));
+	ctrl_if_sync.pending_process = 0;
+	ctrl_if_sync.kcp_ethtool_msg_count = 0;
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	switch (flag) {
+	case RTE_ETHTOOL_CTRL_IF_PROCESS_MSG:
+		process_msg(&msg_storage);
+		break;
+
+	case RTE_ETHTOOL_CTRL_IF_DISCARD_MSG:
+		msg_storage.err = -1;
+		nl_ethtool_msg_send(&msg_storage);
+		break;
+
+	default:
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+msg_add_and_signal(struct nlmsghdr *nlh)
+{
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+
+	if (ctrl_if_sync.pending_process) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return -1;
+	}
+
+	memcpy(&ctrl_if_sync.msg_storage, NLMSG_DATA(nlh),
+			sizeof(struct kcp_ethtool_msg));
+	ctrl_if_sync.kcp_ethtool_msg_count = 1;
+	ctrl_if_sync.msg_storage.flag = KCP_MSG_FLAG_RESPONSE;
+
+	pthread_cond_signal(&ctrl_if_sync.cond);
+
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	return 0;
+}
+
+static void *
+nl_recv(void *arg)
+{
+	int ret;
+
+	for (;;) {
+		ret = recvmsg(sock_fd, &nl_r.msg, 0);
+		if (ret < 0)
+			continue;
+
+		if ((unsigned)ret < sizeof(struct kcp_ethtool_msg)) {
+			RTE_LOG(WARNING, CTRL_IF,
+					"Received %u bytes, payload %lu\n",
+					ret, sizeof(struct kcp_ethtool_msg));
+			continue;
+		}
+
+		msg_add_and_signal(&nl_r.nlh);
+	}
+
+	return arg;
+}
+
+static void
+nl_setup_header(struct ctrl_if_nl *nl)
+{
+	nl->dest_addr.nl_family = AF_NETLINK;
+	nl->dest_addr.nl_pid = 0;   /*  For Linux Kernel */
+	nl->dest_addr.nl_groups = 0;
+
+	memset(nl->nlmsg, 0, NLMSG_SPACE(MAX_PAYLOAD));
+
+	/* Fill the netlink message header */
+	nl->nlh.nlmsg_len = NLMSG_LENGTH(MAX_PAYLOAD);
+	nl->nlh.nlmsg_pid = getpid();  /* self pid */
+	nl->nlh.nlmsg_flags = 0;
+
+	nl->iov.iov_base = (void *)nl->nlmsg;
+	nl->iov.iov_len = nl->nlh.nlmsg_len;
+	memset(&nl->msg, 0, sizeof(struct msghdr));
+	nl->msg.msg_name = (void *)&nl->dest_addr;
+	nl->msg.msg_namelen = sizeof(struct sockaddr_nl);
+	nl->msg.msg_iov = &nl->iov;
+	nl->msg.msg_iovlen = 1;
+}
+
+static int
+nl_socket_init(void)
+{
+	struct sockaddr_nl src_addr;
+	int fd;
+	int ret;
+
+	fd = socket(PF_NETLINK, SOCK_RAW, KCP_NL_GRP);
+	if (fd < 0)
+		return -1;
+
+	src_addr.nl_family = AF_NETLINK;
+	src_addr.nl_pid = getpid();
+	ret = bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
+	if (ret) {
+		close(fd);
+		return -1;
+	}
+
+	nl_setup_header(&nl_s);
+	nl_setup_header(&nl_r);
+
+	return fd;
+}
+
+int
+control_interface_nl_init(void)
+{
+	int ret;
+
+	sock_fd = nl_socket_init();
+	if (sock_fd < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to initialize netlink socket\n");
+		return -1;
+	}
+
+	ret = pthread_create(&thread_id, NULL, nl_recv, NULL);
+	if (ret != 0) {
+		RTE_LOG(ERR, CTRL_IF, "Failed to create receive thread\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+void
+control_interface_nl_release(void)
+{
+	pthread_cancel(thread_id);
+	pthread_join(thread_id, NULL);
+	close(sock_fd);
+}
diff --git a/lib/librte_ctrl_if/rte_nl.h b/lib/librte_ctrl_if/rte_nl.h
new file mode 100644
index 0000000..19daadc
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.h
@@ -0,0 +1,50 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_NL_H_
+#define _RTE_NL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int control_interface_nl_init(void);
+void control_interface_nl_release(void);
+uint8_t control_interface_msg_exist(uint32_t timeout_sec);
+int control_interface_msg_process(uint32_t flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_NL_H_ */
diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h
index 2e47e7f..a0a2c9f 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -79,6 +79,7 @@ extern struct rte_logs rte_logs;
 #define RTE_LOGTYPE_PIPELINE 0x00008000 /**< Log related to pipeline. */
 #define RTE_LOGTYPE_MBUF    0x00010000 /**< Log related to mbuf. */
 #define RTE_LOGTYPE_CRYPTODEV 0x00020000 /**< Log related to cryptodev. */
+#define RTE_LOGTYPE_CTRL_IF 0x00040000 /**< Log related to control interface. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1   0x01000000 /**< User-defined log type 1. */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index d94da7a..7d34e2e 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -114,6 +114,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF_OFFLOAD)   += -lrte_mbuf_offload
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG)        += -lrte_ip_frag
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lethdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHTOOL)        += -lrte_ethtool
+_LDLIBS-$(CONFIG_RTE_LIBRTE_CTRL_IF)        += -lrte_ctrl_if
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)      += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)           += -lrte_ring
-- 
2.5.0

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

* [PATCH v5 4/4] examples/ethtool: add control interface support to the application
  2016-03-09 11:41       ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
                           ` (2 preceding siblings ...)
  2016-03-09 11:41         ` [PATCH v5 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
@ 2016-03-09 11:41         ` Ferruh Yigit
  2016-03-09 12:23           ` Ananyev, Konstantin
  2016-03-14 15:31         ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
  4 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-09 11:41 UTC (permalink / raw)
  To: dev

Control interface APIs added into the sample application.

To have the support corresponding kernel module (KCP) needs to be inserted.
If kernel module is not there, application will run as it is without
kernel control path support.

When KCP module inserted, running application creates a virtual Linux
network interface (dpdk$) per DPDK port. This interface can be used by
traditional Linux tools.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Acked-by: Remy Horton <remy.horton@intel.com>
---

v4, v5:
* No update

v3:
* Use blocking mode control interface processing, instead of poll mode

v2:
* No update on sample app
---
 doc/guides/sample_app_ug/ethtool.rst | 41 ++++++++++++++++++++++++++++++++++++
 examples/ethtool/main.c              | 31 +++++++++++++++++++++++++--
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
index 65240ae..af591c2 100644
--- a/doc/guides/sample_app_ug/ethtool.rst
+++ b/doc/guides/sample_app_ug/ethtool.rst
@@ -130,3 +130,44 @@ interface that accepts commands as described in `using the
 application`_. Individual call-back functions handle the detail
 associated with each command, which make use of librte_ethtool
 library.
+
+Control Interface
+~~~~~~~~~~~~~~~~~
+
+If Kernel Control Path (KCP) kernel module (rte_kcp.ko) inserted,
+virtual interfaces created for each DPDK port for control purposes.
+
+Created interfaces are named as dpdk#, like:
+
+.. code-block:: console
+
+        # ifconfig dpdk0; ifconfig dpdk1
+        dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 90:e2:ba:0e:49:b9  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+        dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
+                ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
+                RX packets 0  bytes 0 (0.0 B)
+                RX errors 0  dropped 0  overruns 0  frame 0
+                TX packets 0  bytes 0 (0.0 B)
+                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
+
+Regular Linux commands can be issued on interfaces:
+
+.. code-block:: console
+
+        # ethtool -i dpdk0
+        driver: rte_ixgbe_pmd
+        version: RTE 2.3.0-rc0
+        firmware-version:
+        expansion-rom-version:
+        bus-info: 0000:08:00.1
+        supports-statistics: yes
+        supports-test: no
+        supports-eeprom-access: yes
+        supports-register-dump: yes
+        supports-priv-flags: no
diff --git a/examples/ethtool/main.c b/examples/ethtool/main.c
index 2c655d8..72fbe4c 100644
--- a/examples/ethtool/main.c
+++ b/examples/ethtool/main.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <rte_memory.h>
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
+#include <rte_ctrl_if.h>
 
 #include "ethapp.h"
 
@@ -54,7 +55,6 @@
 #define PKTPOOL_EXTRA_SIZE 512
 #define PKTPOOL_CACHE 32
 
-
 struct txq_port {
 	uint16_t cnt_unsent;
 	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
@@ -259,11 +259,32 @@ static int slave_main(__attribute__((unused)) void *ptr_data)
 	return 0;
 }
 
+static void *
+control_function(__attribute__((unused)) void *arg)
+{
+	int port_id;
+
+	while (1) {
+		/* blocking call with 1 sec timeout */
+		port_id = rte_eth_control_interface_msg_exist(1);
+		if (port_id < 0)
+			continue;
+
+		lock_port(port_id);
+		rte_eth_control_interface_msg_process(
+			RTE_ETHTOOL_CTRL_IF_PROCESS_MSG);
+		unlock_port(port_id);
+	}
+
+	return 0;
+}
+
 int main(int argc, char **argv)
 {
 	int cnt_args_parsed;
 	uint32_t id_core;
 	uint32_t cnt_ports;
+	pthread_t control_thread;
 
 	/* Init runtime enviornment */
 	cnt_args_parsed = rte_eal_init(argc, argv);
@@ -293,6 +314,9 @@ int main(int argc, char **argv)
 	id_core = rte_get_next_lcore(id_core, 1, 1);
 	rte_eal_remote_launch(slave_main, NULL, id_core);
 
+	pthread_create(&control_thread, NULL, control_function, NULL);
+	rte_eth_control_interface_create();
+
 	ethapp_main();
 
 	app_cfg.exit_now = 1;
@@ -301,5 +325,8 @@ int main(int argc, char **argv)
 			return -1;
 	}
 
+	rte_eth_control_interface_destroy();
+	pthread_cancel(control_thread);
+
 	return 0;
 }
-- 
2.5.0

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

* Re: [PATCH v5 4/4] examples/ethtool: add control interface support to the application
  2016-03-09 11:41         ` [PATCH v5 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
@ 2016-03-09 12:23           ` Ananyev, Konstantin
  0 siblings, 0 replies; 83+ messages in thread
From: Ananyev, Konstantin @ 2016-03-09 12:23 UTC (permalink / raw)
  To: Yigit, Ferruh, dev



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Ferruh Yigit
> Sent: Wednesday, March 09, 2016 11:41 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v5 4/4] examples/ethtool: add control interface support to the application
> 
> Control interface APIs added into the sample application.
> 
> To have the support corresponding kernel module (KCP) needs to be inserted.
> If kernel module is not there, application will run as it is without
> kernel control path support.
> 
> When KCP module inserted, running application creates a virtual Linux
> network interface (dpdk$) per DPDK port. This interface can be used by
> traditional Linux tools.
> 
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> Acked-by: Remy Horton <remy.horton@intel.com>
> ---
> 
> v4, v5:
> * No update
> 
> v3:
> * Use blocking mode control interface processing, instead of poll mode
> 
> v2:
> * No update on sample app
> ---
>  doc/guides/sample_app_ug/ethtool.rst | 41 ++++++++++++++++++++++++++++++++++++
>  examples/ethtool/main.c              | 31 +++++++++++++++++++++++++--
>  2 files changed, 70 insertions(+), 2 deletions(-)
> 
> diff --git a/doc/guides/sample_app_ug/ethtool.rst b/doc/guides/sample_app_ug/ethtool.rst
> index 65240ae..af591c2 100644
> --- a/doc/guides/sample_app_ug/ethtool.rst
> +++ b/doc/guides/sample_app_ug/ethtool.rst
> @@ -130,3 +130,44 @@ interface that accepts commands as described in `using the
>  application`_. Individual call-back functions handle the detail
>  associated with each command, which make use of librte_ethtool
>  library.
> +
> +Control Interface
> +~~~~~~~~~~~~~~~~~
> +
> +If Kernel Control Path (KCP) kernel module (rte_kcp.ko) inserted,
> +virtual interfaces created for each DPDK port for control purposes.
> +
> +Created interfaces are named as dpdk#, like:
> +
> +.. code-block:: console
> +
> +        # ifconfig dpdk0; ifconfig dpdk1
> +        dpdk0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
> +                ether 90:e2:ba:0e:49:b9  txqueuelen 1000  (Ethernet)
> +                RX packets 0  bytes 0 (0.0 B)
> +                RX errors 0  dropped 0  overruns 0  frame 0
> +                TX packets 0  bytes 0 (0.0 B)
> +                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
> +
> +        dpdk1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
> +                ether 00:1b:21:76:fa:21  txqueuelen 1000  (Ethernet)
> +                RX packets 0  bytes 0 (0.0 B)
> +                RX errors 0  dropped 0  overruns 0  frame 0
> +                TX packets 0  bytes 0 (0.0 B)
> +                TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
> +
> +Regular Linux commands can be issued on interfaces:
> +
> +.. code-block:: console
> +
> +        # ethtool -i dpdk0
> +        driver: rte_ixgbe_pmd
> +        version: RTE 2.3.0-rc0
> +        firmware-version:
> +        expansion-rom-version:
> +        bus-info: 0000:08:00.1
> +        supports-statistics: yes
> +        supports-test: no
> +        supports-eeprom-access: yes
> +        supports-register-dump: yes
> +        supports-priv-flags: no
> diff --git a/examples/ethtool/main.c b/examples/ethtool/main.c
> index 2c655d8..72fbe4c 100644
> --- a/examples/ethtool/main.c
> +++ b/examples/ethtool/main.c
> @@ -1,7 +1,7 @@
>  /*-
>   *   BSD LICENSE
>   *
> - *   Copyright(c) 2015 Intel Corporation. All rights reserved.
> + *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
>   *   All rights reserved.
>   *
>   *   Redistribution and use in source and binary forms, with or without
> @@ -44,6 +44,7 @@
>  #include <rte_memory.h>
>  #include <rte_mempool.h>
>  #include <rte_mbuf.h>
> +#include <rte_ctrl_if.h>
> 
>  #include "ethapp.h"
> 
> @@ -54,7 +55,6 @@
>  #define PKTPOOL_EXTRA_SIZE 512
>  #define PKTPOOL_CACHE 32
> 
> -
>  struct txq_port {
>  	uint16_t cnt_unsent;
>  	struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
> @@ -259,11 +259,32 @@ static int slave_main(__attribute__((unused)) void *ptr_data)
>  	return 0;
>  }
> 
> +static void *
> +control_function(__attribute__((unused)) void *arg)
> +{
> +	int port_id;
> +
> +	while (1) {
> +		/* blocking call with 1 sec timeout */
> +		port_id = rte_eth_control_interface_msg_exist(1);
> +		if (port_id < 0)
> +			continue;
> +
> +		lock_port(port_id);
> +		rte_eth_control_interface_msg_process(
> +			RTE_ETHTOOL_CTRL_IF_PROCESS_MSG);
> +		unlock_port(port_id);


As I stated in offline code review, I think that just lock/unlock here is not enough.
You either have to  update port_active flag here based on dev->data->dev_started,
or check  dev->data->dev_started directly in your data-path or somehow else
inform IO thread that the port is stopped and RX/TX is not possible over it.
Otherwise sending stop command over your control interface while RX/TX is active
would cause your app to crash. 
Konstantin

> +	}
> +
> +	return 0;
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	int cnt_args_parsed;
>  	uint32_t id_core;
>  	uint32_t cnt_ports;
> +	pthread_t control_thread;
> 
>  	/* Init runtime enviornment */
>  	cnt_args_parsed = rte_eal_init(argc, argv);
> @@ -293,6 +314,9 @@ int main(int argc, char **argv)
>  	id_core = rte_get_next_lcore(id_core, 1, 1);
>  	rte_eal_remote_launch(slave_main, NULL, id_core);
> 
> +	pthread_create(&control_thread, NULL, control_function, NULL);
> +	rte_eth_control_interface_create();
> +
>  	ethapp_main();
> 
>  	app_cfg.exit_now = 1;
> @@ -301,5 +325,8 @@ int main(int argc, char **argv)
>  			return -1;
>  	}
> 
> +	rte_eth_control_interface_destroy();
> +	pthread_cancel(control_thread);
> +
>  	return 0;
>  }
> --
> 2.5.0

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-02 22:35                         ` Thomas Monjalon
  2016-03-03  8:31                           ` Panu Matilainen
@ 2016-03-10  0:04                           ` Thomas Monjalon
  2016-03-10  6:31                             ` Vincent JARDIN
  1 sibling, 1 reply; 83+ messages in thread
From: Thomas Monjalon @ 2016-03-10  0:04 UTC (permalink / raw)
  To: ferruh.yigit; +Cc: Avi Kivity, dev

2016-03-02 23:35, Thomas Monjalon:
> 2016-03-02 12:21, Thomas Monjalon:
> > 2016-03-02 11:47, Vincent JARDIN:
> > > Le 02/03/2016 09:27, Panu Matilainen a écrit :
> > > >>> I'd like to see these be merged.
> > > >>>
> > > >>> Jay
> > > >>
> > > >> The code is really not ready. I am okay with cooperative development
> > > >> but the current code needs to go into a staging type tree.
> > > >> No compatibility, no ABI guarantees, more of an RFC.
> > > >> Don't want vendors building products with it then screaming when it
> > > >> gets rebuilt/reworked/scrapped.
> > > >>
> > > >
> > > > Exactly.
> > > 
> > > +1 too
> > > 
> > > We need to build on this innovation while there is a path for kernel 
> > > mainstream. The logic of using a staging is a good one.
> > > 
> > > Thomas,
> > > 
> > > can we open a staging folder into the DPDK like it is done into the kernel?
> > 
> > It's possible to create a staging directory if everybody agree.
> > It is important to state in a README file or in the doc/ that
> > there will be no guarantee (no stable ABI, no validation and can be dropped)
> > and that it is a work in progress, a suggestion to discuss with the kernel
> > community.
> > 
> > The kernel modules must clearly target an upstream integration.
> 
> Actually the examples directory has been used as a staging for ethtool and
> lthread. We also have the crypto API which is still experimental.
> So I think we must decide among these 3 solutions:
> 	- no special directory, just mark and document an experimental state
> 	- put only kcp/kdp in the staging directory
> 	- put kcp/kdp in staging and move other experimental libs here

Any opinion? Are we targetting upstream work without any DPDK staging?

Please let's make clear the status of these patches.

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

* Re: [PATCH 1/3] kcp: add kernel control path kernel module
  2016-03-10  0:04                           ` Thomas Monjalon
@ 2016-03-10  6:31                             ` Vincent JARDIN
  0 siblings, 0 replies; 83+ messages in thread
From: Vincent JARDIN @ 2016-03-10  6:31 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: Avi Kivity, dev

Le 10 mars 2016 01:06, "Thomas Monjalon" <thomas.monjalon@6wind.com> a
écrit :
>
> 2016-03-02 23:35, Thomas Monjalon:
> > 2016-03-02 12:21, Thomas Monjalon:
> > > 2016-03-02 11:47, Vincent JARDIN:
> > > > Le 02/03/2016 09:27, Panu Matilainen a écrit :
> > > > >>> I'd like to see these be merged.
> > > > >>>
> > > > >>> Jay
> > > > >>
> > > > >> The code is really not ready. I am okay with cooperative
development
> > > > >> but the current code needs to go into a staging type tree.
> > > > >> No compatibility, no ABI guarantees, more of an RFC.
> > > > >> Don't want vendors building products with it then screaming when
it
> > > > >> gets rebuilt/reworked/scrapped.
> > > > >>
> > > > >
> > > > > Exactly.
> > > >
> > > > +1 too
> > > >
> > > > We need to build on this innovation while there is a path for kernel
> > > > mainstream. The logic of using a staging is a good one.
> > > >
> > > > Thomas,
> > > >
> > > > can we open a staging folder into the DPDK like it is done into the
kernel?
> > >
> > > It's possible to create a staging directory if everybody agree.
> > > It is important to state in a README file or in the doc/ that
> > > there will be no guarantee (no stable ABI, no validation and can be
dropped)
> > > and that it is a work in progress, a suggestion to discuss with the
kernel
> > > community.
> > >
> > > The kernel modules must clearly target an upstream integration.
> >
> > Actually the examples directory has been used as a staging for ethtool
and
> > lthread. We also have the crypto API which is still experimental.
> > So I think we must decide among these 3 solutions:
> >       - no special directory, just mark and document an experimental
state
> >       - put only kcp/kdp in the staging directory

I do prefer this option.

> >       - put kcp/kdp in staging and move other experimental libs here
>
> Any opinion? Are we targetting upstream work without any DPDK staging?
>
> Please let's make clear the status of these patches.

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

* Re: [PATCH v5 0/4] Use common Linux tools to control DPDK ports
  2016-03-09 11:41       ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
                           ` (3 preceding siblings ...)
  2016-03-09 11:41         ` [PATCH v5 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
@ 2016-03-14 15:31         ` Ferruh Yigit
  2016-03-14 17:40           ` Jay Rolette
  4 siblings, 1 reply; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-14 15:31 UTC (permalink / raw)
  To: dev; +Cc: David Marchand, Helin Zhang, Remy Horton

On 3/9/2016 11:41 AM, Ferruh Yigit wrote:
> This patch sent to keep record of latest status of the work.
> 
> 
> This work is to make DPDK ports more visible and to enable using common
> Linux tools to configure DPDK ports.
> 
> Patch is based on KNI but contains only control functionality of it,
> also this patch does not include any Linux kernel network driver as
> part of it.
> 
> Basically with the help of a kernel module (KCP), virtual Linux network
> interfaces named as "dpdk$" are created per DPDK port, control messages
> sent to these virtual interfaces are forwarded to DPDK, and response
> sent back to Linux application.
> 
> Virtual interfaces created when DPDK application started and destroyed
> automatically when DPDK application terminated.
> 
> Communication between kernel-space and DPDK done using netlink socket.
> 
> In long term this patch intends to replace the KNI and KNI will be
> depreciated.
> 

Self-NACK: Will work on netdev to upstream this.

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

* Re: [PATCH v5 0/4] Use common Linux tools to control DPDK ports
  2016-03-14 15:31         ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
@ 2016-03-14 17:40           ` Jay Rolette
  2016-03-15  0:00             ` Ferruh Yigit
  0 siblings, 1 reply; 83+ messages in thread
From: Jay Rolette @ 2016-03-14 17:40 UTC (permalink / raw)
  To: Ferruh Yigit; +Cc: DPDK, David Marchand, Helin Zhang, Remy Horton

Is there some technical reason or is it just the push-back you are getting
from some of the maintainers?

I chimed in on one of the other threads already, but I'm extremely
disappointed that usability and serviceability improvements to existing
DPDK capabilities (KNI) are getting blocked like this.

For companies building network appliances based on DPDK, having a kernel
module that isn't in the tree just isn't that big of a deal. Long term
goals for getting this upstream are great, but why not take advantage of
incremental improvements in the meantime?

Jay

On Mon, Mar 14, 2016 at 10:31 AM, Ferruh Yigit <ferruh.yigit@intel.com>
wrote:

> On 3/9/2016 11:41 AM, Ferruh Yigit wrote:
> > This patch sent to keep record of latest status of the work.
> >
> >
> > This work is to make DPDK ports more visible and to enable using common
> > Linux tools to configure DPDK ports.
> >
> > Patch is based on KNI but contains only control functionality of it,
> > also this patch does not include any Linux kernel network driver as
> > part of it.
> >
> > Basically with the help of a kernel module (KCP), virtual Linux network
> > interfaces named as "dpdk$" are created per DPDK port, control messages
> > sent to these virtual interfaces are forwarded to DPDK, and response
> > sent back to Linux application.
> >
> > Virtual interfaces created when DPDK application started and destroyed
> > automatically when DPDK application terminated.
> >
> > Communication between kernel-space and DPDK done using netlink socket.
> >
> > In long term this patch intends to replace the KNI and KNI will be
> > depreciated.
> >
>
> Self-NACK: Will work on netdev to upstream this.
>
>

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

* Re: [PATCH v5 0/4] Use common Linux tools to control DPDK ports
  2016-03-14 17:40           ` Jay Rolette
@ 2016-03-15  0:00             ` Ferruh Yigit
  0 siblings, 0 replies; 83+ messages in thread
From: Ferruh Yigit @ 2016-03-15  0:00 UTC (permalink / raw)
  To: Jay Rolette; +Cc: DPDK, David Marchand, Helin Zhang, Remy Horton

On 3/14/2016 5:40 PM, Jay Rolette wrote:
> Is there some technical reason or is it just the push-back you are
> getting from some of the maintainers?
> 
The majority of the discussion on the list was based on not having
kernel modules, which cloud the desired technical discussion.

As a result of the opposition, we will give a try to upstreaming and I
will be able to use some of my time to work on this.

If KCP can be upstreamed, this is good for everybody, if not I hope we
can discuss again in community the future of the feature.

And during this process, userspace counterpart in DPDK will be missing,
and kernel part will be in a form of patch for head of latest kernel, so
not sure how community will be able to test this.

> I chimed in on one of the other threads already, but I'm extremely
> disappointed that usability and serviceability improvements to existing
> DPDK capabilities (KNI) are getting blocked like this.
> 
> For companies building network appliances based on DPDK, having a kernel
> module that isn't in the tree just isn't that big of a deal. Long term
> goals for getting this upstream are great, but why not take advantage of
> incremental improvements in the meantime?
> 
> Jay 
> 
> On Mon, Mar 14, 2016 at 10:31 AM, Ferruh Yigit <ferruh.yigit@intel.com
> <mailto:ferruh.yigit@intel.com>> wrote:
> 
>     On 3/9/2016 11:41 AM, Ferruh Yigit wrote:
>     > This patch sent to keep record of latest status of the work.
>     >
>     >
>     > This work is to make DPDK ports more visible and to enable using common
>     > Linux tools to configure DPDK ports.
>     >
>     > Patch is based on KNI but contains only control functionality of it,
>     > also this patch does not include any Linux kernel network driver as
>     > part of it.
>     >
>     > Basically with the help of a kernel module (KCP), virtual Linux network
>     > interfaces named as "dpdk$" are created per DPDK port, control messages
>     > sent to these virtual interfaces are forwarded to DPDK, and response
>     > sent back to Linux application.
>     >
>     > Virtual interfaces created when DPDK application started and destroyed
>     > automatically when DPDK application terminated.
>     >
>     > Communication between kernel-space and DPDK done using netlink socket.
>     >
>     > In long term this patch intends to replace the KNI and KNI will be
>     > depreciated.
>     >
> 
>     Self-NACK: Will work on netdev to upstream this.
> 
> 

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

end of thread, other threads:[~2016-03-15  0:00 UTC | newest]

Thread overview: 83+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-27 16:24 [PATCH 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
2016-01-27 16:24 ` [PATCH 1/3] kcp: add kernel control path kernel module Ferruh Yigit
2016-01-28  9:49   ` Remy Horton
2016-01-28 13:50     ` Ferruh Yigit
2016-02-28 15:34   ` Avi Kivity
2016-02-28 20:16     ` Ferruh Yigit
2016-02-29  9:43       ` Avi Kivity
2016-02-29 10:43         ` Ferruh Yigit
2016-02-29 10:58           ` Avi Kivity
2016-02-29 11:06             ` Thomas Monjalon
2016-02-29 11:35               ` Ferruh Yigit
2016-02-29 15:05                 ` Ferruh Yigit
2016-02-29 15:19                 ` Panu Matilainen
2016-02-29 15:27                   ` Thomas Monjalon
2016-02-29 16:04                     ` Panu Matilainen
2016-02-29 14:33               ` Jay Rolette
2016-03-01 22:40                 ` Bruce Richardson
2016-03-02  2:02                 ` Stephen Hemminger
2016-03-02  8:27                   ` Panu Matilainen
2016-03-02 10:47                     ` Vincent JARDIN
2016-03-02 10:51                       ` Jim Thompson
2016-03-02 12:03                         ` Vincent JARDIN
2016-03-02 22:51                           ` Jim Thompson
2016-03-02 11:21                       ` Thomas Monjalon
2016-03-02 22:35                         ` Thomas Monjalon
2016-03-03  8:31                           ` Panu Matilainen
2016-03-03 10:05                             ` Ferruh Yigit
2016-03-03 10:11                               ` Thomas Monjalon
2016-03-03 10:51                               ` Panu Matilainen
2016-03-10  0:04                           ` Thomas Monjalon
2016-03-10  6:31                             ` Vincent JARDIN
2016-03-02 22:18                   ` Jay Rolette
2016-03-03 10:11                     ` Ferruh Yigit
2016-03-03 16:59                       ` Stephen Hemminger
2016-03-03 18:18                         ` Ferruh Yigit
2016-02-29 11:27             ` Ferruh Yigit
2016-02-29 11:39               ` Avi Kivity
2016-02-29 14:35                 ` Ferruh Yigit
2016-02-29 20:11   ` Stephen Hemminger
2016-03-01  0:35     ` Ferruh Yigit
2016-01-27 16:24 ` [PATCH 2/3] rte_ctrl_if: add control interface library Ferruh Yigit
2016-01-28 11:14   ` Remy Horton
2016-01-28 13:15     ` Ferruh Yigit
2016-01-28 13:24       ` Jay Rolette
2016-01-28 13:56         ` Ferruh Yigit
2016-01-28 13:57       ` Ananyev, Konstantin
2016-01-28 14:22         ` Yigit, Ferruh
2016-01-27 16:24 ` [PATCH 3/3] examples/ethtool: add control interface support to the application Ferruh Yigit
2016-02-12 13:45 ` [PATCH v2 0/3] Use common Linux tools to control DPDK ports Ferruh Yigit
2016-02-12 13:45   ` [PATCH v2 1/3] kcp: add kernel control path kernel module Ferruh Yigit
2016-02-12 13:45   ` [PATCH v2 2/3] rte_ctrl_if: add control interface library Ferruh Yigit
2016-02-17 19:58     ` Ananyev, Konstantin
2016-02-18 10:43       ` Yigit, Ferruh
2016-02-12 13:45   ` [PATCH v2 3/3] examples/ethtool: add control interface support to the application Ferruh Yigit
2016-02-17 19:39     ` Ananyev, Konstantin
2016-02-18 10:11       ` Yigit, Ferruh
2016-02-26 14:10   ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
2016-02-26 14:10     ` [PATCH v3 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
2016-02-26 14:10     ` [PATCH v3 2/4] kcp: add kernel control path kernel module Ferruh Yigit
2016-03-01  1:02       ` Stephen Hemminger
2016-03-01 15:53         ` Ferruh Yigit
2016-02-26 14:10     ` [PATCH v3 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
2016-02-26 14:10     ` [PATCH v3 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
2016-02-29  9:33     ` [PATCH v3 0/4] Use common Linux tools to control DPDK ports Remy Horton
2016-03-01 15:41     ` [PATCH v4 " Ferruh Yigit
2016-03-01 15:41       ` [PATCH v4 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
2016-03-01 15:41       ` [PATCH v4 2/4] kcp: add kernel control path kernel module Ferruh Yigit
2016-03-01 23:06         ` Stephen Hemminger
2016-03-02 11:05           ` Ferruh Yigit
2016-03-01 23:09         ` Stephen Hemminger
2016-03-01 23:10         ` Stephen Hemminger
2016-03-02 11:06           ` Ferruh Yigit
2016-03-01 15:41       ` [PATCH v4 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
2016-03-01 15:42       ` [PATCH v4 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
2016-03-09 11:41       ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
2016-03-09 11:41         ` [PATCH v5 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder Ferruh Yigit
2016-03-09 11:41         ` [PATCH v5 2/4] kcp: add kernel control path kernel module Ferruh Yigit
2016-03-09 11:41         ` [PATCH v5 3/4] rte_ctrl_if: add control interface library Ferruh Yigit
2016-03-09 11:41         ` [PATCH v5 4/4] examples/ethtool: add control interface support to the application Ferruh Yigit
2016-03-09 12:23           ` Ananyev, Konstantin
2016-03-14 15:31         ` [PATCH v5 0/4] Use common Linux tools to control DPDK ports Ferruh Yigit
2016-03-14 17:40           ` Jay Rolette
2016-03-15  0:00             ` Ferruh Yigit

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.