Signed-off-by: Ben Pfaff <b...@ovn.org> Acked-by: Mickey Spiegel <mickeys....@gmail.com> --- include/ovn/actions.h | 5 ++-- ovn/lib/actions.c | 61 ++++++++++++++++++++++++++++++++++++----------- ovn/ovn-sb.xml | 10 ++++++++ ovn/utilities/ovn-trace.c | 19 +++++++++++++++ tests/ovn.at | 5 ++++ 5 files changed, 84 insertions(+), 16 deletions(-)
diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 0bf6145..a1b6b90 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016 Nicira, Inc. + * Copyright (c) 2015, 2016, 2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +60,7 @@ struct simap; OVNACT(CT_DNAT, ovnact_ct_nat) \ OVNACT(CT_SNAT, ovnact_ct_nat) \ OVNACT(CT_LB, ovnact_ct_lb) \ + OVNACT(CLONE, ovnact_nest) \ OVNACT(ARP, ovnact_nest) \ OVNACT(ND_NA, ovnact_nest) \ OVNACT(GET_ARP, ovnact_get_mac_bind) \ @@ -186,7 +187,7 @@ struct ovnact_ct_lb { uint8_t ltable; /* Logical table ID of next table. */ }; -/* OVNACT_ARP, OVNACT_ND_NA. */ +/* OVNACT_ARP, OVNACT_ND_NA, OVNACT_CLONE. */ struct ovnact_nest { struct ovnact ovnact; struct ovnact *nested; diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index 7c5a292..213e22e 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -1001,8 +1001,8 @@ ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb) free(ct_lb->dsts); } -/* Implements the "arp" and "nd_na" actions, which execute nested actions on a - * packet derived from the one being processed. */ +/* Implements the "arp", "nd_na", and "clone" actions, which execute nested + * actions on a packet derived from the one being processed. */ static void parse_nested_action(struct action_context *ctx, enum ovnact_type type, const char *prereq) @@ -1018,13 +1018,21 @@ parse_nested_action(struct action_context *ctx, enum ovnact_type type, .pp = ctx->pp, .lexer = ctx->lexer, .ovnacts = &nested, - .prereqs = NULL + .prereqs = NULL, }; parse_actions(&inner_ctx, LEX_T_RCURLY); - /* XXX Not really sure what we should do with prerequisites for nested - * actions. */ - expr_destroy(inner_ctx.prereqs); + if (prereq) { + /* XXX Not really sure what we should do with prerequisites for "arp" + * and "nd_na" actions. */ + expr_destroy(inner_ctx.prereqs); + add_prerequisite(ctx, prereq); + } else { + /* For "clone", the inner prerequisites should just add to the outer + * ones. */ + ctx->prereqs = expr_combine(EXPR_T_AND, + inner_ctx.prereqs, ctx->prereqs); + } if (inner_ctx.lexer->error) { ovnacts_free(nested.data, nested.size); @@ -1032,8 +1040,6 @@ parse_nested_action(struct action_context *ctx, enum ovnact_type type, return; } - add_prerequisite(ctx, prereq); - struct ovnact_nest *on = ovnact_put(ctx->ovnacts, type, OVNACT_ALIGN(sizeof *on)); on->nested_len = nested.size; @@ -1053,6 +1059,12 @@ parse_ND_NA(struct action_context *ctx) } static void +parse_CLONE(struct action_context *ctx) +{ + parse_nested_action(ctx, OVNACT_CLONE, NULL); +} + +static void format_nested_action(const struct ovnact_nest *on, const char *name, struct ds *s) { @@ -1074,10 +1086,16 @@ format_ND_NA(const struct ovnact_nest *nest, struct ds *s) } static void -encode_nested_actions(const struct ovnact_nest *on, - const struct ovnact_encode_params *ep, - enum action_opcode opcode, - struct ofpbuf *ofpacts) +format_CLONE(const struct ovnact_nest *nest, struct ds *s) +{ + format_nested_action(nest, "clone", s); +} + +static void +encode_nested_neighbor_actions(const struct ovnact_nest *on, + const struct ovnact_encode_params *ep, + enum action_opcode opcode, + struct ofpbuf *ofpacts) { /* Convert nested actions into ofpacts. */ uint64_t inner_ofpacts_stub[1024 / 8]; @@ -1102,7 +1120,7 @@ encode_ARP(const struct ovnact_nest *on, const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_nested_actions(on, ep, ACTION_OPCODE_ARP, ofpacts); + encode_nested_neighbor_actions(on, ep, ACTION_OPCODE_ARP, ofpacts); } static void @@ -1110,9 +1128,22 @@ encode_ND_NA(const struct ovnact_nest *on, const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_nested_actions(on, ep, ACTION_OPCODE_ND_NA, ofpacts); + encode_nested_neighbor_actions(on, ep, ACTION_OPCODE_ND_NA, ofpacts); } +static void +encode_CLONE(const struct ovnact_nest *on, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + size_t ofs = ofpacts->size; + ofpact_put_CLONE(ofpacts); + ovnacts_encode(on->nested, on->nested_len, ep, ofpacts); + + struct ofpact_nest *clone = ofpbuf_at_assert(ofpacts, ofs, sizeof *clone); + ofpacts->header = clone; + ofpact_finish_CLONE(ofpacts, &clone); +} static void ovnact_nest_free(struct ovnact_nest *on) @@ -1664,6 +1695,8 @@ parse_action(struct action_context *ctx) parse_CT_SNAT(ctx); } else if (lexer_match_id(ctx->lexer, "ct_lb")) { parse_ct_lb_action(ctx); + } else if (lexer_match_id(ctx->lexer, "clone")) { + parse_CLONE(ctx); } else if (lexer_match_id(ctx->lexer, "arp")) { parse_ARP(ctx); } else if (lexer_match_id(ctx->lexer, "nd_na")) { diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index 5704f41..a724ae6 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -1137,6 +1137,16 @@ </p> </dd> + + <dt><code>clone { <var>action</var>; </code>...<code> };</code></dt> + <dd> + Makes a copy of the packet being processed and executes each + <code>action</code> on the copy. Actions following the + <var>clone</var> action, if any, apply to the original, unmodified + packet. This can be used as a way to ``save and restore'' the packet + around a set of actions that may modify it and should not persist. + </dd> + <dt><code>arp { <var>action</var>; </code>...<code> };</code></dt> <dd> <p> diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c index c15ea0b..6386b68 100644 --- a/ovn/utilities/ovn-trace.c +++ b/ovn/utilities/ovn-trace.c @@ -1228,6 +1228,20 @@ execute_output(const struct ovntrace_datapath *dp, struct flow *uflow, } static void +execute_clone(const struct ovnact_nest *on, const struct ovntrace_datapath *dp, + const struct flow *uflow, uint8_t table_id, + enum ovntrace_pipeline pipeline, struct ovs_list *super) +{ + struct flow cloned_flow = *uflow; + + struct ovntrace_node *node = ovntrace_node_append( + super, OVNTRACE_NODE_TRANSFORMATION, "clone"); + + trace_actions(on->nested, on->nested_len, dp, &cloned_flow, + table_id, pipeline, &node->subs); +} + +static void execute_arp(const struct ovnact_nest *on, const struct ovntrace_datapath *dp, const struct flow *uflow, uint8_t table_id, enum ovntrace_pipeline pipeline, struct ovs_list *super) @@ -1416,6 +1430,11 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, "*** ct_* actions not implemented"); break; + case OVNACT_CLONE: + execute_clone(ovnact_get_CLONE(a), dp, uflow, table_id, pipeline, + super); + break; + case OVNACT_ARP: execute_arp(ovnact_get_ARP(a), dp, uflow, table_id, pipeline, super); diff --git a/tests/ovn.at b/tests/ovn.at index a514ebbd..67d73c5 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -867,6 +867,11 @@ ct_snat(foo, bar); ct_snat(); Syntax error at `)' expecting IPv4 address. +# clone +clone { ip4.dst = 255.255.255.255; output; }; next(11); + encodes as clone(set_field:255.255.255.255->ip_dst,resubmit(,64)),resubmit(,27) + has prereqs eth.type == 0x800 + # arp arp { eth.dst = ff:ff:ff:ff:ff:ff; output; }; output; encodes as controller(userdata=00.00.00.00.00.00.00.00.00.19.00.10.80.00.06.06.ff.ff.ff.ff.ff.ff.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00),resubmit(,64) -- 2.10.2 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev