From patchwork Fri Mar 9 18:24:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jasvinder Singh X-Patchwork-Id: 35897 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 36C281AFF0; Fri, 9 Mar 2018 19:24:57 +0100 (CET) Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by dpdk.org (Postfix) with ESMTP id EFCF5AACD for ; Fri, 9 Mar 2018 19:24:50 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 09 Mar 2018 10:24:50 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.47,446,1515484800"; d="scan'208";a="181382334" Received: from silpixa00381635.ir.intel.com (HELO silpixa00381635.ger.corp.intel.com) ([10.237.222.149]) by orsmga004.jf.intel.com with ESMTP; 09 Mar 2018 10:24:49 -0800 From: Jasvinder Singh To: dev@dpdk.org Cc: cristian.dumitrescu@intel.com Date: Fri, 9 Mar 2018 18:24:08 +0000 Message-Id: <20180309182426.135278-20-jasvinder.singh@intel.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20180309182426.135278-1-jasvinder.singh@intel.com> References: <20180309182426.135278-1-jasvinder.singh@intel.com> Subject: [dpdk-dev] [PATCH 19/37] ip_pipeline: add pipeline object X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add pipeline object implementation to the application. Signed-off-by: Cristian Dumitrescu Signed-off-by: Jasvinder Singh --- examples/ip_pipeline/Makefile | 1 + examples/ip_pipeline/cli.c | 786 +++++++++++++++++++++++++++++++++ examples/ip_pipeline/cli.h | 2 - examples/ip_pipeline/main.c | 8 + examples/ip_pipeline/meson.build | 1 + examples/ip_pipeline/pipeline.c | 930 +++++++++++++++++++++++++++++++++++++++ examples/ip_pipeline/pipeline.h | 265 +++++++++++ 7 files changed, 1991 insertions(+), 2 deletions(-) create mode 100644 examples/ip_pipeline/pipeline.c create mode 100644 examples/ip_pipeline/pipeline.h diff --git a/examples/ip_pipeline/Makefile b/examples/ip_pipeline/Makefile index 3d7c288..b1cfc2d 100644 --- a/examples/ip_pipeline/Makefile +++ b/examples/ip_pipeline/Makefile @@ -13,6 +13,7 @@ SRCS-y += link.c SRCS-y += main.c SRCS-y += mempool.c SRCS-y += parser.c +SRCS-y += pipeline.c SRCS-y += swq.c SRCS-y += tap.c SRCS-y += tmgr.c diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c index df8445e..96fc33e 100644 --- a/examples/ip_pipeline/cli.c +++ b/examples/ip_pipeline/cli.c @@ -14,6 +14,7 @@ #include "link.h" #include "mempool.h" #include "parser.h" +#include "pipeline.h" #include "swq.h" #include "tap.h" #include "tmgr.h" @@ -994,6 +995,751 @@ cmd_table_action_profile(char **tokens, } } +/** + * pipeline + * period + * offset_port_id + * cpu + */ +static void +cmd_pipeline(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct pipeline_params p; + char *name; + struct pipeline *pipeline; + + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + name = tokens[1]; + + if (strcmp(tokens[2], "period") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); + return; + } + + if (parser_read_uint32(&p.timer_period_ms, tokens[3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); + return; + } + + if (strcmp(tokens[4], "offset_port_id") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id"); + return; + } + + if (parser_read_uint32(&p.offset_port_id, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id"); + return; + } + + if (strcmp(tokens[6], "cpu") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu"); + return; + } + + if (parser_read_uint32(&p.cpu_id, tokens[7]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id"); + return; + } + + pipeline = pipeline_create(name, &p); + if (pipeline == NULL) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** + * pipeline port in + * bsz + * link rxq + * | swq + * | tmgr + * | tap mempool mtu + * | kni + * | source mempool file + * [disabled] + */ +static void +cmd_pipeline_port_in(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct port_in_params p; + char *pipeline_name; + uint32_t t0; + int enabled, status; + + if (n_tokens < 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (strcmp(tokens[3], "in") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); + return; + } + + if (strcmp(tokens[4], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + return; + } + + if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); + return; + } + + t0 = 6; + + if (strcmp(tokens[t0], "link") == 0) { + if (n_tokens < t0 + 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in link"); + return; + } + + p.type = PORT_IN_RXQ; + + p.dev_name = tokens[t0 + 1]; + + if (strcmp(tokens[t0 + 2], "rxq") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); + return; + } + + if (parser_read_uint16(&p.rxq.queue_id, tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "queue_id"); + return; + } + t0 += 4; + } else if (strcmp(tokens[t0], "swq") == 0) { + if (n_tokens < t0 + 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in swq"); + return; + } + + p.type = PORT_IN_SWQ; + + p.dev_name = tokens[t0 + 1]; + + t0 += 2; + } else if (strcmp(tokens[t0], "tmgr") == 0) { + if (n_tokens < t0 + 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in tmgr"); + return; + } + + p.type = PORT_IN_TMGR; + + p.dev_name = tokens[t0 + 1]; + + t0 += 2; + } else if (strcmp(tokens[t0], "tap") == 0) { + if (n_tokens < t0 + 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in tap"); + return; + } + + p.type = PORT_IN_TAP; + + p.dev_name = tokens[t0 + 1]; + + if (strcmp(tokens[t0 + 2], "mempool") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mempool"); + return; + } + + p.tap.mempool_name = tokens[t0 + 3]; + + if (strcmp(tokens[t0 + 4], "mtu") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mtu"); + return; + } + + if (parser_read_uint32(&p.tap.mtu, tokens[t0 + 5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); + return; + } + + t0 += 6; + } else if (strcmp(tokens[t0], "kni") == 0) { + if (n_tokens < t0 + 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in kni"); + return; + } + + p.type = PORT_IN_KNI; + + p.dev_name = tokens[t0 + 1]; + + t0 += 2; + } else if (strcmp(tokens[t0], "source") == 0) { + if (n_tokens < t0 + 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in source"); + return; + } + + p.type = PORT_IN_SOURCE; + + p.dev_name = tokens[t0 + 1]; + + if (strcmp(tokens[t0 + 2], "mempool") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mempool"); + return; + } + + p.source.mempool_name = tokens[t0 + 3]; + + if (strcmp(tokens[t0 + 4], "file") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "file"); + return; + } + + p.source.file_name = tokens[t0 + 5]; + + p.source.n_bytes_per_pkt = 0; + + t0 += 6; + } else { + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); + return; + } + + enabled = 1; + if ((n_tokens > t0) && + (strcmp(tokens[t0], "disabled") == 0)) { + enabled = 0; + + t0 += 1; + } + + if (n_tokens != t0) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + status = pipeline_port_in_create(pipeline_name, + &p, enabled); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** + * pipeline port out + * bsz + * link txq + * | swq + * | tmgr + * | tap + * | kni + * | sink [file ] + */ +static void +cmd_pipeline_port_out(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct port_out_params p; + char *pipeline_name; + int status; + + memset(&p, 0, sizeof(p)); + + if (n_tokens < 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (strcmp(tokens[3], "out") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); + return; + } + + if (strcmp(tokens[4], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + return; + } + + if (parser_read_uint32(&p.burst_size, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); + return; + } + + if (strcmp(tokens[6], "link") == 0) { + if (n_tokens != 10) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out link"); + return; + } + + p.type = PORT_OUT_TXQ; + + p.dev_name = tokens[7]; + + if (strcmp(tokens[8], "txq") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); + return; + } + + if (parser_read_uint16(&p.txq.queue_id, tokens[9]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); + return; + } + } else if (strcmp(tokens[6], "swq") == 0) { + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out swq"); + return; + } + + p.type = PORT_OUT_SWQ; + + p.dev_name = tokens[7]; + } else if (strcmp(tokens[6], "tmgr") == 0) { + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out tmgr"); + return; + } + + p.type = PORT_OUT_TMGR; + + p.dev_name = tokens[7]; + } else if (strcmp(tokens[6], "tap") == 0) { + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out tap"); + return; + } + + p.type = PORT_OUT_TAP; + + p.dev_name = tokens[7]; + } else if (strcmp(tokens[6], "kni") == 0) { + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out kni"); + return; + } + + p.type = PORT_OUT_KNI; + + p.dev_name = tokens[7]; + } else if (strcmp(tokens[6], "sink") == 0) { + if ((n_tokens != 8) && (n_tokens != 10)) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out sink"); + return; + } + + p.type = PORT_OUT_SINK; + + p.dev_name = tokens[7]; + + if (n_tokens == 8) + p.sink.file_name = NULL; + else { + if (strcmp(tokens[8], "file") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "file"); + return; + } + + p.sink.file_name = tokens[9]; + } + + p.sink.max_n_pkts = 0; + } else { + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); + return; + } + + status = pipeline_port_out_create(pipeline_name, &p); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** + * pipeline table + * match + * acl + * ipv4 | ipv6 + * offset + * size + * | array + * offset + * size + * | hash + * ext | lru + * key + * mask + * offset + * buckets + * size + * | lpm + * ipv4 | ipv6 + * offset + * size + * | stub + * action + */ +static void +cmd_pipeline_table(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX]; + struct table_params p; + char *pipeline_name; + uint32_t t0; + int status; + + if (n_tokens < 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "table") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); + return; + } + + if (strcmp(tokens[3], "match") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); + return; + } + + t0 = 4; + if (strcmp(tokens[t0], "acl") == 0) { + if (n_tokens < t0 + 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table acl"); + return; + } + + p.match_type = TABLE_ACL; + + if (strcmp(tokens[t0 + 1], "ipv4") == 0) + p.match.acl.ip_version = 1; + else if (strcmp(tokens[t0 + 1], "ipv6") == 0) + p.match.acl.ip_version = 0; + else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "ipv4 or ipv6"); + return; + } + + if (strcmp(tokens[t0 + 2], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } + + if (parser_read_uint32(&p.match.acl.ip_header_offset, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "ip_header_offset"); + return; + } + + if (strcmp(tokens[t0 + 4], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } + + if (parser_read_uint32(&p.match.acl.n_rules, + tokens[t0 + 5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); + return; + } + + t0 += 6; + } else if (strcmp(tokens[t0], "array") == 0) { + if (n_tokens < t0 + 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table array"); + return; + } + + p.match_type = TABLE_ARRAY; + + if (strcmp(tokens[t0 + 1], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } + + if (parser_read_uint32(&p.match.array.key_offset, + tokens[t0 + 2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + return; + } + + if (strcmp(tokens[t0 + 3], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } + + if (parser_read_uint32(&p.match.array.n_keys, + tokens[t0 + 4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); + return; + } + + t0 += 5; + } else if (strcmp(tokens[t0], "hash") == 0) { + uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX; + + if (n_tokens < t0 + 12) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table hash"); + return; + } + + p.match_type = TABLE_HASH; + + if (strcmp(tokens[t0 + 1], "ext") == 0) + p.match.hash.extendable_bucket = 1; + else if (strcmp(tokens[t0 + 1], "lru") == 0) + p.match.hash.extendable_bucket = 0; + else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "ext or lru"); + return; + } + + if (strcmp(tokens[t0 + 2], "key") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); + return; + } + + if ((parser_read_uint32(&p.match.hash.key_size, + tokens[t0 + 3]) != 0) || + (p.match.hash.key_size == 0) || + (p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX)) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_size"); + return; + } + + if (strcmp(tokens[t0 + 4], "mask") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); + return; + } + + if ((parse_hex_string(tokens[t0 + 5], + key_mask, &key_mask_size) != 0) || + (key_mask_size != p.match.hash.key_size)) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); + return; + } + p.match.hash.key_mask = key_mask; + + if (strcmp(tokens[t0 + 6], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } + + if (parser_read_uint32(&p.match.hash.key_offset, + tokens[t0 + 7]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + return; + } + + if (strcmp(tokens[t0 + 8], "buckets") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); + return; + } + + if (parser_read_uint32(&p.match.hash.n_buckets, + tokens[t0 + 9]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets"); + return; + } + + if (strcmp(tokens[t0 + 10], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } + + if (parser_read_uint32(&p.match.hash.n_keys, + tokens[t0 + 11]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); + return; + } + + t0 += 12; + } else if (strcmp(tokens[t0], "lpm") == 0) { + if (n_tokens < t0 + 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table lpm"); + return; + } + + p.match_type = TABLE_LPM; + + if (strcmp(tokens[t0 + 1], "ipv4") == 0) + p.match.lpm.key_size = 4; + else if (strcmp(tokens[t0 + 1], "ipv6") == 0) + p.match.lpm.key_size = 16; + else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "ipv4 or ipv6"); + return; + } + + if (strcmp(tokens[t0 + 2], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } + + if (parser_read_uint32(&p.match.lpm.key_offset, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + return; + } + + if (strcmp(tokens[t0 + 4], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } + + if (parser_read_uint32(&p.match.lpm.n_rules, + tokens[t0 + 5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); + return; + } + + t0 += 6; + } else if (strcmp(tokens[t0], "stub") == 0) { + if (n_tokens < t0 + 1) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table stub"); + return; + } + + p.match_type = TABLE_STUB; + + t0 += 1; + } else { + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); + return; + } + + if (n_tokens >= t0 + 2) { + if (strcmp(tokens[t0], "action") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); + return; + } + + p.action_profile_name = tokens[t0 + 1]; + + t0 += 2; + } + + if (n_tokens > t0) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + status = pipeline_table_create(pipeline_name, &p); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** + * pipeline port in table + */ +static void +cmd_pipeline_port_in_table(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + char *pipeline_name; + uint32_t port_id, table_id; + int status; + + if (n_tokens != 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (strcmp(tokens[3], "in") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); + return; + } + + if (parser_read_uint32(&port_id, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + return; + } + + if (strcmp(tokens[5], "table") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); + return; + } + + if (parser_read_uint32(&table_id, tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); + return; + } + + status = pipeline_port_in_connect_to_table(pipeline_name, + port_id, + table_id); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + void cli_process(char *in, char *out, size_t out_size) { @@ -1077,6 +1823,46 @@ cli_process(char *in, char *out, size_t out_size) return; } + if (strcmp(tokens[0], "pipeline") == 0) { + if ((n_tokens >= 3) && + (strcmp(tokens[2], "period") == 0)) { + cmd_pipeline(tokens, n_tokens, out, out_size); + return; + } + + if ((n_tokens >= 5) && + (strcmp(tokens[2], "port") == 0) && + (strcmp(tokens[3], "in") == 0) && + (strcmp(tokens[4], "bsz") == 0)) { + cmd_pipeline_port_in(tokens, n_tokens, out, out_size); + return; + } + + if ((n_tokens >= 5) && + (strcmp(tokens[2], "port") == 0) && + (strcmp(tokens[3], "out") == 0) && + (strcmp(tokens[4], "bsz") == 0)) { + cmd_pipeline_port_out(tokens, n_tokens, out, out_size); + return; + } + + if ((n_tokens >= 4) && + (strcmp(tokens[2], "table") == 0) && + (strcmp(tokens[3], "match") == 0)) { + cmd_pipeline_table(tokens, n_tokens, out, out_size); + return; + } + + if ((n_tokens >= 6) && + (strcmp(tokens[2], "port") == 0) && + (strcmp(tokens[3], "in") == 0) && + (strcmp(tokens[5], "table") == 0)) { + cmd_pipeline_port_in_table(tokens, n_tokens, + out, out_size); + return; + } + } + snprintf(out, out_size, MSG_CMD_UNKNOWN, tokens[0]); } diff --git a/examples/ip_pipeline/cli.h b/examples/ip_pipeline/cli.h index 02564a6..992e4c3 100644 --- a/examples/ip_pipeline/cli.h +++ b/examples/ip_pipeline/cli.h @@ -7,8 +7,6 @@ #include -#include "action.h" - void cli_process(char *in, char *out, size_t out_size); diff --git a/examples/ip_pipeline/main.c b/examples/ip_pipeline/main.c index 24b74cf..a7f4486 100644 --- a/examples/ip_pipeline/main.c +++ b/examples/ip_pipeline/main.c @@ -15,6 +15,7 @@ #include "kni.h" #include "link.h" #include "mempool.h" +#include "pipeline.h" #include "swq.h" #include "tap.h" #include "tmgr.h" @@ -215,6 +216,13 @@ main(int argc, char **argv) return status; } + /* Pipeline */ + status = pipeline_init(); + if (status) { + printf("Error: Pipeline initialization failed (%d)\n", status); + return status; + } + /* Script */ if (app.script_name) cli_script_process(app.script_name, diff --git a/examples/ip_pipeline/meson.build b/examples/ip_pipeline/meson.build index 38a1189..ea6c704 100644 --- a/examples/ip_pipeline/meson.build +++ b/examples/ip_pipeline/meson.build @@ -16,6 +16,7 @@ sources = files( 'main.c', 'mempool.c', 'parser.c', + 'pipeline.c', 'swq.c', 'tap.c', 'tmgr.c' diff --git a/examples/ip_pipeline/pipeline.c b/examples/ip_pipeline/pipeline.c new file mode 100644 index 0000000..8efc70d --- /dev/null +++ b/examples/ip_pipeline/pipeline.c @@ -0,0 +1,930 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "kni.h" +#include "link.h" +#include "mempool.h" +#include "pipeline.h" +#include "tap.h" +#include "tmgr.h" +#include "swq.h" + +#include "hash_func.h" + +#ifndef PIPELINE_MSGQ_SIZE +#define PIPELINE_MSGQ_SIZE 64 +#endif + +#ifndef TABLE_LPM_NUMBER_TBL8 +#define TABLE_LPM_NUMBER_TBL8 256 +#endif + +static struct pipeline_list pipeline_list; + +int +pipeline_init(void) +{ + TAILQ_INIT(&pipeline_list); + + return 0; +} + +struct pipeline * +pipeline_find(const char *name) +{ + struct pipeline *pipeline; + + if (name == NULL) + return NULL; + + TAILQ_FOREACH(pipeline, &pipeline_list, node) + if (strcmp(name, pipeline->name) == 0) + return pipeline; + + return NULL; +} + +struct pipeline * +pipeline_create(const char *name, struct pipeline_params *params) +{ + char msgq_name[NAME_MAX]; + struct rte_pipeline_params pp; + struct pipeline *pipeline; + struct rte_pipeline *p; + struct rte_ring *msgq_req; + struct rte_ring *msgq_rsp; + + /* Check input params */ + if ((name == NULL) || + pipeline_find(name) || + (params == NULL) || + (params->timer_period_ms == 0)) + return NULL; + + /* Resource create */ + snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-REQ", name); + + msgq_req = rte_ring_create(msgq_name, + PIPELINE_MSGQ_SIZE, + params->cpu_id, + RING_F_SP_ENQ | RING_F_SC_DEQ); + if (msgq_req == NULL) + return NULL; + + snprintf(msgq_name, sizeof(msgq_name), "%s-MSGQ-RSP", name); + + msgq_rsp = rte_ring_create(msgq_name, + PIPELINE_MSGQ_SIZE, + params->cpu_id, + RING_F_SP_ENQ | RING_F_SC_DEQ); + if (msgq_rsp == NULL) { + rte_ring_free(msgq_req); + return NULL; + } + + pp.name = name; + pp.socket_id = (int) params->cpu_id; + pp.offset_port_id = params->offset_port_id; + + p = rte_pipeline_create(&pp); + if (p == NULL) { + rte_ring_free(msgq_rsp); + rte_ring_free(msgq_req); + return NULL; + } + + /* Node allocation */ + pipeline = calloc(1, sizeof(struct pipeline)); + if (pipeline == NULL) { + rte_pipeline_free(p); + rte_ring_free(msgq_rsp); + rte_ring_free(msgq_req); + return NULL; + } + + /* Node fill in */ + strncpy(pipeline->name, name, sizeof(pipeline->name)); + pipeline->p = p; + pipeline->n_ports_in = 0; + pipeline->n_ports_out = 0; + pipeline->n_tables = 0; + pipeline->msgq_req = msgq_req; + pipeline->msgq_rsp = msgq_rsp; + pipeline->timer_period_ms = params->timer_period_ms; + pipeline->enabled = 0; + pipeline->cpu_id = params->cpu_id; + + /* Node add to list */ + TAILQ_INSERT_TAIL(&pipeline_list, pipeline, node); + + return pipeline; +} + +int +pipeline_port_in_create(const char *pipeline_name, + struct port_in_params *params, + int enabled) +{ + struct rte_pipeline_port_in_params p; + + union { + struct rte_port_ethdev_reader_params ethdev; + struct rte_port_ring_reader_params ring; + struct rte_port_sched_reader_params sched; + struct rte_port_fd_reader_params fd; + struct rte_port_kni_reader_params kni; + struct rte_port_source_params source; + } pp; + + struct pipeline *pipeline; + uint32_t port_id; + int status; + + memset(&pp, 0, sizeof(pp)); + + /* Check input params */ + if ((pipeline_name == NULL) || + (params == NULL) || + (params->burst_size == 0) || + (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) + return -1; + + pipeline = pipeline_find(pipeline_name); + if (pipeline == NULL) + return -1; + + switch (params->type) { + case PORT_IN_RXQ: + { + struct link *link; + + link = link_find(params->dev_name); + if (link == NULL) + return -1; + + if (params->rxq.queue_id >= link->n_rxq) + return -1; + + pp.ethdev.port_id = link->port_id; + pp.ethdev.queue_id = params->rxq.queue_id; + + p.ops = &rte_port_ethdev_reader_ops; + p.arg_create = &pp.ethdev; + break; + } + + case PORT_IN_SWQ: + { + struct swq *swq; + + swq = swq_find(params->dev_name); + if (swq == NULL) + return -1; + + pp.ring.ring = swq->r; + + p.ops = &rte_port_ring_reader_ops; + p.arg_create = &pp.ring; + break; + } + + case PORT_IN_TMGR: + { + struct tmgr_port *tmgr_port; + + tmgr_port = tmgr_port_find(params->dev_name); + if (tmgr_port == NULL) + return -1; + + pp.sched.sched = tmgr_port->s; + + p.ops = &rte_port_sched_reader_ops; + p.arg_create = &pp.sched; + break; + } + + case PORT_IN_TAP: + { + struct tap *tap; + struct mempool *mempool; + + tap = tap_find(params->dev_name); + mempool = mempool_find(params->tap.mempool_name); + if ((tap == NULL) || (mempool == NULL)) + return -1; + + pp.fd.fd = tap->fd; + pp.fd.mempool = mempool->m; + pp.fd.mtu = params->tap.mtu; + + p.ops = &rte_port_fd_reader_ops; + p.arg_create = &pp.fd; + break; + } + + case PORT_IN_KNI: + { + struct kni *kni; + + kni = kni_find(params->dev_name); + if (kni == NULL) + return -1; + + pp.kni.kni = kni->k; + + p.ops = &rte_port_kni_reader_ops; + p.arg_create = &pp.kni; + break; + } + + case PORT_IN_SOURCE: + { + struct mempool *mempool; + + mempool = mempool_find(params->source.mempool_name); + if (mempool == NULL) + return -1; + + pp.source.mempool = mempool->m; + pp.source.file_name = params->source.file_name; + pp.source.n_bytes_per_pkt = params->source.n_bytes_per_pkt; + + p.ops = &rte_port_source_ops; + p.arg_create = &pp.source; + break; + } + + default: + return -1; + } + + p.f_action = NULL; + p.arg_ah = NULL; + p.burst_size = params->burst_size; + + /* Resource create */ + status = rte_pipeline_port_in_create(pipeline->p, + &p, + &port_id); + + if (status) + return -1; + + if (enabled) + rte_pipeline_port_in_enable(pipeline->p, port_id); + + /* Pipeline */ + pipeline->n_ports_in++; + + return 0; +} + +int +pipeline_port_in_connect_to_table(const char *pipeline_name, + uint32_t port_id, + uint32_t table_id) +{ + struct pipeline *pipeline; + int status; + + /* Check input params */ + if (pipeline_name == NULL) + return -1; + + pipeline = pipeline_find(pipeline_name); + if ((pipeline == NULL) || + (port_id >= pipeline->n_ports_in) || + (table_id >= pipeline->n_tables)) + return -1; + + /* Resource */ + status = rte_pipeline_port_in_connect_to_table(pipeline->p, + port_id, + table_id); + + return status; + +} + +int +pipeline_port_out_create(const char *pipeline_name, + struct port_out_params *params) +{ + struct rte_pipeline_port_out_params p; + + union { + struct rte_port_ethdev_writer_params ethdev; + struct rte_port_ring_writer_params ring; + struct rte_port_sched_writer_params sched; + struct rte_port_fd_writer_params fd; + struct rte_port_kni_writer_params kni; + struct rte_port_sink_params sink; + } pp; + + union { + struct rte_port_ethdev_writer_nodrop_params ethdev; + struct rte_port_ring_writer_nodrop_params ring; + struct rte_port_fd_writer_nodrop_params fd; + struct rte_port_kni_writer_nodrop_params kni; + } pp_nodrop; + + struct pipeline *pipeline; + uint32_t port_id; + int status; + + memset(&pp, 0, sizeof(pp)); + memset(&pp_nodrop, 0, sizeof(pp_nodrop)); + + /* Check input params */ + if ((pipeline_name == NULL) || + (params == NULL) || + (params->burst_size == 0) || + (params->burst_size > RTE_PORT_IN_BURST_SIZE_MAX)) + return -1; + + pipeline = pipeline_find(pipeline_name); + if (pipeline == NULL) + return -1; + + switch (params->type) { + case PORT_OUT_TXQ: + { + struct link *link; + + link = link_find(params->dev_name); + if (link == NULL) + return -1; + + if (params->txq.queue_id >= link->n_txq) + return -1; + + pp.ethdev.port_id = link->port_id; + pp.ethdev.queue_id = params->txq.queue_id; + pp.ethdev.tx_burst_sz = params->burst_size; + + pp_nodrop.ethdev.port_id = link->port_id; + pp_nodrop.ethdev.queue_id = params->txq.queue_id; + pp_nodrop.ethdev.tx_burst_sz = params->burst_size; + pp_nodrop.ethdev.n_retries = params->n_retries; + + if (params->retry == 0) { + p.ops = &rte_port_ethdev_writer_ops; + p.arg_create = &pp.ethdev; + } else { + p.ops = &rte_port_ethdev_writer_nodrop_ops; + p.arg_create = &pp_nodrop.ethdev; + } + break; + } + + case PORT_OUT_SWQ: + { + struct swq *swq; + + swq = swq_find(params->dev_name); + if (swq == NULL) + return -1; + + pp.ring.ring = swq->r; + pp.ring.tx_burst_sz = params->burst_size; + + pp_nodrop.ring.ring = swq->r; + pp_nodrop.ring.tx_burst_sz = params->burst_size; + pp_nodrop.ring.n_retries = params->n_retries; + + if (params->retry == 0) { + p.ops = &rte_port_ring_writer_ops; + p.arg_create = &pp.ring; + } else { + p.ops = &rte_port_ring_writer_nodrop_ops; + p.arg_create = &pp_nodrop.ring; + } + break; + } + + case PORT_OUT_TMGR: + { + struct tmgr_port *tmgr_port; + + tmgr_port = tmgr_port_find(params->dev_name); + if (tmgr_port == NULL) + return -1; + + pp.sched.sched = tmgr_port->s; + pp.sched.tx_burst_sz = params->burst_size; + + p.ops = &rte_port_sched_writer_ops; + p.arg_create = &pp.sched; + break; + } + + case PORT_OUT_TAP: + { + struct tap *tap; + + tap = tap_find(params->dev_name); + if (tap == NULL) + return -1; + + pp.fd.fd = tap->fd; + pp.fd.tx_burst_sz = params->burst_size; + + pp_nodrop.fd.fd = tap->fd; + pp_nodrop.fd.tx_burst_sz = params->burst_size; + pp_nodrop.fd.n_retries = params->n_retries; + + if (params->retry == 0) { + p.ops = &rte_port_fd_writer_ops; + p.arg_create = &pp.fd; + } else { + p.ops = &rte_port_fd_writer_nodrop_ops; + p.arg_create = &pp_nodrop.fd; + } + break; + } + + case PORT_OUT_KNI: + { + struct kni *kni; + + kni = kni_find(params->dev_name); + if (kni == NULL) + return -1; + + pp.kni.kni = kni->k; + pp.kni.tx_burst_sz = params->burst_size; + + pp_nodrop.kni.kni = kni->k; + pp_nodrop.kni.tx_burst_sz = params->burst_size; + pp_nodrop.kni.n_retries = params->n_retries; + + if (params->retry == 0) { + p.ops = &rte_port_kni_writer_ops; + p.arg_create = &pp.kni; + } else { + p.ops = &rte_port_kni_writer_nodrop_ops; + p.arg_create = &pp_nodrop.kni; + } + break; + } + + case PORT_OUT_SINK: + { + pp.sink.file_name = params->sink.file_name; + pp.sink.max_n_pkts = params->sink.max_n_pkts; + + p.ops = &rte_port_sink_ops; + p.arg_create = &pp.sink; + break; + } + + default: + return -1; + } + + p.f_action = NULL; + p.arg_ah = NULL; + + /* Resource create */ + status = rte_pipeline_port_out_create(pipeline->p, + &p, + &port_id); + + if (status) + return -1; + + /* Pipeline */ + pipeline->n_ports_out++; + + return 0; +} + +static const struct rte_acl_field_def table_acl_field_format_ipv4[] = { + /* Protocol */ + [0] = { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = 0, + .input_index = 0, + .offset = offsetof(struct ipv4_hdr, next_proto_id), + }, + + /* Source IP address (IPv4) */ + [1] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 1, + .input_index = 1, + .offset = offsetof(struct ipv4_hdr, src_addr), + }, + + /* Destination IP address (IPv4) */ + [2] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 2, + .input_index = 2, + .offset = offsetof(struct ipv4_hdr, dst_addr), + }, + + /* Source Port */ + [3] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 3, + .input_index = 3, + .offset = sizeof(struct ipv4_hdr) + + offsetof(struct tcp_hdr, src_port), + }, + + /* Destination Port */ + [4] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 4, + .input_index = 3, + .offset = sizeof(struct ipv4_hdr) + + offsetof(struct tcp_hdr, dst_port), + }, +}; + +static const struct rte_acl_field_def table_acl_field_format_ipv6[] = { + /* Protocol */ + [0] = { + .type = RTE_ACL_FIELD_TYPE_BITMASK, + .size = sizeof(uint8_t), + .field_index = 0, + .input_index = 0, + .offset = offsetof(struct ipv6_hdr, proto), + }, + + /* Source IP address (IPv6) */ + [1] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 1, + .input_index = 1, + .offset = offsetof(struct ipv6_hdr, src_addr[0]), + }, + + [2] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 2, + .input_index = 2, + .offset = offsetof(struct ipv6_hdr, src_addr[4]), + }, + + [3] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 3, + .input_index = 3, + .offset = offsetof(struct ipv6_hdr, src_addr[8]), + }, + + [4] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 4, + .input_index = 4, + .offset = offsetof(struct ipv6_hdr, src_addr[12]), + }, + + /* Destination IP address (IPv6) */ + [5] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 5, + .input_index = 5, + .offset = offsetof(struct ipv6_hdr, dst_addr[0]), + }, + + [6] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 6, + .input_index = 6, + .offset = offsetof(struct ipv6_hdr, dst_addr[4]), + }, + + [7] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 7, + .input_index = 7, + .offset = offsetof(struct ipv6_hdr, dst_addr[8]), + }, + + [8] = { + .type = RTE_ACL_FIELD_TYPE_MASK, + .size = sizeof(uint32_t), + .field_index = 8, + .input_index = 8, + .offset = offsetof(struct ipv6_hdr, dst_addr[12]), + }, + + /* Source Port */ + [9] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 9, + .input_index = 9, + .offset = sizeof(struct ipv6_hdr) + + offsetof(struct tcp_hdr, src_port), + }, + + /* Destination Port */ + [10] = { + .type = RTE_ACL_FIELD_TYPE_RANGE, + .size = sizeof(uint16_t), + .field_index = 10, + .input_index = 9, + .offset = sizeof(struct ipv6_hdr) + + offsetof(struct tcp_hdr, dst_port), + }, +}; + +int +pipeline_table_create(const char *pipeline_name, + struct table_params *params) +{ + char name[NAME_MAX]; + struct rte_pipeline_table_params p; + + union { + struct rte_table_acl_params acl; + struct rte_table_array_params array; + struct rte_table_hash_params hash; + struct rte_table_lpm_params lpm; + struct rte_table_lpm_ipv6_params lpm_ipv6; + } pp; + + struct pipeline *pipeline; + struct table *table; + struct table_action_profile *ap; + struct rte_table_action *action; + uint32_t table_id; + int status; + + memset(&p, 0, sizeof(p)); + memset(&pp, 0, sizeof(pp)); + + /* Check input params */ + if ((pipeline_name == NULL) || + (params == NULL) || + (params->action_profile_name == NULL)) + return -1; + + pipeline = pipeline_find(pipeline_name); + if ((pipeline == NULL) || + (pipeline->n_tables >= PIPELINE_TABLE_MAX)) + return -1; + + ap = table_action_profile_find(params->action_profile_name); + if (ap == NULL) + return -1; + + snprintf(name, NAME_MAX, "%s_table%u", + pipeline_name, pipeline->n_tables); + + switch (params->match_type) { + case TABLE_ACL: + { + uint32_t ip_header_offset = params->match.acl.ip_header_offset - + (sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM); + uint32_t i; + + if (params->match.acl.n_rules == 0) + return -1; + + pp.acl.name = name; + pp.acl.n_rules = params->match.acl.n_rules; + if (params->match.acl.ip_version) { + memcpy(&pp.acl.field_format, + &table_acl_field_format_ipv4, + sizeof(table_acl_field_format_ipv4)); + pp.acl.n_rule_fields = + RTE_DIM(table_acl_field_format_ipv4); + } else { + memcpy(&pp.acl.field_format, + &table_acl_field_format_ipv6, + sizeof(table_acl_field_format_ipv6)); + pp.acl.n_rule_fields = + RTE_DIM(table_acl_field_format_ipv6); + } + + for (i = 0; i < pp.acl.n_rule_fields; i++) + pp.acl.field_format[i].offset += ip_header_offset; + + p.ops = &rte_table_acl_ops; + p.arg_create = &pp.acl; + break; + } + + case TABLE_ARRAY: + { + if (params->match.array.n_keys == 0) + return -1; + + pp.array.n_entries = params->match.array.n_keys; + pp.array.offset = params->match.array.key_offset; + + p.ops = &rte_table_array_ops; + p.arg_create = &pp.array; + break; + } + + case TABLE_HASH: + { + struct rte_table_ops *ops; + rte_table_hash_op_hash f_hash; + + if (params->match.hash.n_keys == 0) + return -1; + + switch (params->match.hash.key_size) { + case 8: + f_hash = hash_default_key8; + break; + case 16: + f_hash = hash_default_key16; + break; + case 24: + f_hash = hash_default_key24; + break; + case 32: + f_hash = hash_default_key32; + break; + case 40: + f_hash = hash_default_key40; + break; + case 48: + f_hash = hash_default_key48; + break; + case 56: + f_hash = hash_default_key56; + break; + case 64: + f_hash = hash_default_key64; + break; + default: + return -1; + } + + pp.hash.name = name; + pp.hash.key_size = params->match.hash.key_size; + pp.hash.key_offset = params->match.hash.key_offset; + pp.hash.key_mask = params->match.hash.key_mask; + pp.hash.n_keys = params->match.hash.n_keys; + pp.hash.n_buckets = params->match.hash.n_buckets; + pp.hash.f_hash = f_hash; + pp.hash.seed = 0; + + if (params->match.hash.extendable_bucket) + switch (params->match.hash.key_size) { + case 8: + ops = &rte_table_hash_key8_ext_ops; + break; + case 16: + ops = &rte_table_hash_key16_ext_ops; + break; + default: + ops = &rte_table_hash_ext_ops; + } + else + switch (params->match.hash.key_size) { + case 8: + ops = &rte_table_hash_key8_lru_ops; + break; + case 16: + ops = &rte_table_hash_key16_lru_ops; + break; + default: + ops = &rte_table_hash_lru_ops; + } + + p.ops = ops; + p.arg_create = &pp.hash; + break; + } + + case TABLE_LPM: + { + if (params->match.lpm.n_rules == 0) + return -1; + + switch (params->match.lpm.key_size) { + case 4: + { + pp.lpm.name = name; + pp.lpm.n_rules = params->match.lpm.n_rules; + pp.lpm.number_tbl8s = TABLE_LPM_NUMBER_TBL8; + pp.lpm.flags = 0; + pp.lpm.entry_unique_size = p.action_data_size + + sizeof(struct rte_pipeline_table_entry); + pp.lpm.offset = params->match.lpm.key_offset; + + p.ops = &rte_table_lpm_ops; + p.arg_create = &pp.lpm; + break; + } + + case 16: + { + pp.lpm_ipv6.name = name; + pp.lpm_ipv6.n_rules = params->match.lpm.n_rules; + pp.lpm_ipv6.number_tbl8s = TABLE_LPM_NUMBER_TBL8; + pp.lpm_ipv6.entry_unique_size = p.action_data_size + + sizeof(struct rte_pipeline_table_entry); + pp.lpm_ipv6.offset = params->match.lpm.key_offset; + + p.ops = &rte_table_lpm_ipv6_ops; + p.arg_create = &pp.lpm_ipv6; + break; + } + + default: + return -1; + } + + break; + } + + case TABLE_STUB: + { + p.ops = &rte_table_stub_ops; + p.arg_create = NULL; + break; + } + + default: + return -1; + } + + /* Resource create */ + action = rte_table_action_create(ap->ap, + pipeline->cpu_id); + if (action == NULL) + return -1; + + status = rte_table_action_table_params_get( + action, + &p); + if (status || + ((p.action_data_size + + sizeof(struct rte_pipeline_table_entry)) > + TABLE_RULE_ACTION_SIZE_MAX)) { + rte_table_action_free(action); + return -1; + } + + if (params->match_type == TABLE_LPM) { + if (params->match.lpm.key_size == 4) + pp.lpm.entry_unique_size = p.action_data_size + + sizeof(struct rte_pipeline_table_entry); + + if (params->match.lpm.key_size == 16) + pp.lpm_ipv6.entry_unique_size = p.action_data_size + + sizeof(struct rte_pipeline_table_entry); + } + + status = rte_pipeline_table_create(pipeline->p, + &p, + &table_id); + if (status) { + rte_table_action_free(action); + return -1; + } + + /* Pipeline */ + table = &pipeline->table[pipeline->n_tables]; + memcpy(&table->params, params, sizeof(*params)); + table->ap = ap; + table->a = action; + pipeline->n_tables++; + + return 0; +} diff --git a/examples/ip_pipeline/pipeline.h b/examples/ip_pipeline/pipeline.h new file mode 100644 index 0000000..dbc6f77 --- /dev/null +++ b/examples/ip_pipeline/pipeline.h @@ -0,0 +1,265 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2018 Intel Corporation + */ + +#ifndef _INCLUDE_PIPELINE_H_ +#define _INCLUDE_PIPELINE_H_ + +#include +#include + +#include +#include + +#include "common.h" +#include "action.h" + +struct pipeline_params { + uint32_t timer_period_ms; + uint32_t offset_port_id; + uint32_t cpu_id; +}; + +enum port_in_type { + PORT_IN_RXQ, + PORT_IN_SWQ, + PORT_IN_TMGR, + PORT_IN_TAP, + PORT_IN_KNI, + PORT_IN_SOURCE, +}; + +struct port_in_params { + enum port_in_type type; + const char *dev_name; + union { + struct { + uint16_t queue_id; + } rxq; + + struct { + const char *mempool_name; + uint32_t mtu; + } tap; + + struct { + const char *mempool_name; + const char *file_name; + uint32_t n_bytes_per_pkt; + } source; + }; + uint32_t burst_size; +}; + +enum port_out_type { + PORT_OUT_TXQ, + PORT_OUT_SWQ, + PORT_OUT_TMGR, + PORT_OUT_TAP, + PORT_OUT_KNI, + PORT_OUT_SINK, +}; + +struct port_out_params { + enum port_out_type type; + const char *dev_name; + union { + struct { + uint16_t queue_id; + } txq; + + struct { + const char *file_name; + uint32_t max_n_pkts; + } sink; + }; + uint32_t burst_size; + int retry; + uint32_t n_retries; +}; + +enum table_type { + TABLE_ACL, + TABLE_ARRAY, + TABLE_HASH, + TABLE_LPM, + TABLE_STUB, +}; + +struct table_acl_params { + uint32_t n_rules; + uint32_t ip_header_offset; + int ip_version; +}; + +struct table_array_params { + uint32_t n_keys; + uint32_t key_offset; +}; + +struct table_hash_params { + uint32_t n_keys; + uint32_t key_offset; + uint32_t key_size; + uint8_t *key_mask; + uint32_t n_buckets; + int extendable_bucket; +}; + +struct table_lpm_params { + uint32_t n_rules; + uint32_t key_offset; + uint32_t key_size; +}; + +struct table_params { + /* Match */ + enum table_type match_type; + union { + struct table_acl_params acl; + struct table_array_params array; + struct table_hash_params hash; + struct table_lpm_params lpm; + } match; + + /* Action */ + const char *action_profile_name; +}; + +struct table { + struct table_params params; + struct table_action_profile *ap; + struct rte_table_action *a; +}; + +#ifndef PIPELINE_TABLE_MAX +#define PIPELINE_TABLE_MAX 256 +#endif + +struct pipeline { + TAILQ_ENTRY(pipeline) node; + char name[NAME_SIZE]; + + struct rte_pipeline *p; + struct table table[PIPELINE_TABLE_MAX]; + uint32_t n_ports_in; + uint32_t n_ports_out; + uint32_t n_tables; + + struct rte_ring *msgq_req; + struct rte_ring *msgq_rsp; + uint32_t timer_period_ms; + + int enabled; + uint32_t thread_id; + uint32_t cpu_id; +}; + +TAILQ_HEAD(pipeline_list, pipeline); + +int +pipeline_init(void); + +struct pipeline * +pipeline_find(const char *name); + +struct pipeline * +pipeline_create(const char *name, struct pipeline_params *params); + +int +pipeline_port_in_create(const char *pipeline_name, + struct port_in_params *params, + int enabled); + +int +pipeline_port_in_connect_to_table(const char *pipeline_name, + uint32_t port_id, + uint32_t table_id); + +int +pipeline_port_out_create(const char *pipeline_name, + struct port_out_params *params); + +int +pipeline_table_create(const char *pipeline_name, + struct table_params *params); + +struct table_rule_match_acl { + int ip_version; + + RTE_STD_C11 + union { + struct { + uint32_t sa; + uint32_t da; + } ipv4; + + struct { + uint8_t sa[16]; + uint8_t da[16]; + } ipv6; + }; + + uint32_t sa_depth; + uint32_t da_depth; + uint16_t sp0; + uint16_t sp1; + uint16_t dp0; + uint16_t dp1; + uint8_t proto; + uint8_t proto_mask; + uint32_t priority; +}; + +struct table_rule_match_array { + uint32_t pos; +}; + +#ifndef TABLE_RULE_MATCH_SIZE_MAX +#define TABLE_RULE_MATCH_SIZE_MAX 256 +#endif + +#ifndef TABLE_RULE_ACTION_SIZE_MAX +#define TABLE_RULE_ACTION_SIZE_MAX 2048 +#endif + +struct table_rule_match_hash { + uint8_t key[TABLE_RULE_MATCH_SIZE_MAX]; +}; + +struct table_rule_match_lpm { + int ip_version; + + RTE_STD_C11 + union { + uint32_t ipv4; + uint8_t ipv6[16]; + }; + + uint8_t depth; +}; + +struct table_rule_match { + enum table_type match_type; + + union { + struct table_rule_match_acl acl; + struct table_rule_match_array array; + struct table_rule_match_hash hash; + struct table_rule_match_lpm lpm; + } match; +}; + +struct table_rule_action { + uint64_t action_mask; + struct rte_table_action_fwd_params fwd; + struct rte_table_action_mtr_params mtr; + struct rte_table_action_tm_params tm; + struct rte_table_action_encap_params encap; + struct rte_table_action_nat_params nat; + struct rte_table_action_ttl_params ttl; + struct rte_table_action_stats_params stats; + struct rte_table_action_time_params time; +}; + +#endif /* _INCLUDE_PIPELINE_H_ */