diff --git a/config/common_linuxapp b/config/common_linuxapp
index de705d0..ed32ca8 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -506,6 +506,8 @@ CONFIG_RTE_KNI_VHOST_DEBUG_TX=n
 # Compile librte_ctrl_if
 #
 CONFIG_RTE_LIBRTE_CTRL_IF=y
+CONFIG_RTE_KCP_KMOD=y
+CONFIG_RTE_KCP_KO_DEBUG=n
 
 #
 # Compile vhost library
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/kcp/Makefile b/lib/librte_eal/linuxapp/kcp/Makefile
new file mode 100644
index 0000000..e7472f3
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/Makefile
@@ -0,0 +1,58 @@
+#   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 $(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..1097cb4
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_dev.h
@@ -0,0 +1,81 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2010-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; if not, write to the Free Software
+ *   Foundation.
+ *   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>
+
+#define RTE_KCP_NAMESIZE 32
+#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)
+
+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,
+};
+
+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..0f5b583
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_ethtool.c
@@ -0,0 +1,261 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2010-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; if not, write to the Free Software
+ *   Foundation.
+ *   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..eadd1d7
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_misc.c
@@ -0,0 +1,282 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2010-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; if not, write to the Free Software
+ *   Foundation.
+ *   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..8aba386
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_net.c
@@ -0,0 +1,209 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2010-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; if not, write to the Free Software
+ *   Foundation.
+ *   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..3c2ed5b
--- /dev/null
+++ b/lib/librte_eal/linuxapp/kcp/kcp_nl.c
@@ -0,0 +1,194 @@
+/*-
+ * GPL LICENSE SUMMARY
+ *
+ *   Copyright(c) 2010-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;
+}
