All of lore.kernel.org
 help / color / mirror / Atom feed
From: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
To: dev@dpdk.org
Subject: [PATCH V3 2/3] pipeline: improve learner table timers
Date: Fri, 20 May 2022 23:12:54 +0100	[thread overview]
Message-ID: <20220520221255.1731-2-cristian.dumitrescu@intel.com> (raw)
In-Reply-To: <20220520221255.1731-1-cristian.dumitrescu@intel.com>

Enable the pipeline to use the improved learner table timer operation
through the new "rearm" instruction.

Signed-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
 lib/pipeline/rte_swx_ctl.h               |  50 ++++++
 lib/pipeline/rte_swx_pipeline.c          | 217 ++++++++++++++++++++---
 lib/pipeline/rte_swx_pipeline.h          |   7 +-
 lib/pipeline/rte_swx_pipeline_internal.h |  70 +++++++-
 lib/pipeline/rte_swx_pipeline_spec.c     | 146 ++++++++++++---
 lib/pipeline/version.map                 |   4 +
 6 files changed, 439 insertions(+), 55 deletions(-)

diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h
index 204026dc0e..689f45e3e7 100644
--- a/lib/pipeline/rte_swx_ctl.h
+++ b/lib/pipeline/rte_swx_ctl.h
@@ -548,6 +548,9 @@ struct rte_swx_ctl_learner_info {
 
 	/** Learner table size parameter. */
 	uint32_t size;
+
+	/** Number of possible key timeout values. */
+	uint32_t n_key_timeouts;
 };
 
 /**
@@ -615,6 +618,50 @@ rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p,
 				    uint32_t learner_action_id,
 				    struct rte_swx_ctl_table_action_info *learner_action);
 
+/**
+ * Learner table timeout get
+ *
+ * @param[in] p
+ *   Pipeline handle.
+ * @param[in] learner_id
+ *   Learner table ID (0 .. *n_learners* - 1).
+ * @param[in] timeout_id
+ *   Timeout ID.
+ * @param[out] timeout
+ *   Timeout value measured in seconds. Must be non-NULL.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument.
+ */
+__rte_experimental
+int
+rte_swx_ctl_pipeline_learner_timeout_get(struct rte_swx_pipeline *p,
+					 uint32_t learner_id,
+					 uint32_t timeout_id,
+					 uint32_t *timeout);
+
+/**
+ * Learner table timeout set
+ *
+ * @param[in] p
+ *   Pipeline handle.
+ * @param[in] learner_id
+ *   Learner table ID (0 .. *n_learners* - 1).
+ * @param[in] timeout_id
+ *   Timeout ID.
+ * @param[in] timeout
+ *   Timeout value measured in seconds.
+ * @return
+ *   0 on success or the following error codes otherwise:
+ *   -EINVAL: Invalid argument.
+ */
+__rte_experimental
+int
+rte_swx_ctl_pipeline_learner_timeout_set(struct rte_swx_pipeline *p,
+					 uint32_t learner_id,
+					 uint32_t timeout_id,
+					 uint32_t timeout);
+
 /** Learner table statistics. */
 struct rte_swx_learner_stats {
 	/** Number of packets with lookup hit. */
@@ -629,6 +676,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..0d8c184ae7 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -2556,7 +2556,7 @@ instr_learner_af_exec(struct rte_swx_pipeline *p)
 	stats->n_pkts_action[action_id] = n_pkts_action + 1;
 
 	/* Thread. */
-	thread_ip_action_call(p, t, action_id);
+	thread_ip_inc(p);
 
 	/* Action */
 	action_func(p);
@@ -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;
 
@@ -9984,6 +10074,7 @@ rte_swx_ctl_learner_info_get(struct rte_swx_pipeline *p,
 	learner->n_actions = l->n_actions;
 	learner->default_action_is_const = l->default_action_is_const;
 	learner->size = l->size;
+	learner->n_key_timeouts = l->n_timeouts;
 
 	return 0;
 }
@@ -10039,6 +10130,56 @@ rte_swx_ctl_learner_action_info_get(struct rte_swx_pipeline *p,
 	return 0;
 }
 
+int
+rte_swx_ctl_pipeline_learner_timeout_get(struct rte_swx_pipeline *p,
+					 uint32_t learner_id,
+					 uint32_t timeout_id,
+					 uint32_t *timeout)
+{
+	struct learner *l;
+
+	if (!p || (learner_id >= p->n_learners) || !timeout)
+		return -EINVAL;
+
+	l = learner_find_by_id(p, learner_id);
+	if (!l || (timeout_id >= l->n_timeouts))
+		return -EINVAL;
+
+	*timeout = l->timeout[timeout_id];
+	return 0;
+}
+
+int
+rte_swx_ctl_pipeline_learner_timeout_set(struct rte_swx_pipeline *p,
+					 uint32_t learner_id,
+					 uint32_t timeout_id,
+					 uint32_t timeout)
+{
+	struct learner *l;
+	struct rte_swx_table_state *ts;
+	int status;
+
+	if (!p || (learner_id >= p->n_learners) || !timeout)
+		return -EINVAL;
+
+	l = learner_find_by_id(p, learner_id);
+	if (!l || (timeout_id >= l->n_timeouts))
+		return -EINVAL;
+
+	if (!p->build_done)
+		return -EINVAL;
+
+	ts = &p->table_state[p->n_tables + p->n_selectors + l->id];
+
+	status = rte_swx_table_learner_timeout_update(ts->obj, timeout_id, timeout);
+	if (status)
+		return -EINVAL;
+
+	l->timeout[timeout_id] = timeout;
+
+	return 0;
+}
+
 int
 rte_swx_pipeline_table_state_get(struct rte_swx_pipeline *p,
 				 struct rte_swx_table_state **table_state)
@@ -10170,6 +10311,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 +10725,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 +11351,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 +11682,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 +11905,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;
diff --git a/lib/pipeline/version.map b/lib/pipeline/version.map
index 44332aad26..130278ff0d 100644
--- a/lib/pipeline/version.map
+++ b/lib/pipeline/version.map
@@ -140,4 +140,8 @@ EXPERIMENTAL {
 	rte_swx_ctl_learner_info_get;
 	rte_swx_ctl_learner_match_field_info_get;
 	rte_swx_pipeline_learner_config;
+
+	#added in 22.07
+	rte_swx_ctl_pipeline_learner_timeout_get;
+	rte_swx_ctl_pipeline_learner_timeout_set;
 };
-- 
2.17.1


  reply	other threads:[~2022-05-20 22:13 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-21 15:59 [PATCH 1/3] table: improve learner table timers Cristian Dumitrescu
2022-04-21 15:59 ` [PATCH 2/3] pipeline: " Cristian Dumitrescu
2022-04-21 15:59 ` [PATCH 3/3] examples/pipeline: " Cristian Dumitrescu
2022-04-22 13:03 ` [PATCH V2 1/3] table: " Cristian Dumitrescu
2022-04-22 13:03   ` [PATCH V2 2/3] pipeline: " Cristian Dumitrescu
2022-04-22 13:03   ` [PATCH V2 3/3] examples/pipeline: " Cristian Dumitrescu
2022-05-20 22:12   ` [PATCH V3 1/3] table: " Cristian Dumitrescu
2022-05-20 22:12     ` Cristian Dumitrescu [this message]
2022-05-20 22:12     ` [PATCH V3 3/3] examples/pipeline: " Cristian Dumitrescu
2022-06-01 13:57     ` [PATCH V3 1/3] table: " Thomas Monjalon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220520221255.1731-2-cristian.dumitrescu@intel.com \
    --to=cristian.dumitrescu@intel.com \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.