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

Reply via email to