Add two new actions push & pop for stack operations. Signed-off-by: Han Zhou <hz...@ovn.org> --- include/ovn/actions.h | 8 +++++ lib/actions.c | 73 +++++++++++++++++++++++++++++++++++++++++++ ovn-sb.xml | 15 +++++++++ tests/ovn.at | 11 +++++++ utilities/ovn-trace.c | 64 +++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+)
diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 8dfb6fdc5..f55d77d47 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -59,6 +59,8 @@ struct ovn_extend_table; OVNACT(NEXT, ovnact_next) \ OVNACT(LOAD, ovnact_load) \ OVNACT(MOVE, ovnact_move) \ + OVNACT(PUSH, ovnact_push_pop) \ + OVNACT(POP, ovnact_push_pop) \ OVNACT(EXCHANGE, ovnact_move) \ OVNACT(DEC_TTL, ovnact_null) \ OVNACT(CT_NEXT, ovnact_ct_next) \ @@ -234,6 +236,12 @@ struct ovnact_move { struct expr_field rhs; }; +/* OVNACT_PUSH, OVNACT_POP. */ +struct ovnact_push_pop { + struct ovnact ovnact; + struct expr_field field; +}; + /* OVNACT_CT_NEXT. */ struct ovnact_ct_next { struct ovnact ovnact; diff --git a/lib/actions.c b/lib/actions.c index 1c328f88d..7fe80f458 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -573,6 +573,75 @@ ovnact_move_free(struct ovnact_move *move OVS_UNUSED) { } + +static void +parse_push_pop(struct action_context *ctx, bool is_push) +{ + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + + struct expr_field f; + if (!expr_field_parse(ctx->lexer, ctx->pp->symtab, &f, &ctx->prereqs)) { + return; + } + size_t ofs = ctx->ovnacts->size; + char *error = expr_type_check(&f, f.n_bits, !is_push, ctx->scope); + if (error) { + ctx->ovnacts->size = ofs; + lexer_error(ctx->lexer, "%s", error); + free(error); + return; + } + + lexer_force_match(ctx->lexer, LEX_T_RPAREN); + + struct ovnact_push_pop *p; + if (is_push) { + p = ovnact_put_PUSH(ctx->ovnacts); + } else { + p = ovnact_put_POP(ctx->ovnacts); + } + p->field = f; +} + +static void +format_PUSH(const struct ovnact_push_pop *push, struct ds *s) +{ + ds_put_cstr(s, "push("); + expr_field_format(&push->field, s); + ds_put_cstr(s, ");"); +} + +static void +encode_PUSH(const struct ovnact_push_pop *push, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + ofpact_put_STACK_PUSH(ofpacts)->subfield = + expr_resolve_field(&push->field); +} + +static void +format_POP(const struct ovnact_push_pop *pop, struct ds *s) +{ + ds_put_cstr(s, "pop("); + expr_field_format(&pop->field, s); + ds_put_cstr(s, ");"); +} + +static void +encode_POP(const struct ovnact_push_pop *pop, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + ofpact_put_STACK_POP(ofpacts)->subfield = + expr_resolve_field(&pop->field); +} + +static void +ovnact_push_pop_free(struct ovnact_push_pop *push OVS_UNUSED) +{ +} + static void parse_DEC_TTL(struct action_context *ctx) { @@ -4237,6 +4306,10 @@ parse_action(struct action_context *ctx) parse_set_action(ctx); } else if (lexer_match_id(ctx->lexer, "next")) { parse_NEXT(ctx); + } else if (lexer_match_id(ctx->lexer, "push")) { + parse_push_pop(ctx, true); + } else if (lexer_match_id(ctx->lexer, "pop")) { + parse_push_pop(ctx, false); } else if (lexer_match_id(ctx->lexer, "output")) { ovnact_put_OUTPUT(ctx->ovnacts); } else if (lexer_match_id(ctx->lexer, "ip.ttl")) { diff --git a/ovn-sb.xml b/ovn-sb.xml index aa9ee0ff5..65bfc9a59 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -1271,6 +1271,21 @@ </p> </dd> + <dt><code>push(<var>field</var>);</code></dt> + <dd> + <p> + Push the value of <var>field</var> to the stack top. + </p> + </dd> + + <dt><code>pop(<var>field</var>);</code></dt> + <dd> + <p> + Pop the stack top and store the value to <var>field</var>, + which must be modifiable. + </p> + </dd> + <dt><code>ip.ttl--;</code></dt> <dd> <p> diff --git a/tests/ovn.at b/tests/ovn.at index 6306719a5..e9badf477 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1982,6 +1982,17 @@ reg1[1] = lookup_fdb(outport, ip4.src); reg1[1] = lookup_fdb(ip4.src, eth.src); Cannot use numeric field ip4.src where string field is required. +# push/pop +push(xxreg0);push(xxreg1[10..20]);push(eth.src);pop(xxreg0[0..47]);pop(xxreg0[48..57]);pop(xxreg1); + formats as push(xxreg0); push(xxreg1[10..20]); push(eth.src); pop(xxreg0[0..47]); pop(xxreg0[48..57]); pop(xxreg1); + encodes as push:NXM_NX_XXREG0[],push:NXM_NX_XXREG1[10..20],push:NXM_OF_ETH_SRC[],pop:NXM_NX_XXREG0[0..47],pop:NXM_NX_XXREG0[48..57],pop:NXM_NX_XXREG1[] + +pop(eth.type); + Field eth.type is not modifiable. + +push(abc); + Syntax error at `abc' expecting field name. + # Miscellaneous negative tests. ; Syntax error at `;'. diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index d6ff75886..4b652828d 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -1523,6 +1523,59 @@ execute_exchange(const struct ovnact_move *move, struct flow *uflow, mf_subfield_swap(&a, &b, uflow, NULL); } +static void +execute_push(const struct ovnact_push_pop *p, struct ofpbuf *stack, + struct flow *uflow OVS_UNUSED, struct ovs_list *super) +{ + struct mf_subfield sf = expr_resolve_field(&p->field); + union mf_subvalue sv; + mf_read_subfield(&sf, uflow, &sv); + + struct ds s = DS_EMPTY_INITIALIZER; + ds_put_cstr(&s, "push("); + expr_field_format(&p->field, &s); + ds_put_cstr(&s, ") -> "); + mf_format_subvalue(&sv, &s); + + ovntrace_node_append(super, OVNTRACE_NODE_MODIFY, "%s", ds_cstr(&s)); + ds_destroy(&s); + + uint8_t bytes = DIV_ROUND_UP(sf.n_bits, 8); + nx_stack_push(stack, &sv.u8[sizeof sv - bytes], bytes); +} + +static void +execute_pop(const struct ovnact_push_pop *p, struct ofpbuf *stack, + struct flow *uflow OVS_UNUSED, struct ovs_list *super) +{ + struct mf_subfield sf = expr_resolve_field(&p->field); + struct ds s = DS_EMPTY_INITIALIZER; + ds_put_cstr(&s, "pop("); + expr_field_format(&p->field, &s); + ds_put_cstr(&s, ") <- "); + + uint8_t src_bytes; + const void *src = nx_stack_pop(stack, &src_bytes); + if (src) { + union mf_subvalue sv; + uint8_t dst_bytes = DIV_ROUND_UP(sf.n_bits, 8); + + if (src_bytes < dst_bytes) { + memset(&sv.u8[sizeof sv - dst_bytes], 0, + dst_bytes - src_bytes); + } + memcpy(&sv.u8[sizeof sv - src_bytes], src, src_bytes); + mf_write_subfield_flow(&sf, &sv, uflow); + mf_format_subvalue(&sv, &s); + } else { + ds_put_cstr(&s, "/* empty stack */"); + } + + ovntrace_node_append(super, OVNTRACE_NODE_MODIFY, "%s", ds_cstr(&s)); + + ds_destroy(&s); +} + static void trace__(const struct ovntrace_datapath *dp, struct flow *uflow, uint8_t table_id, enum ovnact_pipeline pipeline, @@ -2558,6 +2611,8 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, return; } + struct ofpbuf stack; + ofpbuf_init(&stack, 0); struct ds s = DS_EMPTY_INITIALIZER; const struct ovnact *a; OVNACT_FOR_EACH (a, ovnacts, ovnacts_len) { @@ -2588,6 +2643,14 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, execute_exchange(ovnact_get_EXCHANGE(a), uflow, super); break; + case OVNACT_PUSH: + execute_push(ovnact_get_PUSH(a), &stack, uflow, super); + break; + + case OVNACT_POP: + execute_pop(ovnact_get_POP(a), &stack, uflow, super); + break; + case OVNACT_DEC_TTL: if (is_ip_any(uflow)) { if (uflow->nw_ttl) { @@ -2829,6 +2892,7 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, break; } } + ofpbuf_uninit(&stack); ds_destroy(&s); } -- 2.30.2 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev