From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-lf0-f67.google.com (mail-lf0-f67.google.com [209.85.215.67]) by dpdk.org (Postfix) with ESMTP id 29BBCB3D1 for ; Tue, 21 Jun 2016 13:10:54 +0200 (CEST) Received: by mail-lf0-f67.google.com with SMTP id w130so2758187lfd.2 for ; Tue, 21 Jun 2016 04:10:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=L+CEAMfftZVreoAgAsg31cmOU2oJ96+FcDUXAE8bjPM=; b=SZE0w3IqM/wOajg832IUJaCLCyxo0VAcCVH9lfI5zEFmuKyh9pC4zFYNJQpskSGAsY 8F38MXXApVGew+yfKr8iVs0clPiv+ZcAqBhymvsRfB4DPJntQbnS2sOblsE5tQrZ0r09 GRNKQFhECVOggFHr+Nb6oQUy4+3dXulM+2LJBara9wBnICR/IEExVH5E0YX2cG8kFE6A IlBCSWi4YL2AzfT6Kpeb3/yFsaLsa+e0tYzHls5Qgm+JU4dMP+OTlCK39aWOmEoZNUNo xGyQxfMxE9e+pPRXzZCjtZEG0mcG75xGuUKhP3IFsB5RbeE6MvPznw9XfEqgJ6VTAW8U l03g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=L+CEAMfftZVreoAgAsg31cmOU2oJ96+FcDUXAE8bjPM=; b=YwdjS4b8LAeUmsRhHCIoOK4BfhveH20d6mgGYoxzeXMEWxdG0oce2lQoNWBR975kvw nXVE/vy1zfoNu4qBlCWHwTxHSQCgViC61Q2evhaMBzf5H+5oWKs2IqaFZtlDQZ3vooIC iLDV5YTOT9H011yLxoGicYFwanlnpRfI2to64eeDtZNk4/hxInApWcNVJINrkciOBJ50 elemxeB1JS5kqk5tw2PWpODleOxw//dFaSoiKbqShTKj+meT/iEIff2r5ewrw1CAtnYQ Ixn2JryCJ7kSd2ivBuI39ueevdN3m3VbIlBDAqTLoxOj8n94nuLY/x2muclyAoCe4Qdb NFLw== X-Gm-Message-State: ALyK8tKWHPNlPdKhgk5GlRgZfKl+u/7nPXnN5ekaA21NuHeosAw0h16C+7pJZnjpAjrb9T5K6yZbuLrUnzoBqQ== X-Received: by 10.25.77.13 with SMTP id a13mr5007405lfb.190.1466507453382; Tue, 21 Jun 2016 04:10:53 -0700 (PDT) MIME-Version: 1.0 Sender: zhuangweijie@gmail.com Received: by 10.114.182.239 with HTTP; Tue, 21 Jun 2016 04:10:51 -0700 (PDT) In-Reply-To: <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> <3EB4FA525960D640B5BDFFD6A3D8912647A08FAC@IRSMSX108.ger.corp.intel.com> From: Ethan Date: Tue, 21 Jun 2016 19:10:51 +0800 X-Google-Sender-Auth: Hbh4DdedJnafaTaS-AdoQ-XbLbk Message-ID: To: "Dumitrescu, Cristian" Cc: "dev@dpdk.org" , "Singh, Jasvinder" , "Yigit, Ferruh" Content-Type: text/plain; charset=UTF-8 X-Content-Filtered-By: Mailman/MimeDel 2.1.15 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: Tue, 21 Jun 2016 11:10:54 -0000 Hi Cristian, New patch has been submitted. All comments are fixed except this one: "Here is one bug for you, you need to make sure you add the following line here: param->parsed = 1;" I think the new convention is to set this flag by the macro PARSE_CHECK_DUPLICATE_SECTION. BTW, although I use the --cover-letter and --annotate flags in the send-email command, it seems no cover letter is created. I am not very familiar with this. So sorry! B.R. Ethan 2016-06-19 0:44 GMT+08:00 Dumitrescu, Cristian < cristian.dumitrescu@intel.com>: > 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 > > > > 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 > > --- > > 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 > > > > #include > > +#ifdef RTE_LIBRTE_KNI > > +#include > > +#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 <---| |<-------|<-+ | > > +; |______________| |______________________| > > +; > > There are some errors in the diagram I previously sent you, here is the > corrected version (which matches the PIPELINE1 configuration): > > ; ______________ ______________________ > ; | | 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 = 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); > > + } > > +} > > I suggest you place this function just after the check_tms() function, in > order 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 = { > > .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( > > + ¶m->socket_id, > > + ¶m->core_id, > > + ¶m->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(¶m- > > >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(¶m- > > >burst_write, > > + > > ent->value); > > + > > + PARSE_ERROR((status == 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 > here: > param->parsed = 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[] > > = { > > {"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 > > 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 = 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; > > +} > > + > > 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 = 0; > > if (port_id >= rte_eth_dev_count()) > return -EINVAL; > > ret = (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 >= 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; > > +} > > Same issue about using the rte_eth_dev_start/stop() functions. Based on > function 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/down 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 >= rte_eth_dev_count()) > return -EINVAL; > > if (new_mtu > ETHER_MAX_LEN) > return -EINVAL; > > /* Set new MTU */ > ret = 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 == 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 == 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 = 0; i < app->n_pktq_kni; i++) { > > Please declare the "i" variable at the start of the function, as usual. > Although I personally like this idea, this pattern is not used anywhere in > DPDK 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 = &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 > > As in any other place that just deals with KNI configuration data rather > than KNI init data (e.g. in app.h or config_parse.c), we do not need to > #ifdef 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 = &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++) > > Same comment as above on definition of the "i" variable. > > > + 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 > > #include > > #include > > +#ifdef RTE_LIBRTE_KNI > > +#include > > +#endif > > #include > > > > 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 . > > + * 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 > > + > > +#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 += 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 . > > + * 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 > > + > > +#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; > > > > } 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 > >