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 500F92BC3 for ; Mon, 13 Jun 2016 12:25:19 +0200 (CEST) Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP; 13 Jun 2016 03:25:18 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.26,466,1459839600"; d="scan'208";a="718196089" Received: from irsmsx102.ger.corp.intel.com ([163.33.3.155]) by FMSMGA003.fm.intel.com with ESMTP; 13 Jun 2016 03:25:17 -0700 Received: from irsmsx108.ger.corp.intel.com ([169.254.11.183]) by IRSMSX102.ger.corp.intel.com ([169.254.2.10]) with mapi id 14.03.0248.002; Mon, 13 Jun 2016 11:25:16 +0100 From: "Dumitrescu, Cristian" To: WeiJie Zhuang CC: "dev@dpdk.org" , "Singh, Jasvinder" , "Yigit, Ferruh" Thread-Topic: [PATCH] port: add kni interface support Thread-Index: AQHRuNPzqUvoK3y1DESiX5+hyUDcX5/hyG9ggAV8CeA= Date: Mon, 13 Jun 2016 10:25:15 +0000 Message-ID: <3EB4FA525960D640B5BDFFD6A3D8912647A02427@IRSMSX108.ger.corp.intel.com> References: <1464325653-6912-1-git-send-email-zhuangwj@gmail.com> <1464434757-10860-1-git-send-email-zhuangwj@gmail.com> <3EB4FA525960D640B5BDFFD6A3D8912647A00F57@IRSMSX108.ger.corp.intel.com> In-Reply-To: <3EB4FA525960D640B5BDFFD6A3D8912647A00F57@IRSMSX108.ger.corp.intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiYmU1MWVmNjMtZjFmZC00MjdjLTk4ZDEtYzM0NDZiOTg5ZGU5IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX0lDIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE1LjkuNi42IiwiVHJ1c3RlZExhYmVsSGFzaCI6ImNNbW9SUld3TXNHaEVDNWV2eW5JUnNzXC9aczJlZGNqZ2hsZVZxZ3dzMWJBPSJ9 x-ctpclassification: CTP_IC x-originating-ip: [163.33.239.182] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Subject: Re: [dpdk-dev] [PATCH] 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: Mon, 13 Jun 2016 10:25:20 -0000 Hi Ethan, In the process of testing your patch, I actually had to do the rebase on th= e latest code and fix all the comments that I previously sent as part of my= reply. I also did a few other cosmetic changes and fixes required by the l= atest code (see below), therefore I think it makes sense to send you this c= ode for quick review rather than have you spend time doing the same work. I= t would also save some iterations on the email list and speed up the integr= ation of this patch. Please review this code and let us know as soon as possible if you are OK w= ith us sending it as the next version of this patch keeping your initial si= gnoff as well. Thank you! Changes included in the code below: 1. Rebase on top of latest DPDK head 2. Fixing all the previous code comments 3. Fix the binding of KNI device kernel space thread to CPU core (struct ap= p_pktq_kni_params::force_bind) 4. The KNI requests handled by master pipeline rather than on data path (pi= peline_master_be.c: call to rte_kni_handle_request()) 5. Fixing the tracking feature for KNI (pipeline_common_fe.c: function app_= pipeline_track_pktq_out_to_link()) 6. Enhanced config file with two KNI interfaces connected using a Linux ker= nel bridge (./config/kni.cfg) 7. Cosmetic improvements Regards, Cristian diff --git a/examples/ip_pipeline/app.h b/examples/ip_pipeline/app.h old mode 100644 new mode 100755 index 848244a..555c6bd --- a/examples/ip_pipeline/app.h +++ b/examples/ip_pipeline/app.h @@ -44,6 +44,7 @@ #include =20 #include +#include =20 #include "cpu_core_map.h" #include "pipeline.h" @@ -158,6 +159,20 @@ struct app_pktq_tm_params { uint32_t burst_write; }; =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; +}; + struct app_pktq_source_params { char *name; uint32_t parsed; @@ -185,6 +200,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 +213,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 +437,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 +490,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 +502,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 +516,7 @@ 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]; + struct rte_kni *kni[APP_MAX_PKTQ_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]; @@ -758,6 +780,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 *kn= i) +{ + 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) { @@ -954,6 +1036,67 @@ app_tm_get_writer(struct app_params *app, } =20 static inline uint32_t +app_kni_get_writers(struct app_params *app, struct app_pktq_kni_params *kn= i) +{ + 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; + } + } + + if (n_writers !=3D 1) + return NULL; + + *pktq_out_id =3D id; + return writer; +} + +static inline uint32_t app_sink_get_writers(struct app_params *app, struct app_pktq_sink_params *= sink) { uint32_t pos =3D sink - app->sink_params; @@ -1051,6 +1194,22 @@ app_get_link_for_tm(struct app_params *app, struct a= pp_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/con= fig/kni.cfg new file mode 100755 index 0000000..55ad966 --- /dev/null +++ b/examples/ip_pipeline/config/kni.cfg @@ -0,0 +1,67 @@ +; BSD LICENSE +; +; Copyright(c) 2015-2016 Intel Corporation. All rights reserved. +; All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; * Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; * Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in +; the documentation and/or other materials provided with the +; distribution. +; * Neither the name of Intel Corporation nor the names of its +; contributors may be used to endorse or promote products derived +; from this software without specific prior written permission. +; +; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +; ______________ ______________________=20 +; | | KNI0 | | +; RXQ0.0 --->| |------->|--+ | +; | | KNI1 | | br0 | +; TXQ0.0 <---| |<-------|<-+ | +; | Pass-through | | Linux Kernel | +; | (P1) | | Network Stack | +; | | KNI0 | | +; RXQ0.0 --->| |------->|--+ | +; | | KNI1 | | br0 | +; TXQ0.0 <---| |<-------|<-+ | +; |______________| |______________________| +; +; Insert Linux kernel KNI module: +; [Linux]$ insmod rte_kni.ko +; +; Configure Linux kernel bridge between KNI0 and KNI1 interfaces: +; [Linux]$ ifconfig KNI0 up +; [Linux]$ ifconfig KNI1 up +; [Linux]$ brctl addbr "br0" +; [Linux]$ brctl addif br0 KNI0 +; [Linux]$ brctl addif br0 KNI1 +; [Linux]$ ifconfig br0 up + +[EAL] +log_level =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/con= fig_check.c old mode 100644 new mode 100755 index 18f57be..01fa030 --- a/examples/ip_pipeline/config_check.c +++ b/examples/ip_pipeline/config_check.c @@ -316,6 +316,29 @@ check_tms(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); + } +} + +static void check_sources(struct app_params *app) { uint32_t i; @@ -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/con= fig_parse.c old mode 100644 new mode 100755 index 504018e..a286291 --- 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,87 @@ 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); + + param->force_bind =3D 1; + + PARSE_ERROR((status =3D=3D 0), section_name, + ent->name); + 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); + } + + param->parsed =3D 1; + + free(entries); +} + +static void parse_source(struct app_params *app, const char *section_name, struct rte_cfgfile *cfg) @@ -2147,6 +2260,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 +2399,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 +2762,46 @@ 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_read); + + fputc('\n', f); + } +} + +static void save_source_params(struct app_params *app, FILE *f) { struct app_pktq_source_params *p; @@ -2753,6 +2908,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 +2945,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 +3033,7 @@ app_config_save(struct app_params *app, const char *f= ile_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 +3083,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 old mode 100644 new mode 100755 index 7120bab..0c76d91 --- a/examples/ip_pipeline/init.c +++ b/examples/ip_pipeline/init.c @@ -1176,6 +1176,109 @@ app_init_tm(struct app_params *app) } } =20 +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; +} + +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; +} + +static void +app_init_kni(struct app_params *app) { + uint32_t i; + + if (app->n_pktq_kni =3D=3D 0) + return; + + rte_kni_init(app->n_pktq_kni); + + for (i =3D 0; i < app->n_pktq_kni; i++) { + 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); + } +} + static void app_init_msgq(struct app_params *app) { @@ -1285,6 +1388,11 @@ void app_pipeline_params_get(struct app_params *app, out->params.sched.sched =3D app->tm[in->id]; out->burst_size =3D app->tm_params[in->id].burst_read; break; + 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; case APP_PKTQ_IN_SOURCE: { uint32_t mempool_id =3D @@ -1409,7 +1517,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 +1528,11 @@ void app_pipeline_params_get(struct app_params *app, app->tm_params[in->id].burst_write; break; } + 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; case APP_PKTQ_OUT_SINK: { out->type =3D PIPELINE_PORT_OUT_SINK; @@ -1607,6 +1721,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 old mode 100644 new mode 100755 index 70c57e4..cd1d082 --- a/examples/ip_pipeline/pipeline/pipeline_common_fe.c +++ b/examples/ip_pipeline/pipeline/pipeline_common_fe.c @@ -130,6 +130,33 @@ app_pipeline_track_pktq_out_to_link(struct app_params = *app, break; } =20 + 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; + } + 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 old mode 100644 new mode 100755 index 79869a4..ba2a863 --- a/examples/ip_pipeline/pipeline/pipeline_master_be.c +++ b/examples/ip_pipeline/pipeline/pipeline_master_be.c @@ -105,6 +105,7 @@ pipeline_run(void *pipeline) { struct pipeline_master *p =3D (struct pipeline_master *) pipeline; struct app_params *app =3D p->app; + uint32_t i; int status; =20 /* Application post-init phase */ @@ -144,6 +145,10 @@ pipeline_run(void *pipeline) rte_exit(0, "Bye!\n"); } =20 + /* Handle KNI requests from Linux kernel */ + for (i =3D 0; i < app->n_pktq_kni; i++) + rte_kni_handle_request(app->kni[i]); + return 0; } =20 diff --git a/examples/ip_pipeline/pipeline_be.h b/examples/ip_pipeline/pipe= line_be.h old mode 100644 new mode 100755 index 5501ab7..972708e --- a/examples/ip_pipeline/pipeline_be.h +++ b/examples/ip_pipeline/pipeline_be.h @@ -40,6 +40,7 @@ #include #include #include +#include #include =20 enum pipeline_port_in_type { @@ -49,6 +50,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 +63,7 @@ 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; + struct rte_port_kni_reader_params kni; struct rte_port_source_params source; } params; uint32_t burst_size; @@ -82,6 +85,8 @@ pipeline_port_in_params_convert(struct pipeline_port_in_p= arams *p) return (void *) &p->params.ring_ipv6_frag; case PIPELINE_PORT_IN_SCHED_READER: return (void *) &p->params.sched; + case PIPELINE_PORT_IN_KNI_READER: + return (void *) &p->params.kni; case PIPELINE_PORT_IN_SOURCE: return (void *) &p->params.source; default: @@ -105,6 +110,8 @@ 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; + case PIPELINE_PORT_IN_KNI_READER: + return &rte_port_kni_reader_ops; case PIPELINE_PORT_IN_SOURCE: return &rte_port_source_ops; default: @@ -122,6 +129,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 +145,7 @@ 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; + struct rte_port_kni_writer_params kni; struct rte_port_sink_params sink; } params; }; @@ -163,6 +172,8 @@ pipeline_port_out_params_convert(struct pipeline_port_o= ut_params *p) return (void *) &p->params.ring_ipv6_ras; case PIPELINE_PORT_OUT_SCHED_WRITER: return (void *) &p->params.sched; + case PIPELINE_PORT_OUT_KNI_WRITER: + return (void *) &p->params.kni; case PIPELINE_PORT_OUT_SINK: return (void *) &p->params.sink; default: @@ -192,6 +203,8 @@ pipeline_port_out_params_get_ops(struct pipeline_port_o= ut_params *p) return &rte_port_ring_writer_ipv6_ras_ops; case PIPELINE_PORT_OUT_SCHED_WRITER: return &rte_port_sched_writer_ops; + case PIPELINE_PORT_OUT_KNI_WRITER: + return &rte_port_kni_writer_ops; case PIPELINE_PORT_OUT_SINK: return &rte_port_sink_ops; default: diff --git a/lib/librte_port/Makefile b/lib/librte_port/Makefile old mode 100644 new mode 100755 index d4de5af..52d2485 --- a/lib/librte_port/Makefile +++ b/lib/librte_port/Makefile @@ -57,6 +57,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_PORT) +=3D rte_port_ras.c endif SRCS-$(CONFIG_RTE_LIBRTE_PORT) +=3D rte_port_sched.c SRCS-$(CONFIG_RTE_LIBRTE_PORT) +=3D rte_port_source_sink.c +ifeq ($(CONFIG_RTE_LIBRTE_KNI),y) +SRCS-$(CONFIG_RTE_LIBRTE_PORT) +=3D rte_port_kni.c +endif =20 # install includes SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port.h @@ -68,6 +71,9 @@ SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port_r= as.h endif SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port_sched.h SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port_source_sink.h +ifeq ($(CONFIG_RTE_LIBRTE_KNI),y) +SYMLINK-$(CONFIG_RTE_LIBRTE_PORT)-include +=3D rte_port_kni.h +endif =20 # this lib depends upon: DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) :=3D lib/librte_eal @@ -75,5 +81,8 @@ DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) +=3D lib/librte_mbuf 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 +ifeq ($(CONFIG_RTE_LIBRTE_KNI),y) +DEPDIRS-$(CONFIG_RTE_LIBRTE_PORT) +=3D lib/librte_kni +endif =20 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 100755 index 0000000..ddc26c9 --- /dev/null +++ b/lib/librte_port/rte_port_kni.c @@ -0,0 +1,318 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#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; + uint16_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_kni.= h new file mode 100755 index 0000000..5b729c6 --- /dev/null +++ b/lib/librte_port/rte_port_kni.h @@ -0,0 +1,82 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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