examples/ip_pipeline: support KNI

1. add KNI support to the IP Pipeline sample Application
2. some bug fix
3. update doc
4. add config file with two KNI interfaces connected using
   a Linux kernel bridge

Signed-off-by: WeiJie Zhuang <zhuangwj@gmail.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
This commit is contained in:
WeiJie Zhuang 2016-06-21 18:55:53 +08:00 committed by Thomas Monjalon
parent 9fc37d1c07
commit 81d084dd2a
9 changed files with 769 additions and 41 deletions

View File

@ -1,5 +1,5 @@
.. BSD LICENSE
Copyright(c) 2015 Intel Corporation. All rights reserved.
Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -351,33 +351,35 @@ Application resources present in the configuration file
.. table:: Application resource names in the configuration file
+--------------------------+-----------------------------+-------------------------------------------------+
| Resource type | Format | Examples |
+==========================+=============================+=================================================+
| Pipeline | ``PIPELINE<ID>`` | ``PIPELINE0``, ``PIPELINE1`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Mempool | ``MEMPOOL<ID>`` | ``MEMPOOL0``, ``MEMPOOL1`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Link (network interface) | ``LINK<ID>`` | ``LINK0``, ``LINK1`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Link RX queue | ``RXQ<LINK_ID>.<QUEUE_ID>`` | ``RXQ0.0``, ``RXQ1.5`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Link TX queue | ``TXQ<LINK_ID>.<QUEUE_ID>`` | ``TXQ0.0``, ``TXQ1.5`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Software queue | ``SWQ<ID>`` | ``SWQ0``, ``SWQ1`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Traffic Manager | ``TM<LINK_ID>`` | ``TM0``, ``TM1`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Source | ``SOURCE<ID>`` | ``SOURCE0``, ``SOURCE1`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Sink | ``SINK<ID>`` | ``SINK0``, ``SINK1`` |
+--------------------------+-----------------------------+-------------------------------------------------+
| Message queue | ``MSGQ<ID>`` | ``MSGQ0``, ``MSGQ1``, |
| | ``MSGQ-REQ-PIPELINE<ID>`` | ``MSGQ-REQ-PIPELINE2``, ``MSGQ-RSP-PIPELINE2,`` |
| | ``MSGQ-RSP-PIPELINE<ID>`` | ``MSGQ-REQ-CORE-s0c1``, ``MSGQ-RSP-CORE-s0c1`` |
| | ``MSGQ-REQ-CORE-<CORE_ID>`` | |
| | ``MSGQ-RSP-CORE-<CORE_ID>`` | |
+--------------------------+-----------------------------+-------------------------------------------------+
+----------------------------+-----------------------------+-------------------------------------------------+
| Resource type | Format | Examples |
+============================+=============================+=================================================+
| Pipeline | ``PIPELINE<ID>`` | ``PIPELINE0``, ``PIPELINE1`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Mempool | ``MEMPOOL<ID>`` | ``MEMPOOL0``, ``MEMPOOL1`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Link (network interface) | ``LINK<ID>`` | ``LINK0``, ``LINK1`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Link RX queue | ``RXQ<LINK_ID>.<QUEUE_ID>`` | ``RXQ0.0``, ``RXQ1.5`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Link TX queue | ``TXQ<LINK_ID>.<QUEUE_ID>`` | ``TXQ0.0``, ``TXQ1.5`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Software queue | ``SWQ<ID>`` | ``SWQ0``, ``SWQ1`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Traffic Manager | ``TM<LINK_ID>`` | ``TM0``, ``TM1`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| KNI (kernel NIC interface) | ``KNI<LINK_ID>`` | ``KNI0``, ``KNI1`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Source | ``SOURCE<ID>`` | ``SOURCE0``, ``SOURCE1`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Sink | ``SINK<ID>`` | ``SINK0``, ``SINK1`` |
+----------------------------+-----------------------------+-------------------------------------------------+
| Message queue | ``MSGQ<ID>`` | ``MSGQ0``, ``MSGQ1``, |
| | ``MSGQ-REQ-PIPELINE<ID>`` | ``MSGQ-REQ-PIPELINE2``, ``MSGQ-RSP-PIPELINE2,`` |
| | ``MSGQ-RSP-PIPELINE<ID>`` | ``MSGQ-REQ-CORE-s0c1``, ``MSGQ-RSP-CORE-s0c1`` |
| | ``MSGQ-REQ-CORE-<CORE_ID>`` | |
| | ``MSGQ-RSP-CORE-<CORE_ID>`` | |
+----------------------------+-----------------------------+-------------------------------------------------+
``LINK`` instances are created implicitly based on the ``PORT_MASK`` application startup argument.
``LINK0`` is the first port enabled in the ``PORT_MASK``, port 1 is the next one, etc.
@ -386,7 +388,7 @@ For example, if bit 5 is the first bit set in the bitmask, then ``LINK0`` is hav
This mechanism creates a contiguous LINK ID space and isolates the configuration file against changes in the board
PCIe slots where NICs are plugged in.
``RXQ``, ``TXQ`` and ``TM`` instances have the LINK ID as part of their name.
``RXQ``, ``TXQ``, ``TM`` and ``KNI`` instances have the LINK ID as part of their name.
For example, ``RXQ2.1``, ``TXQ2.1`` and ``TM2`` are all associated with ``LINK2``.
@ -707,6 +709,58 @@ TM section
+---------------+---------------------------------------------+----------+----------+---------------+
KNI section
~~~~~~~~~~~
.. _table_ip_pipelines_kni_section:
.. tabularcolumns:: |p{2.5cm}|p{7cm}|p{1.5cm}|p{1.5cm}|p{1.5cm}|
.. table:: Configuration file KNI section
+---------------+----------------------------------------------+----------+------------------+---------------+
| Section | Description | Optional | Type | Default value |
+===============+==============================================+==========+==================+===============+
| core | CPU core to run the KNI kernel thread. | YES | See "CPU Core | Not set |
| | When core config is set, the KNI kernel | | notation" | |
| | thread will be bound to the particular core. | | | |
| | When core config is not set, the KNI kernel | | | |
| | thread will be scheduled by the OS. | | | |
+---------------+----------------------------------------------+----------+------------------+---------------+
| mempool | Mempool to use for buffer allocation for | YES | uint32_t | MEMPOOL0 |
| | current KNI port. The mempool ID has | | | |
| | to be associated with a valid instance | | | |
| | defined in the mempool entry of the global | | | |
| | section. | | | |
+---------------+----------------------------------------------+----------+------------------+---------------+
| burst_read | Read burst size (number of packets) | YES | uint32_t | 32 |
| | | | power of 2 | |
| | | | 0 < burst < size | |
+---------------+----------------------------------------------+----------+------------------+---------------+
| burst_write | Write burst size (number of packets) | YES | uint32_t | 32 |
| | | | power of 2 | |
| | | | 0 < burst < size | |
+---------------+----------------------------------------------+----------+------------------+---------------+
| dropless | When dropless is set to NO, packets can be | YES | YES/NO | NO |
| | dropped if not enough free slots are | | | |
| | currently available in the queue, so the | | | |
| | write operation to the queue is non- | | | |
| | blocking. | | | |
| | When dropless is set to YES, packets cannot | | | |
| | be dropped if not enough free slots are | | | |
| | currently available in the queue, so the | | | |
| | write operation to the queue is blocking, as | | | |
| | the write operation is retried until enough | | | |
| | free slots become available and all the | | | |
| | packets are successfully written to the | | | |
| | queue. | | | |
+---------------+----------------------------------------------+----------+------------------+---------------+
| n_retries | Number of retries. Valid only when dropless | YES | uint64_t | 0 |
| | is set to YES. When set to 0, it indicates | | | |
| | unlimited number of retries. | | | |
+---------------+----------------------------------------------+----------+------------------+---------------+
SOURCE section
~~~~~~~~~~~~~~

View File

@ -44,6 +44,9 @@
#include <cmdline_parse.h>
#include <rte_ethdev.h>
#ifdef RTE_LIBRTE_KNI
#include <rte_kni.h>
#endif
#include "cpu_core_map.h"
#include "pipeline.h"
@ -132,6 +135,22 @@ 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;
uint32_t dropless;
uint64_t n_retries;
};
#ifndef APP_FILE_NAME_SIZE
#define APP_FILE_NAME_SIZE 256
#endif
@ -185,6 +204,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 +217,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 +441,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 +494,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 +506,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 +520,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 +695,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 +755,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];
@ -757,6 +785,66 @@ app_tm_get_reader(struct app_params *app,
return reader;
}
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 +949,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 +1011,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 +1027,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))
(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 +1202,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);

View File

@ -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 |
; 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

View File

@ -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
@ -315,6 +315,29 @@ check_tms(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);
}
}
static void
check_sources(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);

View File

@ -189,6 +189,20 @@ 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,
.dropless = 0,
.n_retries = 0,
};
struct app_pktq_source_params default_source_params = {
.parsed = 0,
.mempool_id = 0,
@ -300,6 +314,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 +852,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 +901,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);
@ -1581,6 +1615,15 @@ parse_txq(struct app_params *app,
continue;
}
if (strcmp(ent->name, "n_retries") == 0) {
int status = parser_read_uint64(&param->n_retries,
ent->value);
PARSE_ERROR((status == 0), section_name,
ent->name);
continue;
}
/* unrecognized */
PARSE_ERROR_INVALID(0, section_name, ent->name);
}
@ -1816,7 +1859,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];
@ -1852,6 +1895,102 @@ parse_tm(struct app_params *app,
free(entries);
}
static void
parse_kni(struct app_params *app,
const char *section_name,
struct rte_cfgfile *cfg)
{
struct app_pktq_kni_params *param;
struct rte_cfgfile_entry *entries;
int n_entries, i;
ssize_t param_idx;
n_entries = rte_cfgfile_section_num_entries(cfg, section_name);
PARSE_ERROR_SECTION_NO_ENTRIES((n_entries > 0), section_name);
entries = malloc(n_entries * sizeof(struct rte_cfgfile_entry));
PARSE_ERROR_MALLOC(entries != NULL);
rte_cfgfile_section_entries(cfg, section_name, entries, n_entries);
param_idx = APP_PARAM_ADD(app->kni_params, section_name);
param = &app->kni_params[param_idx];
PARSE_CHECK_DUPLICATE_SECTION(param);
APP_PARAM_ADD_LINK_FOR_KNI(app, section_name);
for (i = 0; i < n_entries; i++) {
struct rte_cfgfile_entry *ent = &entries[i];
if (strcmp(ent->name, "core") == 0) {
int status = parse_pipeline_core(
&param->socket_id,
&param->core_id,
&param->hyper_th_id,
ent->value);
PARSE_ERROR((status == 0), section_name,
ent->name);
param->force_bind = 1;
continue;
}
if (strcmp(ent->name, "mempool") == 0) {
int status = validate_name(ent->value,
"MEMPOOL", 1);
ssize_t idx;
PARSE_ERROR((status == 0), section_name,
ent->name);
idx = APP_PARAM_ADD(app->mempool_params, ent->value);
param->mempool_id = idx;
continue;
}
if (strcmp(ent->name, "burst_read") == 0) {
int status = parser_read_uint32(&param->burst_read,
ent->value);
PARSE_ERROR((status == 0), section_name,
ent->name);
continue;
}
if (strcmp(ent->name, "burst_write") == 0) {
int status = parser_read_uint32(&param->burst_write,
ent->value);
PARSE_ERROR((status == 0), section_name,
ent->name);
continue;
}
if (strcmp(ent->name, "dropless") == 0) {
int status = parser_read_arg_bool(ent->value);
PARSE_ERROR((status != -EINVAL), section_name,
ent->name);
param->dropless = status;
continue;
}
if (strcmp(ent->name, "n_retries") == 0) {
int status = parser_read_uint64(&param->n_retries,
ent->value);
PARSE_ERROR((status == 0), section_name,
ent->name);
continue;
}
/* unrecognized */
PARSE_ERROR_INVALID(0, section_name, ent->name);
}
free(entries);
}
static void
parse_source(struct app_params *app,
const char *section_name,
@ -2147,6 +2286,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 +2425,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);
@ -2582,6 +2723,7 @@ save_txq_params(struct app_params *app, FILE *f)
fprintf(f, "%s = %s\n",
"dropless",
p->dropless ? "yes" : "no");
fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
fputc('\n', f);
}
@ -2646,6 +2788,53 @@ 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);
/* dropless */
fprintf(f, "%s = %s\n",
"dropless",
p->dropless ? "yes" : "no");
/* n_retries */
fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
fputc('\n', f);
}
}
static void
save_source_params(struct app_params *app, FILE *f)
{
@ -2753,6 +2942,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 +2979,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 +3067,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 +3117,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,

View File

@ -1176,6 +1176,111 @@ app_init_tm(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;
ret = (if_up) ?
rte_eth_dev_set_link_up(port_id) :
rte_eth_dev_set_link_down(port_id);
return ret;
}
static int
kni_change_mtu(uint8_t port_id, unsigned new_mtu) {
int ret;
if (port_id >= rte_eth_dev_count())
return -EINVAL;
if (new_mtu > ETHER_MAX_LEN)
return -EINVAL;
/* Set new MTU */
ret = rte_eth_dev_set_mtu(port_id, new_mtu);
if (ret < 0)
return ret;
return 0;
}
#endif /* RTE_LIBRTE_KNI */
#ifndef RTE_LIBRTE_KNI
static void
app_init_kni(struct app_params *app) {
if (app->n_pktq_kni == 0)
return;
rte_panic("Can not init KNI without librte_kni support.\n");
}
#else
static void
app_init_kni(struct app_params *app) {
uint32_t i;
if (app->n_pktq_kni == 0)
return;
rte_kni_init(app->n_pktq_kni);
for (i = 0; i < app->n_pktq_kni; i++) {
struct app_pktq_kni_params *p_kni = &app->kni_params[i];
struct app_link_params *p_link;
struct rte_eth_dev_info dev_info;
struct app_mempool_params *mempool_params;
struct rte_mempool *mempool;
struct rte_kni_conf conf;
struct rte_kni_ops ops;
/* LINK */
p_link = app_get_link_for_kni(app, p_kni);
memset(&dev_info, 0, sizeof(dev_info));
rte_eth_dev_info_get(p_link->pmd_id, &dev_info);
/* MEMPOOL */
mempool_params = &app->mempool_params[p_kni->mempool_id];
mempool = app->mempool[p_kni->mempool_id];
/* KNI */
memset(&conf, 0, sizeof(conf));
snprintf(conf.name, RTE_KNI_NAMESIZE, "%s", p_kni->name);
conf.force_bind = p_kni->force_bind;
if (conf.force_bind) {
int lcore_id;
lcore_id = cpu_core_map_get_lcore_id(app->core_map,
p_kni->socket_id,
p_kni->core_id,
p_kni->hyper_th_id);
if (lcore_id < 0)
rte_panic("%s invalid CPU core\n", p_kni->name);
conf.core_id = (uint32_t) lcore_id;
}
conf.group_id = p_link->pmd_id;
conf.mbuf_size = mempool_params->buffer_size;
conf.addr = dev_info.pci_dev->addr;
conf.id = dev_info.pci_dev->id;
memset(&ops, 0, sizeof(ops));
ops.port_id = (uint8_t) p_link->pmd_id;
ops.change_mtu = kni_change_mtu;
ops.config_network_if = kni_config_network_interface;
APP_LOG(app, HIGH, "Initializing %s ...", p_kni->name);
app->kni[i] = rte_kni_alloc(mempool, &conf, &ops);
if (!app->kni[i])
rte_panic("%s init error\n", p_kni->name);
}
}
#endif /* RTE_LIBRTE_KNI */
static void
app_init_msgq(struct app_params *app)
{
@ -1281,10 +1386,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 +1525,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 +1536,34 @@ 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:
{
struct app_pktq_kni_params *p_kni =
&app->kni_params[in->id];
if (p_kni->dropless == 0) {
struct rte_port_kni_writer_params *params =
&out->params.kni;
out->type = PIPELINE_PORT_OUT_KNI_WRITER;
params->kni = app->kni[in->id];
params->tx_burst_sz =
app->kni_params[in->id].burst_write;
} else {
struct rte_port_kni_writer_nodrop_params
*params = &out->params.kni_nodrop;
out->type = PIPELINE_PORT_OUT_KNI_WRITER_NODROP;
params->kni = app->kni[in->id];
params->tx_burst_sz =
app->kni_params[in->id].burst_write;
params->n_retries =
app->kni_params[in->id].n_retries;
}
break;
}
#endif /* RTE_LIBRTE_KNI */
case APP_PKTQ_OUT_SINK:
{
out->type = PIPELINE_PORT_OUT_SINK;
@ -1607,6 +1752,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);

View File

@ -130,6 +130,33 @@ app_pipeline_track_pktq_out_to_link(struct app_params *app,
break;
}
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;
}
case APP_PKTQ_OUT_SINK:
default:
return NULL;

View File

@ -106,6 +106,9 @@ pipeline_run(void *pipeline)
struct pipeline_master *p = (struct pipeline_master *) pipeline;
struct app_params *app = p->app;
int status;
#ifdef RTE_LIBRTE_KNI
uint32_t i;
#endif /* RTE_LIBRTE_KNI */
/* Application post-init phase */
if (p->post_init_done == 0) {
@ -144,6 +147,12 @@ pipeline_run(void *pipeline)
rte_exit(0, "Bye!\n");
}
#ifdef RTE_LIBRTE_KNI
/* Handle KNI requests from Linux kernel */
for (i = 0; i < app->n_pktq_kni; i++)
rte_kni_handle_request(app->kni[i]);
#endif /* RTE_LIBRTE_KNI */
return 0;
}

View File

@ -40,6 +40,9 @@
#include <rte_port_ras.h>
#include <rte_port_sched.h>
#include <rte_port_source_sink.h>
#ifdef RTE_LIBRTE_KNI
#include <rte_port_kni.h>
#endif
#include <rte_pipeline.h>
enum pipeline_port_in_type {
@ -49,6 +52,7 @@ enum pipeline_port_in_type {
PIPELINE_PORT_IN_RING_READER_IPV4_FRAG,
PIPELINE_PORT_IN_RING_READER_IPV6_FRAG,
PIPELINE_PORT_IN_SCHED_READER,
PIPELINE_PORT_IN_KNI_READER,
PIPELINE_PORT_IN_SOURCE,
};
@ -61,6 +65,9 @@ struct pipeline_port_in_params {
struct rte_port_ring_reader_ipv4_frag_params ring_ipv4_frag;
struct rte_port_ring_reader_ipv6_frag_params ring_ipv6_frag;
struct rte_port_sched_reader_params sched;
#ifdef RTE_LIBRTE_KNI
struct rte_port_kni_reader_params kni;
#endif
struct rte_port_source_params source;
} params;
uint32_t burst_size;
@ -82,6 +89,10 @@ pipeline_port_in_params_convert(struct pipeline_port_in_params *p)
return (void *) &p->params.ring_ipv6_frag;
case PIPELINE_PORT_IN_SCHED_READER:
return (void *) &p->params.sched;
#ifdef RTE_LIBRTE_KNI
case PIPELINE_PORT_IN_KNI_READER:
return (void *) &p->params.kni;
#endif
case PIPELINE_PORT_IN_SOURCE:
return (void *) &p->params.source;
default:
@ -105,6 +116,10 @@ pipeline_port_in_params_get_ops(struct pipeline_port_in_params *p)
return &rte_port_ring_reader_ipv6_frag_ops;
case PIPELINE_PORT_IN_SCHED_READER:
return &rte_port_sched_reader_ops;
#ifdef RTE_LIBRTE_KNI
case PIPELINE_PORT_IN_KNI_READER:
return &rte_port_kni_reader_ops;
#endif
case PIPELINE_PORT_IN_SOURCE:
return &rte_port_source_ops;
default:
@ -122,6 +137,8 @@ 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_KNI_WRITER_NODROP,
PIPELINE_PORT_OUT_SINK,
};
@ -137,6 +154,10 @@ 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;
struct rte_port_kni_writer_nodrop_params kni_nodrop;
#endif
struct rte_port_sink_params sink;
} params;
};
@ -163,6 +184,12 @@ 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;
case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
return (void *) &p->params.kni_nodrop;
#endif
case PIPELINE_PORT_OUT_SINK:
return (void *) &p->params.sink;
default:
@ -192,6 +219,12 @@ 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;
case PIPELINE_PORT_OUT_KNI_WRITER_NODROP:
return &rte_port_kni_writer_nodrop_ops;
#endif
case PIPELINE_PORT_OUT_SINK:
return &rte_port_sink_ops;
default: