This is a little bit simpler and marginally more efficient, but also makes following changes easier.
Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/meta-flow.c | 10 +--- lib/meta-flow.h | 10 +++- lib/nx-match.c | 131 ++---------------------------------------- lib/nx-match.h | 2 - lib/ofp-actions.c | 93 +++++++++++++++++++++++++----- lib/ofp-actions.h | 18 +++++- lib/ofp-parse.c | 15 +++-- lib/ofp-util.c | 59 +++++++++++++++++++ lib/ofp-util.h | 5 ++ ofproto/ofproto-dpif-xlate.c | 9 +++ 10 files changed, 194 insertions(+), 158 deletions(-) diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 3ac396f..a826165 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -41,7 +41,7 @@ VLOG_DEFINE_THIS_MODULE(meta_flow); sizeof ((union mf_value *)0)->MEMBER, \ 8 * sizeof ((union mf_value *)0)->MEMBER -static const struct mf_field mf_fields[MFF_N_IDS] = { +const struct mf_field mf_fields[MFF_N_IDS] = { /* ## -------- ## */ /* ## metadata ## */ /* ## -------- ## */ @@ -717,14 +717,6 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); const struct mf_field *mf_from_nxm_header__(uint32_t header); static void nxm_init(void); -/* Returns the field with the given 'id'. */ -const struct mf_field * -mf_from_id(enum mf_field_id id) -{ - ovs_assert((unsigned int) id < MFF_N_IDS); - return &mf_fields[id]; -} - /* Returns the field with the given 'name', or a null pointer if no field has * that name. */ const struct mf_field * diff --git a/lib/meta-flow.h b/lib/meta-flow.h index a3f6701..03d7794 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -24,6 +24,7 @@ #include "ofp-errors.h" #include "ofp-util.h" #include "packets.h" +#include "util.h" struct ds; struct match; @@ -329,11 +330,18 @@ union mf_subvalue { BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue)); /* Finding mf_fields. */ -const struct mf_field *mf_from_id(enum mf_field_id); const struct mf_field *mf_from_name(const char *name); const struct mf_field *mf_from_nxm_header(uint32_t nxm_header); const struct mf_field *mf_from_nxm_name(const char *nxm_name); +static inline const struct mf_field * +mf_from_id(enum mf_field_id id) +{ + extern const struct mf_field mf_fields[MFF_N_IDS]; + ovs_assert((unsigned int) id < MFF_N_IDS); + return &mf_fields[id]; +} + /* Inspecting wildcarded bits. */ bool mf_is_all_wild(const struct mf_field *, const struct flow_wildcards *); diff --git a/lib/nx-match.c b/lib/nx-match.c index 15143f1..dd91b01 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1088,39 +1088,14 @@ nxm_format_reg_move(const struct ofpact_reg_move *move, struct ds *s) mf_format_subfield(&move->dst, s); } -static void -set_field_format(const struct ofpact_reg_load *load, struct ds *s) -{ - const struct mf_field *mf = load->dst.field; - union mf_value value; - - ovs_assert(load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD); - ds_put_format(s, "set_field:"); - memset(&value, 0, sizeof value); - bitwise_copy(&load->subvalue, sizeof load->subvalue, 0, - &value, mf->n_bytes, 0, load->dst.n_bits); - mf_format(mf, &value, NULL, s); - ds_put_format(s, "->%s", mf->name); -} - -static void -load_format(const struct ofpact_reg_load *load, struct ds *s) +void +nxm_format_reg_load(const struct ofpact_reg_load *load, struct ds *s) { ds_put_cstr(s, "load:"); mf_format_subvalue(&load->subvalue, s); ds_put_cstr(s, "->"); mf_format_subfield(&load->dst, s); } - -void -nxm_format_reg_load(const struct ofpact_reg_load *load, struct ds *s) -{ - if (load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD) { - set_field_format(load, s); - } else { - load_format(load, s); - } -} enum ofperr nxm_reg_move_from_openflow(const struct nx_action_reg_move *narm, @@ -1160,38 +1135,6 @@ nxm_reg_load_from_openflow(const struct nx_action_reg_load *narl, return nxm_reg_load_check(load, NULL); } - -enum ofperr -nxm_reg_load_from_openflow12_set_field( - const struct ofp12_action_set_field * oasf, struct ofpbuf *ofpacts) -{ - uint16_t oasf_len = ntohs(oasf->len); - uint32_t oxm_header = ntohl(oasf->dst); - uint8_t oxm_length = NXM_LENGTH(oxm_header); - struct ofpact_reg_load *load; - const struct mf_field *mf; - - /* ofp12_action_set_field is padded to 64 bits by zero */ - if (oasf_len != ROUND_UP(sizeof(*oasf) + oxm_length, 8)) { - return OFPERR_OFPBAC_BAD_SET_LEN; - } - if (!is_all_zeros((const uint8_t *)(oasf) + sizeof *oasf + oxm_length, - oasf_len - oxm_length - sizeof *oasf)) { - return OFPERR_OFPBAC_BAD_SET_ARGUMENT; - } - - if (NXM_HASMASK(oxm_header)) { - return OFPERR_OFPBAC_BAD_SET_TYPE; - } - mf = mf_from_nxm_header(oxm_header); - if (!mf) { - return OFPERR_OFPBAC_BAD_SET_TYPE; - } - load = ofpact_put_REG_LOAD(ofpacts); - ofpact_set_field_init(load, mf, oasf + 1); - - return nxm_reg_load_check(load, NULL); -} enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *move, const struct flow *flow) @@ -1226,8 +1169,9 @@ nxm_reg_move_to_nxast(const struct ofpact_reg_move *move, narm->dst = htonl(move->dst.field->nxm_header); } -static void -reg_load_to_nxast(const struct ofpact_reg_load *load, struct ofpbuf *openflow) +void +nxm_reg_load_to_nxast(const struct ofpact_reg_load *load, + struct ofpbuf *openflow) { struct nx_action_reg_load *narl; @@ -1236,71 +1180,6 @@ reg_load_to_nxast(const struct ofpact_reg_load *load, struct ofpbuf *openflow) narl->dst = htonl(load->dst.field->nxm_header); narl->value = load->subvalue.be64[1]; } - -static void -set_field_to_ofast(const struct ofpact_reg_load *load, - struct ofpbuf *openflow) -{ - const struct mf_field *mf = load->dst.field; - uint16_t padded_value_len = ROUND_UP(mf->n_bytes, 8); - struct ofp12_action_set_field *oasf; - char *value; - - /* Set field is the only action of variable length (so far), - * so handling the variable length portion is open-coded here */ - oasf = ofputil_put_OFPAT12_SET_FIELD(openflow); - oasf->dst = htonl(mf->oxm_header); - oasf->len = htons(ntohs(oasf->len) + padded_value_len); - - value = ofpbuf_put_zeros(openflow, padded_value_len); - bitwise_copy(&load->subvalue, sizeof load->subvalue, load->dst.ofs, - value, mf->n_bytes, load->dst.ofs, load->dst.n_bits); -} - -void -nxm_reg_load_to_nxast(const struct ofpact_reg_load *load, - struct ofpbuf *openflow) -{ - - if (load->ofpact.compat == OFPUTIL_OFPAT12_SET_FIELD) { - struct ofp_header *oh = (struct ofp_header *)openflow->l2; - - switch(oh->version) { - case OFP13_VERSION: - case OFP12_VERSION: - set_field_to_ofast(load, openflow); - break; - - case OFP11_VERSION: - case OFP10_VERSION: - if (load->dst.n_bits < 64) { - reg_load_to_nxast(load, openflow); - } else { - /* Split into 64bit chunks */ - int chunk, ofs; - for (ofs = 0; ofs < load->dst.n_bits; ofs += chunk) { - struct ofpact_reg_load subload = *load; - - chunk = MIN(load->dst.n_bits - ofs, 64); - - subload.dst.field = load->dst.field; - subload.dst.ofs = load->dst.ofs + ofs; - subload.dst.n_bits = chunk; - bitwise_copy(&load->subvalue, sizeof load->subvalue, ofs, - &subload.subvalue, sizeof subload.subvalue, 0, - chunk); - reg_load_to_nxast(&subload, openflow); - } - } - break; - - default: - NOT_REACHED(); - } - } else { - reg_load_to_nxast(load, openflow); - } -} /* nxm_execute_reg_move(), nxm_execute_reg_load(). */ diff --git a/lib/nx-match.h b/lib/nx-match.h index 7065225..ee3f24c 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -70,8 +70,6 @@ enum ofperr nxm_reg_move_from_openflow(const struct nx_action_reg_move *, struct ofpbuf *ofpacts); enum ofperr nxm_reg_load_from_openflow(const struct nx_action_reg_load *, struct ofpbuf *ofpacts); -enum ofperr nxm_reg_load_from_openflow12_set_field( - const struct ofp12_action_set_field * oasf, struct ofpbuf *ofpacts); enum ofperr nxm_reg_move_check(const struct ofpact_reg_move *, const struct flow *); diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index e702bab..c666069 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -736,6 +736,55 @@ decode_openflow11_action(const union ofp_action *a, } static enum ofperr +oxm_set_field_from_openflow12( + const struct ofp12_action_set_field * oasf, struct ofpbuf *ofpacts) +{ + uint16_t oasf_len = ntohs(oasf->len); + uint32_t oxm_header = ntohl(oasf->dst); + uint8_t oxm_length = NXM_LENGTH(oxm_header); + struct ofpact_set_field *sf; + const struct mf_field *mf; + size_t prune; + + /* ofp12_action_set_field is padded to 64 bits by zero */ + if (oasf_len != ROUND_UP(sizeof(*oasf) + oxm_length, 8)) { + return OFPERR_OFPBAC_BAD_SET_LEN; + } + if (!is_all_zeros((const uint8_t *)(oasf) + sizeof *oasf + oxm_length, + oasf_len - oxm_length - sizeof *oasf)) { + return OFPERR_OFPBAC_BAD_SET_ARGUMENT; + } + + if (NXM_HASMASK(oxm_header)) { + return OFPERR_OFPBAC_BAD_SET_TYPE; + } + mf = mf_from_nxm_header(oxm_header); + if (!mf) { + return OFPERR_OFPBAC_BAD_SET_TYPE; + } + ovs_assert(mf->n_bytes == oxm_length); + /* oxm_length is now validated to be compatible with mf_value. */ + if (!mf->writable) { + VLOG_WARN_RL(&rl, "destination field %s is not writable", + mf->name); + return OFPERR_OFPBAC_BAD_SET_ARGUMENT; + } + + sf = ofpact_put_SET_FIELD(ofpacts); + sf->field = mf->id; + + memcpy(&sf->value.u8, oasf + 1, mf->n_bytes); + prune = sizeof(union mf_value) - mf->n_bytes; + sf->ofpact.len -= prune; + ofpacts->size -= ROUND_DOWN(prune, OFPACT_ALIGNTO); + + if (!mf_is_value_valid(mf, &sf->value)) { + return OFPERR_OFPBAC_BAD_SET_ARGUMENT; + } + return 0; +} + +static enum ofperr output_from_openflow11(const struct ofp11_action_output *oao, struct ofpbuf *out) { @@ -855,7 +904,7 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out) break; case OFPUTIL_OFPAT12_SET_FIELD: - return nxm_reg_load_from_openflow12_set_field( + return oxm_set_field_from_openflow12( (const struct ofp12_action_set_field *)a, out); case OFPUTIL_OFPAT11_SET_MPLS_TTL: { @@ -914,6 +963,7 @@ static bool ofpact_is_set_action(const struct ofpact *a) { switch (a->type) { + case OFPACT_SET_FIELD: case OFPACT_REG_LOAD: case OFPACT_SET_ETH_DST: case OFPACT_SET_ETH_SRC: @@ -978,6 +1028,7 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) case OFPACT_PUSH_MPLS: case OFPACT_PUSH_VLAN: case OFPACT_REG_LOAD: + case OFPACT_SET_FIELD: case OFPACT_SET_ETH_DST: case OFPACT_SET_ETH_SRC: case OFPACT_SET_IPV4_DSCP: @@ -1230,6 +1281,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) case OFPACT_SET_L4_DST_PORT: case OFPACT_REG_MOVE: case OFPACT_REG_LOAD: + case OFPACT_SET_FIELD: case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: case OFPACT_DEC_TTL: @@ -1483,6 +1535,7 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports, uint8_t table_id) { const struct ofpact_enqueue *enqueue; + const struct mf_field *mf; switch (a->type) { case OFPACT_OUTPUT: @@ -1528,6 +1581,15 @@ ofpact_check__(const struct ofpact *a, struct flow *flow, ofp_port_t max_ports, case OFPACT_REG_LOAD: return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow); + case OFPACT_SET_FIELD: + mf = mf_from_id(ofpact_get_SET_FIELD(a)->field); + if (!mf_are_prereqs_ok(mf, flow)) { + VLOG_WARN_RL(&rl, "set_field %s lacks correct prerequisites", + mf->name); + return OFPERR_OFPBAC_MATCH_INCONSISTENT; + } + return 0; + case OFPACT_STACK_PUSH: return nxm_stack_push_check(ofpact_get_STACK_PUSH(a), flow); @@ -1816,6 +1878,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out) nxm_reg_load_to_nxast(ofpact_get_REG_LOAD(a), out); break; + case OFPACT_SET_FIELD: + ofputil_set_field_to_openflow(ofpact_get_SET_FIELD(a), out); + break; + case OFPACT_STACK_PUSH: nxm_stack_push_to_nxast(ofpact_get_STACK_PUSH(a), out); break; @@ -2017,6 +2083,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out) case OFPACT_BUNDLE: case OFPACT_REG_MOVE: case OFPACT_REG_LOAD: + case OFPACT_SET_FIELD: case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: case OFPACT_DEC_TTL: @@ -2207,6 +2274,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out) case OFPACT_BUNDLE: case OFPACT_REG_MOVE: case OFPACT_REG_LOAD: + case OFPACT_SET_FIELD: case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: case OFPACT_SET_TUNNEL: @@ -2363,6 +2431,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) case OFPACT_SET_L4_DST_PORT: case OFPACT_REG_MOVE: case OFPACT_REG_LOAD: + case OFPACT_SET_FIELD: case OFPACT_STACK_PUSH: case OFPACT_STACK_POP: case OFPACT_DEC_TTL: @@ -2518,6 +2587,8 @@ ofpact_format(const struct ofpact *a, struct ds *s) const struct ofpact_metadata *metadata; const struct ofpact_tunnel *tunnel; const struct ofpact_sample *sample; + const struct ofpact_set_field *set_field; + const struct mf_field *mf; ofp_port_t port; switch (a->type) { @@ -2644,6 +2715,14 @@ ofpact_format(const struct ofpact *a, struct ds *s) nxm_format_reg_load(ofpact_get_REG_LOAD(a), s); break; + case OFPACT_SET_FIELD: + set_field = ofpact_get_SET_FIELD(a); + mf = mf_from_id(set_field->field); + ds_put_format(s, "set_field:"); + mf_format(mf, &set_field->value, NULL, s); + ds_put_format(s, "->%s", mf->name); + break; + case OFPACT_STACK_PUSH: nxm_format_stack_push(ofpact_get_STACK_PUSH(a), s); break; @@ -2861,15 +2940,3 @@ ofpact_pad(struct ofpbuf *ofpacts) ofpbuf_put_zeros(ofpacts, OFPACT_ALIGNTO - rem); } } - -void -ofpact_set_field_init(struct ofpact_reg_load *load, const struct mf_field *mf, - const void *src) -{ - load->ofpact.compat = OFPUTIL_OFPAT12_SET_FIELD; - load->dst.field = mf; - load->dst.ofs = 0; - load->dst.n_bits = mf->n_bits; - bitwise_copy(src, mf->n_bytes, load->dst.ofs, - &load->subvalue, sizeof load->subvalue, 0, mf->n_bits); -} diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 29d9200..128e2ab 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -59,6 +59,7 @@ DEFINE_OFPACT(BUNDLE, ofpact_bundle, slaves) \ \ /* Header changes. */ \ + DEFINE_OFPACT(SET_FIELD, ofpact_set_field, ofpact) \ DEFINE_OFPACT(SET_VLAN_VID, ofpact_vlan_vid, ofpact) \ DEFINE_OFPACT(SET_VLAN_PCP, ofpact_vlan_pcp, ofpact) \ DEFINE_OFPACT(STRIP_VLAN, ofpact_null, ofpact) \ @@ -338,13 +339,28 @@ struct ofpact_stack { /* OFPACT_REG_LOAD. * - * Used for NXAST_REG_LOAD, OFPAT12_SET_FIELD. */ + * Used for NXAST_REG_LOAD. */ struct ofpact_reg_load { struct ofpact ofpact; struct mf_subfield dst; union mf_subvalue subvalue; /* Least-significant bits are used. */ }; +/* OFPACT_SET_FIELD. + * + * Used for OFPAT12_SET_FIELD. + * + * Note: Actual size may be less than sizeof(struct ofpact_set_field), + * as most of the time 'value' would have trailing zeroes that are + * never referenced. 'ofpact.len' tells the correct size, and is never + * less than needed for the field in question. */ +struct ofpact_set_field { + struct ofpact ofpact; + enum mf_field_id field; + union mf_value value; /* Most-significant bits are used, the rest + * might not be here. */ +}; + /* OFPACT_PUSH_VLAN/MPLS/PBB * * Used for NXAST_PUSH_MPLS, OFPAT11_PUSH_MPLS. */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 74538fd..bf7f56f 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -464,13 +464,13 @@ static char * WARN_UNUSED_RESULT set_field_parse__(char *arg, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols) { - struct ofpact_reg_load *load = ofpact_put_REG_LOAD(ofpacts); + struct ofpact_set_field *sf = ofpact_put_SET_FIELD(ofpacts); char *value; char *delim; char *key; const struct mf_field *mf; char *error; - union mf_value mf_value; + size_t prune; value = arg; delim = strstr(arg, "->"); @@ -489,16 +489,19 @@ set_field_parse__(char *arg, struct ofpbuf *ofpacts, if (!mf->writable) { return xasprintf("%s is read-only", key); } - + sf->field = mf->id; delim[0] = '\0'; - error = mf_parse_value(mf, value, &mf_value); + error = mf_parse_value(mf, value, &sf->value); if (error) { return error; } - if (!mf_is_value_valid(mf, &mf_value)) { + prune = sizeof(union mf_value) - mf->n_bytes; + sf->ofpact.len -= prune; + ofpacts->size -= ROUND_DOWN(prune, OFPACT_ALIGNTO); + + if (!mf_is_value_valid(mf, &sf->value)) { return xasprintf("%s is not a valid value for field %s", value, key); } - ofpact_set_field_init(load, mf, &mf_value); *usable_protocols &= mf->usable_protocols; return NULL; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 173b534..f689d1d 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -6132,3 +6132,62 @@ ofputil_append_queue_stat(struct list *replies, NOT_REACHED(); } } + +static void +set_field_to_ofast(const struct ofpact_set_field *sf, + struct ofpbuf *openflow) +{ + const struct mf_field *mf = mf_from_id(sf->field); + uint16_t padded_value_len = ROUND_UP(mf->n_bytes, 8); + struct ofp12_action_set_field *oasf; + char *value; + + /* Set field is the only action of variable length (so far), + * so handling the variable length portion is open-coded here */ + oasf = ofputil_put_OFPAT12_SET_FIELD(openflow); + oasf->dst = htonl(mf->oxm_header); + oasf->len = htons(ntohs(oasf->len) + padded_value_len); + + value = ofpbuf_put_zeros(openflow, padded_value_len); + memcpy(value, &sf->value, mf->n_bytes); +} + +void +ofputil_set_field_to_openflow(const struct ofpact_set_field *sf, + struct ofpbuf *openflow) +{ + struct ofp_header *oh = (struct ofp_header *)openflow->l2; + struct nx_action_reg_load *narl; + const struct mf_field *mf; + + if (oh->version >= OFP12_VERSION) { + set_field_to_ofast(sf, openflow); + return; + } + + mf = mf_from_id(sf->field); + + /* Convert to one or two REG_LOADs */ + + if (mf->n_bits > 64) { + ovs_assert(mf->n_bytes == 16); /* IPv6 addr. */ + /* Split into 64bit chunks */ + /* Lower bits first. */ + narl = ofputil_put_NXAST_REG_LOAD(openflow); + narl->ofs_nbits = nxm_encode_ofs_nbits(0, 64); + narl->dst = htonl(mf->nxm_header); + narl->value = *(&sf->value.be64 + 1); + /* Higher bits next. */ + narl = ofputil_put_NXAST_REG_LOAD(openflow); + narl->ofs_nbits = nxm_encode_ofs_nbits(64, mf->n_bits - 64); + narl->dst = htonl(mf->nxm_header); + narl->value = sf->value.be64; + } else { + narl = ofputil_put_NXAST_REG_LOAD(openflow); + narl->ofs_nbits = nxm_encode_ofs_nbits(0, mf->n_bits); + narl->dst = htonl(mf->nxm_header); + memset(&narl->value, 0, 8 - mf->n_bytes); + memcpy((char*)&narl->value + (8 - mf->n_bytes), + &sf->value, mf->n_bytes); + } +} diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 937423e..f998e09 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -31,6 +31,7 @@ struct ofpbuf; union ofp_action; +struct ofpact_set_field; /* Port numbers. */ enum ofperr ofputil_port_from_ofp11(ovs_be32 ofp11_port, @@ -981,4 +982,8 @@ void ofputil_append_group_desc_reply(const struct ofputil_group_desc *, struct list *replies); struct ofpbuf *ofputil_encode_group_desc_request(enum ofp_version); +void +ofputil_set_field_to_openflow(const struct ofpact_set_field *, + struct ofpbuf *); + #endif /* ofp-util.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 37472ef..65ee8e2 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -2288,6 +2288,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { struct ofpact_controller *controller; const struct ofpact_metadata *metadata; + const struct ofpact_set_field *set_field; + const struct mf_field *mf; if (ctx->exit) { break; @@ -2421,6 +2423,13 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, nxm_execute_reg_load(ofpact_get_REG_LOAD(a), flow, wc); break; + case OFPACT_SET_FIELD: + set_field = ofpact_get_SET_FIELD(a); + mf = mf_from_id(set_field->field); + mf_mask_field_and_prereqs(mf, &wc->masks); + mf_set_flow_value(mf, &set_field->value, flow); + break; + case OFPACT_STACK_PUSH: nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), flow, wc, &ctx->stack); -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev