1. add KNI port type to the packet framework
2. add KNI support to the IP Pipeline sample Application
3. some bug fix

Signed-off-by: WeiJie Zhuang <zhuangwj at gmail.com>
---
v2:
* Fix check patch error.
v3:
* Fix code review comments.
---
 doc/api/doxy-api-index.md                          |   1 +
 examples/ip_pipeline/Makefile                      |   2 +-
 examples/ip_pipeline/app.h                         | 181 +++++++++++-
 examples/ip_pipeline/config/kni.cfg                |  67 +++++
 examples/ip_pipeline/config_check.c                |  26 +-
 examples/ip_pipeline/config_parse.c                | 166 ++++++++++-
 examples/ip_pipeline/init.c                        | 132 ++++++++-
 examples/ip_pipeline/pipeline/pipeline_common_fe.c |  29 ++
 examples/ip_pipeline/pipeline/pipeline_master_be.c |   6 +
 examples/ip_pipeline/pipeline_be.h                 |  27 ++
 lib/librte_port/Makefile                           |   7 +
 lib/librte_port/rte_port_kni.c                     | 325 +++++++++++++++++++++
 lib/librte_port/rte_port_kni.h                     |  82 ++++++
 lib/librte_port/rte_port_version.map               |   8 +
 14 files changed, 1047 insertions(+), 12 deletions(-)
 create mode 100644 examples/ip_pipeline/config/kni.cfg
 create mode 100644 lib/librte_port/rte_port_kni.c
 create mode 100644 lib/librte_port/rte_port_kni.h

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index f626386..5e7f024 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -118,6 +118,7 @@ There are many libraries, so their headers may be grouped 
by topics:
     [frag]             (@ref rte_port_frag.h),
     [reass]            (@ref rte_port_ras.h),
     [sched]            (@ref rte_port_sched.h),
+    [kni]              (@ref rte_port_kni.h),
     [src/sink]         (@ref rte_port_source_sink.h)
   * [table]            (@ref rte_table.h):
     [lpm IPv4]         (@ref rte_table_lpm.h),
diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile
index 5827117..6dc3f52 100644
--- a/examples/ip_pipeline/Makefile
+++ b/examples/ip_pipeline/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
diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h
index 7611341..abbd6d4 100644
--- a/examples/ip_pipeline/app.h
+++ b/examples/ip_pipeline/app.h
@@ -44,6 +44,9 @@
 #include <cmdline_parse.h>

 #include <rte_ethdev.h>
+#ifdef RTE_LIBRTE_KNI
+#include <rte_kni.h>
+#endif

 #include "cpu_core_map.h"
 #include "pipeline.h"
@@ -132,6 +135,20 @@ struct app_pktq_swq_params {
        uint32_t mempool_indirect_id;
 };

+struct app_pktq_kni_params {
+       char *name;
+       uint32_t parsed;
+
+       uint32_t socket_id;
+       uint32_t core_id;
+       uint32_t hyper_th_id;
+       uint32_t force_bind;
+
+       uint32_t mempool_id; /* Position in the app->mempool_params */
+       uint32_t burst_read;
+       uint32_t burst_write;
+};
+
 #ifndef APP_FILE_NAME_SIZE
 #define APP_FILE_NAME_SIZE                       256
 #endif
@@ -185,6 +202,7 @@ enum app_pktq_in_type {
        APP_PKTQ_IN_HWQ,
        APP_PKTQ_IN_SWQ,
        APP_PKTQ_IN_TM,
+       APP_PKTQ_IN_KNI,
        APP_PKTQ_IN_SOURCE,
 };

@@ -197,6 +215,7 @@ enum app_pktq_out_type {
        APP_PKTQ_OUT_HWQ,
        APP_PKTQ_OUT_SWQ,
        APP_PKTQ_OUT_TM,
+       APP_PKTQ_OUT_KNI,
        APP_PKTQ_OUT_SINK,
 };

@@ -420,6 +439,8 @@ struct app_eal_params {

 #define APP_MAX_PKTQ_TM                          APP_MAX_LINKS

+#define APP_MAX_PKTQ_KNI                         APP_MAX_LINKS
+
 #ifndef APP_MAX_PKTQ_SOURCE
 #define APP_MAX_PKTQ_SOURCE                      64
 #endif
@@ -471,6 +492,7 @@ struct app_params {
        struct app_pktq_hwq_out_params hwq_out_params[APP_MAX_HWQ_OUT];
        struct app_pktq_swq_params swq_params[APP_MAX_PKTQ_SWQ];
        struct app_pktq_tm_params tm_params[APP_MAX_PKTQ_TM];
+       struct app_pktq_kni_params kni_params[APP_MAX_PKTQ_KNI];
        struct app_pktq_source_params source_params[APP_MAX_PKTQ_SOURCE];
        struct app_pktq_sink_params sink_params[APP_MAX_PKTQ_SINK];
        struct app_msgq_params msgq_params[APP_MAX_MSGQ];
@@ -482,6 +504,7 @@ struct app_params {
        uint32_t n_pktq_hwq_out;
        uint32_t n_pktq_swq;
        uint32_t n_pktq_tm;
+       uint32_t n_pktq_kni;
        uint32_t n_pktq_source;
        uint32_t n_pktq_sink;
        uint32_t n_msgq;
@@ -495,6 +518,9 @@ struct app_params {
        struct app_link_data link_data[APP_MAX_LINKS];
        struct rte_ring *swq[APP_MAX_PKTQ_SWQ];
        struct rte_sched_port *tm[APP_MAX_PKTQ_TM];
+#ifdef RTE_LIBRTE_KNI
+       struct rte_kni *kni[APP_MAX_PKTQ_KNI];
+#endif /* RTE_LIBRTE_KNI */
        struct rte_ring *msgq[APP_MAX_MSGQ];
        struct pipeline_type pipeline_type[APP_MAX_PIPELINE_TYPES];
        struct app_pipeline_data pipeline_data[APP_MAX_PIPELINES];
@@ -667,11 +693,11 @@ app_swq_get_reader(struct app_params *app,
        struct app_pktq_swq_params *swq,
        uint32_t *pktq_in_id)
 {
-       struct app_pipeline_params *reader;
+       struct app_pipeline_params *reader = NULL;
        uint32_t pos = swq - app->swq_params;
        uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
                RTE_DIM(app->pipeline_params));
-       uint32_t n_readers = 0, id, i;
+       uint32_t n_readers = 0, id = 0, i;

        for (i = 0; i < n_pipelines; i++) {
                struct app_pipeline_params *p = &app->pipeline_params[i];
@@ -727,11 +753,11 @@ app_tm_get_reader(struct app_params *app,
        struct app_pktq_tm_params *tm,
        uint32_t *pktq_in_id)
 {
-       struct app_pipeline_params *reader;
+       struct app_pipeline_params *reader = NULL;
        uint32_t pos = tm - app->tm_params;
        uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
                RTE_DIM(app->pipeline_params));
-       uint32_t n_readers = 0, id, i;
+       uint32_t n_readers = 0, id = 0, i;

        for (i = 0; i < n_pipelines; i++) {
                struct app_pipeline_params *p = &app->pipeline_params[i];
@@ -758,6 +784,66 @@ app_tm_get_reader(struct app_params *app,
 }

 static inline uint32_t
+app_kni_get_readers(struct app_params *app, struct app_pktq_kni_params *kni)
+{
+       uint32_t pos = kni - app->kni_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_readers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_in; j++) {
+                       struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+                       if ((pktq->type == APP_PKTQ_IN_KNI) &&
+                               (pktq->id == pos))
+                               n_readers++;
+               }
+       }
+
+       return n_readers;
+}
+
+static inline struct app_pipeline_params *
+app_kni_get_reader(struct app_params *app,
+                                 struct app_pktq_kni_params *kni,
+                                 uint32_t *pktq_in_id)
+{
+       struct app_pipeline_params *reader = NULL;
+       uint32_t pos = kni - app->kni_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_readers = 0, id = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_in = RTE_MIN(p->n_pktq_in, RTE_DIM(p->pktq_in));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_in; j++) {
+                       struct app_pktq_in_params *pktq = &p->pktq_in[j];
+
+                       if ((pktq->type == APP_PKTQ_IN_KNI) &&
+                               (pktq->id == pos)) {
+                               n_readers++;
+                               reader = p;
+                               id = j;
+                       }
+               }
+       }
+
+       if (n_readers != 1)
+               return NULL;
+
+       *pktq_in_id = id;
+       return reader;
+}
+
+static inline uint32_t
 app_source_get_readers(struct app_params *app,
 struct app_pktq_source_params *source)
 {
@@ -861,11 +947,11 @@ app_swq_get_writer(struct app_params *app,
        struct app_pktq_swq_params *swq,
        uint32_t *pktq_out_id)
 {
-       struct app_pipeline_params *writer;
+       struct app_pipeline_params *writer = NULL;
        uint32_t pos = swq - app->swq_params;
        uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
                RTE_DIM(app->pipeline_params));
-       uint32_t n_writers = 0, id, i;
+       uint32_t n_writers = 0, id = 0, i;

        for (i = 0; i < n_pipelines; i++) {
                struct app_pipeline_params *p = &app->pipeline_params[i];
@@ -923,11 +1009,11 @@ app_tm_get_writer(struct app_params *app,
        struct app_pktq_tm_params *tm,
        uint32_t *pktq_out_id)
 {
-       struct app_pipeline_params *writer;
+       struct app_pipeline_params *writer = NULL;
        uint32_t pos = tm - app->tm_params;
        uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
                RTE_DIM(app->pipeline_params));
-       uint32_t n_writers = 0, id, i;
+       uint32_t n_writers = 0, id = 0, i;

        for (i = 0; i < n_pipelines; i++) {
                struct app_pipeline_params *p = &app->pipeline_params[i];
@@ -939,10 +1025,73 @@ app_tm_get_writer(struct app_params *app,
                        struct app_pktq_out_params *pktq = &p->pktq_out[j];

                        if ((pktq->type == APP_PKTQ_OUT_TM) &&
+                               (pktq->id == pos)) {
+                               n_writers++;
+                               writer = p;
+                               id = j;
+                       }
+               }
+       }
+
+       if (n_writers != 1)
+               return NULL;
+
+       *pktq_out_id = id;
+       return writer;
+}
+
+static inline uint32_t
+app_kni_get_writers(struct app_params *app, struct app_pktq_kni_params *kni)
+{
+       uint32_t pos = kni - app->kni_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_writers = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+                       RTE_DIM(p->pktq_out));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_out; j++) {
+                       struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+                       if ((pktq->type == APP_PKTQ_OUT_KNI) &&
                                (pktq->id == pos))
                                n_writers++;
+               }
+       }
+
+       return n_writers;
+}
+
+static inline struct app_pipeline_params *
+app_kni_get_writer(struct app_params *app,
+                                 struct app_pktq_kni_params *kni,
+                                 uint32_t *pktq_out_id)
+{
+       struct app_pipeline_params *writer = NULL;
+       uint32_t pos = kni - app->kni_params;
+       uint32_t n_pipelines = RTE_MIN(app->n_pipelines,
+               RTE_DIM(app->pipeline_params));
+       uint32_t n_writers = 0, id = 0, i;
+
+       for (i = 0; i < n_pipelines; i++) {
+               struct app_pipeline_params *p = &app->pipeline_params[i];
+               uint32_t n_pktq_out = RTE_MIN(p->n_pktq_out,
+                       RTE_DIM(p->pktq_out));
+               uint32_t j;
+
+               for (j = 0; j < n_pktq_out; j++) {
+                       struct app_pktq_out_params *pktq = &p->pktq_out[j];
+
+                       if ((pktq->type == APP_PKTQ_OUT_KNI) &&
+                               (pktq->id == pos)) {
+                               n_writers++;
                                writer = p;
                                id = j;
+                       }
                }
        }

@@ -1051,6 +1200,22 @@ app_get_link_for_tm(struct app_params *app, struct 
app_pktq_tm_params *p_tm)
        return &app->link_params[link_param_idx];
 }

+static inline struct app_link_params *
+app_get_link_for_kni(struct app_params *app, struct app_pktq_kni_params *p_kni)
+{
+       char link_name[APP_PARAM_NAME_SIZE];
+       uint32_t link_id;
+       ssize_t link_param_idx;
+
+       sscanf(p_kni->name, "KNI%" PRIu32, &link_id);
+       sprintf(link_name, "LINK%" PRIu32, link_id);
+       link_param_idx = APP_PARAM_FIND(app->link_params, link_name);
+       APP_CHECK((link_param_idx >= 0),
+                         "Cannot find %s for %s", link_name, p_kni->name);
+
+       return &app->link_params[link_param_idx];
+}
+
 void app_pipeline_params_get(struct app_params *app,
        struct app_pipeline_params *p_in,
        struct pipeline_params *p_out);
diff --git a/examples/ip_pipeline/config/kni.cfg 
b/examples/ip_pipeline/config/kni.cfg
new file mode 100644
index 0000000..c339080
--- /dev/null
+++ b/examples/ip_pipeline/config/kni.cfg
@@ -0,0 +1,67 @@
+;   BSD LICENSE
+;
+;   Copyright(c) 2016 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.
+
+;             ______________          ______________________
+;            |              |  KNI0  |                      |
+; RXQ0.0 --->|              |------->|--+                   |
+;            |              |  KNI1  |  | br0               |
+; TXQ0.0 <---|              |<-------|<-+                   |
+;            | Pass-through |        |     Linux Kernel     |
+;            |     (P1)     |        |     Network Stack    |
+;            |              |  KNI0  |                      |
+; RXQ0.0 --->|              |------->|--+                   |
+;            |              |  KNI1  |  | br0               |
+; TXQ0.0 <---|              |<-------|<-+                   |
+;            |______________|        |______________________|
+;
+; Insert Linux kernel KNI module:
+;    [Linux]$ insmod rte_kni.ko
+;
+; Configure Linux kernel bridge between KNI0 and KNI1 interfaces:
+;    [Linux]$ ifconfig KNI0 up
+;    [Linux]$ ifconfig KNI1 up
+;    [Linux]$ brctl addbr "br0"
+;    [Linux]$ brctl addif br0 KNI0
+;    [Linux]$ brctl addif br0 KNI1
+;    [Linux]$ ifconfig br0 up
+
+[EAL]
+log_level = 0
+
+[PIPELINE0]
+type = MASTER
+core = 0
+
+[PIPELINE1]
+type = PASS-THROUGH
+core = 1
+pktq_in = RXQ0.0 KNI1 RXQ1.0 KNI0
+pktq_out = KNI0 TXQ1.0 KNI1 TXQ0.0
diff --git a/examples/ip_pipeline/config_check.c 
b/examples/ip_pipeline/config_check.c
index 18f57be..7e90342 100644
--- a/examples/ip_pipeline/config_check.c
+++ b/examples/ip_pipeline/config_check.c
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -444,6 +444,29 @@ check_pipelines(struct app_params *app)
        }
 }

+static void
+check_knis(struct app_params *app) {
+       uint32_t i;
+
+       for (i = 0; i < app->n_pktq_kni; i++) {
+               struct app_pktq_kni_params *p = &app->kni_params[i];
+               uint32_t n_readers = app_kni_get_readers(app, p);
+               uint32_t n_writers = app_kni_get_writers(app, p);
+
+               APP_CHECK((n_readers != 0),
+                       "%s has no reader\n", p->name);
+
+               APP_CHECK((n_readers == 1),
+                       "%s has more than one reader\n", p->name);
+
+               APP_CHECK((n_writers != 0),
+                       "%s has no writer\n", p->name);
+
+               APP_CHECK((n_writers == 1),
+                       "%s has more than one writer\n", p->name);
+       }
+}
+
 int
 app_config_check(struct app_params *app)
 {
@@ -453,6 +476,7 @@ app_config_check(struct app_params *app)
        check_txqs(app);
        check_swqs(app);
        check_tms(app);
+       check_knis(app);
        check_sources(app);
        check_sinks(app);
        check_msgqs(app);
diff --git a/examples/ip_pipeline/config_parse.c 
b/examples/ip_pipeline/config_parse.c
index 504018e..c55be31 100644
--- a/examples/ip_pipeline/config_parse.c
+++ b/examples/ip_pipeline/config_parse.c
@@ -189,6 +189,18 @@ struct app_pktq_tm_params default_tm_params = {
        .burst_write = 32,
 };

+struct app_pktq_kni_params default_kni_params = {
+       .parsed = 0,
+       .socket_id = 0,
+       .core_id = 0,
+       .hyper_th_id = 0,
+       .force_bind = 0,
+
+       .mempool_id = 0,
+       .burst_read = 32,
+       .burst_write = 32,
+};
+
 struct app_pktq_source_params default_source_params = {
        .parsed = 0,
        .mempool_id = 0,
@@ -300,6 +312,18 @@ app_print_usage(char *prgname)
        link_param_pos;                                                 \
 })

+#define APP_PARAM_ADD_LINK_FOR_KNI(app, kni_name)                      \
+({                                                                     \
+       char link_name[APP_PARAM_NAME_SIZE];                            \
+       ssize_t link_param_pos;                                         \
+       uint32_t link_id;                                               \
+                                                                       \
+       sscanf((kni_name), "KNI%" SCNu32, &link_id);            \
+       sprintf(link_name, "LINK%" PRIu32, link_id);                    \
+       link_param_pos = APP_PARAM_ADD((app)->link_params, link_name);  \
+       link_param_pos;                                                 \
+})
+
 #define PARSE_CHECK_DUPLICATE_SECTION(obj)                             \
 do {                                                                   \
        APP_CHECK(((obj)->parsed == 0),                                 \
@@ -826,6 +850,10 @@ parse_pipeline_pktq_in(struct app_params *app,
                        type = APP_PKTQ_IN_TM;
                        id = APP_PARAM_ADD(app->tm_params, name);
                        APP_PARAM_ADD_LINK_FOR_TM(app, name);
+               } else if (validate_name(name, "KNI", 1) == 0) {
+                       type = APP_PKTQ_IN_KNI;
+                       id = APP_PARAM_ADD(app->kni_params, name);
+                       APP_PARAM_ADD_LINK_FOR_KNI(app, name);
                } else if (validate_name(name, "SOURCE", 1) == 0) {
                        type = APP_PKTQ_IN_SOURCE;
                        id = APP_PARAM_ADD(app->source_params, name);
@@ -871,6 +899,10 @@ parse_pipeline_pktq_out(struct app_params *app,
                        type = APP_PKTQ_OUT_TM;
                        id = APP_PARAM_ADD(app->tm_params, name);
                        APP_PARAM_ADD_LINK_FOR_TM(app, name);
+               } else if (validate_name(name, "KNI", 1) == 0) {
+                       type = APP_PKTQ_OUT_KNI;
+                       id = APP_PARAM_ADD(app->kni_params, name);
+                       APP_PARAM_ADD_LINK_FOR_KNI(app, name);
                } else if (validate_name(name, "SINK", 1) == 0) {
                        type = APP_PKTQ_OUT_SINK;
                        id = APP_PARAM_ADD(app->sink_params, name);
@@ -1816,7 +1848,7 @@ parse_tm(struct app_params *app,
        param = &app->tm_params[param_idx];
        PARSE_CHECK_DUPLICATE_SECTION(param);

-       APP_PARAM_ADD_LINK_FOR_TXQ(app, section_name);
+       APP_PARAM_ADD_LINK_FOR_TM(app, section_name);

        for (i = 0; i < n_entries; i++) {
                struct rte_cfgfile_entry *ent = &entries[i];
@@ -1853,6 +1885,85 @@ parse_tm(struct app_params *app,
 }

 static void
+parse_kni(struct app_params *app,
+                 const char *section_name,
+                 struct rte_cfgfile *cfg)
+{
+       struct app_pktq_kni_params *param;
+       struct rte_cfgfile_entry *entries;
+       int n_entries, i;
+       ssize_t param_idx;
+
+       n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
+       PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
+
+       entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
+       PARSE_ERROR_MALLOC(entries != NULL);
+
+       rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
+
+       param_idx = APP_PARAM_ADD(app->kni_params, section_name);
+       param = &app->kni_params[param_idx];
+       PARSE_CHECK_DUPLICATE_SECTION(param);
+
+       APP_PARAM_ADD_LINK_FOR_KNI(app, section_name);
+
+
+       for (i = 0; i < n_entries; i++) {
+               struct rte_cfgfile_entry *ent = &entries[i];
+
+               if (strcmp(ent->name, "core") == 0) {
+                       int status = parse_pipeline_core(
+                                       &param->socket_id,
+                                       &param->core_id,
+                                       &param->hyper_th_id,
+                                       ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                                               ent->name);
+                       param->force_bind = 1;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "mempool") == 0) {
+                       int status = validate_name(ent->value,
+                                                                          
"MEMPOOL", 1);
+                       ssize_t idx;
+
+                       PARSE_ERROR((status == 0), section_name,
+                                               ent->name);
+
+                       idx = APP_PARAM_ADD(app->mempool_params, ent->value);
+                       param->mempool_id = idx;
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst_read") == 0) {
+                       int status = parser_read_uint32(&param->burst_read,
+                                                                               
        ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                                               ent->name);
+                       continue;
+               }
+
+               if (strcmp(ent->name, "burst_write") == 0) {
+                       int status = parser_read_uint32(&param->burst_write,
+                                                                               
        ent->value);
+
+                       PARSE_ERROR((status == 0), section_name,
+                                               ent->name);
+                       continue;
+               }
+
+               /* unrecognized */
+               PARSE_ERROR_INVALID(0, section_name, ent->name);
+       }
+
+       free(entries);
+}
+
+static void
 parse_source(struct app_params *app,
        const char *section_name,
        struct rte_cfgfile *cfg)
@@ -2147,6 +2258,7 @@ static const struct config_section cfg_file_scheme[] = {
        {"TXQ", 2, parse_txq},
        {"SWQ", 1, parse_swq},
        {"TM", 1, parse_tm},
+       {"KNI", 1, parse_kni},
        {"SOURCE", 1, parse_source},
        {"SINK", 1, parse_sink},
        {"MSGQ-REQ-PIPELINE", 1, parse_msgq_req_pipeline},
@@ -2285,6 +2397,7 @@ app_config_parse(struct app_params *app, const char 
*file_name)
        APP_PARAM_COUNT(app->hwq_out_params, app->n_pktq_hwq_out);
        APP_PARAM_COUNT(app->swq_params, app->n_pktq_swq);
        APP_PARAM_COUNT(app->tm_params, app->n_pktq_tm);
+       APP_PARAM_COUNT(app->kni_params, app->n_pktq_kni);
        APP_PARAM_COUNT(app->source_params, app->n_pktq_source);
        APP_PARAM_COUNT(app->sink_params, app->n_pktq_sink);
        APP_PARAM_COUNT(app->msgq_params, app->n_msgq);
@@ -2647,6 +2760,45 @@ save_tm_params(struct app_params *app, FILE *f)
 }

 static void
+save_kni_params(struct app_params *app, FILE *f)
+{
+       struct app_pktq_kni_params *p;
+       size_t i, count;
+
+       count = RTE_DIM(app->kni_params);
+       for (i = 0; i < count; i++) {
+               p = &app->kni_params[i];
+               if (!APP_PARAM_VALID(p))
+                       continue;
+
+               /* section name */
+               fprintf(f, "[%s]\n", p->name);
+
+               /* core */
+               if (p->force_bind) {
+                       fprintf(f, "; force_bind = 1\n");
+                       fprintf(f, "core = s%" PRIu32 "c%" PRIu32 "%s\n",
+                                       p->socket_id,
+                                       p->core_id,
+                                       (p->hyper_th_id) ? "h" : "");
+               } else
+                       fprintf(f, "; force_bind = 0\n");
+
+               /* mempool */
+               fprintf(f, "%s = %s\n", "mempool",
+                               app->mempool_params[p->mempool_id].name);
+
+               /* burst_read */
+               fprintf(f, "%s = %" PRIu32 "\n", "burst_read", p->burst_read);
+
+               /* burst_write */
+               fprintf(f, "%s = %" PRIu32 "\n", "burst_write", p->burst_write);
+
+               fputc('\n', f);
+       }
+}
+
+static void
 save_source_params(struct app_params *app, FILE *f)
 {
        struct app_pktq_source_params *p;
@@ -2753,6 +2905,9 @@ save_pipeline_params(struct app_params *app, FILE *f)
                                case APP_PKTQ_IN_TM:
                                        name = app->tm_params[pp->id].name;
                                        break;
+                               case APP_PKTQ_IN_KNI:
+                                       name = app->kni_params[pp->id].name;
+                                       break;
                                case APP_PKTQ_IN_SOURCE:
                                        name = app->source_params[pp->id].name;
                                        break;
@@ -2787,6 +2942,9 @@ save_pipeline_params(struct app_params *app, FILE *f)
                                case APP_PKTQ_OUT_TM:
                                        name = app->tm_params[pp->id].name;
                                        break;
+                               case APP_PKTQ_OUT_KNI:
+                                       name = app->kni_params[pp->id].name;
+                                       break;
                                case APP_PKTQ_OUT_SINK:
                                        name = app->sink_params[pp->id].name;
                                        break;
@@ -2872,6 +3030,7 @@ app_config_save(struct app_params *app, const char 
*file_name)
        save_txq_params(app, file);
        save_swq_params(app, file);
        save_tm_params(app, file);
+       save_kni_params(app, file);
        save_source_params(app, file);
        save_sink_params(app, file);
        save_msgq_params(app, file);
@@ -2921,6 +3080,11 @@ app_config_init(struct app_params *app)
                        &default_tm_params,
                        sizeof(default_tm_params));

+       for (i = 0; i < RTE_DIM(app->kni_params); i++)
+               memcpy(&app->kni_params[i],
+                          &default_kni_params,
+                          sizeof(default_kni_params));
+
        for (i = 0; i < RTE_DIM(app->source_params); i++)
                memcpy(&app->source_params[i],
                        &default_source_params,
diff --git a/examples/ip_pipeline/init.c b/examples/ip_pipeline/init.c
index 7120bab..d522de4 100644
--- a/examples/ip_pipeline/init.c
+++ b/examples/ip_pipeline/init.c
@@ -1281,10 +1281,21 @@ void app_pipeline_params_get(struct app_params *app,
                        break;
                }
                case APP_PKTQ_IN_TM:
+               {
                        out->type = PIPELINE_PORT_IN_SCHED_READER;
                        out->params.sched.sched = app->tm[in->id];
                        out->burst_size = app->tm_params[in->id].burst_read;
                        break;
+               }
+#ifdef RTE_LIBRTE_KNI
+               case APP_PKTQ_IN_KNI:
+               {
+                       out->type = PIPELINE_PORT_IN_KNI_READER;
+                       out->params.kni.kni = app->kni[in->id];
+                       out->burst_size = app->kni_params[in->id].burst_read;
+                       break;
+               }
+#endif /* RTE_LIBRTE_KNI */
                case APP_PKTQ_IN_SOURCE:
                {
                        uint32_t mempool_id =
@@ -1409,7 +1420,8 @@ void app_pipeline_params_get(struct app_params *app,
                        }
                        break;
                }
-               case APP_PKTQ_OUT_TM: {
+               case APP_PKTQ_OUT_TM:
+               {
                        struct rte_port_sched_writer_params *params =
                                &out->params.sched;

@@ -1419,6 +1431,16 @@ void app_pipeline_params_get(struct app_params *app,
                                app->tm_params[in->id].burst_write;
                        break;
                }
+#ifdef RTE_LIBRTE_KNI
+               case APP_PKTQ_OUT_KNI:
+               {
+                       out->type = PIPELINE_PORT_OUT_KNI_WRITER;
+                       out->params.kni.kni = app->kni[in->id];
+                       out->params.kni.tx_burst_sz =
+                               app->kni_params[in->id].burst_write;
+                       break;
+               }
+#endif /* RTE_LIBRTE_KNI */
                case APP_PKTQ_OUT_SINK:
                {
                        out->type = PIPELINE_PORT_OUT_SINK;
@@ -1452,6 +1474,113 @@ void app_pipeline_params_get(struct app_params *app,
        }
 }

+#ifdef RTE_LIBRTE_KNI
+static int
+kni_config_network_interface(uint8_t port_id, uint8_t if_up) {
+       int ret = 0;
+
+       if (port_id >= rte_eth_dev_count())
+               return -EINVAL;
+
+       if (if_up) {
+               rte_eth_dev_stop(port_id);
+               ret = rte_eth_dev_start(port_id);
+       } else
+               rte_eth_dev_stop(port_id);
+
+       return ret;
+}
+
+static int
+kni_change_mtu(uint8_t port_id, unsigned new_mtu) {
+       int ret;
+
+       if (port_id >= rte_eth_dev_count())
+               return -EINVAL;
+
+       if (new_mtu > ETHER_MAX_LEN)
+               return -EINVAL;
+
+       /* Stop specific port */
+       rte_eth_dev_stop(port_id);
+
+       /* Set new MTU */
+       ret = rte_eth_dev_set_mtu(port_id, new_mtu);
+       if (ret < 0)
+               return ret;
+
+       /* Restart specific port */
+       ret = rte_eth_dev_start(port_id);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+#endif /* RTE_LIBRTE_KNI */
+
+static void
+app_init_kni(struct app_params *app) {
+       if (app->n_pktq_kni == 0)
+               return;
+#ifndef RTE_LIBRTE_KNI
+       else
+               rte_panic("Can not init KNI without librte_kni support.\n");
+#else
+       rte_kni_init(app->n_pktq_kni);
+
+       for (uint32_t i = 0; i < app->n_pktq_kni; i++) {
+               struct app_pktq_kni_params *p_kni = &app->kni_params[i];
+               struct app_link_params *p_link;
+               struct rte_eth_dev_info dev_info;
+               struct app_mempool_params *mempool_params;
+               struct rte_mempool *mempool;
+               struct rte_kni_conf conf;
+               struct rte_kni_ops ops;
+
+               /* LINK */
+               p_link = app_get_link_for_kni(app, p_kni);
+               memset(&dev_info, 0, sizeof(dev_info));
+               rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
+
+               /* MEMPOOL */
+               mempool_params = &app->mempool_params[p_kni->mempool_id];
+               mempool = app->mempool[p_kni->mempool_id];
+
+               /* KNI */
+               memset(&conf, 0, sizeof(conf));
+               snprintf(conf.name, RTE_KNI_NAMESIZE, "%s", p_kni->name);
+               conf.force_bind = p_kni->force_bind;
+               if (conf.force_bind) {
+                       int lcore_id;
+
+                       lcore_id = cpu_core_map_get_lcore_id(app->core_map,
+                               p_kni->socket_id,
+                               p_kni->core_id,
+                               p_kni->hyper_th_id);
+
+                       if (lcore_id < 0)
+                               rte_panic("%s invalid CPU core\n", p_kni->name);
+
+                       conf.core_id = (uint32_t) lcore_id;
+               }
+               conf.group_id = p_link->pmd_id;
+               conf.mbuf_size = mempool_params->buffer_size;
+               conf.addr = dev_info.pci_dev->addr;
+               conf.id = dev_info.pci_dev->id;
+
+               memset(&ops, 0, sizeof(ops));
+               ops.port_id = (uint8_t) p_link->pmd_id;
+               ops.change_mtu = kni_change_mtu;
+               ops.config_network_if = kni_config_network_interface;
+
+               APP_LOG(app, HIGH, "Initializing %s ...", p_kni->name);
+               app->kni[i] = rte_kni_alloc(mempool, &conf, &ops);
+               if (!app->kni[i])
+                       rte_panic("%s init error\n", p_kni->name);
+       }
+#endif /* RTE_LIBRTE_KNI */
+}
+
 static void
 app_init_pipelines(struct app_params *app)
 {
@@ -1607,6 +1736,7 @@ int app_init(struct app_params *app)
        app_init_link(app);
        app_init_swq(app);
        app_init_tm(app);
+       app_init_kni(app);
        app_init_msgq(app);

        app_pipeline_common_cmd_push(app);
diff --git a/examples/ip_pipeline/pipeline/pipeline_common_fe.c 
b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
index 70c57e4..63723cd 100644
--- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c
+++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c
@@ -130,6 +130,35 @@ app_pipeline_track_pktq_out_to_link(struct app_params *app,
                        break;
                }

+#ifdef RTE_LIBRTE_KNI
+               case APP_PKTQ_OUT_KNI:
+               {
+                       struct pipeline_params pp;
+                       struct pipeline_type *ptype;
+                       struct app_pktq_kni_params *kni;
+                       uint32_t pktq_in_id;
+                       int status;
+
+                       kni = &app->kni_params[pktq_out->id];
+                       p = app_kni_get_reader(app, kni, &pktq_in_id);
+                       if (p == NULL)
+                               return NULL;
+
+                       ptype = app_pipeline_type_find(app, p->type);
+                       if ((ptype == NULL) || (ptype->fe_ops->f_track == NULL))
+                               return NULL;
+
+                       app_pipeline_params_get(app, p, &pp);
+                       status = ptype->fe_ops->f_track(&pp,
+                               pktq_in_id,
+                               &pktq_out_id);
+                       if (status)
+                               return NULL;
+
+                       break;
+               }
+#endif
+
                case APP_PKTQ_OUT_SINK:
                default:
                        return NULL;
diff --git a/examples/ip_pipeline/pipeline/pipeline_master_be.c 
b/examples/ip_pipeline/pipeline/pipeline_master_be.c
index 79869a4..32d4635 100644
--- a/examples/ip_pipeline/pipeline/pipeline_master_be.c
+++ b/examples/ip_pipeline/pipeline/pipeline_master_be.c
@@ -144,6 +144,12 @@ pipeline_run(void *pipeline)
                rte_exit(0, "Bye!\n");
        }

+#ifdef RTE_LIBRTE_KNI
+       /* Handle KNI requests from Linux kernel */
+       for (uint32_t i = 0; i < app->n_pktq_kni; i++)
+               rte_kni_handle_request(app->kni[i]);
+#endif /* RTE_LIBRTE_KNI */
+
        return 0;
 }

diff --git a/examples/ip_pipeline/pipeline_be.h 
b/examples/ip_pipeline/pipeline_be.h
index 5501ab7..0ee208c 100644
--- a/examples/ip_pipeline/pipeline_be.h
+++ b/examples/ip_pipeline/pipeline_be.h
@@ -40,6 +40,9 @@
 #include <rte_port_ras.h>
 #include <rte_port_sched.h>
 #include <rte_port_source_sink.h>
+#ifdef RTE_LIBRTE_KNI
+#include <rte_port_kni.h>
+#endif
 #include <rte_pipeline.h>

 enum pipeline_port_in_type {
@@ -49,6 +52,7 @@ enum pipeline_port_in_type {
        PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
        PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
        PIPELINE_PORT_IN_SCHED_READER,
+       PIPELINE_PORT_IN_KNI_READER,
        PIPELINE_PORT_IN_SOURCE,
 };

@@ -61,6 +65,9 @@ struct pipeline_port_in_params {
                struct rte_port_ring_reader_ipv4_frag_params ring_ipv4_frag;
                struct rte_port_ring_reader_ipv6_frag_params ring_ipv6_frag;
                struct rte_port_sched_reader_params sched;
+#ifdef RTE_LIBRTE_KNI
+               struct rte_port_kni_reader_params kni;
+#endif
                struct rte_port_source_params source;
        } params;
        uint32_t burst_size;
@@ -82,6 +89,10 @@ pipeline_port_in_params_convert(struct 
pipeline_port_in_params  *p)
                return (void *) &p->params.ring_ipv6_frag;
        case PIPELINE_PORT_IN_SCHED_READER:
                return (void *) &p->params.sched;
+#ifdef RTE_LIBRTE_KNI
+       case PIPELINE_PORT_IN_KNI_READER:
+               return (void *) &p->params.kni;
+#endif
        case PIPELINE_PORT_IN_SOURCE:
                return (void *) &p->params.source;
        default:
@@ -105,6 +116,10 @@ pipeline_port_in_params_get_ops(struct 
pipeline_port_in_params  *p)
                return &rte_port_ring_reader_ipv6_frag_ops;
        case PIPELINE_PORT_IN_SCHED_READER:
                return &rte_port_sched_reader_ops;
+#ifdef RTE_LIBRTE_KNI
+       case PIPELINE_PORT_IN_KNI_READER:
+               return &rte_port_kni_reader_ops;
+#endif
        case PIPELINE_PORT_IN_SOURCE:
                return &rte_port_source_ops;
        default:
@@ -122,6 +137,7 @@ enum pipeline_port_out_type {
        PIPELINE_PORT_OUT_RING_WRITER_IPV4_RAS,
        PIPELINE_PORT_OUT_RING_WRITER_IPV6_RAS,
        PIPELINE_PORT_OUT_SCHED_WRITER,
+       PIPELINE_PORT_OUT_KNI_WRITER,
        PIPELINE_PORT_OUT_SINK,
 };

@@ -137,6 +153,9 @@ struct pipeline_port_out_params {
                struct rte_port_ring_writer_ipv4_ras_params ring_ipv4_ras;
                struct rte_port_ring_writer_ipv6_ras_params ring_ipv6_ras;
                struct rte_port_sched_writer_params sched;
+#ifdef RTE_LIBRTE_KNI
+               struct rte_port_kni_writer_params kni;
+#endif
                struct rte_port_sink_params sink;
        } params;
 };
@@ -163,6 +182,10 @@ pipeline_port_out_params_convert(struct 
pipeline_port_out_params  *p)
                return (void *) &p->params.ring_ipv6_ras;
        case PIPELINE_PORT_OUT_SCHED_WRITER:
                return (void *) &p->params.sched;
+#ifdef RTE_LIBRTE_KNI
+       case PIPELINE_PORT_OUT_KNI_WRITER:
+               return (void *) &p->params.kni;
+#endif
        case PIPELINE_PORT_OUT_SINK:
                return (void *) &p->params.sink;
        default:
@@ -192,6 +215,10 @@ pipeline_port_out_params_get_ops(struct 
pipeline_port_out_params  *p)
                return &rte_port_ring_writer_ipv6_ras_ops;
        case PIPELINE_PORT_OUT_SCHED_WRITER:
                return &rte_port_sched_writer_ops;
+#ifdef RTE_LIBRTE_KNI
+       case PIPELINE_PORT_OUT_KNI_WRITER:
+               return &rte_port_kni_writer_ops;
+#endif
        case PIPELINE_PORT_OUT_SINK:
                return &rte_port_sink_ops;
        default:
diff --git a/lib/librte_port/Makefile b/lib/librte_port/Makefile
index dc6a601..0fc929b 100644
--- a/lib/librte_port/Makefile
+++ b/lib/librte_port/Makefile
@@ -56,6 +56,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_frag.c
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_ras.c
 endif
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_sched.c
+ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
+SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_kni.c
+endif
 SRCS-$(CONFIG_RTE_LIBRTE_PORT) += rte_port_source_sink.c

 # install includes
@@ -67,6 +70,9 @@ SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_frag.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_ras.h
 endif
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_sched.h
+ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
+SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_kni.h
+endif
 SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include += rte_port_source_sink.h

 # this lib depends upon:
@@ -76,5 +82,6 @@ DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) += lib/librte_mempool
 DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) += lib/librte_ether
 DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) += lib/librte_ip_frag
 DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) += lib/librte_sched
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) += lib/librte_kni

 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_port/rte_port_kni.c b/lib/librte_port/rte_port_kni.c
new file mode 100644
index 0000000..4cbc345
--- /dev/null
+++ b/lib/librte_port/rte_port_kni.c
@@ -0,0 +1,325 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Ethan Zhuang <zhuangwj at gmail.com>.
+ *   Copyright(c) 2016 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 <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_kni.h>
+
+#include "rte_port_kni.h"
+
+/*
+ * Port KNI Reader
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_KNI_READER_STATS_PKTS_IN_ADD(port, val) \
+       port->stats.n_pkts_in += val
+#define RTE_PORT_KNI_READER_STATS_PKTS_DROP_ADD(port, val) \
+       port->stats.n_pkts_drop += val
+
+#else
+
+#define RTE_PORT_KNI_READER_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_KNI_READER_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_kni_reader {
+       struct rte_port_in_stats stats;
+
+       struct rte_kni *kni;
+};
+
+static void *
+rte_port_kni_reader_create(void *params, int socket_id)
+{
+       struct rte_port_kni_reader_params *conf =
+                       (struct rte_port_kni_reader_params *) params;
+       struct rte_port_kni_reader *port;
+
+       /* Check input parameters */
+       if (conf == NULL) {
+               RTE_LOG(ERR, PORT, "%s: params is NULL\n", __func__);
+               return NULL;
+       }
+
+       /* Memory allocation */
+       port = rte_zmalloc_socket("PORT", sizeof(*port),
+               RTE_CACHE_LINE_SIZE, socket_id);
+       if (port == NULL) {
+               RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+               return NULL;
+       }
+
+       /* Initialization */
+       port->kni = conf->kni;
+
+       return port;
+}
+
+static int
+rte_port_kni_reader_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
+{
+       struct rte_port_kni_reader *p =
+                       (struct rte_port_kni_reader *) port;
+       uint16_t rx_pkt_cnt;
+
+       rx_pkt_cnt = rte_kni_rx_burst(p->kni, pkts, n_pkts);
+       RTE_PORT_KNI_READER_STATS_PKTS_IN_ADD(p, rx_pkt_cnt);
+       return rx_pkt_cnt;
+}
+
+static int
+rte_port_kni_reader_free(void *port)
+{
+       if (port == NULL) {
+               RTE_LOG(ERR, PORT, "%s: port is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       rte_free(port);
+
+       return 0;
+}
+
+static int rte_port_kni_reader_stats_read(void *port,
+       struct rte_port_in_stats *stats, int clear)
+{
+       struct rte_port_kni_reader *p =
+                       (struct rte_port_kni_reader *) port;
+
+       if (stats != NULL)
+               memcpy(stats, &p->stats, sizeof(p->stats));
+
+       if (clear)
+               memset(&p->stats, 0, sizeof(p->stats));
+
+       return 0;
+}
+
+/*
+ * Port KNI Writer
+ */
+#ifdef RTE_PORT_STATS_COLLECT
+
+#define RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(port, val) \
+       port->stats.n_pkts_in += val
+#define RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(port, val) \
+       port->stats.n_pkts_drop += val
+
+#else
+
+#define RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(port, val)
+#define RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(port, val)
+
+#endif
+
+struct rte_port_kni_writer {
+       struct rte_port_out_stats stats;
+
+       struct rte_mbuf *tx_buf[2 * RTE_PORT_IN_BURST_SIZE_MAX];
+       uint32_t tx_burst_sz;
+       uint32_t tx_buf_count;
+       uint64_t bsz_mask;
+       struct rte_kni *kni;
+};
+
+static void *
+rte_port_kni_writer_create(void *params, int socket_id)
+{
+       struct rte_port_kni_writer_params *conf =
+                       (struct rte_port_kni_writer_params *) params;
+       struct rte_port_kni_writer *port;
+
+       /* Check input parameters */
+       if ((conf == NULL) ||
+               (conf->tx_burst_sz == 0) ||
+               (conf->tx_burst_sz > RTE_PORT_IN_BURST_SIZE_MAX) ||
+               (!rte_is_power_of_2(conf->tx_burst_sz))) {
+               RTE_LOG(ERR, PORT, "%s: Invalid input parameters\n", __func__);
+               return NULL;
+       }
+
+       /* Memory allocation */
+       port = rte_zmalloc_socket("PORT", sizeof(*port),
+               RTE_CACHE_LINE_SIZE, socket_id);
+       if (port == NULL) {
+               RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
+               return NULL;
+       }
+
+       /* Initialization */
+       port->kni = conf->kni;
+       port->tx_burst_sz = conf->tx_burst_sz;
+       port->tx_buf_count = 0;
+       port->bsz_mask = 1LLU << (conf->tx_burst_sz - 1);
+
+       return port;
+}
+
+static inline void
+send_burst(struct rte_port_kni_writer *p)
+{
+       uint32_t nb_tx;
+
+       nb_tx = rte_kni_tx_burst(p->kni, p->tx_buf, p->tx_buf_count);
+
+       RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(p, p->tx_buf_count - nb_tx);
+       for (; nb_tx < p->tx_buf_count; nb_tx++)
+               rte_pktmbuf_free(p->tx_buf[nb_tx]);
+
+       p->tx_buf_count = 0;
+}
+
+static int
+rte_port_kni_writer_tx(void *port, struct rte_mbuf *pkt)
+{
+       struct rte_port_kni_writer *p =
+                       (struct rte_port_kni_writer *) port;
+
+       p->tx_buf[p->tx_buf_count++] = pkt;
+       RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, 1);
+       if (p->tx_buf_count >= p->tx_burst_sz)
+               send_burst(p);
+
+       return 0;
+}
+
+static int
+rte_port_kni_writer_tx_bulk(void *port,
+       struct rte_mbuf **pkts,
+       uint64_t pkts_mask)
+{
+       struct rte_port_kni_writer *p =
+                       (struct rte_port_kni_writer *) port;
+       uint64_t bsz_mask = p->bsz_mask;
+       uint32_t tx_buf_count = p->tx_buf_count;
+       uint64_t expr = (pkts_mask & (pkts_mask + 1)) |
+                                       ((pkts_mask & bsz_mask) ^ bsz_mask);
+
+       if (expr == 0) {
+               uint64_t n_pkts = __builtin_popcountll(pkts_mask);
+               uint32_t n_pkts_ok;
+
+               if (tx_buf_count)
+                       send_burst(p);
+
+               RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, n_pkts);
+               n_pkts_ok = rte_kni_tx_burst(p->kni, pkts, n_pkts);
+
+               RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(p, n_pkts - n_pkts_ok);
+               for (; n_pkts_ok < n_pkts; n_pkts_ok++) {
+                       struct rte_mbuf *pkt = pkts[n_pkts_ok];
+
+                       rte_pktmbuf_free(pkt);
+               }
+       } else {
+               for (; pkts_mask;) {
+                       uint32_t pkt_index = __builtin_ctzll(pkts_mask);
+                       uint64_t pkt_mask = 1LLU << pkt_index;
+                       struct rte_mbuf *pkt = pkts[pkt_index];
+
+                       p->tx_buf[tx_buf_count++] = pkt;
+                       RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, 1);
+                       pkts_mask &= ~pkt_mask;
+               }
+
+               p->tx_buf_count = tx_buf_count;
+               if (tx_buf_count >= p->tx_burst_sz)
+                       send_burst(p);
+       }
+
+       return 0;
+}
+
+static int
+rte_port_kni_writer_flush(void *port)
+{
+       struct rte_port_kni_writer *p =
+                       (struct rte_port_kni_writer *) port;
+
+       if (p->tx_buf_count > 0)
+               send_burst(p);
+
+       return 0;
+}
+
+static int
+rte_port_kni_writer_free(void *port)
+{
+       if (port == NULL) {
+               RTE_LOG(ERR, PORT, "%s: Port is NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       rte_port_kni_writer_flush(port);
+       rte_free(port);
+
+       return 0;
+}
+
+static int rte_port_kni_writer_stats_read(void *port,
+       struct rte_port_out_stats *stats, int clear)
+{
+       struct rte_port_kni_writer *p =
+                       (struct rte_port_kni_writer *) port;
+
+       if (stats != NULL)
+               memcpy(stats, &p->stats, sizeof(p->stats));
+
+       if (clear)
+               memset(&p->stats, 0, sizeof(p->stats));
+
+       return 0;
+}
+
+/*
+ * Summary of port operations
+ */
+struct rte_port_in_ops rte_port_kni_reader_ops = {
+       .f_create = rte_port_kni_reader_create,
+       .f_free = rte_port_kni_reader_free,
+       .f_rx = rte_port_kni_reader_rx,
+       .f_stats = rte_port_kni_reader_stats_read,
+};
+
+struct rte_port_out_ops rte_port_kni_writer_ops = {
+       .f_create = rte_port_kni_writer_create,
+       .f_free = rte_port_kni_writer_free,
+       .f_tx = rte_port_kni_writer_tx,
+       .f_tx_bulk = rte_port_kni_writer_tx_bulk,
+       .f_flush = rte_port_kni_writer_flush,
+       .f_stats = rte_port_kni_writer_stats_read,
+};
diff --git a/lib/librte_port/rte_port_kni.h b/lib/librte_port/rte_port_kni.h
new file mode 100644
index 0000000..d4de8c4
--- /dev/null
+++ b/lib/librte_port/rte_port_kni.h
@@ -0,0 +1,82 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 Ethan Zhuang <zhuangwj at gmail.com>.
+ *   Copyright(c) 2016 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.
+ */
+
+#ifndef __INCLUDE_RTE_PORT_KNI_H__
+#define __INCLUDE_RTE_PORT_KNI_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * RTE Port KNI Interface
+ *
+ * kni_reader: input port built on top of pre-initialized KNI interface
+ * kni_writer: output port built on top of pre-initialized KNI interface
+ *
+ ***/
+
+#include <stdint.h>
+
+#include <rte_kni.h>
+
+#include "rte_port.h"
+
+/** kni_reader port parameters */
+struct rte_port_kni_reader_params {
+       /** KNI interface reference */
+       struct rte_kni *kni;
+};
+
+/** kni_reader port operations */
+extern struct rte_port_in_ops rte_port_kni_reader_ops;
+
+
+/** kni_writer port parameters */
+struct rte_port_kni_writer_params {
+       /** KNI interface reference */
+       struct rte_kni *kni;
+       /** Burst size to KNI interface. */
+       uint32_t tx_burst_sz;
+};
+
+/** kni_writer port operations */
+extern struct rte_port_out_ops rte_port_kni_writer_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/librte_port/rte_port_version.map 
b/lib/librte_port/rte_port_version.map
index 7a0b34d..e61b3fa 100644
--- a/lib/librte_port/rte_port_version.map
+++ b/lib/librte_port/rte_port_version.map
@@ -35,3 +35,11 @@ DPDK_2.2 {
        rte_port_ring_multi_writer_nodrop_ops;

 } DPDK_2.1;
+
+DPDK_16.07 {
+       global:
+
+       rte_port_kni_reader_ops;
+       rte_port_kni_writer_ops;
+
+} DPDK_2.2;
-- 
2.7.4

Reply via email to