@@ -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;
@@ -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")) {
@@ -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>
@@ -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 `;'.
@@ -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);
}
Add two new actions push & pop for stack operations. Signed-off-by: Han Zhou <hzhou@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(+)