[dpdk-dev,v9] net/kni: add KNI PMD

Message ID 20170217134238.27064-1-ferruh.yigit@intel.com (mailing list archive)
State Accepted, archived
Delegated to: Ferruh Yigit
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK

Commit Message

Ferruh Yigit Feb. 17, 2017, 1:42 p.m. UTC
  Add KNI PMD which wraps librte_kni for ease of use.

KNI PMD can be used as any regular PMD to send / receive packets to the
Linux networking stack.

Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
Reviewed-by: Yong Wang <yongwang@vmware.com>
---

v9:
* update for 17.05

v8:
* Don't try to link against librte_pmd_kni if librte_kni is disabled

v7:
* Add dependency to CONFIG_RTE_LIBRTE_KNI config

v6:
* documentation typos fixed

v5:
* add kvargs "no_request_thread" to disable a specific pthread creation
to handle control requests.
* add documentation

v4:
* allow only single queue
* use driver.name as name

v3:
* rebase on top of latest master

v2:
* updated driver name eth_kni -> net_kni
---
 MAINTAINERS                             |   5 +
 config/common_base                      |   1 +
 config/common_linuxapp                  |   1 +
 doc/guides/nics/features/kni.ini        |   7 +
 doc/guides/nics/index.rst               |   1 +
 doc/guides/nics/kni.rst                 | 197 ++++++++++++
 drivers/net/Makefile                    |   4 +
 drivers/net/kni/Makefile                |  64 ++++
 drivers/net/kni/rte_eth_kni.c           | 515 ++++++++++++++++++++++++++++++++
 drivers/net/kni/rte_pmd_kni_version.map |   4 +
 mk/rte.app.mk                           |  12 +-
 11 files changed, 806 insertions(+), 5 deletions(-)
 create mode 100644 doc/guides/nics/features/kni.ini
 create mode 100644 doc/guides/nics/kni.rst
 create mode 100644 drivers/net/kni/Makefile
 create mode 100644 drivers/net/kni/rte_eth_kni.c
 create mode 100644 drivers/net/kni/rte_pmd_kni_version.map
  

Comments

Thomas Monjalon Feb. 17, 2017, 1:47 p.m. UTC | #1
2017-02-17 13:42, Ferruh Yigit:
> Add KNI PMD which wraps librte_kni for ease of use.
> 
> KNI PMD can be used as any regular PMD to send / receive packets to the
> Linux networking stack.
> 
> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> Reviewed-by: Yong Wang <yongwang@vmware.com>
> ---
> 
> v9:
> * update for 17.05

You keep updating this patch in the hope that someone would be interested :)

Please let's make clear that I am OK to merge it
but you asked me to wait for someone supporting its inclusion.
  
Eelco Chaudron Feb. 17, 2017, 2 p.m. UTC | #2
On 17/02/17 14:47, Thomas Monjalon wrote:
> 2017-02-17 13:42, Ferruh Yigit:
>> Add KNI PMD which wraps librte_kni for ease of use.
>>
>> KNI PMD can be used as any regular PMD to send / receive packets to the
>> Linux networking stack.
>>
>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>> Reviewed-by: Yong Wang <yongwang@vmware.com>
>> ---
>>
>> v9:
>> * update for 17.05
> You keep updating this patch in the hope that someone would be interested :)

We needed this a while back in DPDK for warp17, however I ended up 
implementing this myself, 
https://github.com/Juniper/warp17/blob/master/src/kni_if/tpg_kni_pmd.c

I think its useful,  so you do not have to use different APIs when 
sending/receiving over multiple types of interfaces.

> Please let's make clear that I am OK to merge it
> but you asked me to wait for someone supporting its inclusion.
  
Ferruh Yigit Feb. 17, 2017, 2:29 p.m. UTC | #3
On 2/17/2017 1:47 PM, Thomas Monjalon wrote:
> 2017-02-17 13:42, Ferruh Yigit:
>> Add KNI PMD which wraps librte_kni for ease of use.
>>
>> KNI PMD can be used as any regular PMD to send / receive packets to the
>> Linux networking stack.
>>
>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>> Reviewed-by: Yong Wang <yongwang@vmware.com>
>> ---
>>
>> v9:
>> * update for 17.05
> 
> You keep updating this patch in the hope that someone would be interested :)
> 
> Please let's make clear that I am OK to merge it
> but you asked me to wait for someone supporting its inclusion.

Right, it is good to mention that I explicitly asked to wait community
response.

I keep updating it because I believe this is something useful.

Meanwhile adding this into repo means maintenance cost, so this should
not be merged without any usecase or interest from community.

Patch is waiting for an ACK or NAK from community.

Thanks,
ferruh
  
Bruce Richardson Feb. 17, 2017, 2:57 p.m. UTC | #4
On Fri, Feb 17, 2017 at 02:29:51PM +0000, Ferruh Yigit wrote:
> On 2/17/2017 1:47 PM, Thomas Monjalon wrote:
> > 2017-02-17 13:42, Ferruh Yigit:
> >> Add KNI PMD which wraps librte_kni for ease of use.
> >>
> >> KNI PMD can be used as any regular PMD to send / receive packets to the
> >> Linux networking stack.
> >>
> >> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> >> Reviewed-by: Yong Wang <yongwang@vmware.com>
> >> ---
> >>
> >> v9:
> >> * update for 17.05
> > 
> > You keep updating this patch in the hope that someone would be interested :)
> > 
> > Please let's make clear that I am OK to merge it
> > but you asked me to wait for someone supporting its inclusion.
> 
> Right, it is good to mention that I explicitly asked to wait community
> response.
> 
> I keep updating it because I believe this is something useful.
> 
> Meanwhile adding this into repo means maintenance cost, so this should
> not be merged without any usecase or interest from community.
> 
> Patch is waiting for an ACK or NAK from community.
> 
I believe this is useful. No reason for KNI to have to use special
custom rx/tx functions when it can be made to use regular ethdev ones.
So:

Acked-by: Bruce Richardson <bruce.richardson@intel.com>
  
Yong Wang Feb. 17, 2017, 5:52 p.m. UTC | #5
> -----Original Message-----

> From: Ferruh Yigit [mailto:ferruh.yigit@intel.com]

> Sent: Friday, February 17, 2017 6:30 AM

> To: Thomas Monjalon <thomas.monjalon@6wind.com>

> Cc: dev@dpdk.org; John McNamara <john.mcnamara@intel.com>; Yong

> Wang <yongwang@vmware.com>

> Subject: Re: [PATCH v9] net/kni: add KNI PMD

> 

> On 2/17/2017 1:47 PM, Thomas Monjalon wrote:

> > 2017-02-17 13:42, Ferruh Yigit:

> >> Add KNI PMD which wraps librte_kni for ease of use.

> >>

> >> KNI PMD can be used as any regular PMD to send / receive packets to the

> >> Linux networking stack.

> >>

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

> >> Reviewed-by: Yong Wang <yongwang@vmware.com>

> >> ---


I have the impression that Reviewed-by is good enough for a change to be accepted, which does not seem to be the case.

Acked-by: Yong Wang <yongwang@vmware.com>


> >>

> >> v9:

> >> * update for 17.05

> >

> > You keep updating this patch in the hope that someone would be

> interested :)

> >

> > Please let's make clear that I am OK to merge it

> > but you asked me to wait for someone supporting its inclusion.

> 

> Right, it is good to mention that I explicitly asked to wait community

> response.

> 

> I keep updating it because I believe this is something useful.

> 

> Meanwhile adding this into repo means maintenance cost, so this should

> not be merged without any usecase or interest from community.

> 

> Patch is waiting for an ACK or NAK from community.

> 

> Thanks,

> ferruh
  
Thomas Monjalon Feb. 17, 2017, 10:37 p.m. UTC | #6
2017-02-17 17:52, Yong Wang:
> From: Ferruh Yigit [mailto:ferruh.yigit@intel.com]
> > On 2/17/2017 1:47 PM, Thomas Monjalon wrote:
> > > 2017-02-17 13:42, Ferruh Yigit:
> > >> Add KNI PMD which wraps librte_kni for ease of use.
> > >>
> > >> KNI PMD can be used as any regular PMD to send / receive packets to the
> > >> Linux networking stack.
> > >>
> > >> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
> > >> Reviewed-by: Yong Wang <yongwang@vmware.com>
> > >> ---
> 
> I have the impression that Reviewed-by is good enough for a change to be accepted, which does not seem to be the case.
> 
> Acked-by: Yong Wang <yongwang@vmware.com>

Sorry, it is not what I meant.
Your Reviewed-by is really strong to make confident the patch is good.
But Ferruh wanted to make sure more people wants this PMD.
  
Ferruh Yigit Feb. 20, 2017, 12:54 p.m. UTC | #7
On 2/17/2017 5:52 PM, Yong Wang wrote:
>> -----Original Message-----
>> From: Ferruh Yigit [mailto:ferruh.yigit@intel.com]
>> Sent: Friday, February 17, 2017 6:30 AM
>> To: Thomas Monjalon <thomas.monjalon@6wind.com>
>> Cc: dev@dpdk.org; John McNamara <john.mcnamara@intel.com>; Yong
>> Wang <yongwang@vmware.com>
>> Subject: Re: [PATCH v9] net/kni: add KNI PMD
>>
>> On 2/17/2017 1:47 PM, Thomas Monjalon wrote:
>>> 2017-02-17 13:42, Ferruh Yigit:
>>>> Add KNI PMD which wraps librte_kni for ease of use.
>>>>
>>>> KNI PMD can be used as any regular PMD to send / receive packets to the
>>>> Linux networking stack.
>>>>
>>>> Signed-off-by: Ferruh Yigit <ferruh.yigit@intel.com>
>>>> Reviewed-by: Yong Wang <yongwang@vmware.com>
<...>
> Acked-by: Yong Wang <yongwang@vmware.com>

Applied to dpdk-next-net/master, thanks.
  

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 8305237..b4617fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -412,6 +412,11 @@  M: Keith Wiles <keith.wiles@intel.com>
 F: drivers/net/tap/
 F: doc/guides/nics/tap.rst
 
+KNI PMD
+M: Ferruh Yigit <ferruh.yigit@intel.com>
+F: drivers/net/kni/
+F: doc/guides/nics/kni.rst
+
 Ring PMD
 M: Bruce Richardson <bruce.richardson@intel.com>
 F: drivers/net/ring/
diff --git a/config/common_base b/config/common_base
index 71a4fcb..63756c4 100644
--- a/config/common_base
+++ b/config/common_base
@@ -581,6 +581,7 @@  CONFIG_RTE_PIPELINE_STATS_COLLECT=n
 # Compile librte_kni
 #
 CONFIG_RTE_LIBRTE_KNI=n
+CONFIG_RTE_LIBRTE_PMD_KNI=n
 CONFIG_RTE_KNI_KMOD=n
 CONFIG_RTE_KNI_KMOD_ETHTOOL=n
 CONFIG_RTE_KNI_PREEMPT_DEFAULT=y
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 00ebaac..d03a60a 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_PMD_KNI=y
 CONFIG_RTE_LIBRTE_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_VHOST=y
 CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
diff --git a/doc/guides/nics/features/kni.ini b/doc/guides/nics/features/kni.ini
new file mode 100644
index 0000000..6deb66a
--- /dev/null
+++ b/doc/guides/nics/features/kni.ini
@@ -0,0 +1,7 @@ 
+;
+; Supported features of the 'kni' network poll mode driver.
+;
+; Refer to default.ini for the full list of available PMD features.
+;
+[Features]
+Usage doc            = Y
diff --git a/doc/guides/nics/index.rst b/doc/guides/nics/index.rst
index 87f9334..5248625 100644
--- a/doc/guides/nics/index.rst
+++ b/doc/guides/nics/index.rst
@@ -46,6 +46,7 @@  Network Interface Controller Drivers
     i40e
     ixgbe
     intel_vf
+    kni
     mlx4
     mlx5
     nfp
diff --git a/doc/guides/nics/kni.rst b/doc/guides/nics/kni.rst
new file mode 100644
index 0000000..77542b5
--- /dev/null
+++ b/doc/guides/nics/kni.rst
@@ -0,0 +1,197 @@ 
+..  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.
+
+KNI Poll Mode Driver
+======================
+
+KNI PMD is wrapper to the :ref:`librte_kni <kni>` library.
+
+This PMD enables using KNI without having a KNI specific application,
+any forwarding application can use PMD interface for KNI.
+
+Sending packets to any DPDK controlled interface or sending to the
+Linux networking stack will be transparent to the DPDK application.
+
+To create a KNI device ``net_kni#`` device name should be used, and this
+will create ``kni#`` Linux virtual network interface.
+
+There is no physical device backend for the virtual KNI device.
+
+Packets sent to the KNI Linux interface will be received by the DPDK
+application, and DPDK application may forward packets to a physical NIC
+or to a virtual device (like another KNI interface or PCAP interface).
+
+To forward any traffic from physical NIC to the Linux networking stack,
+an application should control a physical port and create one virtual KNI port,
+and forward between two.
+
+Using this PMD requires KNI kernel module be inserted.
+
+
+Usage
+-----
+
+EAL ``--vdev`` argument can be used to create KNI device instance, like::
+
+        testpmd --vdev=net_kni0 --vdev=net_kn1 -- -i
+
+Above command will create ``kni0`` and ``kni1`` Linux network interfaces,
+those interfaces can be controlled by standard Linux tools.
+
+When testpmd forwarding starts, any packets sent to ``kni0`` interface
+forwarded to the ``kni1`` interface and vice versa.
+
+There is no hard limit on number of interfaces that can be created.
+
+
+Default interface configuration
+-------------------------------
+
+``librte_kni`` can create Linux network interfaces with different features,
+feature set controlled by a configuration struct, and KNI PMD uses a fixed
+configuration:
+
+    .. code-block:: console
+
+        Interface name: kni#
+        force bind kernel thread to a core : NO
+        mbuf size: MAX_PACKET_SZ
+
+KNI control path is not supported with the PMD, since there is no physical
+backend device by default.
+
+
+PMD arguments
+-------------
+
+``no_request_thread``, by default PMD creates a phtread for each KNI interface
+to handle Linux network interface control commands, like ``ifconfig kni0 up``
+
+With ``no_request_thread`` option, pthread is not created and control commands
+not handled by PMD.
+
+By default request thread is enabled. And this argument should not be used
+most of the time, unless this PMD used with customized DPDK application to handle
+requests itself.
+
+Argument usage::
+
+        testpmd --vdev "net_kni0,no_request_thread=1" -- -i
+
+
+PMD log messages
+----------------
+
+If KNI kernel module (rte_kni.ko) not inserted, following error log printed::
+
+        "KNI: KNI subsystem has not been initialized. Invoke rte_kni_init() first"
+
+
+PMD testing
+-----------
+
+It is possible to test PMD quickly using KNI kernel module loopback feature:
+
+* Insert KNI kernel module with loopback support:
+
+    .. code-block:: console
+
+        insmod build/kmod/rte_kni.ko lo_mode=lo_mode_fifo_skb
+
+* Start testpmd with no physical device but two KNI virtual devices:
+
+    .. code-block:: console
+
+        ./testpmd --vdev net_kni0 --vdev net_kni1 -- -i
+
+    .. code-block:: console
+
+        ...
+        Configuring Port 0 (socket 0)
+        KNI: pci: 00:00:00       c580:b8
+        Port 0: 1A:4A:5B:7C:A2:8C
+        Configuring Port 1 (socket 0)
+        KNI: pci: 00:00:00       600:b9
+        Port 1: AE:95:21:07:93:DD
+        Checking link statuses...
+        Port 0 Link Up - speed 10000 Mbps - full-duplex
+        Port 1 Link Up - speed 10000 Mbps - full-duplex
+        Done
+        testpmd>
+
+* Observe Linux interfaces
+
+    .. code-block:: console
+
+        $ ifconfig kni0 && ifconfig kni1
+        kni0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
+                ether ae:8e:79:8e:9b:c8  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
+
+        kni1: flags=4098<BROADCAST,MULTICAST>  mtu 1500
+                ether 9e:76:43:53:3e:9b  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
+
+
+* Start forwarding with tx_first:
+
+    .. code-block:: console
+
+        testpmd> start tx_first
+
+* Quit and check forwarding stats:
+
+    .. code-block:: console
+
+        testpmd> quit
+        Telling cores to stop...
+        Waiting for lcores to finish...
+
+        ---------------------- Forward statistics for port 0  ----------------------
+        RX-packets: 35637905       RX-dropped: 0             RX-total: 35637905
+        TX-packets: 35637947       TX-dropped: 0             TX-total: 35637947
+        ----------------------------------------------------------------------------
+
+        ---------------------- Forward statistics for port 1  ----------------------
+        RX-packets: 35637915       RX-dropped: 0             RX-total: 35637915
+        TX-packets: 35637937       TX-dropped: 0             TX-total: 35637937
+        ----------------------------------------------------------------------------
+
+        +++++++++++++++ Accumulated forward statistics for all ports+++++++++++++++
+        RX-packets: 71275820       RX-dropped: 0             RX-total: 71275820
+        TX-packets: 71275884       TX-dropped: 0             TX-total: 71275884
+        ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 40fc333..ab60cb8 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -58,6 +58,10 @@  DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
 DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_XENVIRT) += xenvirt
 
+ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_KNI) += kni
+endif
+
 ifeq ($(CONFIG_RTE_LIBRTE_VHOST),y)
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_VHOST) += vhost
 endif # $(CONFIG_RTE_LIBRTE_VHOST)
diff --git a/drivers/net/kni/Makefile b/drivers/net/kni/Makefile
new file mode 100644
index 0000000..b3017b1
--- /dev/null
+++ b/drivers/net/kni/Makefile
@@ -0,0 +1,64 @@ 
+#   BSD LICENSE
+#
+#   Copyright(c) 2017 Intel Corporation. All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (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_pmd_kni.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lpthread
+
+EXPORT_MAP := rte_pmd_kni_version.map
+
+LIBABIVER := 1
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_KNI) += rte_eth_kni.c
+
+#
+# Export include files
+#
+SYMLINK-y-include +=
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_KNI) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_KNI) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_KNI) += lib/librte_kni
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_KNI) += lib/librte_kvargs
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_KNI) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_KNI) += lib/librte_mempool
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/kni/rte_eth_kni.c b/drivers/net/kni/rte_eth_kni.c
new file mode 100644
index 0000000..59205e7
--- /dev/null
+++ b/drivers/net/kni/rte_eth_kni.c
@@ -0,0 +1,515 @@ 
+/*-
+ *   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 <pthread.h>
+#include <unistd.h>
+
+#include <rte_ethdev.h>
+#include <rte_kni.h>
+#include <rte_kvargs.h>
+#include <rte_malloc.h>
+#include <rte_vdev.h>
+
+/* Only single queue supported */
+#define KNI_MAX_QUEUE_PER_PORT 1
+
+#define MAX_PACKET_SZ 2048
+#define MAX_KNI_PORTS 8
+
+#define ETH_KNI_NO_REQUEST_THREAD_ARG	"no_request_thread"
+static const char * const valid_arguments[] = {
+	ETH_KNI_NO_REQUEST_THREAD_ARG,
+	NULL
+};
+
+struct eth_kni_args {
+	int no_request_thread;
+};
+
+struct pmd_queue_stats {
+	uint64_t pkts;
+	uint64_t bytes;
+	uint64_t err_pkts;
+};
+
+struct pmd_queue {
+	struct pmd_internals *internals;
+	struct rte_mempool *mb_pool;
+
+	struct pmd_queue_stats rx;
+	struct pmd_queue_stats tx;
+};
+
+struct pmd_internals {
+	struct rte_kni *kni;
+	int is_kni_started;
+
+	pthread_t thread;
+	int stop_thread;
+	int no_request_thread;
+
+	struct ether_addr eth_addr;
+
+	struct pmd_queue rx_queues[KNI_MAX_QUEUE_PER_PORT];
+	struct pmd_queue tx_queues[KNI_MAX_QUEUE_PER_PORT];
+};
+
+static const struct rte_eth_link pmd_link = {
+		.link_speed = ETH_SPEED_NUM_10G,
+		.link_duplex = ETH_LINK_FULL_DUPLEX,
+		.link_status = ETH_LINK_DOWN,
+		.link_autoneg = ETH_LINK_SPEED_AUTONEG,
+};
+static int is_kni_initialized;
+
+static uint16_t
+eth_kni_rx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	struct pmd_queue *kni_q = q;
+	struct rte_kni *kni = kni_q->internals->kni;
+	uint16_t nb_pkts;
+
+	nb_pkts = rte_kni_rx_burst(kni, bufs, nb_bufs);
+
+	kni_q->rx.pkts += nb_pkts;
+	kni_q->rx.err_pkts += nb_bufs - nb_pkts;
+
+	return nb_pkts;
+}
+
+static uint16_t
+eth_kni_tx(void *q, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+	struct pmd_queue *kni_q = q;
+	struct rte_kni *kni = kni_q->internals->kni;
+	uint16_t nb_pkts;
+
+	nb_pkts =  rte_kni_tx_burst(kni, bufs, nb_bufs);
+
+	kni_q->tx.pkts += nb_pkts;
+	kni_q->tx.err_pkts += nb_bufs - nb_pkts;
+
+	return nb_pkts;
+}
+
+static void *
+kni_handle_request(void *param)
+{
+	struct pmd_internals *internals = param;
+#define MS 1000
+
+	while (!internals->stop_thread) {
+		rte_kni_handle_request(internals->kni);
+		usleep(500 * MS);
+	}
+
+	return param;
+}
+
+static int
+eth_kni_start(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	uint16_t port_id = dev->data->port_id;
+	struct rte_mempool *mb_pool;
+	struct rte_kni_conf conf;
+	const char *name = dev->data->name + 4; /* remove net_ */
+
+	snprintf(conf.name, RTE_KNI_NAMESIZE, "%s", name);
+	conf.force_bind = 0;
+	conf.group_id = port_id;
+	conf.mbuf_size = MAX_PACKET_SZ;
+	mb_pool = internals->rx_queues[0].mb_pool;
+
+	internals->kni = rte_kni_alloc(mb_pool, &conf, NULL);
+	if (internals->kni == NULL) {
+		RTE_LOG(ERR, PMD,
+			"Fail to create kni interface for port: %d\n",
+			port_id);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+eth_kni_dev_start(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+
+	if (internals->is_kni_started == 0) {
+		ret = eth_kni_start(dev);
+		if (ret)
+			return -1;
+		internals->is_kni_started = 1;
+	}
+
+	if (internals->no_request_thread == 0) {
+		ret = pthread_create(&internals->thread, NULL,
+			kni_handle_request, internals);
+		if (ret) {
+			RTE_LOG(ERR, PMD,
+				"Fail to create kni request thread\n");
+			return -1;
+		}
+	}
+
+	dev->data->dev_link.link_status = 1;
+
+	return 0;
+}
+
+static void
+eth_kni_dev_stop(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	int ret;
+
+	if (internals->no_request_thread == 0) {
+		internals->stop_thread = 1;
+
+		ret = pthread_cancel(internals->thread);
+		if (ret)
+			RTE_LOG(ERR, PMD, "Can't cancel the thread\n");
+
+		ret = pthread_join(internals->thread, NULL);
+		if (ret)
+			RTE_LOG(ERR, PMD, "Can't join the thread\n");
+
+		internals->stop_thread = 0;
+	}
+
+	dev->data->dev_link.link_status = 0;
+}
+
+static int
+eth_kni_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+	return 0;
+}
+
+static void
+eth_kni_dev_info(struct rte_eth_dev *dev __rte_unused,
+		struct rte_eth_dev_info *dev_info)
+{
+	dev_info->max_mac_addrs = 1;
+	dev_info->max_rx_pktlen = UINT32_MAX;
+	dev_info->max_rx_queues = KNI_MAX_QUEUE_PER_PORT;
+	dev_info->max_tx_queues = KNI_MAX_QUEUE_PER_PORT;
+	dev_info->min_rx_bufsize = 0;
+	dev_info->pci_dev = NULL;
+}
+
+static int
+eth_kni_rx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t rx_queue_id,
+		uint16_t nb_rx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_rxconf *rx_conf __rte_unused,
+		struct rte_mempool *mb_pool)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	struct pmd_queue *q;
+
+	q = &internals->rx_queues[rx_queue_id];
+	q->internals = internals;
+	q->mb_pool = mb_pool;
+
+	dev->data->rx_queues[rx_queue_id] = q;
+
+	return 0;
+}
+
+static int
+eth_kni_tx_queue_setup(struct rte_eth_dev *dev,
+		uint16_t tx_queue_id,
+		uint16_t nb_tx_desc __rte_unused,
+		unsigned int socket_id __rte_unused,
+		const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+	struct pmd_internals *internals = dev->data->dev_private;
+	struct pmd_queue *q;
+
+	q = &internals->tx_queues[tx_queue_id];
+	q->internals = internals;
+
+	dev->data->tx_queues[tx_queue_id] = q;
+
+	return 0;
+}
+
+static void
+eth_kni_queue_release(void *q __rte_unused)
+{
+}
+
+static int
+eth_kni_link_update(struct rte_eth_dev *dev __rte_unused,
+		int wait_to_complete __rte_unused)
+{
+	return 0;
+}
+
+static void
+eth_kni_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	unsigned long rx_packets_total = 0, rx_bytes_total = 0;
+	unsigned long tx_packets_total = 0, tx_bytes_total = 0;
+	struct rte_eth_dev_data *data = dev->data;
+	unsigned long tx_packets_err_total = 0;
+	unsigned int i, num_stats;
+	struct pmd_queue *q;
+
+	num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
+			data->nb_rx_queues);
+	for (i = 0; i < num_stats; i++) {
+		q = data->rx_queues[i];
+		stats->q_ipackets[i] = q->rx.pkts;
+		stats->q_ibytes[i] = q->rx.bytes;
+		rx_packets_total += stats->q_ipackets[i];
+		rx_bytes_total += stats->q_ibytes[i];
+	}
+
+	num_stats = RTE_MIN((unsigned int)RTE_ETHDEV_QUEUE_STAT_CNTRS,
+			data->nb_tx_queues);
+	for (i = 0; i < num_stats; i++) {
+		q = data->tx_queues[i];
+		stats->q_opackets[i] = q->tx.pkts;
+		stats->q_obytes[i] = q->tx.bytes;
+		stats->q_errors[i] = q->tx.err_pkts;
+		tx_packets_total += stats->q_opackets[i];
+		tx_bytes_total += stats->q_obytes[i];
+		tx_packets_err_total += stats->q_errors[i];
+	}
+
+	stats->ipackets = rx_packets_total;
+	stats->ibytes = rx_bytes_total;
+	stats->opackets = tx_packets_total;
+	stats->obytes = tx_bytes_total;
+	stats->oerrors = tx_packets_err_total;
+}
+
+static void
+eth_kni_stats_reset(struct rte_eth_dev *dev)
+{
+	struct rte_eth_dev_data *data = dev->data;
+	struct pmd_queue *q;
+	unsigned int i;
+
+	for (i = 0; i < data->nb_rx_queues; i++) {
+		q = data->rx_queues[i];
+		q->rx.pkts = 0;
+		q->rx.bytes = 0;
+	}
+	for (i = 0; i < data->nb_tx_queues; i++) {
+		q = data->tx_queues[i];
+		q->tx.pkts = 0;
+		q->tx.bytes = 0;
+		q->tx.err_pkts = 0;
+	}
+}
+
+static const struct eth_dev_ops eth_kni_ops = {
+	.dev_start = eth_kni_dev_start,
+	.dev_stop = eth_kni_dev_stop,
+	.dev_configure = eth_kni_dev_configure,
+	.dev_infos_get = eth_kni_dev_info,
+	.rx_queue_setup = eth_kni_rx_queue_setup,
+	.tx_queue_setup = eth_kni_tx_queue_setup,
+	.rx_queue_release = eth_kni_queue_release,
+	.tx_queue_release = eth_kni_queue_release,
+	.link_update = eth_kni_link_update,
+	.stats_get = eth_kni_stats_get,
+	.stats_reset = eth_kni_stats_reset,
+};
+
+static struct rte_vdev_driver eth_kni_drv;
+
+static struct rte_eth_dev *
+eth_kni_create(const char *name, struct eth_kni_args *args,
+		unsigned int numa_node)
+{
+	struct pmd_internals *internals = NULL;
+	struct rte_eth_dev_data *data;
+	struct rte_eth_dev *eth_dev;
+
+	RTE_LOG(INFO, PMD, "Creating kni ethdev on numa socket %u\n",
+			numa_node);
+
+	data = rte_zmalloc_socket(name, sizeof(*data), 0, numa_node);
+	if (data == NULL)
+		goto error;
+
+	internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
+	if (internals == NULL)
+		goto error;
+
+	/* reserve an ethdev entry */
+	eth_dev = rte_eth_dev_allocate(name);
+	if (eth_dev == NULL)
+		goto error;
+
+	data->dev_private = internals;
+	data->port_id = eth_dev->data->port_id;
+	memmove(data->name, eth_dev->data->name, sizeof(data->name));
+	data->nb_rx_queues = 1;
+	data->nb_tx_queues = 1;
+	data->dev_link = pmd_link;
+	data->mac_addrs = &internals->eth_addr;
+
+	eth_random_addr(internals->eth_addr.addr_bytes);
+
+	eth_dev->data = data;
+	eth_dev->dev_ops = &eth_kni_ops;
+	eth_dev->driver = NULL;
+
+	data->dev_flags = RTE_ETH_DEV_DETACHABLE;
+	data->kdrv = RTE_KDRV_NONE;
+	data->drv_name = eth_kni_drv.driver.name;
+	data->numa_node = numa_node;
+
+	internals->no_request_thread = args->no_request_thread;
+
+	return eth_dev;
+
+error:
+	rte_free(data);
+	rte_free(internals);
+
+	return NULL;
+}
+
+static int
+kni_init(void)
+{
+	if (is_kni_initialized == 0)
+		rte_kni_init(MAX_KNI_PORTS);
+
+	is_kni_initialized++;
+
+	return 0;
+}
+
+static int
+eth_kni_kvargs_process(struct eth_kni_args *args, const char *params)
+{
+	struct rte_kvargs *kvlist;
+
+	kvlist = rte_kvargs_parse(params, valid_arguments);
+	if (kvlist == NULL)
+		return -1;
+
+	memset(args, 0, sizeof(struct eth_kni_args));
+
+	if (rte_kvargs_count(kvlist, ETH_KNI_NO_REQUEST_THREAD_ARG) == 1)
+		args->no_request_thread = 1;
+
+	rte_kvargs_free(kvlist);
+
+	return 0;
+}
+
+static int
+eth_kni_probe(const char *name, const char *params)
+{
+	struct rte_eth_dev *eth_dev;
+	struct eth_kni_args args;
+	int ret;
+
+	RTE_LOG(INFO, PMD, "Initializing eth_kni for %s\n", name);
+
+	ret = eth_kni_kvargs_process(&args, params);
+	if (ret < 0)
+		return ret;
+
+	ret = kni_init();
+	if (ret < 0)
+		return ret;
+
+	eth_dev = eth_kni_create(name, &args, rte_socket_id());
+	if (eth_dev == NULL)
+		goto kni_uninit;
+
+	eth_dev->rx_pkt_burst = eth_kni_rx;
+	eth_dev->tx_pkt_burst = eth_kni_tx;
+
+	return 0;
+
+kni_uninit:
+	is_kni_initialized--;
+	if (is_kni_initialized == 0)
+		rte_kni_close();
+	return -1;
+}
+
+static int
+eth_kni_remove(const char *name)
+{
+	struct rte_eth_dev *eth_dev;
+	struct pmd_internals *internals;
+
+	RTE_LOG(INFO, PMD, "Un-Initializing eth_kni for %s\n", name);
+
+	/* find the ethdev entry */
+	eth_dev = rte_eth_dev_allocated(name);
+	if (eth_dev == NULL)
+		return -1;
+
+	eth_kni_dev_stop(eth_dev);
+
+	if (eth_dev->data) {
+		internals = eth_dev->data->dev_private;
+		rte_kni_release(internals->kni);
+
+		rte_free(internals);
+	}
+	rte_free(eth_dev->data);
+
+	rte_eth_dev_release_port(eth_dev);
+
+	is_kni_initialized--;
+	if (is_kni_initialized == 0)
+		rte_kni_close();
+
+	return 0;
+}
+
+static struct rte_vdev_driver eth_kni_drv = {
+	.probe = eth_kni_probe,
+	.remove = eth_kni_remove,
+};
+
+RTE_PMD_REGISTER_VDEV(net_kni, eth_kni_drv);
+RTE_PMD_REGISTER_PARAM_STRING(net_kni, ETH_KNI_NO_REQUEST_THREAD_ARG "=<int>");
diff --git a/drivers/net/kni/rte_pmd_kni_version.map b/drivers/net/kni/rte_pmd_kni_version.map
new file mode 100644
index 0000000..8591cc0
--- /dev/null
+++ b/drivers/net/kni/rte_pmd_kni_version.map
@@ -0,0 +1,4 @@ 
+DPDK_17.05 {
+
+	local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 92f3635..236da9c 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -59,11 +59,6 @@  _LDLIBS-y += -L$(RTE_SDK_BIN)/lib
 #
 # Order is important: from higher level to lower level
 #
-
-ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
-_LDLIBS-$(CONFIG_RTE_LIBRTE_KNI)            += -lrte_kni
-endif
-
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PIPELINE)       += -lrte_pipeline
 _LDLIBS-$(CONFIG_RTE_LIBRTE_TABLE)          += -lrte_table
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PORT)           += -lrte_port
@@ -100,6 +95,10 @@  _LDLIBS-$(CONFIG_RTE_LIBRTE_EAL)            += -lrte_eal
 _LDLIBS-$(CONFIG_RTE_LIBRTE_CMDLINE)        += -lrte_cmdline
 _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER)        += -lrte_reorder
 
+ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
+_LDLIBS-$(CONFIG_RTE_LIBRTE_KNI)            += -lrte_kni
+endif
+
 ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),n)
 # plugins (link only if static libraries)
 
@@ -114,6 +113,9 @@  _LDLIBS-$(CONFIG_RTE_LIBRTE_ENIC_PMD)       += -lrte_pmd_enic
 _LDLIBS-$(CONFIG_RTE_LIBRTE_FM10K_PMD)      += -lrte_pmd_fm10k
 _LDLIBS-$(CONFIG_RTE_LIBRTE_I40E_PMD)       += -lrte_pmd_i40e
 _LDLIBS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD)      += -lrte_pmd_ixgbe
+ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI)        += -lrte_pmd_kni
+endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MPIPE_PMD)      += -lrte_pmd_mpipe -lgxio