From patchwork Wed Sep 23 18:06:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Dumitrescu X-Patchwork-Id: 78611 X-Patchwork-Delegate: david.marchand@redhat.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 65E0FA04B1; Wed, 23 Sep 2020 20:12:03 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id F366C1DD5C; Wed, 23 Sep 2020 20:08:21 +0200 (CEST) Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by dpdk.org (Postfix) with ESMTP id 8D09B1DCA7 for ; Wed, 23 Sep 2020 20:07:23 +0200 (CEST) IronPort-SDR: GlBHrxclVP9SGaJZOCZLY+oWnQ4gE8VIMbPz8a5XBZvhKXNa8+UyadL6j4hEelLFqTK4djC6u3 T3E5SK1oWCew== X-IronPort-AV: E=McAfee;i="6000,8403,9753"; a="245809573" X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="245809573" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Sep 2020 11:07:23 -0700 IronPort-SDR: rR4wwN9tfIJ/K7DtkLBMLxC3wdWGFkz/Qv2NQ/Zzt4nM4VGhdh0ismH3ahVecpkuDR4uFpA2mW lSd9LNBhYyNg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.77,293,1596524400"; d="scan'208";a="305477949" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by orsmga003.jf.intel.com with ESMTP; 23 Sep 2020 11:07:21 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Cc: thomas@monjalon.net, david.marchand@redhat.com Date: Wed, 23 Sep 2020 19:06:33 +0100 Message-Id: <20200923180645.55852-30-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200923180645.55852-1-cristian.dumitrescu@intel.com> References: <20200910152645.9342-2-cristian.dumitrescu@intel.com> <20200923180645.55852-1-cristian.dumitrescu@intel.com> Subject: [dpdk-dev] [PATCH v5 29/41] pipeline: add SWX pipeline query API 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" Query API to be used by the control plane to detect the configuration and state of the SWX pipeline and its internal objects. Signed-off-by: Cristian Dumitrescu --- lib/librte_pipeline/rte_pipeline_version.map | 10 + lib/librte_pipeline/rte_swx_ctl.h | 313 +++++++++++++++++++ lib/librte_pipeline/rte_swx_pipeline.c | 219 +++++++++++++ 3 files changed, 542 insertions(+) diff --git a/lib/librte_pipeline/rte_pipeline_version.map b/lib/librte_pipeline/rte_pipeline_version.map index 793957eb9..bb992fdd0 100644 --- a/lib/librte_pipeline/rte_pipeline_version.map +++ b/lib/librte_pipeline/rte_pipeline_version.map @@ -76,4 +76,14 @@ EXPERIMENTAL { rte_swx_pipeline_run; rte_swx_pipeline_table_state_get; rte_swx_pipeline_table_state_set; + rte_swx_ctl_pipeline_info_get; + rte_swx_ctl_pipeline_numa_node_get; + rte_swx_ctl_pipeline_port_in_stats_read; + rte_swx_ctl_pipeline_port_out_stats_read; + rte_swx_ctl_action_info_get; + rte_swx_ctl_action_arg_info_get; + rte_swx_ctl_table_info_get; + rte_swx_ctl_table_match_field_info_get; + rte_swx_ctl_table_action_info_get; + rte_swx_ctl_table_ops_get; }; diff --git a/lib/librte_pipeline/rte_swx_ctl.h b/lib/librte_pipeline/rte_swx_ctl.h index c824ab56f..344c7c833 100644 --- a/lib/librte_pipeline/rte_swx_ctl.h +++ b/lib/librte_pipeline/rte_swx_ctl.h @@ -18,8 +18,321 @@ extern "C" { #include +#include "rte_swx_port.h" #include "rte_swx_table.h" +struct rte_swx_pipeline; + +/** Name size. */ +#ifndef RTE_SWX_CTL_NAME_SIZE +#define RTE_SWX_CTL_NAME_SIZE 64 +#endif + +/* + * Pipeline Query API. + */ + +/** Pipeline info. */ +struct rte_swx_ctl_pipeline_info { + /** Number of input ports. */ + uint32_t n_ports_in; + + /** Number of input ports. */ + uint32_t n_ports_out; + + /** Number of actions. */ + uint32_t n_actions; + + /** Number of tables. */ + uint32_t n_tables; +}; + +/** + * Pipeline info get + * + * @param[in] p + * Pipeline handle. + * @param[out] pipeline + * Pipeline info. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p, + struct rte_swx_ctl_pipeline_info *pipeline); + +/** + * Pipeline NUMA node get + * + * @param[in] p + * Pipeline handle. + * @param[out] numa_node + * Pipeline NUMA node. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, + int *numa_node); + +/* + * Ports Query API. + */ + +/** + * Input port statistics counters read + * + * @param[in] p + * Pipeline handle. + * @param[in] port_id + * Port ID (0 .. *n_ports_in* - 1). + * @param[out] stats + * Input port stats. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p, + uint32_t port_id, + struct rte_swx_port_in_stats *stats); + +/** + * Output port statistics counters read + * + * @param[in] p + * Pipeline handle. + * @param[in] port_id + * Port ID (0 .. *n_ports_out* - 1). + * @param[out] stats + * Output port stats. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p, + uint32_t port_id, + struct rte_swx_port_out_stats *stats); + +/* + * Action Query API. + */ + +/** Action info. */ +struct rte_swx_ctl_action_info { + /** Action name. */ + char name[RTE_SWX_CTL_NAME_SIZE]; + + /** Number of action arguments. */ + uint32_t n_args; +}; + +/** + * Action info get + * + * @param[in] p + * Pipeline handle. + * @param[in] action_id + * Action ID (0 .. *n_actions* - 1). + * @param[out] action + * Action info. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p, + uint32_t action_id, + struct rte_swx_ctl_action_info *action); + +/** Action argument info. */ +struct rte_swx_ctl_action_arg_info { + /** Action argument name. */ + char name[RTE_SWX_CTL_NAME_SIZE]; + + /** Action argument size (in bits). */ + uint32_t n_bits; +}; + +/** + * Action argument info get + * + * @param[in] p + * Pipeline handle. + * @param[in] action_id + * Action ID (0 .. *n_actions* - 1). + * @param[in] action_arg_id + * Action ID (0 .. *n_args* - 1). + * @param[out] action + * Action argument info. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p, + uint32_t action_id, + uint32_t action_arg_id, + struct rte_swx_ctl_action_arg_info *action_arg); + +/* + * Table Query API. + */ + +/** Table info. */ +struct rte_swx_ctl_table_info { + /** Table name. */ + char name[RTE_SWX_CTL_NAME_SIZE]; + + /** Table creation arguments. */ + char args[RTE_SWX_CTL_NAME_SIZE]; + + /** Number of match fields. */ + uint32_t n_match_fields; + + /** Number of actions. */ + uint32_t n_actions; + + /** Non-zero (true) when the default action is constant, therefore it + * cannot be changed; zero (false) when the default action not constant, + * therefore it can be changed. + */ + int default_action_is_const; + + /** Table size parameter. */ + uint32_t size; +}; + +/** + * Table info get + * + * @param[in] p + * Pipeline handle. + * @param[in] table_id + * Table ID (0 .. *n_tables* - 1). + * @param[out] table + * Table info. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p, + uint32_t table_id, + struct rte_swx_ctl_table_info *table); + +/** Table match field info. + * + * If (n_bits, offset) are known for all the match fields of the table, then the + * table (key_offset, key_size, key_mask0) can be computed. + */ +struct rte_swx_ctl_table_match_field_info { + /** Match type of the current match field. */ + enum rte_swx_table_match_type match_type; + + /** Non-zero (true) when the current match field is part of a registered + * header, zero (false) when it is part of the registered meta-data. + */ + int is_header; + + /** Match field size (in bits). */ + uint32_t n_bits; + + /** Match field offset within its parent struct (one of the headers or + * the meta-data). + */ + uint32_t offset; +}; + +/** + * Table match field info get + * + * @param[in] p + * Pipeline handle. + * @param[in] table_id + * Table ID (0 .. *n_tables*). + * @param[in] match_field_id + * Match field ID (0 .. *n_match_fields* - 1). + * @param[out] match_field + * Table match field info. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p, + uint32_t table_id, + uint32_t match_field_id, + struct rte_swx_ctl_table_match_field_info *match_field); + +/** Table action info. */ +struct rte_swx_ctl_table_action_info { + /** Action ID. */ + uint32_t action_id; +}; + +/** + * Table action info get + * + * @param[in] p + * Pipeline handle. + * @param[in] table_id + * Table ID (0 .. *n_tables*). + * @param[in] table_action_id + * Action index within the set of table actions (0 .. table n_actions - 1). + * Not to be confused with the action ID, which works at the pipeline level + * (0 .. pipeline n_actions - 1), which is precisely what this function + * returns as part of *table_action*. + * @param[out] table_action + * Table action info. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p, + uint32_t table_id, + uint32_t table_action_id, + struct rte_swx_ctl_table_action_info *table_action); + +/** + * Table operations get + * + * @param[in] p + * Pipeline handle. + * @param[in] table_id + * Table ID (0 .. *n_tables*). + * @param[out] table_ops + * Table operations. Only valid when function returns success and *is_stub* is + * zero (false). + * @param[out] is_stub + * A stub table is a table with no match fields. No "regular" table entries + * (i.e. entries other than the default entry) can be added to such a table, + * therefore the lookup operation always results in lookup miss. Non-zero + * (true) when the current table is a stub table, zero (false) otherwise. + * @return + * 0 on success or the following error codes otherwise: + * -EINVAL: Invalid argument. + */ +__rte_experimental +int +rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p, + uint32_t table_id, + struct rte_swx_table_ops *table_ops, + int *is_stub); + /* * Table Update API. */ diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c index 77eae1927..da69bab49 100644 --- a/lib/librte_pipeline/rte_swx_pipeline.c +++ b/lib/librte_pipeline/rte_swx_pipeline.c @@ -6152,6 +6152,18 @@ action_find(struct rte_swx_pipeline *p, const char *name) return NULL; } +static struct action * +action_find_by_id(struct rte_swx_pipeline *p, uint32_t id) +{ + struct action *action = NULL; + + TAILQ_FOREACH(action, &p->actions, node) + if (action->id == id) + return action; + + return NULL; +} + static struct field * action_field_find(struct action *a, const char *name) { @@ -6942,6 +6954,177 @@ rte_swx_pipeline_run(struct rte_swx_pipeline *p, uint32_t n_instructions) /* * Control. */ +int +rte_swx_ctl_pipeline_info_get(struct rte_swx_pipeline *p, + struct rte_swx_ctl_pipeline_info *pipeline) +{ + struct action *action; + struct table *table; + uint32_t n_actions = 0, n_tables = 0; + + if (!p || !pipeline) + return -EINVAL; + + TAILQ_FOREACH(action, &p->actions, node) + n_actions++; + + TAILQ_FOREACH(table, &p->tables, node) + n_tables++; + + pipeline->n_ports_in = p->n_ports_in; + pipeline->n_ports_out = p->n_ports_out; + pipeline->n_actions = n_actions; + pipeline->n_tables = n_tables; + + return 0; +} + +int +rte_swx_ctl_pipeline_numa_node_get(struct rte_swx_pipeline *p, int *numa_node) +{ + if (!p || !numa_node) + return -EINVAL; + + *numa_node = p->numa_node; + return 0; +} + +int +rte_swx_ctl_action_info_get(struct rte_swx_pipeline *p, + uint32_t action_id, + struct rte_swx_ctl_action_info *action) +{ + struct action *a = NULL; + + if (!p || (action_id >= p->n_actions) || !action) + return -EINVAL; + + a = action_find_by_id(p, action_id); + if (!a) + return -EINVAL; + + strcpy(action->name, a->name); + action->n_args = a->st ? a->st->n_fields : 0; + return 0; +} + +int +rte_swx_ctl_action_arg_info_get(struct rte_swx_pipeline *p, + uint32_t action_id, + uint32_t action_arg_id, + struct rte_swx_ctl_action_arg_info *action_arg) +{ + struct action *a = NULL; + struct field *arg = NULL; + + if (!p || (action_id >= p->n_actions) || !action_arg) + return -EINVAL; + + a = action_find_by_id(p, action_id); + if (!a || !a->st || (action_arg_id >= a->st->n_fields)) + return -EINVAL; + + arg = &a->st->fields[action_arg_id]; + strcpy(action_arg->name, arg->name); + action_arg->n_bits = arg->n_bits; + + return 0; +} + +int +rte_swx_ctl_table_info_get(struct rte_swx_pipeline *p, + uint32_t table_id, + struct rte_swx_ctl_table_info *table) +{ + struct table *t = NULL; + + if (!p || !table) + return -EINVAL; + + t = table_find_by_id(p, table_id); + if (!t) + return -EINVAL; + + strcpy(table->name, t->name); + strcpy(table->args, t->args); + table->n_match_fields = t->n_fields; + table->n_actions = t->n_actions; + table->default_action_is_const = t->default_action_is_const; + table->size = t->size; + return 0; +} + +int +rte_swx_ctl_table_match_field_info_get(struct rte_swx_pipeline *p, + uint32_t table_id, + uint32_t match_field_id, + struct rte_swx_ctl_table_match_field_info *match_field) +{ + struct table *t; + struct match_field *f; + + if (!p || (table_id >= p->n_tables) || !match_field) + return -EINVAL; + + t = table_find_by_id(p, table_id); + if (!t || (match_field_id >= t->n_fields)) + return -EINVAL; + + f = &t->fields[match_field_id]; + match_field->match_type = f->match_type; + match_field->is_header = t->is_header; + match_field->n_bits = f->field->n_bits; + match_field->offset = f->field->offset; + + return 0; +} + +int +rte_swx_ctl_table_action_info_get(struct rte_swx_pipeline *p, + uint32_t table_id, + uint32_t table_action_id, + struct rte_swx_ctl_table_action_info *table_action) +{ + struct table *t; + + if (!p || (table_id >= p->n_tables) || !table_action) + return -EINVAL; + + t = table_find_by_id(p, table_id); + if (!t || (table_action_id >= t->n_actions)) + return -EINVAL; + + table_action->action_id = t->actions[table_action_id]->id; + + return 0; +} + +int +rte_swx_ctl_table_ops_get(struct rte_swx_pipeline *p, + uint32_t table_id, + struct rte_swx_table_ops *table_ops, + int *is_stub) +{ + struct table *t; + + if (!p || (table_id >= p->n_tables)) + return -EINVAL; + + t = table_find_by_id(p, table_id); + if (!t) + return -EINVAL; + + if (t->type) { + if (table_ops) + memcpy(table_ops, &t->type->ops, sizeof(*table_ops)); + *is_stub = 0; + } else { + *is_stub = 1; + } + + return 0; +} + int rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p, struct rte_swx_table_state **table_state) @@ -6963,3 +7146,39 @@ rte_swx_pipeline_table_state_set(struct rte_swx_pipeline *p, p->table_state = table_state; return 0; } + +int +rte_swx_ctl_pipeline_port_in_stats_read(struct rte_swx_pipeline *p, + uint32_t port_id, + struct rte_swx_port_in_stats *stats) +{ + struct port_in *port; + + if (!p || !stats) + return -EINVAL; + + port = port_in_find(p, port_id); + if (!port) + return -EINVAL; + + port->type->ops.stats_read(port->obj, stats); + return 0; +} + +int +rte_swx_ctl_pipeline_port_out_stats_read(struct rte_swx_pipeline *p, + uint32_t port_id, + struct rte_swx_port_out_stats *stats) +{ + struct port_out *port; + + if (!p || !stats) + return -EINVAL; + + port = port_out_find(p, port_id); + if (!port) + return -EINVAL; + + port->type->ops.stats_read(port->obj, stats); + return 0; +}