[PATCH 0/3] Use common Linux tools to control DPDK ports

STALE3804d

83 messages, 11 authors, 2016-03-15 · page 1 of 2 · open the first message on its own page

[PATCH 0/3] Use common Linux tools to control DPDK ports

From: Ferruh Yigit <hidden>
Date: 2016-01-27 16:24:28

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

[PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-01-27 16:24:32

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 <redacted>
---
 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

[PATCH 2/3] rte_ctrl_if: add control interface library

From: Ferruh Yigit <hidden>
Date: 2016-01-27 16:24:43

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 <redacted>
---
 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

[PATCH 3/3] examples/ethtool: add control interface support to the application

From: Ferruh Yigit <hidden>
Date: 2016-01-27 16:24:55

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 <redacted>
---
 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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Remy Horton <hidden>
Date: 2016-01-28 09:50:13

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 [off-list ref]
 > ---


 > +	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?

Re: [PATCH 2/3] rte_ctrl_if: add control interface library

From: Remy Horton <hidden>
Date: 2016-01-28 11:14:49

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

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

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

Re: [PATCH 2/3] rte_ctrl_if: add control interface library

From: Ferruh Yigit <hidden>
Date: 2016-01-28 13:15:03

On Thu, Jan 28, 2016 at 11:14:47AM +0000, Remy Horton wrote:
On 27/01/2016 16:24, Ferruh Yigit wrote:
quoted
+	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 

Re: [PATCH 2/3] rte_ctrl_if: add control interface library

From: Jay Rolette <hidden>
Date: 2016-01-28 13:24:51

On Thu, Jan 28, 2016 at 7:15 AM, Ferruh Yigit [off-list ref]
wrote:
On Thu, Jan 28, 2016 at 11:14:47AM +0000, Remy Horton wrote:
quoted
On 27/01/2016 16:24, Ferruh Yigit wrote:
quoted
+   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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-01-28 13:50:43

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:
quoted
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 <redacted>
---
quoted
+	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.
quoted
+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.
quoted
+	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

Re: [PATCH 2/3] rte_ctrl_if: add control interface library

From: Ferruh Yigit <hidden>
Date: 2016-01-28 13:56:40

On Thu, Jan 28, 2016 at 07:24:51AM -0600, Jay Rolette wrote:
On Thu, Jan 28, 2016 at 7:15 AM, Ferruh Yigit [off-list ref]
wrote:
quoted
On Thu, Jan 28, 2016 at 11:14:47AM +0000, Remy Horton wrote:
quoted
On 27/01/2016 16:24, Ferruh Yigit wrote:
quoted
+   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

Re: [PATCH 2/3] rte_ctrl_if: add control interface library

From: Ananyev, Konstantin <hidden>
Date: 2016-01-28 13:57:07

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:
quoted
On 27/01/2016 16:24, Ferruh Yigit wrote:
quoted
+	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

Re: [PATCH 2/3] rte_ctrl_if: add control interface library

From: Yigit, Ferruh <hidden>
Date: 2016-01-28 14:23:50

On Thu, Jan 28, 2016 at 01:57:04PM +0000, Ananyev, Konstantin wrote:
Hi Ferruh,
quoted
-----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:
quoted
On 27/01/2016 16:24, Ferruh Yigit wrote:
quoted
+	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

[PATCH v2 0/3] Use common Linux tools to control DPDK ports

From: Ferruh Yigit <hidden>
Date: 2016-02-12 13:45:42

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

[PATCH v2 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-02-12 13:45:54

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 <redacted>

---

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

[PATCH v2 2/3] rte_ctrl_if: add control interface library

From: Ferruh Yigit <hidden>
Date: 2016-02-12 13:46:03

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 <redacted>

---

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

[PATCH v2 3/3] examples/ethtool: add control interface support to the application

From: Ferruh Yigit <hidden>
Date: 2016-02-12 13:46:12

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 <redacted>
---
 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

Re: [PATCH v2 3/3] examples/ethtool: add control interface support to the application

From: Ananyev, Konstantin <hidden>
Date: 2016-02-17 19:39:08

Hi Ferruh,
quoted hunk
-----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 <redacted>
---
 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.
quoted hunk
+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
  

Re: [PATCH v2 2/3] rte_ctrl_if: add control interface library

From: Ananyev, Konstantin <hidden>
Date: 2016-02-17 19:58:19

quoted hunk
-----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 <redacted>

---

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);
+}
+};
....
quoted hunk
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;
+}
+

Re: [PATCH v2 3/3] examples/ethtool: add control interface support to the application

From: Yigit, Ferruh <hidden>
Date: 2016-02-18 10:11:43

On Wed, Feb 17, 2016 at 07:39:05PM +0000, Ananyev, Konstantin wrote:
Hi Ferruh,
quoted
-----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 <redacted>
---
 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
quoted
+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

Re: [PATCH v2 2/3] rte_ctrl_if: add control interface library

From: Yigit, Ferruh <hidden>
Date: 2016-02-18 10:43:15

On Wed, Feb 17, 2016 at 07:58:16PM +0000, Ananyev, Konstantin wrote:
quoted
-----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 <redacted>

---

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?
quoted
+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);
+}
+};
....
quoted
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.
quoted
+
+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
quoted
+
+	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

[PATCH v3 0/4] Use common Linux tools to control DPDK ports

From: Ferruh Yigit <hidden>
Date: 2016-02-26 14:10:46

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

[PATCH v3 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder

From: Ferruh Yigit <hidden>
Date: 2016-02-26 14:11:03

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 <redacted>
---
 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

[PATCH v3 3/4] rte_ctrl_if: add control interface library

From: Ferruh Yigit <hidden>
Date: 2016-02-26 14:11:19

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 <redacted>
---

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

[PATCH v3 4/4] examples/ethtool: add control interface support to the application

From: Ferruh Yigit <hidden>
Date: 2016-02-26 14:11:26

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 <redacted>
---

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

[PATCH v3 2/4] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-02-26 14:11:30

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 <redacted>
---

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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Avi Kivity <hidden>
Date: 2016-02-28 15:34:23

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.
quoted hunk
Signed-off-by: Ferruh Yigit <redacted>
---
  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;
+}

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-02-28 20:16:34

On 2/28/2016 3:34 PM, Avi Kivity wrote:
On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
quoted
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

Re: [PATCH v3 0/4] Use common Linux tools to control DPDK ports

From: Remy Horton <hidden>
Date: 2016-02-29 09:33:49


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 <redacted>

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Avi Kivity <hidden>
Date: 2016-02-29 09:43:32

On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
On 2/28/2016 3:34 PM, Avi Kivity wrote:
quoted
On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-02-29 10:43:52

On 2/29/2016 9:43 AM, Avi Kivity wrote:
On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
quoted
On 2/28/2016 3:34 PM, Avi Kivity wrote:
quoted
On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
quoted
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?
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Avi Kivity <hidden>
Date: 2016-02-29 10:58:45


On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
On 2/29/2016 9:43 AM, Avi Kivity wrote:
quoted
On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
quoted
On 2/28/2016 3:34 PM, Avi Kivity wrote:
quoted
On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
quoted
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.
quoted
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.
quoted
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Thomas Monjalon <hidden>
Date: 2016-02-29 11:07:44

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:
quoted
On 2/29/2016 9:43 AM, Avi Kivity wrote:
quoted
On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
quoted
On 2/28/2016 3:34 PM, Avi Kivity wrote:
quoted
On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
quoted
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
quoted
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
 
quoted
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.
quoted
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
quoted
quoted
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-02-29 11:27:33

On 2/29/2016 10:58 AM, Avi Kivity wrote:

On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
quoted
On 2/29/2016 9:43 AM, Avi Kivity wrote:
quoted
On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
quoted
On 2/28/2016 3:34 PM, Avi Kivity wrote:
quoted
On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
quoted
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.
quoted
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).
quoted
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.
quoted
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.
quoted
quoted
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-02-29 11:35:04

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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Avi Kivity <hidden>
Date: 2016-02-29 11:39:57


On 02/29/2016 01:27 PM, Ferruh Yigit wrote:
On 2/29/2016 10:58 AM, Avi Kivity wrote:
quoted
On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
quoted
On 2/29/2016 9:43 AM, Avi Kivity wrote:
quoted
On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
quoted
On 2/28/2016 3:34 PM, Avi Kivity wrote:
quoted
On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
quoted
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
quoted
quoted
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).
quoted
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.
quoted
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.
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Jay Rolette <hidden>
Date: 2016-02-29 14:33:26

On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon [off-list ref]
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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-02-29 14:37:20

On 2/29/2016 11:39 AM, Avi Kivity wrote:

On 02/29/2016 01:27 PM, Ferruh Yigit wrote:
quoted
On 2/29/2016 10:58 AM, Avi Kivity wrote:
quoted
On 02/29/2016 12:43 PM, Ferruh Yigit wrote:
quoted
On 2/29/2016 9:43 AM, Avi Kivity wrote:
quoted
On 02/28/2016 10:16 PM, Ferruh Yigit wrote:
quoted
On 2/28/2016 3:34 PM, Avi Kivity wrote:
quoted
On 01/27/2016 06:24 PM, Ferruh Yigit wrote:
quoted
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.
quoted
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.
quoted
quoted
quoted
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).
quoted
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.
quoted
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.
quoted
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.
quoted
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-02-29 15:05:18

On 2/29/2016 11:35 AM, Ferruh Yigit wrote:
On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
quoted
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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Panu Matilainen <hidden>
Date: 2016-02-29 15:19:45

On 02/29/2016 01:35 PM, Ferruh Yigit wrote:
On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
quoted
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 -

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Thomas Monjalon <hidden>
Date: 2016-02-29 15:29:27

2016-02-29 17:19, Panu Matilainen:
On 02/29/2016 01:35 PM, Ferruh Yigit wrote:
quoted
On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
quoted
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?

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Panu Matilainen <hidden>
Date: 2016-02-29 16:04:34

On 02/29/2016 05:27 PM, Thomas Monjalon wrote:
2016-02-29 17:19, Panu Matilainen:
quoted
On 02/29/2016 01:35 PM, Ferruh Yigit wrote:
quoted
On 2/29/2016 11:06 AM, Thomas Monjalon wrote:
quoted
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 -

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Stephen Hemminger <stephen@networkplumber.org>
Date: 2016-02-29 20:11:46

On Wed, 27 Jan 2016 16:24:07 +0000
Ferruh Yigit [off-list ref] 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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-01 00:35:05

On 2/29/2016 8:11 PM, Stephen Hemminger wrote:
On Wed, 27 Jan 2016 16:24:07 +0000
Ferruh Yigit [off-list ref] wrote:
quoted
+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

Re: [PATCH v3 2/4] kcp: add kernel control path kernel module

From: Stephen Hemminger <stephen@networkplumber.org>
Date: 2016-03-01 01:02:29

On Fri, 26 Feb 2016 14:10:39 +0000
Ferruh Yigit [off-list ref] 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

[PATCH v4 0/4] Use common Linux tools to control DPDK ports

From: Ferruh Yigit <hidden>
Date: 2016-03-01 15:42:10

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

[PATCH v4 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder

From: Ferruh Yigit <hidden>
Date: 2016-03-01 15:42:21

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 <redacted>
Acked-by: Remy Horton <redacted>
---

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

[PATCH v4 2/4] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-01 15:42:31

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 <redacted>
Acked-by: Remy Horton <redacted>
---

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

[PATCH v4 3/4] rte_ctrl_if: add control interface library

From: Ferruh Yigit <hidden>
Date: 2016-03-01 15:42:45

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 <redacted>
Acked-by: Remy Horton <redacted>
---

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

[PATCH v4 4/4] examples/ethtool: add control interface support to the application

From: Ferruh Yigit <hidden>
Date: 2016-03-01 15:42:53

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 <redacted>
Acked-by: Remy Horton <redacted>
---

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

Re: [PATCH v3 2/4] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-01 15:53:25

On 3/1/2016 1:02 AM, Stephen Hemminger wrote:
On Fri, 26 Feb 2016 14:10:39 +0000
Ferruh Yigit [off-list ref] wrote:
quoted
+#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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Bruce Richardson <hidden>
Date: 2016-03-01 22:40:31

On Mon, Feb 29, 2016 at 08:33:25AM -0600, Jay Rolette wrote:
On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon [off-list ref]
wrote:
quoted
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

Re: [PATCH v4 2/4] kcp: add kernel control path kernel module

From: Stephen Hemminger <stephen@networkplumber.org>
Date: 2016-03-01 23:06:18

On Tue,  1 Mar 2016 15:41:58 +0000
Ferruh Yigit [off-list ref] 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.

Re: [PATCH v4 2/4] kcp: add kernel control path kernel module

From: Stephen Hemminger <stephen@networkplumber.org>
Date: 2016-03-01 23:09:15

On Tue,  1 Mar 2016 15:41:58 +0000
Ferruh Yigit [off-list ref] 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;
+}
+

Re: [PATCH v4 2/4] kcp: add kernel control path kernel module

From: Stephen Hemminger <stephen@networkplumber.org>
Date: 2016-03-01 23:10:45

On Tue,  1 Mar 2016 15:41:58 +0000
Ferruh Yigit [off-list ref] 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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Stephen Hemminger <stephen@networkplumber.org>
Date: 2016-03-02 02:02:43

On Mon, 29 Feb 2016 08:33:25 -0600
Jay Rolette [off-list ref] wrote:
On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon [off-list ref]
wrote:
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Panu Matilainen <hidden>
Date: 2016-03-02 08:28:03

On 03/02/2016 04:02 AM, Stephen Hemminger wrote:
On Mon, 29 Feb 2016 08:33:25 -0600
Jay Rolette [off-list ref] wrote:
quoted
On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon [off-list ref]
wrote:
quoted
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 -

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Vincent JARDIN <hidden>
Date: 2016-03-02 10:47:43

Le 02/03/2016 09:27, Panu Matilainen a écrit :
quoted
quoted
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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Jim Thompson <hidden>
Date: 2016-03-02 10:51:05

On Mar 2, 2016, at 4:47 AM, Vincent JARDIN [off-list ref] wrote:

Le 02/03/2016 09:27, Panu Matilainen a écrit :
quoted
quoted
quoted
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?

Re: [PATCH v4 2/4] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-02 11:05:57

On 3/1/2016 11:06 PM, Stephen Hemminger wrote:
On Tue,  1 Mar 2016 15:41:58 +0000
Ferruh Yigit [off-list ref] wrote:
quoted
+#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

Re: [PATCH v4 2/4] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-02 11:06:31

On 3/1/2016 11:10 PM, Stephen Hemminger wrote:
On Tue,  1 Mar 2016 15:41:58 +0000
Ferruh Yigit [off-list ref] wrote:
quoted
+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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Thomas Monjalon <hidden>
Date: 2016-03-02 11:23:08

2016-03-02 11:47, Vincent JARDIN:
Le 02/03/2016 09:27, Panu Matilainen a écrit :
quoted
quoted
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Vincent JARDIN <hidden>
Date: 2016-03-02 12:04:04

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?

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Jay Rolette <hidden>
Date: 2016-03-02 22:18:39

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 [off-list ref] wrote:
quoted
On Mon, Feb 29, 2016 at 5:06 AM, Thomas Monjalon <
thomas.monjalon@6wind.com>
quoted
wrote:
quoted
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.
quoted
quoted
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
quoted
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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Thomas Monjalon <hidden>
Date: 2016-03-02 22:37:06

2016-03-02 12:21, Thomas Monjalon:
2016-03-02 11:47, Vincent JARDIN:
quoted
Le 02/03/2016 09:27, Panu Matilainen a écrit :
quoted
quoted
quoted
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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Jim Thompson <hidden>
Date: 2016-03-02 22:51:43

On Mar 2, 2016, at 6:03 AM, Vincent JARDIN [off-list ref] wrote:

Le 02/03/2016 11:51, Jim Thompson a écrit :
quoted
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. 

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Panu Matilainen <hidden>
Date: 2016-03-03 08:31:29

On 03/03/2016 12:35 AM, Thomas Monjalon wrote:
2016-03-02 12:21, Thomas Monjalon:
quoted
2016-03-02 11:47, Vincent JARDIN:
quoted
Le 02/03/2016 09:27, Panu Matilainen a écrit :
quoted
quoted
quoted
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 -

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-03 10:05:49

On 3/3/2016 8:31 AM, Panu Matilainen wrote:
On 03/03/2016 12:35 AM, Thomas Monjalon wrote:
quoted
2016-03-02 12:21, Thomas Monjalon:
quoted
2016-03-02 11:47, Vincent JARDIN:
quoted
Le 02/03/2016 09:27, Panu Matilainen a écrit :
quoted
quoted
quoted
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:
quoted
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 -

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-03 10:12:01

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

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Thomas Monjalon <hidden>
Date: 2016-03-03 10:12:50

2016-03-03 10:05, Ferruh Yigit:
On 3/3/2016 8:31 AM, Panu Matilainen wrote:
quoted
On 03/03/2016 12:35 AM, Thomas Monjalon wrote:
quoted
2016-03-02 12:21, Thomas Monjalon:
quoted
2016-03-02 11:47, Vincent JARDIN:
quoted
Le 02/03/2016 09:27, Panu Matilainen a écrit :
quoted
quoted
quoted
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:
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Panu Matilainen <hidden>
Date: 2016-03-03 10:51:09

On 03/03/2016 12:05 PM, Ferruh Yigit wrote:
On 3/3/2016 8:31 AM, Panu Matilainen wrote:
quoted
On 03/03/2016 12:35 AM, Thomas Monjalon wrote:
quoted
2016-03-02 12:21, Thomas Monjalon:
quoted
2016-03-02 11:47, Vincent JARDIN:
quoted
Le 02/03/2016 09:27, Panu Matilainen a écrit :
quoted
quoted
quoted
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:
quoted
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 -

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Stephen Hemminger <stephen@networkplumber.org>
Date: 2016-03-03 16:59:04

On Thu, 3 Mar 2016 10:11:57 +0000
Ferruh Yigit [off-list ref] wrote:
On 3/2/2016 10:18 PM, Jay Rolette wrote:
quoted
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.

Re: [PATCH 1/3] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-03 18:19:05

On 3/3/2016 4:59 PM, Stephen Hemminger wrote:
On Thu, 3 Mar 2016 10:11:57 +0000
Ferruh Yigit [off-list ref] wrote:
quoted
On 3/2/2016 10:18 PM, Jay Rolette wrote:
quoted
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

[PATCH v5 0/4] Use common Linux tools to control DPDK ports

From: Ferruh Yigit <hidden>
Date: 2016-03-09 11:41:35

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

[PATCH v5 1/4] lib/librte_ethtool: move librte_ethtool form examples to lib folder

From: Ferruh Yigit <hidden>
Date: 2016-03-09 11:41:50

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 <redacted>
Acked-by: Remy Horton <redacted>
---

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

[PATCH v5 2/4] kcp: add kernel control path kernel module

From: Ferruh Yigit <hidden>
Date: 2016-03-09 11:41:58

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 <redacted>
Acked-by: Remy Horton <redacted>
---

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
Next 8 of 8 remaining
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help