From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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; }; -- 2.17.1