From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by dpdk.org (Postfix) with ESMTP id 273F0CCD4 for ; Sat, 18 Jun 2016 18:45:12 +0200 (CEST) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 18 Jun 2016 09:45:12 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.26,487,1459839600"; d="scan'208";a="978707580" Received: from irsmsx101.ger.corp.intel.com ([163.33.3.153]) by orsmga001.jf.intel.com with ESMTP; 18 Jun 2016 09:44:53 -0700 Received: from irsmsx108.ger.corp.intel.com ([169.254.11.183]) by IRSMSX101.ger.corp.intel.com ([169.254.1.155]) with mapi id 14.03.0248.002; Sat, 18 Jun 2016 17:44:52 +0100 From: "Dumitrescu, Cristian" To: WeiJie Zhuang CC: "dev@dpdk.org" , "Singh, Jasvinder" , "Yigit, Ferruh" Thread-Topic: [PATCH v3 1/3] port: add kni interface support Thread-Index: AQHRx8IwASRHPFpF9Em0P9BBr1KCG5/vZKUQ Date: Sat, 18 Jun 2016 16:44:52 +0000 Message-ID: <3EB4FA525960D640B5BDFFD6A3D8912647A08FAC@IRSMSX108.ger.corp.intel.com> References: <1464434757-10860-1-git-send-email-zhuangwj@gmail.com> <1466076423-8680-1-git-send-email-zhuangwj@gmail.com> In-Reply-To: <1466076423-8680-1-git-send-email-zhuangwj@gmail.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiNzBhYTEwMjQtNjMxNS00YjA2LWIyYTMtNWJkZjNjYjY4NTIyIiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX0lDIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE1LjkuNi42IiwiVHJ1c3RlZExhYmVsSGFzaCI6IjZIMW45VGxiYnM0OXpFVmJjU2Z1bWREZDhQd0FxMFwvc0JTVEtxVDlzUHpRPSJ9 x-ctpclassification: CTP_IC x-originating-ip: [163.33.239.180] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [PATCH v3 1/3] port: add kni interface support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 18 Jun 2016 16:45:14 -0000 Hi Ethan, Thank you, here are some comments inlined below. Please reorganize this patch in a slightly different way to look similar to= other DPDK patch sets and also ease up the integration work for Thomas: Patch 0: I suggest adding a cover letter; Patch 1: all librte_port changes (rte_port_kni.h, rte_port_kni.c, Makefile= , rte_port_version.map), including the "nodrop" KNI port version Patch 2: all ip_pipeline app changes Patch 3: ip_pipeline app kni.cfg file Patch 4: Documentation changes > -----Original Message----- > From: WeiJie Zhuang [mailto:zhuangwj@gmail.com] > Sent: Thursday, June 16, 2016 12:27 PM > To: Dumitrescu, Cristian > Cc: dev@dpdk.org; Singh, Jasvinder ; Yigit, > Ferruh ; WeiJie Zhuang > Subject: [PATCH v3 1/3] port: add kni interface support >=20 > 1. add KNI port type to the packet framework > 2. add KNI support to the IP Pipeline sample Application > 3. some bug fix >=20 > Signed-off-by: WeiJie Zhuang > --- > 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 >=20 > 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/Makefil= e > 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 >=20 > #include > +#ifdef RTE_LIBRTE_KNI > +#include > +#endif >=20 > #include "cpu_core_map.h" > #include "pipeline.h" > @@ -132,6 +135,20 @@ struct app_pktq_swq_params { > uint32_t mempool_indirect_id; > }; >=20 > +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, > }; >=20 > @@ -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, > }; >=20 > @@ -420,6 +439,8 @@ struct app_eal_params { >=20 > #define APP_MAX_PKTQ_TM APP_MAX_LINKS >=20 > +#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 =3D NULL; > uint32_t pos =3D swq - app->swq_params; > uint32_t n_pipelines =3D RTE_MIN(app->n_pipelines, > RTE_DIM(app->pipeline_params)); > - uint32_t n_readers =3D 0, id, i; > + uint32_t n_readers =3D 0, id =3D 0, i; >=20 > for (i =3D 0; i < n_pipelines; i++) { > struct app_pipeline_params *p =3D &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 =3D NULL; > uint32_t pos =3D tm - app->tm_params; > uint32_t n_pipelines =3D RTE_MIN(app->n_pipelines, > RTE_DIM(app->pipeline_params)); > - uint32_t n_readers =3D 0, id, i; > + uint32_t n_readers =3D 0, id =3D 0, i; >=20 > for (i =3D 0; i < n_pipelines; i++) { > struct app_pipeline_params *p =3D &app->pipeline_params[i]; > @@ -758,6 +784,66 @@ app_tm_get_reader(struct app_params *app, > } >=20 > static inline uint32_t > +app_kni_get_readers(struct app_params *app, struct > app_pktq_kni_params *kni) > +{ > + uint32_t pos =3D kni - app->kni_params; > + uint32_t n_pipelines =3D RTE_MIN(app->n_pipelines, > + RTE_DIM(app->pipeline_params)); > + uint32_t n_readers =3D 0, i; > + > + for (i =3D 0; i < n_pipelines; i++) { > + struct app_pipeline_params *p =3D &app->pipeline_params[i]; > + uint32_t n_pktq_in =3D RTE_MIN(p->n_pktq_in, RTE_DIM(p- > >pktq_in)); > + uint32_t j; > + > + for (j =3D 0; j < n_pktq_in; j++) { > + struct app_pktq_in_params *pktq =3D &p->pktq_in[j]; > + > + if ((pktq->type =3D=3D APP_PKTQ_IN_KNI) && > + (pktq->id =3D=3D 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 =3D NULL; > + uint32_t pos =3D kni - app->kni_params; > + uint32_t n_pipelines =3D RTE_MIN(app->n_pipelines, > + RTE_DIM(app->pipeline_params)); > + uint32_t n_readers =3D 0, id =3D 0, i; > + > + for (i =3D 0; i < n_pipelines; i++) { > + struct app_pipeline_params *p =3D &app->pipeline_params[i]; > + uint32_t n_pktq_in =3D RTE_MIN(p->n_pktq_in, RTE_DIM(p- > >pktq_in)); > + uint32_t j; > + > + for (j =3D 0; j < n_pktq_in; j++) { > + struct app_pktq_in_params *pktq =3D &p->pktq_in[j]; > + > + if ((pktq->type =3D=3D APP_PKTQ_IN_KNI) && > + (pktq->id =3D=3D pos)) { > + n_readers++; > + reader =3D p; > + id =3D j; > + } > + } > + } > + > + if (n_readers !=3D 1) > + return NULL; > + > + *pktq_in_id =3D 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 =3D NULL; > uint32_t pos =3D swq - app->swq_params; > uint32_t n_pipelines =3D RTE_MIN(app->n_pipelines, > RTE_DIM(app->pipeline_params)); > - uint32_t n_writers =3D 0, id, i; > + uint32_t n_writers =3D 0, id =3D 0, i; >=20 > for (i =3D 0; i < n_pipelines; i++) { > struct app_pipeline_params *p =3D &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 =3D NULL; > uint32_t pos =3D tm - app->tm_params; > uint32_t n_pipelines =3D RTE_MIN(app->n_pipelines, > RTE_DIM(app->pipeline_params)); > - uint32_t n_writers =3D 0, id, i; > + uint32_t n_writers =3D 0, id =3D 0, i; >=20 > for (i =3D 0; i < n_pipelines; i++) { > struct app_pipeline_params *p =3D &app->pipeline_params[i]; > @@ -939,10 +1025,73 @@ app_tm_get_writer(struct app_params *app, > struct app_pktq_out_params *pktq =3D &p- > >pktq_out[j]; >=20 > if ((pktq->type =3D=3D APP_PKTQ_OUT_TM) && > + (pktq->id =3D=3D pos)) { > + n_writers++; > + writer =3D p; > + id =3D j; > + } > + } > + } > + > + if (n_writers !=3D 1) > + return NULL; > + > + *pktq_out_id =3D id; > + return writer; > +} > + > +static inline uint32_t > +app_kni_get_writers(struct app_params *app, struct > app_pktq_kni_params *kni) > +{ > + uint32_t pos =3D kni - app->kni_params; > + uint32_t n_pipelines =3D RTE_MIN(app->n_pipelines, > + RTE_DIM(app->pipeline_params)); > + uint32_t n_writers =3D 0, i; > + > + for (i =3D 0; i < n_pipelines; i++) { > + struct app_pipeline_params *p =3D &app->pipeline_params[i]; > + uint32_t n_pktq_out =3D RTE_MIN(p->n_pktq_out, > + RTE_DIM(p->pktq_out)); > + uint32_t j; > + > + for (j =3D 0; j < n_pktq_out; j++) { > + struct app_pktq_out_params *pktq =3D &p- > >pktq_out[j]; > + > + if ((pktq->type =3D=3D APP_PKTQ_OUT_KNI) && > (pktq->id =3D=3D 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 =3D NULL; > + uint32_t pos =3D kni - app->kni_params; > + uint32_t n_pipelines =3D RTE_MIN(app->n_pipelines, > + RTE_DIM(app->pipeline_params)); > + uint32_t n_writers =3D 0, id =3D 0, i; > + > + for (i =3D 0; i < n_pipelines; i++) { > + struct app_pipeline_params *p =3D &app->pipeline_params[i]; > + uint32_t n_pktq_out =3D RTE_MIN(p->n_pktq_out, > + RTE_DIM(p->pktq_out)); > + uint32_t j; > + > + for (j =3D 0; j < n_pktq_out; j++) { > + struct app_pktq_out_params *pktq =3D &p- > >pktq_out[j]; > + > + if ((pktq->type =3D=3D APP_PKTQ_OUT_KNI) && > + (pktq->id =3D=3D pos)) { > + n_writers++; > writer =3D p; > id =3D j; > + } > } > } >=20 > @@ -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]; > } >=20 > +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 =3D APP_PARAM_FIND(app->link_params, link_name); > + APP_CHECK((link_param_idx >=3D 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 copyrigh= t > +; 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 <---| |<-------|<-+ | > +; |______________| |______________________| > +; There are some errors in the diagram I previously sent you, here is the cor= rected version (which matches the PIPELINE1 configuration): ; ______________ ______________________=20 ; | | KNI0 | | ; RXQ0.0 --->| |------->|--+ | ; | | KNI1 | | br0 | ; TXQ1.0 <---| |<-------|<-+ | ; | Pass-through | | Linux Kernel | ; | (P1) | | Network Stack | ; | | KNI1 | | ; RXQ1.0 --->| |------->|--+ | ; | | KNI0 | | 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 =3D 0 > + > +[PIPELINE0] > +type =3D MASTER > +core =3D 0 > + > +[PIPELINE1] > +type =3D PASS-THROUGH > +core =3D 1 > +pktq_in =3D RXQ0.0 KNI1 RXQ1.0 KNI0 > +pktq_out =3D 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) > } > } >=20 > +static void > +check_knis(struct app_params *app) { > + uint32_t i; > + > + for (i =3D 0; i < app->n_pktq_kni; i++) { > + struct app_pktq_kni_params *p =3D &app->kni_params[i]; > + uint32_t n_readers =3D app_kni_get_readers(app, p); > + uint32_t n_writers =3D app_kni_get_writers(app, p); > + > + APP_CHECK((n_readers !=3D 0), > + "%s has no reader\n", p->name); > + > + APP_CHECK((n_readers =3D=3D 1), > + "%s has more than one reader\n", p->name); > + > + APP_CHECK((n_writers !=3D 0), > + "%s has no writer\n", p->name); > + > + APP_CHECK((n_writers =3D=3D 1), > + "%s has more than one writer\n", p->name); > + } > +} I suggest you place this function just after the check_tms() function, in o= rder to keep consistency with our conventions. > + > 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 =3D { > .burst_write =3D 32, > }; >=20 > +struct app_pktq_kni_params default_kni_params =3D { > + .parsed =3D 0, > + .socket_id =3D 0, > + .core_id =3D 0, > + .hyper_th_id =3D 0, > + .force_bind =3D 0, > + > + .mempool_id =3D 0, > + .burst_read =3D 32, > + .burst_write =3D 32, > +}; > + > struct app_pktq_source_params default_source_params =3D { > .parsed =3D 0, > .mempool_id =3D 0, > @@ -300,6 +312,18 @@ app_print_usage(char *prgname) > link_param_pos; > \ > }) >=20 > +#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 =3D APP_PARAM_ADD((app)->link_params, > link_name); \ > + link_param_pos; > \ > +}) > + > #define PARSE_CHECK_DUPLICATE_SECTION(obj) > \ > do { \ > APP_CHECK(((obj)->parsed =3D=3D 0), > \ > @@ -826,6 +850,10 @@ parse_pipeline_pktq_in(struct app_params *app, > type =3D APP_PKTQ_IN_TM; > id =3D APP_PARAM_ADD(app->tm_params, name); > APP_PARAM_ADD_LINK_FOR_TM(app, name); > + } else if (validate_name(name, "KNI", 1) =3D=3D 0) { > + type =3D APP_PKTQ_IN_KNI; > + id =3D APP_PARAM_ADD(app->kni_params, name); > + APP_PARAM_ADD_LINK_FOR_KNI(app, name); > } else if (validate_name(name, "SOURCE", 1) =3D=3D 0) { > type =3D APP_PKTQ_IN_SOURCE; > id =3D APP_PARAM_ADD(app->source_params, name); > @@ -871,6 +899,10 @@ parse_pipeline_pktq_out(struct app_params *app, > type =3D APP_PKTQ_OUT_TM; > id =3D APP_PARAM_ADD(app->tm_params, name); > APP_PARAM_ADD_LINK_FOR_TM(app, name); > + } else if (validate_name(name, "KNI", 1) =3D=3D 0) { > + type =3D APP_PKTQ_OUT_KNI; > + id =3D APP_PARAM_ADD(app->kni_params, name); > + APP_PARAM_ADD_LINK_FOR_KNI(app, name); > } else if (validate_name(name, "SINK", 1) =3D=3D 0) { > type =3D APP_PKTQ_OUT_SINK; > id =3D APP_PARAM_ADD(app->sink_params, name); > @@ -1816,7 +1848,7 @@ parse_tm(struct app_params *app, > param =3D &app->tm_params[param_idx]; > PARSE_CHECK_DUPLICATE_SECTION(param); >=20 > - APP_PARAM_ADD_LINK_FOR_TXQ(app, section_name); > + APP_PARAM_ADD_LINK_FOR_TM(app, section_name); >=20 > for (i =3D 0; i < n_entries; i++) { > struct rte_cfgfile_entry *ent =3D &entries[i]; > @@ -1853,6 +1885,85 @@ parse_tm(struct app_params *app, > } >=20 > 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 =3D rte_cfgfile_section_num_entries(cfg, section_name); > + PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), > section_name); > + > + entries =3D malloc(n_entries * sizeof(struct rte_cfgfile_entry)); > + PARSE_ERROR_MALLOC(entries !=3D NULL); > + > + rte_cfgfile_section_entries(cfg, section_name, entries, n_entries); > + > + param_idx =3D APP_PARAM_ADD(app->kni_params, section_name); > + param =3D &app->kni_params[param_idx]; > + PARSE_CHECK_DUPLICATE_SECTION(param); > + > + APP_PARAM_ADD_LINK_FOR_KNI(app, section_name); > + > + > + for (i =3D 0; i < n_entries; i++) { > + struct rte_cfgfile_entry *ent =3D &entries[i]; > + > + if (strcmp(ent->name, "core") =3D=3D 0) { > + int status =3D parse_pipeline_core( > + ¶m->socket_id, > + ¶m->core_id, > + ¶m->hyper_th_id, > + ent->value); > + > + PARSE_ERROR((status =3D=3D 0), section_name, > + ent->name); > + param->force_bind =3D 1; > + continue; > + } > + > + if (strcmp(ent->name, "mempool") =3D=3D 0) { > + int status =3D validate_name(ent->value, > + > "MEMPOOL", 1); > + ssize_t idx; > + > + PARSE_ERROR((status =3D=3D 0), section_name, > + ent->name); > + > + idx =3D APP_PARAM_ADD(app->mempool_params, > ent->value); > + param->mempool_id =3D idx; > + continue; > + } > + > + if (strcmp(ent->name, "burst_read") =3D=3D 0) { > + int status =3D parser_read_uint32(¶m- > >burst_read, > + > ent->value); > + > + PARSE_ERROR((status =3D=3D 0), section_name, > + ent->name); > + continue; > + } > + > + if (strcmp(ent->name, "burst_write") =3D=3D 0) { > + int status =3D parser_read_uint32(¶m- > >burst_write, > + > ent->value); > + > + PARSE_ERROR((status =3D=3D 0), section_name, > + ent->name); > + continue; > + } > + > + /* unrecognized */ > + PARSE_ERROR_INVALID(0, section_name, ent->name); > + } > + Here is one bug for you, you need to make sure you add the following line h= ere: param->parsed =3D 1; > + 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[= ] > =3D { > {"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) > } >=20 > static void > +save_kni_params(struct app_params *app, FILE *f) > +{ > + struct app_pktq_kni_params *p; > + size_t i, count; > + > + count =3D RTE_DIM(app->kni_params); > + for (i =3D 0; i < count; i++) { > + p =3D &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 =3D 1\n"); > + fprintf(f, "core =3D s%" PRIu32 "c%" PRIu32 "%s\n", > + p->socket_id, > + p->core_id, > + (p->hyper_th_id) ? "h" : ""); > + } else > + fprintf(f, "; force_bind =3D 0\n"); > + > + /* mempool */ > + fprintf(f, "%s =3D %s\n", "mempool", > + app->mempool_params[p- > >mempool_id].name); > + > + /* burst_read */ > + fprintf(f, "%s =3D %" PRIu32 "\n", "burst_read", p- > >burst_read); > + > + /* burst_write */ > + fprintf(f, "%s =3D %" 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 =3D app->tm_params[pp- > >id].name; > break; > + case APP_PKTQ_IN_KNI: > + name =3D app->kni_params[pp- > >id].name; > + break; > case APP_PKTQ_IN_SOURCE: > name =3D 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 =3D app->tm_params[pp- > >id].name; > break; > + case APP_PKTQ_OUT_KNI: > + name =3D app->kni_params[pp- > >id].name; > + break; > case APP_PKTQ_OUT_SINK: > name =3D 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)); >=20 > + for (i =3D 0; i < RTE_DIM(app->kni_params); i++) > + memcpy(&app->kni_params[i], > + &default_kni_params, > + sizeof(default_kni_params)); > + > for (i =3D 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 In order to keep up with our existing code conventions, please move the KNI= code (functions kni_change_mtu(), kni_config_network_interface(), app_init= _kni()) just after function app_init_tm(). > 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 =3D PIPELINE_PORT_IN_SCHED_READER; > out->params.sched.sched =3D app->tm[in->id]; > out->burst_size =3D app->tm_params[in- > >id].burst_read; > break; > + } > +#ifdef RTE_LIBRTE_KNI > + case APP_PKTQ_IN_KNI: > + { > + out->type =3D PIPELINE_PORT_IN_KNI_READER; > + out->params.kni.kni =3D app->kni[in->id]; > + out->burst_size =3D app->kni_params[in- > >id].burst_read; > + break; > + } > +#endif /* RTE_LIBRTE_KNI */ > case APP_PKTQ_IN_SOURCE: > { > uint32_t mempool_id =3D > @@ -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 =3D > &out->params.sched; >=20 > @@ -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 =3D PIPELINE_PORT_OUT_KNI_WRITER; > + out->params.kni.kni =3D app->kni[in->id]; > + out->params.kni.tx_burst_sz =3D > + app->kni_params[in->id].burst_write; > + break; > + } > +#endif /* RTE_LIBRTE_KNI */ > case APP_PKTQ_OUT_SINK: > { > out->type =3D PIPELINE_PORT_OUT_SINK; > @@ -1452,6 +1474,113 @@ void app_pipeline_params_get(struct > app_params *app, > } > } >=20 > +#ifdef RTE_LIBRTE_KNI > +static int > +kni_config_network_interface(uint8_t port_id, uint8_t if_up) { > + int ret =3D 0; > + > + if (port_id >=3D rte_eth_dev_count()) > + return -EINVAL; > + > + if (if_up) { > + rte_eth_dev_stop(port_id); > + ret =3D rte_eth_dev_start(port_id); > + } else > + rte_eth_dev_stop(port_id); > + > + return ret; > +} > + Here is a critical issue that we found out recently during testing the KNI = code: the correct PMD API functions to use here are rte_eth_dev_set_link_up= /down(); stopping and restarting the device while the device is running can= lead to segfault and nondeterministic behaviour. Here is my proposal: static int kni_config_network_interface(uint8_t port_id, uint8_t if_up) { int ret =3D 0; if (port_id >=3D rte_eth_dev_count()) return -EINVAL; ret =3D (if_up)? rte_eth_dev_set_link_up(port_id) : rte_eth_dev_set_link_down(port_id); return ret; } I tested this function successfully. > +static int > +kni_change_mtu(uint8_t port_id, unsigned new_mtu) { > + int ret; > + > + if (port_id >=3D 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 =3D rte_eth_dev_set_mtu(port_id, new_mtu); > + if (ret < 0) > + return ret; > + > + /* Restart specific port */ > + ret =3D rte_eth_dev_start(port_id); > + if (ret < 0) > + return ret; > + > + return 0; > +} Same issue about using the rte_eth_dev_start/stop() functions. Based on fun= ction port_mtu_set() of the app/test-pmd application, it looks like rte_eth= _dev_set_mtu() function could be called directly with no start/stop or up/d= own preparations. Here is my version, although I did not fully test this one: static int kni_change_mtu(uint8_t port_id, unsigned new_mtu) { int ret; if (port_id >=3D rte_eth_dev_count()) return -EINVAL; if (new_mtu > ETHER_MAX_LEN) return -EINVAL; /* Set new MTU */ ret =3D rte_eth_dev_set_mtu(port_id, new_mtu); 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 =3D=3D 0) > + return; > +#ifndef RTE_LIBRTE_KNI > + else > + rte_panic("Can not init KNI without librte_kni support.\n"); > +#else I would like to avoid #ifdefs in the middle of the function code as much as= possible. I suggest we do the following: #ifndef RTE_LIBRTE_KNI static void app_init_kni(struct app_params *app) { if (app->n_pktq_kni =3D=3D 0) return; rte_panic("Cannot init KNI without librte_kni support.\n"); } #else static void app_init_kni(struct app_params *app) { //the real function code } #endif > + rte_kni_init(app->n_pktq_kni); > + > + for (uint32_t i =3D 0; i < app->n_pktq_kni; i++) { Please declare the "i" variable at the start of the function, as usual. Alt= hough I personally like this idea, this pattern is not used anywhere in DPD= K and it might trigger warnings/errors from some C compilers. Btw, any idea= whether this is mentioned in any way by the ANSI C/C99 standards? > + struct app_pktq_kni_params *p_kni =3D &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 =3D 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 =3D &app->mempool_params[p_kni- > >mempool_id]; > + mempool =3D 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 =3D p_kni->force_bind; > + if (conf.force_bind) { > + int lcore_id; > + > + lcore_id =3D 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 =3D (uint32_t) lcore_id; > + } > + conf.group_id =3D p_link->pmd_id; > + conf.mbuf_size =3D mempool_params->buffer_size; > + conf.addr =3D dev_info.pci_dev->addr; > + conf.id =3D dev_info.pci_dev->id; > + > + memset(&ops, 0, sizeof(ops)); > + ops.port_id =3D (uint8_t) p_link->pmd_id; > + ops.change_mtu =3D kni_change_mtu; > + ops.config_network_if =3D kni_config_network_interface; > + > + APP_LOG(app, HIGH, "Initializing %s ...", p_kni->name); > + app->kni[i] =3D 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); >=20 > 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; > } >=20 > +#ifdef RTE_LIBRTE_KNI As in any other place that just deals with KNI configuration data rather th= an KNI init data (e.g. in app.h or config_parse.c), we do not need to #ifde= f the code fragment below. Please remove this instance of #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 =3D &app->kni_params[pktq_out->id]; > + p =3D app_kni_get_reader(app, kni, &pktq_in_id); > + if (p =3D=3D NULL) > + return NULL; > + > + ptype =3D app_pipeline_type_find(app, p->type); > + if ((ptype =3D=3D NULL) || (ptype->fe_ops->f_track =3D=3D > NULL)) > + return NULL; > + > + app_pipeline_params_get(app, p, &pp); > + status =3D 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"); > } >=20 > +#ifdef RTE_LIBRTE_KNI > + /* Handle KNI requests from Linux kernel */ > + for (uint32_t i =3D 0; i < app->n_pktq_kni; i++) Same comment as above on definition of the "i" variable. > + rte_kni_handle_request(app->kni[i]); > +#endif /* RTE_LIBRTE_KNI */ > + > return 0; > } >=20 > 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 > #include > #include > +#ifdef RTE_LIBRTE_KNI > +#include > +#endif > #include >=20 > 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, > }; >=20 > @@ -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, > }; >=20 > @@ -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) +=3D rte_port_frag.c > SRCS-$(CONFIG_RTE_LIBRTE_PORT) +=3D rte_port_ras.c > endif > SRCS-$(CONFIG_RTE_LIBRTE_PORT) +=3D rte_port_sched.c > +ifeq ($(CONFIG_RTE_LIBRTE_KNI),y) > +SRCS-$(CONFIG_RTE_LIBRTE_PORT) +=3D rte_port_kni.c > +endif > SRCS-$(CONFIG_RTE_LIBRTE_PORT) +=3D rte_port_source_sink.c >=20 > # install includes > @@ -67,6 +70,9 @@ SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D > rte_port_frag.h > SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port_ras.h > endif > SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port_sched.h > +ifeq ($(CONFIG_RTE_LIBRTE_KNI),y) > +SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port_kni.h > +endif > SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port_source_sink.h >=20 > # this lib depends upon: > @@ -76,5 +82,6 @@ DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) +=3D > lib/librte_mempool > DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) +=3D lib/librte_ether > DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) +=3D lib/librte_ip_frag > DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) +=3D lib/librte_sched > +DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) +=3D lib/librte_kni >=20 > include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/lib/librte_port/rte_port_kni.c b/lib/librte_port/rte_port_kn= i.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 . > + * 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 copyrig= ht > + * 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 > + > +#include > +#include > +#include > + > +#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 +=3D val > +#define RTE_PORT_KNI_READER_STATS_PKTS_DROP_ADD(port, val) \ > + port->stats.n_pkts_drop +=3D 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 =3D > + (struct rte_port_kni_reader_params *) params; > + struct rte_port_kni_reader *port; > + > + /* Check input parameters */ > + if (conf =3D=3D NULL) { > + RTE_LOG(ERR, PORT, "%s: params is NULL\n", __func__); > + return NULL; > + } > + > + /* Memory allocation */ > + port =3D rte_zmalloc_socket("PORT", sizeof(*port), > + RTE_CACHE_LINE_SIZE, socket_id); > + if (port =3D=3D NULL) { > + RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", > __func__); > + return NULL; > + } > + > + /* Initialization */ > + port->kni =3D 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 =3D > + (struct rte_port_kni_reader *) port; > + uint16_t rx_pkt_cnt; > + > + rx_pkt_cnt =3D 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 =3D=3D 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 =3D > + (struct rte_port_kni_reader *) port; > + > + if (stats !=3D 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 +=3D val > +#define RTE_PORT_KNI_WRITER_STATS_PKTS_DROP_ADD(port, val) \ > + port->stats.n_pkts_drop +=3D 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 =3D > + (struct rte_port_kni_writer_params *) params; > + struct rte_port_kni_writer *port; > + > + /* Check input parameters */ > + if ((conf =3D=3D NULL) || > + (conf->tx_burst_sz =3D=3D 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 =3D rte_zmalloc_socket("PORT", sizeof(*port), > + RTE_CACHE_LINE_SIZE, socket_id); > + if (port =3D=3D NULL) { > + RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", > __func__); > + return NULL; > + } > + > + /* Initialization */ > + port->kni =3D conf->kni; > + port->tx_burst_sz =3D conf->tx_burst_sz; > + port->tx_buf_count =3D 0; > + port->bsz_mask =3D 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 =3D 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 =3D 0; > +} > + > +static int > +rte_port_kni_writer_tx(void *port, struct rte_mbuf *pkt) > +{ > + struct rte_port_kni_writer *p =3D > + (struct rte_port_kni_writer *) port; > + > + p->tx_buf[p->tx_buf_count++] =3D pkt; > + RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, 1); > + if (p->tx_buf_count >=3D 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 =3D > + (struct rte_port_kni_writer *) port; > + uint64_t bsz_mask =3D p->bsz_mask; > + uint32_t tx_buf_count =3D p->tx_buf_count; > + uint64_t expr =3D (pkts_mask & (pkts_mask + 1)) | > + ((pkts_mask & bsz_mask) ^ > bsz_mask); > + > + if (expr =3D=3D 0) { > + uint64_t n_pkts =3D __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 =3D 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 =3D pkts[n_pkts_ok]; > + > + rte_pktmbuf_free(pkt); > + } > + } else { > + for (; pkts_mask;) { > + uint32_t pkt_index =3D __builtin_ctzll(pkts_mask); > + uint64_t pkt_mask =3D 1LLU << pkt_index; > + struct rte_mbuf *pkt =3D pkts[pkt_index]; > + > + p->tx_buf[tx_buf_count++] =3D pkt; > + RTE_PORT_KNI_WRITER_STATS_PKTS_IN_ADD(p, 1); > + pkts_mask &=3D ~pkt_mask; > + } > + > + p->tx_buf_count =3D tx_buf_count; > + if (tx_buf_count >=3D p->tx_burst_sz) > + send_burst(p); > + } > + > + return 0; > +} > + > +static int > +rte_port_kni_writer_flush(void *port) > +{ > + struct rte_port_kni_writer *p =3D > + (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 =3D=3D 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 =3D > + (struct rte_port_kni_writer *) port; > + > + if (stats !=3D 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 =3D { > + .f_create =3D rte_port_kni_reader_create, > + .f_free =3D rte_port_kni_reader_free, > + .f_rx =3D rte_port_kni_reader_rx, > + .f_stats =3D rte_port_kni_reader_stats_read, > +}; > + > +struct rte_port_out_ops rte_port_kni_writer_ops =3D { > + .f_create =3D rte_port_kni_writer_create, > + .f_free =3D rte_port_kni_writer_free, > + .f_tx =3D rte_port_kni_writer_tx, > + .f_tx_bulk =3D rte_port_kni_writer_tx_bulk, > + .f_flush =3D rte_port_kni_writer_flush, > + .f_stats =3D rte_port_kni_writer_stats_read, > +}; > diff --git a/lib/librte_port/rte_port_kni.h b/lib/librte_port/rte_port_kn= i.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 . > + * 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 copyrig= ht > + * 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 > + > +#include > + > +#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; >=20 > } DPDK_2.1; > + > +DPDK_16.07 { > + global: > + > + rte_port_kni_reader_ops; > + rte_port_kni_writer_ops; > + > +} DPDK_2.2; > -- > 2.7.4 Regards, Cristian