.. 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
.. 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.
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``.
+---------------+---------------------------------------------+----------+----------+---------------+
+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
~~~~~~~~~~~~~~
#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"
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
APP_PKTQ_IN_HWQ,
APP_PKTQ_IN_SWQ,
APP_PKTQ_IN_TM,
+ APP_PKTQ_IN_KNI,
APP_PKTQ_IN_SOURCE,
};
APP_PKTQ_OUT_HWQ,
APP_PKTQ_OUT_SWQ,
APP_PKTQ_OUT_TM,
+ APP_PKTQ_OUT_KNI,
APP_PKTQ_OUT_SINK,
};
#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
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];
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;
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];
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];
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];
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)
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];
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];
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;
+ }
}
}
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);
--- /dev/null
+; 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
/*-
* 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
}
}
+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)
{
check_txqs(app);
check_swqs(app);
check_tms(app);
+ check_knis(app);
check_sources(app);
check_sinks(app);
check_msgqs(app);
.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,
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), \
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);
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);
continue;
}
+ if (strcmp(ent->name, "n_retries") == 0) {
+ int status = parser_read_uint64(¶m->n_retries,
+ ent->value);
+
+ PARSE_ERROR((status == 0), section_name,
+ ent->name);
+ continue;
+ }
+
/* unrecognized */
PARSE_ERROR_INVALID(0, section_name, ent->name);
}
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];
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(
+ ¶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;
+ }
+
+ 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(¶m->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,
{"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},
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);
fprintf(f, "%s = %s\n",
"dropless",
p->dropless ? "yes" : "no");
+ fprintf(f, "%s = %" PRIu64 "\n", "n_retries", p->n_retries);
fputc('\n', 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)
{
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;
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;
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);
&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,
}
}
+#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)
{
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 =
}
break;
}
- case APP_PKTQ_OUT_TM: {
+ case APP_PKTQ_OUT_TM:
+ {
struct rte_port_sched_writer_params *params =
&out->params.sched;
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;
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);
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;
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) {
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;
}
#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 {
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,
};
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;
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:
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:
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,
};
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;
};
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:
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: