From patchwork Thu Apr 21 15:59:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Dumitrescu X-Patchwork-Id: 110017 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0C178A0093; Thu, 21 Apr 2022 17:59:57 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A44E740042; Thu, 21 Apr 2022 17:59:56 +0200 (CEST) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mails.dpdk.org (Postfix) with ESMTP id A548340040 for ; Thu, 21 Apr 2022 17:59:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1650556794; x=1682092794; h=from:to:subject:date:message-id; bh=mg6//6IBLo7iLjOlAtkodoDoH694e3AvLnhafrER5Qc=; b=OVog76B7AgZBOma4EtG53edbr5wc777BsP0Z/OKkwZxCSeNUnAODAgxF 77zvhO6vFljapSlIxvUDEWdq6WVTj/zBSbDGqHrT6Uplvid0rcRKdBjKI cmrRN/nGyOjjQ0vwoaD/oGXr40lmw1QkurcvZJ7S3VK/2OPf5JC3lpoa3 ihcoMQerkDghkqzzXTSIgM1zKLStmOtbfQPcJ4MTUwvxsnUv45reO+2Lv mK7hf5urqcKUpcxkjWemxxCYAmGTy+o1e+eUL+OagN7SgpoSz3t0L1w3z bfBQVt8cxn9S7Pcdu4wpERo97Yc3kRV6yY/0djjTqShRrjHdcOd+gEyJC A==; X-IronPort-AV: E=McAfee;i="6400,9594,10324"; a="244973280" X-IronPort-AV: E=Sophos;i="5.90,279,1643702400"; d="scan'208";a="244973280" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2022 08:59:53 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.90,279,1643702400"; d="scan'208";a="728066537" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by orsmga005.jf.intel.com with ESMTP; 21 Apr 2022 08:59:52 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Subject: [PATCH 1/3] table: improve learner table timers Date: Thu, 21 Apr 2022 16:59:49 +0100 Message-Id: <20220421155951.31811-1-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Signed-off-by: Cristian Dumitrescu --- lib/pipeline/rte_swx_pipeline.c | 3 +- lib/pipeline/rte_swx_pipeline_internal.h | 3 +- lib/table/rte_swx_table_learner.c | 109 ++++++++++++++++++++--- lib/table/rte_swx_table_learner.h | 90 +++++++++++++++++-- lib/table/version.map | 4 + 5 files changed, 189 insertions(+), 20 deletions(-) diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c index dfbac929c7..17be31d5a4 100644 --- a/lib/pipeline/rte_swx_pipeline.c +++ b/lib/pipeline/rte_swx_pipeline.c @@ -8788,7 +8788,8 @@ learner_params_get(struct learner *l) params->n_keys_max = l->size; /* Timeout. */ - params->key_timeout = l->timeout; + params->key_timeout[0] = l->timeout; + params->n_key_timeouts = 1; return params; diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h index 381a35c6e0..51bb464f5f 100644 --- a/lib/pipeline/rte_swx_pipeline_internal.h +++ b/lib/pipeline/rte_swx_pipeline_internal.h @@ -2215,7 +2215,8 @@ __instr_learn_exec(struct rte_swx_pipeline *p, l->mailbox, t->time, action_id, - &t->metadata[mf_offset]); + &t->metadata[mf_offset], + 0); TRACE("[Thread %2u] learner %u learn %s\n", p->thread_id, diff --git a/lib/table/rte_swx_table_learner.c b/lib/table/rte_swx_table_learner.c index 15576c2aa3..02f7613c22 100644 --- a/lib/table/rte_swx_table_learner.c +++ b/lib/table/rte_swx_table_learner.c @@ -231,11 +231,14 @@ table_keycmp(void *a, void *b, void *b_mask, uint32_t n_bytes) #define TABLE_KEYS_PER_BUCKET 4 #define TABLE_BUCKET_PAD_SIZE \ - (RTE_CACHE_LINE_SIZE - TABLE_KEYS_PER_BUCKET * (sizeof(uint32_t) + sizeof(uint32_t))) + (RTE_CACHE_LINE_SIZE - TABLE_KEYS_PER_BUCKET * (sizeof(uint32_t) + \ + sizeof(uint32_t) + \ + sizeof(uint8_t))) struct table_bucket { uint32_t time[TABLE_KEYS_PER_BUCKET]; uint32_t sig[TABLE_KEYS_PER_BUCKET]; + uint8_t key_timeout_id[TABLE_KEYS_PER_BUCKET]; uint8_t pad[TABLE_BUCKET_PAD_SIZE]; uint8_t key[0]; }; @@ -284,8 +287,11 @@ struct table_params { /* log2(bucket_size). Purpose: avoid multiplication with non-power of 2 numbers. */ size_t bucket_size_log2; - /* Timeout in CPU clock cycles. */ - uint64_t key_timeout; + /* Set of all possible key timeout values measured in CPU clock cycles. */ + uint64_t key_timeout[RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX]; + + /* Number of key timeout values. */ + uint32_t n_key_timeouts; /* Total memory size. */ size_t total_size; @@ -305,15 +311,23 @@ struct table { static int table_params_get(struct table_params *p, struct rte_swx_table_learner_params *params) { + uint32_t i; + /* Check input parameters. */ if (!params || !params->key_size || (params->key_size > 64) || !params->n_keys_max || (params->n_keys_max > 1U << 31) || - !params->key_timeout) + !params->key_timeout || + !params->n_key_timeouts || + (params->n_key_timeouts > RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX)) return -EINVAL; + for (i = 0; i < params->n_key_timeouts; i++) + if (!params->key_timeout[i]) + return -EINVAL; + /* Key. */ p->key_size = params->key_size; @@ -346,7 +360,17 @@ table_params_get(struct table_params *p, struct rte_swx_table_learner_params *pa p->bucket_size_log2 = __builtin_ctzll(p->bucket_size); /* Timeout. */ - p->key_timeout = params->key_timeout * rte_get_tsc_hz(); + for (i = 0; i < params->n_key_timeouts; i++) { + p->key_timeout[i] = params->key_timeout[i] * rte_get_tsc_hz(); + + if (!(p->key_timeout[i] >> 32)) + p->key_timeout[i] = 1LLU << 32; + } + + p->n_key_timeouts = rte_align32pow2(params->n_key_timeouts); + + for ( ; i < p->n_key_timeouts; i++) + p->key_timeout[i] = p->key_timeout[0]; /* Total size. */ p->total_size = sizeof(struct table) + p->n_buckets * p->bucket_size; @@ -505,8 +529,6 @@ rte_swx_table_learner_lookup(void *table, /* Hit. */ rte_prefetch0(data); - b->time[i] = (input_time + t->params.key_timeout) >> 32; - m->hit = 1; m->bucket_key_pos = i; m->state = 0; @@ -536,23 +558,83 @@ rte_swx_table_learner_lookup(void *table, } } +void +rte_swx_table_learner_rearm(void *table, + void *mailbox, + uint64_t input_time) +{ + struct table *t = table; + struct mailbox *m = mailbox; + struct table_bucket *b; + size_t bucket_key_pos; + uint64_t key_timeout; + uint32_t key_timeout_id; + + if (!m->hit) + return; + + b = m->bucket; + bucket_key_pos = m->bucket_key_pos; + + key_timeout_id = b->key_timeout_id[bucket_key_pos]; + key_timeout = t->params.key_timeout[key_timeout_id]; + b->time[bucket_key_pos] = (input_time + key_timeout) >> 32; +} + +void +rte_swx_table_learner_rearm_new(void *table, + void *mailbox, + uint64_t input_time, + uint32_t key_timeout_id) +{ + struct table *t = table; + struct mailbox *m = mailbox; + struct table_bucket *b; + size_t bucket_key_pos; + uint64_t key_timeout; + + if (!m->hit) + return; + + b = m->bucket; + bucket_key_pos = m->bucket_key_pos; + + key_timeout_id &= t->params.n_key_timeouts - 1; + key_timeout = t->params.key_timeout[key_timeout_id]; + b->time[bucket_key_pos] = (input_time + key_timeout) >> 32; + b->key_timeout_id[bucket_key_pos] = (uint8_t)key_timeout_id; +} + uint32_t rte_swx_table_learner_add(void *table, void *mailbox, uint64_t input_time, uint64_t action_id, - uint8_t *action_data) + uint8_t *action_data, + uint32_t key_timeout_id) { struct table *t = table; struct mailbox *m = mailbox; struct table_bucket *b = m->bucket; + uint64_t key_timeout; uint32_t i; - /* Lookup hit: The key, key signature and key time are already properly configured (the key - * time was bumped by lookup), only the key data need to be updated. + /* Adjust the key timeout ID to fit the valid range. */ + key_timeout_id &= t->params.n_key_timeouts - 1; + key_timeout = t->params.key_timeout[key_timeout_id]; + + /* Lookup hit: The following bucket fields need to be updated: + * - key (key, sig): NO (already correctly set). + * - key timeout (key_timeout_id, time): YES. + * - key data (data): YES. */ if (m->hit) { - uint64_t *data = table_bucket_data_get(t, b, m->bucket_key_pos); + size_t bucket_key_pos = m->bucket_key_pos; + uint64_t *data = table_bucket_data_get(t, b, bucket_key_pos); + + /* Install the key timeout. */ + b->time[bucket_key_pos] = (input_time + key_timeout) >> 32; + b->key_timeout_id[bucket_key_pos] = (uint8_t)key_timeout_id; /* Install the key data. */ data[0] = action_id; @@ -576,9 +658,10 @@ rte_swx_table_learner_add(void *table, uint8_t *key = table_bucket_key_get(t, b, i); uint64_t *data = table_bucket_data_get(t, b, i); - /* Install the key. */ - b->time[i] = (input_time + t->params.key_timeout) >> 32; + /* Install the key and the key timeout. */ + b->time[i] = (input_time + key_timeout) >> 32; b->sig[i] = m->input_sig; + b->key_timeout_id[i] = (uint8_t)key_timeout_id; memcpy(key, m->input_key, t->params.key_size); /* Install the key data. */ diff --git a/lib/table/rte_swx_table_learner.h b/lib/table/rte_swx_table_learner.h index eb9d7689fd..8b3128ec5d 100644 --- a/lib/table/rte_swx_table_learner.h +++ b/lib/table/rte_swx_table_learner.h @@ -18,13 +18,43 @@ extern "C" { * implementation of the "add on miss" scenario: whenever the lookup key is not found in the table * (lookup miss), the data plane can decide to add this key to the table with a given action with no * control plane intervention. Likewise, the table keys expire based on a configurable timeout and - * are automatically deleted from the table with no control plane intervention. + * are thus automatically removed from the table with no control plane intervention. + * + * The keys are not automatically rearmed on lookup hit. To delay the key expiration, the key timer + * has to be explicitly reinitialized on lookup hit. The key will be kept in the table as long as it + * is frequently hit and explicitly rearmed on every hit. + * + * Operation overview: + * 1) Lookup miss: + * a) add: Add the current input key (the key that missed the lookup) to the table with given + * action, action parameters and expiration timeout. This is the way to populate the + * table (which is empty initially). Data plane operation. + * b) Do nothing: Keep the current input key out of the table. + * 2) Lookup hit: + * a) add: Update the action, action parameters and/or the expiration timeout for the current + * input key, which is already in the table. The expiration timer of the key is + * automatically rearmed. Data plane operation. + * b) rearm: Rearm the expiration timer for the current input key, which is already in the + * table. The timeout value used for the expiration timer is either the same as the one + * currently associated with the key or a new one can be provided as input. Data plane + * operation. + * c) delete: Delete the current input key from the table. The purpose of this operation is to + * force the deletion of the key from the table before the key expires on timeout due + * to inactivity. Data plane operation. + * d) Do nothing: Keep the expiration timer of the current input key running down. This key + * will thus expire naturally, unless it is hit again as part of a subsequent lookup + * operation, when the key timer can be rearmed or re-added to prolong its life. */ #include #include +/** Maximum number of key timeout values per learner table. */ +#ifndef RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX +#define RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX 16 +#endif + /** Learner table creation parameters. */ struct rte_swx_table_learner_params { /** Key size in bytes. Must be non-zero. */ @@ -50,10 +80,16 @@ struct rte_swx_table_learner_params { /** Maximum number of keys to be stored in the table together with their associated data. */ uint32_t n_keys_max; - /** Key timeout in seconds. Must be non-zero. Each table key expires and is automatically - * deleted from the table after this many seconds. + /** The set of all possible key timeout values measured in seconds. Each value must be + * non-zero. Each table key expires and is automatically deleted from the table after + * this many seconds. */ - uint32_t key_timeout; + uint32_t *key_timeout; + + /** Number of possible key timeout values present in the *key_timeout* set. It must be less + * than or equal to *RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX*. + */ + uint32_t n_key_timeouts; }; /** @@ -160,6 +196,8 @@ rte_swx_table_learner_lookup(void *table, * ID of the action associated with the key. * @param[out] action_data * Action data for the *action_id* action. + * @param[in] key_timeout_id + * Key timeout ID. * @return * 0 on success, 1 or error (table full). */ @@ -169,7 +207,49 @@ rte_swx_table_learner_add(void *table, void *mailbox, uint64_t time, uint64_t action_id, - uint8_t *action_data); + uint8_t *action_data, + uint32_t key_timeout_id); + +/** + * Learner table key rearm with same timeout value + * + * This operation takes the latest key that was looked up in the table and, in case of lookup hit, + * it rearms its expiration timer using the same timeout value currently associated with the key. + * + * @param[in] table + * Table handle. + * @param[in] mailbox + * Mailbox for the current operation. + * @param[in] time + * Current time measured in CPU clock cycles. + */ +__rte_experimental +void +rte_swx_table_learner_rearm(void *table, + void *mailbox, + uint64_t time); + +/** + * Learner table key rearm with given timeout value + * + * This operation takes the latest key that was looked up in the table and, in case of lookup hit, + * it rearms its expiration timer using the given timeout value. + * + * @param[in] table + * Table handle. + * @param[in] mailbox + * Mailbox for the current operation. + * @param[in] time + * Current time measured in CPU clock cycles. + * @param[in] key_timeout_id + * Key timeout ID. + */ +__rte_experimental +void +rte_swx_table_learner_rearm_new(void *table, + void *mailbox, + uint64_t time, + uint32_t key_timeout_id); /** * Learner table key delete diff --git a/lib/table/version.map b/lib/table/version.map index efe5f6e52c..d27d649332 100644 --- a/lib/table/version.map +++ b/lib/table/version.map @@ -45,4 +45,8 @@ EXPERIMENTAL { rte_swx_table_learner_free; rte_swx_table_learner_lookup; rte_swx_table_learner_mailbox_size_get; + + #added in 22.07 + rte_swx_table_learner_rearm; + rte_swx_table_learner_rearm_new; }; From patchwork Thu Apr 21 15:59:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Dumitrescu X-Patchwork-Id: 110018 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id DBAE2A0093; Thu, 21 Apr 2022 18:00:04 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B637D410FB; Thu, 21 Apr 2022 17:59:59 +0200 (CEST) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mails.dpdk.org (Postfix) with ESMTP id 935FF40040 for ; Thu, 21 Apr 2022 17:59:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1650556795; x=1682092795; h=from:to:subject:date:message-id:in-reply-to:references; bh=4to/JKluhd2xm/KT/9l8o61FXO0dtl88wim85rB2/J4=; b=mrsxMPa3bFKSjkRC37OmeIgq2FkPZ3Qd84HeD+ePBeBdAam4qAx7P5yh fWq5lFRTEwckQK46p0g6xxX1SlBKQQgQHk3859FOfmLjakqI7vpGMUsI4 wQoi0pYZJi+rYtLRK+9QQKwdyyt4bb2jhuwlU8zkPy7qiEOuowz0XqLDr FuoX2kRSgWMG2GYw8EIYPAZ91mkPVSNE/U9kb2uy4bvh2gwuP3ZxvO4AC tWidq2AbDdRxUztjgzmi2D06JjCc1wmBq77BoGn6qWcxc9tvVAdb/zAr1 UxPom3gP9RM/ikgt9HPYG6iRtPcZBvlF3S6a+1Xk9Jt2VDaM82lN3FAn7 w==; X-IronPort-AV: E=McAfee;i="6400,9594,10324"; a="244973287" X-IronPort-AV: E=Sophos;i="5.90,279,1643702400"; d="scan'208";a="244973287" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2022 08:59:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.90,279,1643702400"; d="scan'208";a="728066549" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by orsmga005.jf.intel.com with ESMTP; 21 Apr 2022 08:59:53 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Subject: [PATCH 2/3] pipeline: improve learner table timers Date: Thu, 21 Apr 2022 16:59:50 +0100 Message-Id: <20220421155951.31811-2-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220421155951.31811-1-cristian.dumitrescu@intel.com> References: <20220421155951.31811-1-cristian.dumitrescu@intel.com> X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Signed-off-by: Cristian Dumitrescu --- lib/pipeline/rte_swx_ctl.h | 3 + lib/pipeline/rte_swx_pipeline.c | 164 ++++++++++++++++++++--- lib/pipeline/rte_swx_pipeline.h | 7 +- lib/pipeline/rte_swx_pipeline_internal.h | 70 +++++++++- lib/pipeline/rte_swx_pipeline_spec.c | 146 ++++++++++++++++---- 5 files changed, 336 insertions(+), 54 deletions(-) diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h index 204026dc0e..e4cdc840fc 100644 --- a/lib/pipeline/rte_swx_ctl.h +++ b/lib/pipeline/rte_swx_ctl.h @@ -629,6 +629,9 @@ struct rte_swx_learner_stats { /** Number of packets with learning error. */ uint64_t n_pkts_learn_err; + /** Number of packets with rearm event. */ + uint64_t n_pkts_rearm; + /** Number of packets with forget event. */ uint64_t n_pkts_forget; diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c index 17be31d5a4..228f309750 100644 --- a/lib/pipeline/rte_swx_pipeline.c +++ b/lib/pipeline/rte_swx_pipeline.c @@ -2583,31 +2583,38 @@ instr_learn_translate(struct rte_swx_pipeline *p, struct instruction_data *data __rte_unused) { struct action *a; - const char *mf_name; - uint32_t mf_offset = 0; + struct field *mf_first_arg = NULL, *mf_timeout_id = NULL; + const char *mf_first_arg_name, *mf_timeout_id_name; CHECK(action, EINVAL); - CHECK((n_tokens == 2) || (n_tokens == 3), EINVAL); + CHECK((n_tokens == 3) || (n_tokens == 4), EINVAL); + /* Action. */ a = action_find(p, tokens[1]); CHECK(a, EINVAL); CHECK(!action_has_nbo_args(a), EINVAL); - mf_name = (n_tokens > 2) ? tokens[2] : NULL; - CHECK(!learner_action_args_check(p, a, mf_name), EINVAL); - - if (mf_name) { - struct field *mf; - - mf = metadata_field_parse(p, mf_name); - CHECK(mf, EINVAL); + /* Action first argument. */ + mf_first_arg_name = (n_tokens == 4) ? tokens[2] : NULL; + CHECK(!learner_action_args_check(p, a, mf_first_arg_name), EINVAL); - mf_offset = mf->offset / 8; + if (mf_first_arg_name) { + mf_first_arg = metadata_field_parse(p, mf_first_arg_name); + CHECK(mf_first_arg, EINVAL); } + /* Timeout ID. */ + mf_timeout_id_name = (n_tokens == 4) ? tokens[3] : tokens[2]; + CHECK_NAME(mf_timeout_id_name, EINVAL); + mf_timeout_id = metadata_field_parse(p, mf_timeout_id_name); + CHECK(mf_timeout_id, EINVAL); + + /* Instruction. */ instr->type = INSTR_LEARNER_LEARN; instr->learn.action_id = a->id; - instr->learn.mf_offset = mf_offset; + instr->learn.mf_first_arg_offset = mf_first_arg ? (mf_first_arg->offset / 8) : 0; + instr->learn.mf_timeout_id_offset = mf_timeout_id->offset / 8; + instr->learn.mf_timeout_id_n_bits = mf_timeout_id->n_bits; return 0; } @@ -2624,6 +2631,66 @@ instr_learn_exec(struct rte_swx_pipeline *p) thread_ip_inc(p); } +/* + * rearm. + */ +static int +instr_rearm_translate(struct rte_swx_pipeline *p, + struct action *action, + char **tokens, + int n_tokens, + struct instruction *instr, + struct instruction_data *data __rte_unused) +{ + struct field *mf_timeout_id; + const char *mf_timeout_id_name; + + CHECK(action, EINVAL); + CHECK((n_tokens == 1) || (n_tokens == 2), EINVAL); + + /* INSTR_LEARNER_REARM. */ + if (n_tokens == 1) { + instr->type = INSTR_LEARNER_REARM; + return 0; + } + + /* INSTR_LEARNER_REARM_NEW. */ + mf_timeout_id_name = tokens[1]; + CHECK_NAME(mf_timeout_id_name, EINVAL); + mf_timeout_id = metadata_field_parse(p, mf_timeout_id_name); + CHECK(mf_timeout_id, EINVAL); + + instr->type = INSTR_LEARNER_REARM_NEW; + instr->learn.mf_timeout_id_offset = mf_timeout_id->offset / 8; + instr->learn.mf_timeout_id_n_bits = mf_timeout_id->n_bits; + + return 0; +} + +static inline void +instr_rearm_exec(struct rte_swx_pipeline *p) +{ + struct thread *t = &p->threads[p->thread_id]; + struct instruction *ip = t->ip; + + __instr_rearm_exec(p, t, ip); + + /* Thread. */ + thread_ip_inc(p); +} + +static inline void +instr_rearm_new_exec(struct rte_swx_pipeline *p) +{ + struct thread *t = &p->threads[p->thread_id]; + struct instruction *ip = t->ip; + + __instr_rearm_new_exec(p, t, ip); + + /* Thread. */ + thread_ip_inc(p); +} + /* * forget. */ @@ -6051,6 +6118,13 @@ instr_translate(struct rte_swx_pipeline *p, n_tokens - tpos, instr, data); + if (!strcmp(tokens[tpos], "rearm")) + return instr_rearm_translate(p, + action, + &tokens[tpos], + n_tokens - tpos, + instr, + data); if (!strcmp(tokens[tpos], "forget")) return instr_forget_translate(p, @@ -7040,6 +7114,8 @@ static instr_exec_t instruction_table[] = { [INSTR_LEARNER] = instr_learner_exec, [INSTR_LEARNER_AF] = instr_learner_af_exec, [INSTR_LEARNER_LEARN] = instr_learn_exec, + [INSTR_LEARNER_REARM] = instr_rearm_exec, + [INSTR_LEARNER_REARM_NEW] = instr_rearm_new_exec, [INSTR_LEARNER_FORGET] = instr_forget_exec, [INSTR_EXTERN_OBJ] = instr_extern_obj_exec, [INSTR_EXTERN_FUNC] = instr_extern_func_exec, @@ -8546,7 +8622,8 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, const char *name, struct rte_swx_pipeline_learner_params *params, uint32_t size, - uint32_t timeout) + uint32_t *timeout, + uint32_t n_timeouts) { struct learner *l = NULL; struct action *default_action; @@ -8616,6 +8693,7 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, /* Any other checks. */ CHECK(size, EINVAL); CHECK(timeout, EINVAL); + CHECK(n_timeouts && (n_timeouts < RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX), EINVAL); /* Memory allocation. */ l = calloc(1, sizeof(struct learner)); @@ -8702,7 +8780,10 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, l->size = size; - l->timeout = timeout; + for (i = 0; i < n_timeouts; i++) + l->timeout[i] = timeout[i]; + + l->n_timeouts = n_timeouts; l->id = p->n_learners; @@ -8734,6 +8815,8 @@ learner_params_free(struct rte_swx_table_learner_params *params) free(params->key_mask0); + free(params->key_timeout); + free(params); } @@ -8787,9 +8870,16 @@ learner_params_get(struct learner *l) /* Maximum number of keys. */ params->n_keys_max = l->size; + /* Memory allocation. */ + params->key_timeout = calloc(l->n_timeouts, sizeof(uint32_t)); + if (!params->key_timeout) + goto error; + /* Timeout. */ - params->key_timeout[0] = l->timeout; - params->n_key_timeouts = 1; + for (i = 0; i < l->n_timeouts; i++) + params->key_timeout[i] = l->timeout[i]; + + params->n_key_timeouts = l->n_timeouts; return params; @@ -10170,6 +10260,7 @@ rte_swx_ctl_pipeline_learner_stats_read(struct rte_swx_pipeline *p, stats->n_pkts_learn_ok = learner_stats->n_pkts_learn[0]; stats->n_pkts_learn_err = learner_stats->n_pkts_learn[1]; + stats->n_pkts_rearm = learner_stats->n_pkts_rearm; stats->n_pkts_forget = learner_stats->n_pkts_forget; return 0; @@ -10583,6 +10674,8 @@ instr_type_to_name(struct instruction *instr) case INSTR_LEARNER_AF: return "INSTR_LEARNER_AF"; case INSTR_LEARNER_LEARN: return "INSTR_LEARNER_LEARN"; + case INSTR_LEARNER_REARM: return "INSTR_LEARNER_REARM"; + case INSTR_LEARNER_REARM_NEW: return "INSTR_LEARNER_REARM_NEW"; case INSTR_LEARNER_FORGET: return "INSTR_LEARNER_FORGET"; case INSTR_EXTERN_OBJ: return "INSTR_EXTERN_OBJ"; @@ -11207,11 +11300,40 @@ instr_learn_export(struct instruction *instr, FILE *f) "\t{\n" "\t\t.type = %s,\n" "\t\t.learn = {\n" - "\t\t\t\t.action_id = %u,\n" + "\t\t\t.action_id = %u,\n" + "\t\t\t.mf_first_arg_offset = %u,\n" + "\t\t\t.mf_timeout_id_offset = %u,\n" + "\t\t\t.mf_timeout_id_n_bits = %u,\n" "\t\t},\n" "\t},\n", instr_type_to_name(instr), - instr->learn.action_id); + instr->learn.action_id, + instr->learn.mf_first_arg_offset, + instr->learn.mf_timeout_id_offset, + instr->learn.mf_timeout_id_n_bits); +} + +static void +instr_rearm_export(struct instruction *instr, FILE *f) +{ + if (instr->type == INSTR_LEARNER_REARM) + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t},\n", + instr_type_to_name(instr)); + else + fprintf(f, + "\t{\n" + "\t\t.type = %s,\n" + "\t\t.learn = {\n" + "\t\t\t.mf_timeout_id_offset = %u,\n" + "\t\t\t.mf_timeout_id_n_bits = %u,\n" + "\t\t},\n" + "\t},\n", + instr_type_to_name(instr), + instr->learn.mf_timeout_id_offset, + instr->learn.mf_timeout_id_n_bits); } static void @@ -11509,6 +11631,8 @@ static instruction_export_t export_table[] = { [INSTR_LEARNER_AF] = instr_table_export, [INSTR_LEARNER_LEARN] = instr_learn_export, + [INSTR_LEARNER_REARM] = instr_rearm_export, + [INSTR_LEARNER_REARM_NEW] = instr_rearm_export, [INSTR_LEARNER_FORGET] = instr_forget_export, [INSTR_EXTERN_OBJ] = instr_extern_export, @@ -11730,6 +11854,8 @@ instr_type_to_func(struct instruction *instr) case INSTR_LEARNER_AF: return NULL; case INSTR_LEARNER_LEARN: return "__instr_learn_exec"; + case INSTR_LEARNER_REARM: return "__instr_rearm_exec"; + case INSTR_LEARNER_REARM_NEW: return "__instr_rearm_new_exec"; case INSTR_LEARNER_FORGET: return "__instr_forget_exec"; case INSTR_EXTERN_OBJ: return NULL; diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h index c95d0c7682..a5a0954915 100644 --- a/lib/pipeline/rte_swx_pipeline.h +++ b/lib/pipeline/rte_swx_pipeline.h @@ -786,7 +786,9 @@ struct rte_swx_pipeline_learner_params { * @param[in] size * The maximum number of table entries. Must be non-zero. * @param[in] timeout - * Table entry timeout in seconds. Must be non-zero. + * Array of possible table entry timeouts in seconds. Must be non-NULL. + * @param[in] n_timeouts + * Number of elements in the *timeout* array. * @return * 0 on success or the following error codes otherwise: * -EINVAL: Invalid argument; @@ -800,7 +802,8 @@ rte_swx_pipeline_learner_config(struct rte_swx_pipeline *p, const char *name, struct rte_swx_pipeline_learner_params *params, uint32_t size, - uint32_t timeout); + uint32_t *timeout, + uint32_t n_timeouts); /** * Pipeline register array configure diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h index 51bb464f5f..f8a6661f75 100644 --- a/lib/pipeline/rte_swx_pipeline_internal.h +++ b/lib/pipeline/rte_swx_pipeline_internal.h @@ -476,9 +476,13 @@ enum instruction_type { INSTR_LEARNER, INSTR_LEARNER_AF, - /* learn LEARNER ACTION_NAME [ m.action_first_arg ] */ + /* learn ACTION_NAME [ m.action_first_arg ] m.timeout_id */ INSTR_LEARNER_LEARN, + /* rearm [ m.timeout_id ] */ + INSTR_LEARNER_REARM, + INSTR_LEARNER_REARM_NEW, + /* forget */ INSTR_LEARNER_FORGET, @@ -611,7 +615,9 @@ struct instr_table { struct instr_learn { uint8_t action_id; - uint8_t mf_offset; + uint8_t mf_first_arg_offset; + uint8_t mf_timeout_id_offset; + uint8_t mf_timeout_id_n_bits; }; struct instr_extern_obj { @@ -850,7 +856,8 @@ struct learner { int *action_is_for_default_entry; uint32_t size; - uint32_t timeout; + uint32_t timeout[RTE_SWX_TABLE_LEARNER_N_KEY_TIMEOUTS_MAX]; + uint32_t n_timeouts; uint32_t id; }; @@ -864,6 +871,7 @@ struct learner_runtime { struct learner_statistics { uint64_t n_pkts_hit[2]; /* 0 = Miss, 1 = Hit. */ uint64_t n_pkts_learn[2]; /* 0 = Learn OK, 1 = Learn error. */ + uint64_t n_pkts_rearm; uint64_t n_pkts_forget; uint64_t *n_pkts_action; }; @@ -2202,7 +2210,9 @@ __instr_learn_exec(struct rte_swx_pipeline *p, const struct instruction *ip) { uint64_t action_id = ip->learn.action_id; - uint32_t mf_offset = ip->learn.mf_offset; + uint32_t mf_first_arg_offset = ip->learn.mf_first_arg_offset; + uint32_t timeout_id = METADATA_READ(t, ip->learn.mf_timeout_id_offset, + ip->learn.mf_timeout_id_n_bits); uint32_t learner_id = t->learner_id; struct rte_swx_table_state *ts = &t->table_state[p->n_tables + p->n_selectors + learner_id]; @@ -2215,8 +2225,8 @@ __instr_learn_exec(struct rte_swx_pipeline *p, l->mailbox, t->time, action_id, - &t->metadata[mf_offset], - 0); + &t->metadata[mf_first_arg_offset], + timeout_id); TRACE("[Thread %2u] learner %u learn %s\n", p->thread_id, @@ -2226,6 +2236,54 @@ __instr_learn_exec(struct rte_swx_pipeline *p, stats->n_pkts_learn[status] += 1; } +/* + * rearm. + */ +static inline void +__instr_rearm_exec(struct rte_swx_pipeline *p, + struct thread *t, + const struct instruction *ip __rte_unused) +{ + uint32_t learner_id = t->learner_id; + struct rte_swx_table_state *ts = &t->table_state[p->n_tables + + p->n_selectors + learner_id]; + struct learner_runtime *l = &t->learners[learner_id]; + struct learner_statistics *stats = &p->learner_stats[learner_id]; + + /* Table. */ + rte_swx_table_learner_rearm(ts->obj, l->mailbox, t->time); + + TRACE("[Thread %2u] learner %u rearm\n", + p->thread_id, + learner_id); + + stats->n_pkts_rearm += 1; +} + +static inline void +__instr_rearm_new_exec(struct rte_swx_pipeline *p, + struct thread *t, + const struct instruction *ip) +{ + uint32_t timeout_id = METADATA_READ(t, ip->learn.mf_timeout_id_offset, + ip->learn.mf_timeout_id_n_bits); + uint32_t learner_id = t->learner_id; + struct rte_swx_table_state *ts = &t->table_state[p->n_tables + + p->n_selectors + learner_id]; + struct learner_runtime *l = &t->learners[learner_id]; + struct learner_statistics *stats = &p->learner_stats[learner_id]; + + /* Table. */ + rte_swx_table_learner_rearm_new(ts->obj, l->mailbox, t->time, timeout_id); + + TRACE("[Thread %2u] learner %u rearm with timeout ID %u\n", + p->thread_id, + learner_id, + timeout_id); + + stats->n_pkts_rearm += 1; +} + /* * forget. */ diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c index b2f2469b18..904b9eb471 100644 --- a/lib/pipeline/rte_swx_pipeline_spec.c +++ b/lib/pipeline/rte_swx_pipeline_spec.c @@ -29,7 +29,8 @@ #define LEARNER_BLOCK 7 #define LEARNER_KEY_BLOCK 8 #define LEARNER_ACTIONS_BLOCK 9 -#define APPLY_BLOCK 10 +#define LEARNER_TIMEOUT_BLOCK 10 +#define APPLY_BLOCK 11 /* * extobj. @@ -1395,14 +1396,18 @@ selector_block_parse(struct selector_spec *s, * } * default_action ACTION_NAME args none | ARG0_NAME ARG0_VALUE ... [ const ] * size SIZE - * timeout TIMEOUT_IN_SECONDS + * timeout { + * TIMEOUT_IN_SECONDS + * ... + * } * } */ struct learner_spec { char *name; struct rte_swx_pipeline_learner_params params; uint32_t size; - uint32_t timeout; + uint32_t *timeout; + uint32_t n_timeouts; }; static void @@ -1457,7 +1462,10 @@ learner_spec_free(struct learner_spec *s) s->size = 0; - s->timeout = 0; + free(s->timeout); + s->timeout = NULL; + + s->n_timeouts = 0; } static int @@ -1719,6 +1727,95 @@ learner_default_action_statement_parse(struct learner_spec *s, return status; } +static int +learner_timeout_statement_parse(uint32_t *block_mask, + char **tokens, + uint32_t n_tokens, + uint32_t n_lines, + uint32_t *err_line, + const char **err_msg) +{ + /* Check format. */ + if ((n_tokens != 2) || strcmp(tokens[1], "{")) { + if (err_line) + *err_line = n_lines; + if (err_msg) + *err_msg = "Invalid timeout statement."; + return -EINVAL; + } + + /* block_mask. */ + *block_mask |= 1 << LEARNER_TIMEOUT_BLOCK; + + return 0; +} + +static int +learner_timeout_block_parse(struct learner_spec *s, + uint32_t *block_mask, + char **tokens, + uint32_t n_tokens, + uint32_t n_lines, + uint32_t *err_line, + const char **err_msg) +{ + uint32_t *new_timeout = NULL; + char *str; + uint32_t val; + int status = 0; + + /* Handle end of block. */ + if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { + *block_mask &= ~(1 << LEARNER_TIMEOUT_BLOCK); + return 0; + } + + /* Check input arguments. */ + if (n_tokens != 1) { + status = -EINVAL; + goto error; + } + + str = tokens[0]; + val = strtoul(str, &str, 0); + if (str[0]) { + status = -EINVAL; + goto error; + } + + new_timeout = realloc(s->timeout, (s->n_timeouts + 1) * sizeof(uint32_t)); + if (!new_timeout) { + status = -ENOMEM; + goto error; + } + + s->timeout = new_timeout; + s->timeout[s->n_timeouts] = val; + s->n_timeouts++; + + return 0; + +error: + free(new_timeout); + + if (err_line) + *err_line = n_lines; + + if (err_msg) + switch (status) { + case -ENOMEM: + *err_msg = "Memory allocation failed."; + break; + + default: + *err_msg = "Invalid timeout value statement."; + break; + } + + return status; +} + + static int learner_statement_parse(struct learner_spec *s, uint32_t *block_mask, @@ -1780,6 +1877,15 @@ learner_block_parse(struct learner_spec *s, err_line, err_msg); + if (*block_mask & (1 << LEARNER_TIMEOUT_BLOCK)) + return learner_timeout_block_parse(s, + block_mask, + tokens, + n_tokens, + n_lines, + err_line, + err_msg); + /* Handle end of block. */ if ((n_tokens == 1) && !strcmp(tokens[0], "}")) { *block_mask &= ~(1 << LEARNER_BLOCK); @@ -1833,28 +1939,13 @@ learner_block_parse(struct learner_spec *s, return 0; } - if (!strcmp(tokens[0], "timeout")) { - char *p = tokens[1]; - - if (n_tokens != 2) { - if (err_line) - *err_line = n_lines; - if (err_msg) - *err_msg = "Invalid timeout statement."; - return -EINVAL; - } - - s->timeout = strtoul(p, &p, 0); - if (p[0]) { - if (err_line) - *err_line = n_lines; - if (err_msg) - *err_msg = "Invalid timeout argument."; - return -EINVAL; - } - - return 0; - } + if (!strcmp(tokens[0], "timeout")) + return learner_timeout_statement_parse(block_mask, + tokens, + n_tokens, + n_lines, + err_line, + err_msg); /* Anything else. */ if (err_line) @@ -2365,7 +2456,8 @@ rte_swx_pipeline_build_from_spec(struct rte_swx_pipeline *p, learner_spec.name, &learner_spec.params, learner_spec.size, - learner_spec.timeout); + learner_spec.timeout, + learner_spec.n_timeouts); if (status) { if (err_line) *err_line = n_lines; From patchwork Thu Apr 21 15:59:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Dumitrescu X-Patchwork-Id: 110019 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 308DDA0093; Thu, 21 Apr 2022 18:00:11 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8AA6E427EF; Thu, 21 Apr 2022 18:00:00 +0200 (CEST) Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mails.dpdk.org (Postfix) with ESMTP id EA23D40042 for ; Thu, 21 Apr 2022 17:59:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1650556796; x=1682092796; h=from:to:subject:date:message-id:in-reply-to:references; bh=I5uKwo8MX+l339sRNLPNB2/Vbwn3i9yBEjJeEsy7kLg=; b=JBtfjzc6V+HgtWPkcDVoywS5Chw9LZV3JNLI3+kuKh1Of1sLaGappuYw wbGjDLbw3KGJ4MjY9ABD0xdojeByS4cqMM7pgOm0UCrXQTiE9SV4d3cXg XLILx7SmFYuVTRaDtTv1LHidECrqUp45rr8FxxCHhse/D7PycEhe2P1Pt S+sqyjlLVUkeABqGTDwTDhJuV6dYIEbI/lKJqsN+r4MB1rkLStjx77649 HUhCKY/xbGgfTdn90vUMgh1SePaZdV713QfLp4mpf9r/HIu4/xaSv1+eb I0YO8I4z05FWVUq9yVQgS1/gAhAISE+FpW9gG5ZxYGJOhgCGbw0gaPxPc w==; X-IronPort-AV: E=McAfee;i="6400,9594,10324"; a="244973292" X-IronPort-AV: E=Sophos;i="5.90,279,1643702400"; d="scan'208";a="244973292" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Apr 2022 08:59:55 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.90,279,1643702400"; d="scan'208";a="728066557" Received: from silpixa00400573.ir.intel.com (HELO silpixa00400573.ger.corp.intel.com) ([10.237.223.107]) by orsmga005.jf.intel.com with ESMTP; 21 Apr 2022 08:59:54 -0700 From: Cristian Dumitrescu To: dev@dpdk.org Subject: [PATCH 3/3] examples/pipeline: improve learner table timers Date: Thu, 21 Apr 2022 16:59:51 +0100 Message-Id: <20220421155951.31811-3-cristian.dumitrescu@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220421155951.31811-1-cristian.dumitrescu@intel.com> References: <20220421155951.31811-1-cristian.dumitrescu@intel.com> X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Signed-off-by: Cristian Dumitrescu --- examples/pipeline/cli.c | 2 ++ examples/pipeline/examples/learner.spec | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/examples/pipeline/cli.c b/examples/pipeline/cli.c index d52ad6b61e..0334616bd9 100644 --- a/examples/pipeline/cli.c +++ b/examples/pipeline/cli.c @@ -2677,12 +2677,14 @@ cmd_pipeline_stats(char **tokens, "\t\tMiss (packets): %" PRIu64 "\n" "\t\tLearn OK (packets): %" PRIu64 "\n" "\t\tLearn error (packets): %" PRIu64 "\n" + "\t\tRearm (packets): %" PRIu64 "\n" "\t\tForget (packets): %" PRIu64 "\n", learner_info.name, stats.n_pkts_hit, stats.n_pkts_miss, stats.n_pkts_learn_ok, stats.n_pkts_learn_err, + stats.n_pkts_rearm, stats.n_pkts_forget); out_size -= strlen(out); out += strlen(out); diff --git a/examples/pipeline/examples/learner.spec b/examples/pipeline/examples/learner.spec index 4ee52da7ac..095325c293 100644 --- a/examples/pipeline/examples/learner.spec +++ b/examples/pipeline/examples/learner.spec @@ -48,6 +48,9 @@ struct metadata_t { bit<32> port_in bit<32> port_out + // Key timeout. + bit<32> timeout_id + // Arguments for the "fwd_action" action. bit<32> fwd_action_arg_port_out } @@ -68,10 +71,14 @@ struct fwd_action_args_t { action fwd_action args instanceof fwd_action_args_t { mov m.port_out t.port_out + rearm return } action learn_action args none { + // Pick the key timeout. Timeout ID #1 (i.e. 120 seconds) is selected. + mov m.timeout_id 1 + // Read current counter value into m.fwd_action_arg_port_out. regrd m.fwd_action_arg_port_out counter 0 @@ -84,7 +91,7 @@ action learn_action args none { // Add the current lookup key to the table with fwd_action as the key action. The action // arguments are read from the packet meta-data (the m.fwd_action_arg_port_out field). These // packet meta-data fields have to be written before the "learn" instruction is invoked. - learn fwd_action m.fwd_action_arg_port_out + learn fwd_action m.fwd_action_arg_port_out m.timeout_id // Send the current packet to the same output port. mov m.port_out m.fwd_action_arg_port_out @@ -110,7 +117,11 @@ learner fwd_table { size 1048576 - timeout 120 + timeout { + 60 + 120 + 180 + } } //