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); + /* 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); - if (mf_name) { - struct field *mf; - - mf = metadata_field_parse(p, mf_name); - CHECK(mf, 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 0a36c92337..dd1d499f57 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; }; @@ -2208,7 +2216,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]; @@ -2221,8 +2231,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, @@ -2232,6 +2242,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; };