diff --git a/MAINTAINERS b/MAINTAINERS
index 8d1fb0431..2fb18ab79 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -280,6 +280,7 @@ F: doc/guides/sample_app_ug/kernel_nic_interface.rst
 Linux Userspace Network Control Interface (UNCI)
 M: Ferruh Yigit <ferruh.yigit@intel.com>
 F: lib/librte_eal/linuxapp/unci/
+F: lib/librte_ctrl_if/
 
 Linux AF_PACKET
 M: John W. Linville <linville@tuxdriver.com>
diff --git a/config/common_base b/config/common_base
index f50ccc193..98652b556 100644
--- a/config/common_base
+++ b/config/common_base
@@ -710,6 +710,11 @@ CONFIG_RTE_UNCI_KMOD=n
 CONFIG_RTE_UNCI_KO_DEBUG=n
 
 #
+# Compile librte_ctrl_if
+#
+CONFIG_RTE_LIBRTE_CTRL_IF=n
+
+#
 # Compile vhost user library
 #
 CONFIG_RTE_LIBRTE_VHOST=n
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 4deab42c3..209a6d3d1 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -42,6 +42,7 @@ CONFIG_RTE_LIBRTE_KNI=y
 CONFIG_RTE_LIBRTE_PMD_KNI=y
 CONFIG_RTE_LIBRTE_ETHTOOL=y
 CONFIG_RTE_UNCI_KMOD=y
+CONFIG_RTE_LIBRTE_CTRL_IF=y
 CONFIG_RTE_LIBRTE_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 71350849f..ba45ff69a 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -162,4 +162,5 @@ There are many libraries, so their headers may be grouped by topics:
   [bitrate statistics] (@ref rte_bitrate.h),
   [latency statistics] (@ref rte_latencystats.h),
   [version]            (@ref rte_version.h),
-  [ethtool]            (@ref rte_ethtool.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 b66e86541..896c2b247 100644
--- a/doc/api/doxy-api.conf
+++ b/doc/api/doxy-api.conf
@@ -42,6 +42,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_efd \
                           lib/librte_ether \
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 000000000..407cf0dca
--- /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 UNCI 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 54f9538ea..c7cb4b0f8 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -55,6 +55,7 @@ Programmer's Guide
     ip_fragment_reassembly_lib
     pdump_lib
     ethtool_lib
+    ctrl_if_lib
     multi_proc_support
     kernel_nic_interface
     thread_safety_dpdk_functions
diff --git a/doc/guides/rel_notes/release_17_08.rst b/doc/guides/rel_notes/release_17_08.rst
index dbe1ee906..af7ddace0 100644
--- a/doc/guides/rel_notes/release_17_08.rst
+++ b/doc/guides/rel_notes/release_17_08.rst
@@ -75,6 +75,14 @@ New Features
 
   Added support for firmwares with multiple Ethernet ports per physical port.
 
+* **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/unci kernel module
+
 
 Resolved Issues
 ---------------
@@ -183,6 +191,7 @@ The libraries prepended with a plus sign were incremented in this version.
      librte_cfgfile.so.2
      librte_cmdline.so.2
      librte_cryptodev.so.2
+   + librte_ctrl_if.so.1
      librte_distributor.so.1
      librte_eal.so.4
      librte_ethdev.so.6
diff --git a/lib/Makefile b/lib/Makefile
index 434237d6e..45c3168e3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -108,6 +108,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
 DEPDIRS-librte_pdump := librte_eal librte_mempool librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_ETHTOOL) += librte_ethtool
 DEPDIRS-librte_ethtool := librte_eal librte_ether
+DIRS-$(CONFIG_RTE_LIBRTE_CTRL_IF) += librte_ctrl_if
+DEPDIRS-librte_ctrl_if := librte_ether
 
 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 000000000..686eb25d2
--- /dev/null
+++ b/lib/librte_ctrl_if/Makefile
@@ -0,0 +1,56 @@
+#   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)
+LDLIBS += -lpthread
+
+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
+
+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 000000000..70c60197b
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_ethtool.c
@@ -0,0 +1,390 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <error.h>
+
+#include <linux/if_link.h>
+
+#include <rte_version.h>
+#include <rte_ethdev.h>
+#include <rte_ethtool.h>
+#include "rte_ctrl_ethtool.h"
+
+#define ETHTOOL_GEEPROM_LEN 99
+#define ETHTOOL_GREGS_LEN 98
+#define ETHTOOL_GSSET_COUNT 97
+
+static int
+get_settings(uint8_t port_id __rte_unused, void *data, size_t *data_len)
+{
+	struct ethtool_cmd *ecmd = data;
+
+	/* No PMD equivalent, added to make get pauseparam work */
+	memset(ecmd, 0, sizeof(struct ethtool_cmd));
+
+	*data_len = sizeof(struct ethtool_cmd);
+	return 0;
+}
+
+static int
+get_drvinfo(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct ethtool_drvinfo *info = data;
+	int ret;
+
+	ret = rte_ethtool_get_drvinfo(port_id, info);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_drvinfo);
+
+	return 0;
+}
+
+static int
+get_reg_len(uint8_t port_id, void *data, size_t *data_len)
+{
+	int reg_length = 0;
+
+	reg_length = rte_ethtool_get_regs_len(port_id);
+	if (reg_length < 0)
+		return reg_length;
+
+	*(int *)data = reg_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_reg_len_internal(uint8_t port_id, size_t *reg_length)
+{
+	size_t reg_length_out_len;
+
+	return get_reg_len(port_id, reg_length, &reg_length_out_len);
+}
+
+static int
+get_reg(uint8_t port_id, void *in_data, void *out_data, size_t *out_data_len)
+{
+	size_t reg_length;
+	struct ethtool_regs *ethtool_regs = in_data;
+	int ret;
+
+	ret = get_reg_len_internal(port_id, &reg_length);
+	/* not enough space in out data buffer */
+	if (ret < 0 || reg_length > ethtool_regs->len)
+		return -1;
+
+	ret = rte_ethtool_get_regs(port_id, ethtool_regs, out_data);
+	if (ret < 0)
+		return ret;
+
+	*out_data_len = reg_length;
+
+	return 0;
+}
+
+static int
+get_link(uint8_t port_id, void *data, size_t *data_len)
+{
+	int ret;
+
+	ret = rte_ethtool_get_link(port_id);
+
+	*(int *)data = ret;
+	*data_len = sizeof(size_t);
+
+	return 0;
+}
+
+static int
+get_eeprom_length(uint8_t port_id, void *data, size_t *data_len)
+{
+	int eeprom_length = 0;
+
+	eeprom_length = rte_ethtool_get_eeprom_len(port_id);
+	if (eeprom_length < 0)
+		return eeprom_length;
+
+	*(int *)data = eeprom_length;
+	*data_len = sizeof(int);
+
+	return 0;
+}
+
+static int
+get_eeprom(uint8_t port_id, void *in_data, void *out_data,
+		size_t *out_data_len)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	int ret;
+
+	ret = rte_ethtool_get_eeprom(port_id, eeprom, out_data);
+	if (ret < 0)
+		return ret;
+
+	*out_data_len = eeprom->len;
+
+	return 0;
+}
+
+static int
+set_eeprom(uint8_t port_id, void *in_data)
+{
+	struct ethtool_eeprom *eeprom = in_data;
+	int ret;
+
+	ret = rte_ethtool_set_eeprom(port_id, eeprom, eeprom->data);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+get_ringparam(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct ethtool_ringparam *ringparam = data;
+	int ret;
+
+	ret = rte_ethtool_get_ringparam(port_id, ringparam);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_ringparam);
+
+	return 0;
+}
+
+static int
+set_ringparam(uint8_t port_id, void *data)
+{
+	struct ethtool_ringparam *ringparam = data;
+	int ret;
+
+	ret = rte_ethtool_set_ringparam(port_id, ringparam);
+	if (ret != 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+get_pauseparam(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+	int ret;
+
+	ret = rte_ethtool_get_pauseparam(port_id, pauseparam);
+	if (ret < 0)
+		return ret;
+
+	*data_len = sizeof(struct ethtool_pauseparam);
+
+	return 0;
+}
+
+static int
+set_pauseparam(uint8_t port_id, void *data)
+{
+	struct ethtool_pauseparam *pauseparam = data;
+
+	return rte_ethtool_set_pauseparam(port_id, pauseparam);
+}
+
+int
+rte_eth_dev_ethtool_process(uint32_t cmd_id, uint8_t port_id, void *in_data,
+		void *out_data, size_t *out_data_len)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case ETHTOOL_GSET:
+		return get_settings(port_id, out_data, out_data_len);
+	case ETHTOOL_GDRVINFO:
+		return get_drvinfo(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS_LEN:
+		return get_reg_len(port_id, out_data, out_data_len);
+	case ETHTOOL_GREGS:
+		return get_reg(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_GLINK:
+		return get_link(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM_LEN:
+		return get_eeprom_length(port_id, out_data, out_data_len);
+	case ETHTOOL_GEEPROM:
+		return get_eeprom(port_id, in_data, out_data, out_data_len);
+	case ETHTOOL_SEEPROM:
+		return set_eeprom(port_id, in_data);
+	case ETHTOOL_GRINGPARAM:
+		return get_ringparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SRINGPARAM:
+		return set_ringparam(port_id, in_data);
+	case ETHTOOL_GPAUSEPARAM:
+		return get_pauseparam(port_id, out_data, out_data_len);
+	case ETHTOOL_SPAUSEPARAM:
+		return set_pauseparam(port_id, in_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int
+set_mtu(uint8_t port_id, void *in_data)
+{
+	int *mtu = in_data;
+
+	return rte_eth_dev_set_mtu(port_id, *mtu);
+}
+
+static int
+get_stats(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct rte_eth_stats stats;
+	struct rtnl_link_stats64 *if_stats = data;
+	int ret;
+
+	ret = rte_eth_stats_get(port_id, &stats);
+	if (ret < 0)
+		return -EOPNOTSUPP;
+
+	if_stats->rx_packets = stats.ipackets;
+	if_stats->tx_packets = stats.opackets;
+	if_stats->rx_bytes = stats.ibytes;
+	if_stats->tx_bytes = stats.obytes;
+	if_stats->rx_errors = stats.ierrors;
+	if_stats->tx_errors = stats.oerrors;
+	if_stats->rx_dropped = stats.imissed;
+
+	*data_len = sizeof(struct rtnl_link_stats64);
+
+	return 0;
+}
+
+static int
+get_mac(uint8_t port_id, void *data, size_t *data_len)
+{
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(port_id, &addr);
+	memcpy(data, &addr, sizeof(struct ether_addr));
+
+	*data_len = sizeof(struct ether_addr);
+
+	return 0;
+}
+
+static int
+set_mac(uint8_t port_id, void *in_data)
+{
+	struct ether_addr addr;
+
+	memcpy(&addr, in_data, ETHER_ADDR_LEN);
+
+	return rte_eth_dev_default_mac_addr_set(port_id, &addr);
+}
+
+static int
+start_port(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return rte_eth_dev_start(port_id);
+}
+
+static int
+stop_port(uint8_t port_id)
+{
+	rte_eth_dev_stop(port_id);
+	return 0;
+}
+
+static int
+set_promisc(uint8_t port_id, void *in_data)
+{
+	int *promisc = in_data;
+
+	if (*promisc)
+		rte_eth_promiscuous_enable(port_id);
+	else
+		rte_eth_promiscuous_disable(port_id);
+
+	return 0;
+}
+
+static int
+set_allmulti(uint8_t port_id, void *in_data)
+{
+	int *allmulti = in_data;
+
+	if (*allmulti)
+		rte_eth_allmulticast_enable(port_id);
+	else
+		rte_eth_allmulticast_disable(port_id);
+
+	return 0;
+}
+
+int
+rte_eth_dev_control_process(uint32_t cmd_id, uint8_t port_id, void *in_data,
+		void *out_data, size_t *out_data_len)
+{
+	if (!rte_eth_dev_is_valid_port(port_id))
+		return -ENODEV;
+
+	switch (cmd_id) {
+	case RTE_UNCI_REQ_CHANGE_MTU:
+		return set_mtu(port_id, in_data);
+	case RTE_UNCI_REQ_GET_STATS:
+		return get_stats(port_id, out_data, out_data_len);
+	case RTE_UNCI_REQ_GET_MAC:
+		return get_mac(port_id, out_data, out_data_len);
+	case RTE_UNCI_REQ_SET_MAC:
+		return set_mac(port_id, in_data);
+	case RTE_UNCI_REQ_START_PORT:
+		return start_port(port_id);
+	case RTE_UNCI_REQ_STOP_PORT:
+		return stop_port(port_id);
+	case RTE_UNCI_REQ_SET_PROMISC:
+		return set_promisc(port_id, in_data);
+	case RTE_UNCI_REQ_SET_ALLMULTI:
+		return set_allmulti(port_id, in_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
diff --git a/lib/librte_ctrl_if/rte_ctrl_ethtool.h b/lib/librte_ctrl_if/rte_ctrl_ethtool.h
new file mode 100644
index 000000000..caa4f15f3
--- /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_unci_common.h>
+
+int rte_eth_dev_ethtool_process(uint32_t cmd_id, uint8_t port_id, void *in_data,
+		void *out_data, size_t *out_data_len);
+int rte_eth_dev_control_process(uint32_t cmd_id, uint8_t port_id, void *in_data,
+		void *out_data, size_t *out_data_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CTRL_ETHTOOL_H_ */
diff --git a/lib/librte_ctrl_if/rte_ctrl_if.c b/lib/librte_ctrl_if/rte_ctrl_if.c
new file mode 100644
index 000000000..6255a2a1a
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.c
@@ -0,0 +1,347 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (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 <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <rte_log.h>
+#include "rte_ctrl_if.h"
+#include "rte_nl.h"
+
+#define NAMESZ 32
+#define IFNAME "dpdk"
+#define BUFSZ 1024
+
+static int unci_rtnl_fd = -1;
+static uint32_t unci_fd_ref;
+
+struct unci_request {
+	struct nlmsghdr nlmsg;
+	uint8_t buf[BUFSZ];
+};
+
+static int
+conrol_interface_rtnl_init(void)
+{
+	struct sockaddr_nl src;
+	int ret;
+
+	unci_rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (unci_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(unci_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(unci_rtnl_fd);
+		unci_rtnl_fd = -1;
+	}
+
+	return ret;
+}
+
+static int
+control_interface_ref_get(void)
+{
+	int ret = 0;
+
+	if (unci_fd_ref == 0)
+		ret = control_interface_init();
+
+	if (ret == 0)
+		unci_fd_ref++;
+	else
+		RTE_LOG(ERR, CTRL_IF,
+				"Failed to initialize control interface\n");
+
+	return unci_fd_ref;
+}
+
+static void
+control_interface_release(void)
+{
+	close(unci_rtnl_fd);
+	control_interface_nl_release();
+}
+
+static int
+control_interface_ref_put(void)
+{
+	if (unci_fd_ref == 0)
+		return 0;
+
+	unci_fd_ref--;
+
+	if (unci_fd_ref == 0)
+		control_interface_release();
+
+	return unci_fd_ref;
+}
+
+static int
+add_attr(struct unci_request *req, uint16_t type, void *buf, size_t len)
+{
+	struct rtattr *rta;
+	int nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((char *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(len) > sizeof(struct unci_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 unci_request *req, unsigned short type)
+{
+	struct rtattr *rta;
+	uint32_t nlmsg_len;
+
+	nlmsg_len = NLMSG_ALIGN(req->nlmsg.nlmsg_len);
+	rta = (struct rtattr *)((uint8_t *)&req->nlmsg + nlmsg_len);
+	if (nlmsg_len + RTA_LENGTH(0) > sizeof(struct unci_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 unci_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 unci_request req;
+	struct ifinfomsg *info;
+	struct rtattr *rta1;
+	struct rtattr *rta2;
+	uint32_t pid = getpid();
+	char name[NAMESZ];
+	char type[NAMESZ];
+	struct iovec iov;
+	struct msghdr msg;
+	struct sockaddr_nl nladdr;
+	int ret;
+	uint8_t buf[BUFSZ];
+
+	memset(&req, 0, sizeof(struct unci_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, UNCI_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_UNCI_PORTID, &port_id, sizeof(uint8_t));
+	if (ret < 0)
+		return -1;
+
+	ret = add_attr(&req, IFLA_UNCI_PID, &pid, sizeof(uint32_t));
+	if (ret < 0)
+		return -1;
+
+	end_attr_nested(&req, rta2);
+	end_attr_nested(&req, rta1);
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	iov.iov_base = (void *)&req.nlmsg;
+	iov.iov_len = req.nlmsg.nlmsg_len;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_name = &nladdr;
+	msg.msg_namelen = sizeof(nladdr);
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+
+	ret = sendmsg(unci_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(unci_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Recv for create failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+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;
+}
+
+static int
+rte_eth_rtnl_destroy(uint8_t port_id)
+{
+	struct unci_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 unci_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(unci_rtnl_fd, &msg, 0);
+	if (ret < 0) {
+		RTE_LOG(ERR, CTRL_IF, "Send for destroy failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+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;
+}
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 000000000..54696bd93
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if.h
@@ -0,0 +1,88 @@
+/*-
+ *   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_unci_common.h>
+
+/**
+ * Creates control interfaces (Linux virtual network interface)for
+ * given ethdev port.
+ *
+ * This API opens device created by supportive kernel module and initializes
+ * kernel communication interface.
+ *
+ * With first interface created, a pthread created to receive the control
+ * messages.
+ *
+ * If supportive kernel module is not inserted this API will return
+ * an error.
+ *
+ * @param port_id
+ *  port id to create virtual interface
+ * @return
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_create_one(uint8_t port_id);
+
+/**
+ * Destroys control interfaces.
+ *
+ * This API close device created by supportive kernel module and release
+ * underlying communication interface.
+ *
+ * @return
+ * @param port_id
+ *  port id to destroy virtual interface
+ *  0 on success.
+ *  Negative value on error.
+ */
+int rte_eth_control_interface_destroy_one(uint8_t port_id);
+
+#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 000000000..3a86ab1a8
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_ctrl_if_version.map
@@ -0,0 +1,10 @@
+DPDK_17.02 {
+	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 000000000..011f5207b
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.c
@@ -0,0 +1,291 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (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 <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <rte_spinlock.h>
+#include <rte_log.h>
+#include "rte_ctrl_ethtool.h"
+#include "rte_nl.h"
+#include "rte_ctrl_if.h"
+
+#define MAX_PAYLOAD sizeof(struct unci_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 {
+	struct unci_ethtool_msg msg_storage;
+	pthread_mutex_t msg_lock;
+	uint32_t pending_process;
+};
+
+
+/**
+ * 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,
+};
+
+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 = {
+	.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 unci_ethtool_msg *msg)
+{
+	return nl_send((void *)msg, sizeof(struct unci_ethtool_msg));
+}
+
+static void
+process_msg(struct unci_ethtool_msg *msg)
+{
+	if (msg->cmd_id > RTE_UNCI_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);
+}
+
+static int
+control_interface_msg_process(uint32_t flag)
+{
+	struct unci_ethtool_msg msg_storage;
+	int ret = 0;
+
+	pthread_mutex_lock(&ctrl_if_sync.msg_lock);
+	if (ctrl_if_sync.pending_process == 0) {
+		pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+		return 0;
+	}
+
+	memcpy(&msg_storage, &ctrl_if_sync.msg_storage,
+			sizeof(struct unci_ethtool_msg));
+	ctrl_if_sync.pending_process = 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_process(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 unci_ethtool_msg));
+	ctrl_if_sync.msg_storage.flag = UNCI_MSG_FLAG_RESPONSE;
+	ctrl_if_sync.pending_process = 1;
+
+	pthread_mutex_unlock(&ctrl_if_sync.msg_lock);
+
+	control_interface_msg_process(RTE_ETHTOOL_CTRL_IF_PROCESS_MSG);
+
+	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 int)ret < sizeof(struct unci_ethtool_msg)) {
+			RTE_LOG(WARNING, CTRL_IF,
+					"Received %d bytes, payload %zu\n",
+					ret, sizeof(struct unci_ethtool_msg));
+			continue;
+		}
+
+		msg_add_and_process(&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, UNCI_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 000000000..889be87e8
--- /dev/null
+++ b/lib/librte_ctrl_if/rte_nl.h
@@ -0,0 +1,48 @@
+/*-
+ *   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);
+
+#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 341913851..1dbf6b1a3 100644
--- a/lib/librte_eal/common/include/rte_log.h
+++ b/lib/librte_eal/common/include/rte_log.h
@@ -87,6 +87,7 @@ extern struct rte_logs rte_logs;
 #define RTE_LOGTYPE_CRYPTODEV 17 /**< Log related to cryptodev. */
 #define RTE_LOGTYPE_EFD       18 /**< Log related to EFD. */
 #define RTE_LOGTYPE_EVENTDEV  19 /**< Log related to eventdev. */
+#define RTE_LOGTYPE_CTRL_IF   20 /**< Log related to control interface. */
 
 /* these log types can be used in an application */
 #define RTE_LOGTYPE_USER1     24 /**< User-defined log type 1. */
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 449bd2f61..866bd41c5 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -91,6 +91,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_MBUF)           += -lrte_mbuf
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NET)            += -lrte_net
 _LDLIBS-$(CONFIG_RTE_LIBRTE_ETHER)          += -lrte_ethdev
 _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_EVENTDEV)       += -lrte_eventdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)        += -lrte_mempool
