In OpenFlow 1.1, we add support for OFPIT_WRITE_METADATA. This allows us to
write to the metadata field. Internally it is represented using ofpact_metadata.

We introduce NXAST_WRITE_METADATA to handle writing to the metadata field in
OpenFlow 1.0+. This structure reflects OFPIT_WRITE_METADATA.

When writing out the structure to OpenFlow 1.1, it uses the OFPIT_WRITE_METADATA
instruction only, and not the new NXAST action (which would be redundant).

Signed-off-by: Joe Stringer <j...@wand.net.nz>
---
v2: Dropped unused function
---
 NEWS                          |    1 +
 include/openflow/nicira-ext.h |   15 +++++++
 lib/ofp-actions.c             |   84 ++++++++++++++++++++++++++++++++++++++++-
 lib/ofp-actions.h             |   13 ++++++
 lib/ofp-parse.c               |   22 +++++++++++
 lib/ofp-util.def              |    2 +
 lib/ofp-util.h                |    1 +
 ofproto/ofproto-dpif.c        |    8 ++++
 tests/ofp-actions.at          |   55 ++++++++++++++++++++++++--
 tests/ofproto.at              |    6 +++
 utilities/ovs-ofctl.8.in      |   16 ++++++++
 11 files changed, 217 insertions(+), 6 deletions(-)

diff --git a/NEWS b/NEWS
index 84f1ec1..9b67872 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,7 @@ post-v1.7.0
         the multicast bit in the destination address could be individually
        masked.)
       - New field OXM_OF_METADATA, to align with OpenFlow 1.1.
+      - Adds support for writing to the metadata field for a flow.
       - The OFPST_QUEUE request now reports an error if a specified port or
         queue does not exist, or for requests for a specific queue on all
         ports, if the specified queue does not exist on any port.  (Previous
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 82deeb0..2e42dcb 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -341,6 +341,7 @@ enum nx_action_subtype {
     NXAST_DEC_TTL,              /* struct nx_action_header */
     NXAST_FIN_TIMEOUT,          /* struct nx_action_fin_timeout */
     NXAST_CONTROLLER,           /* struct nx_action_controller */
+    NXAST_WRITE_METADATA,       /* struct nx_action_write_metadata */
 };
 
 /* Header for Nicira-defined actions. */
@@ -1977,4 +1978,18 @@ struct nx_action_controller {
 };
 OFP_ASSERT(sizeof(struct nx_action_controller) == 16);
 
+/* Action structure for NXAST_WRITE_METADATA.
+ *
+ * Modifies the 'mask' bits of the metadata value. */
+struct nx_action_write_metadata {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 32. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_WRITE_METADATA. */
+    uint8_t pad[6];
+    ovs_be64 metadata;              /* Metadata register. */
+    ovs_be64 mask;                  /* Metadata mask. */
+};
+OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32);
+
 #endif /* openflow/nicira-ext.h */
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 93f6bf7..bafaf1e 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -136,6 +136,17 @@ controller_from_openflow(const struct nx_action_controller 
*nac,
 }
 
 static void
+metadata_from_openflow(const struct nx_action_write_metadata *nawm,
+                       struct ofpbuf *out)
+{
+    struct ofpact_metadata *om;
+
+    om = ofpact_put_WRITE_METADATA(out);
+    om->metadata = ntohll(nawm->metadata);
+    om->mask = ntohll(nawm->mask);
+}
+
+static void
 note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
 {
     struct ofpact_note *note;
@@ -224,6 +235,7 @@ ofpact_from_nxast(const union ofp_action *a, enum 
ofputil_action_code code,
     const struct nx_action_set_queue *nasq;
     const struct nx_action_note *nan;
     const struct nx_action_set_tunnel64 *nast64;
+    const struct nx_action_write_metadata *nawm;
     struct ofpact_tunnel *tunnel;
     enum ofperr error = 0;
 
@@ -245,6 +257,11 @@ ofpact_from_nxast(const union ofp_action *a, enum 
ofputil_action_code code,
         tunnel->tun_id = ntohl(nast->tun_id);
         break;
 
+    case OFPUTIL_NXAST_WRITE_METADATA:
+        nawm = (const struct nx_action_write_metadata *) a;
+        metadata_from_openflow(nawm, out);
+        break;
+
     case OFPUTIL_NXAST_SET_QUEUE:
         nasq = (const struct nx_action_set_queue *) a;
         ofpact_put_SET_QUEUE(out)->queue_id = ntohl(nasq->queue_id);
@@ -889,12 +906,21 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf 
*openflow,
         if (error) {
             goto exit;
         }
+    } else if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {
+        const struct ofp11_instruction_write_metadata *oiwm;
+        struct ofpact_metadata *om;
+
+        oiwm = (const struct ofp11_instruction_write_metadata *)
+            insts[OVSINST_OFPIT11_WRITE_METADATA];
+
+        om = (struct ofpact_metadata *)ofpact_put_WRITE_METADATA(ofpacts);
+        om->metadata = ntohll(oiwm->metadata);
+        om->mask = ntohll(oiwm->metadata_mask);
     }
 
     ofpact_pad(ofpacts);
 
     if (insts[OVSINST_OFPIT11_GOTO_TABLE] ||
-        insts[OVSINST_OFPIT11_WRITE_METADATA] ||
         insts[OVSINST_OFPIT11_WRITE_ACTIONS] ||
         insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
         error = OFPERR_OFPBIC_UNSUP_INST;
@@ -955,6 +981,7 @@ ofpact_check__(const struct ofpact *a, const struct flow 
*flow, int max_ports)
 
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
+    case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
@@ -1043,6 +1070,17 @@ ofpact_set_tunnel_to_nxast(const struct ofpact_tunnel 
*tunnel,
 }
 
 static void
+ofpact_write_metadata_to_nxast(const struct ofpact_metadata *om,
+                         struct ofpbuf *out)
+{
+    struct nx_action_write_metadata *nawm;
+
+    nawm = ofputil_put_NXAST_WRITE_METADATA(out);
+    nawm->metadata = htonll(om->metadata);
+    nawm->mask = htonll(om->mask);
+}
+
+static void
 ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out)
 {
     size_t start_ofs = out->size;
@@ -1117,6 +1155,10 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf 
*out)
         ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
         break;
 
+    case OFPACT_WRITE_METADATA:
+        ofpact_write_metadata_to_nxast(ofpact_get_WRITE_METADATA(a), out);
+        break;
+
     case OFPACT_SET_QUEUE:
         ofputil_put_NXAST_SET_QUEUE(out)->queue_id
             = htonl(ofpact_get_SET_QUEUE(a)->queue_id);
@@ -1262,6 +1304,7 @@ ofpact_to_openflow10(const struct ofpact *a, struct 
ofpbuf *out)
     case OFPACT_REG_LOAD:
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
+    case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
@@ -1363,6 +1406,10 @@ ofpact_to_openflow11(const struct ofpact *a, struct 
ofpbuf *out)
             = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
         break;
 
+    case OFPACT_WRITE_METADATA:
+        /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
+        break;
+
     case OFPACT_CONTROLLER:
     case OFPACT_OUTPUT_REG:
     case OFPACT_BUNDLE:
@@ -1398,6 +1445,29 @@ ofpacts_put_openflow11_actions(const struct ofpact 
ofpacts[],
     }
 }
 
+/* Searches for a write-metadata instruction in 'ofpacts' and if found,
+ * converts to the OpenFlow 1.1 instruction format, appending the instruction
+ * to any existing data in 'openflow'. */
+void
+ofpacts_put_openflow11_write_metadata(const struct ofpact ofpacts[],
+                                      size_t ofpacts_len,
+                                      struct ofpbuf *openflow)
+{
+    struct ofp11_instruction_write_metadata *oiwm;
+    const struct ofpact *a;
+    const struct ofpact_metadata *om;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        if (a->type == OFPACT_WRITE_METADATA) {
+            om = ofpact_get_WRITE_METADATA(a);
+            oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
+            oiwm->metadata = htonll(om->metadata);
+            oiwm->metadata_mask = htonll(om->mask);
+            return;
+        }
+    }
+}
+
 void
 ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
                                     size_t ofpacts_len,
@@ -1418,6 +1488,8 @@ ofpacts_put_openflow11_instructions(const struct ofpact 
ofpacts[],
     } else {
         openflow->size = ofs;
     }
+
+    ofpacts_put_openflow11_write_metadata(ofpacts, ofpacts_len, openflow);
 }
 
 /* Returns true if 'action' outputs to 'port', false otherwise. */
@@ -1448,6 +1520,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, 
uint16_t port)
     case OFPACT_REG_LOAD:
     case OFPACT_DEC_TTL:
     case OFPACT_SET_TUNNEL:
+    case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
@@ -1527,6 +1600,7 @@ ofpact_format(const struct ofpact *a, struct ds *s)
     const struct ofpact_autopath *autopath;
     const struct ofpact_controller *controller;
     const struct ofpact_tunnel *tunnel;
+    const struct ofpact_metadata *metadata;
     uint16_t port;
 
     switch (a->type) {
@@ -1649,6 +1723,14 @@ ofpact_format(const struct ofpact *a, struct ds *s)
                       tunnel->tun_id);
         break;
 
+    case OFPACT_WRITE_METADATA:
+        metadata = ofpact_get_WRITE_METADATA(a);
+        ds_put_format(s, "write_metadata:%#"PRIx64, metadata->metadata);
+        if (metadata->mask != UINT64_MAX) {
+            ds_put_format(s, "/%#"PRIx64, metadata->mask);
+        }
+        break;
+
     case OFPACT_SET_QUEUE:
         ds_put_format(s, "set_queue:%"PRIu32,
                       ofpact_get_SET_QUEUE(a)->queue_id);
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 7c9cb05..58942bc 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -73,6 +73,7 @@
                                                                     \
     /* Metadata. */                                                 \
     DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact)    \
+    DEFINE_OFPACT(WRITE_METADATA,  ofpact_metadata,      ofpact)    \
     DEFINE_OFPACT(SET_QUEUE,       ofpact_queue,         ofpact)    \
     DEFINE_OFPACT(POP_QUEUE,       ofpact_null,          ofpact)    \
     DEFINE_OFPACT(FIN_TIMEOUT,     ofpact_fin_timeout,   ofpact)    \
@@ -303,6 +304,15 @@ struct ofpact_fin_timeout {
     uint16_t fin_hard_timeout;
 };
 
+/* OFPACT_WRITE_METADATA.
+ *
+ * Used for NXAST_WRITE_METADATA. */
+struct ofpact_metadata {
+    struct ofpact ofpact;
+    uint64_t metadata;
+    uint64_t mask;
+};
+
 /* OFPACT_RESUBMIT.
  *
  * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */
@@ -398,6 +408,9 @@ void ofpacts_put_openflow10(const struct ofpact[], size_t 
ofpacts_len,
                             struct ofpbuf *openflow);
 void ofpacts_put_openflow11_actions(const struct ofpact[], size_t ofpacts_len,
                                     struct ofpbuf *openflow);
+void ofpacts_put_openflow11_write_metadata(const struct ofpact ofpacts[],
+                                           size_t ofpacts_len,
+                                           struct ofpbuf *openflow);
 void ofpacts_put_openflow11_instructions(const struct ofpact[],
                                          size_t ofpacts_len,
                                          struct ofpbuf *openflow);
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 922e296..5e7185d 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -279,6 +279,24 @@ parse_controller(struct ofpbuf *b, char *arg)
 }
 
 static void
+parse_metadata(struct ofpbuf *b, char *arg)
+{
+    struct ofpact_metadata *om;
+    char *mask = strchr(arg, '/');
+
+    om = ofpact_put_WRITE_METADATA(b);
+
+    if (mask) {
+        *mask = '\0';
+        om->mask = str_to_u64(mask + 1);
+    } else {
+        om->mask = UINT64_MAX;
+    }
+
+    om->metadata = str_to_u64(arg);
+}
+
+static void
 parse_named_action(enum ofputil_action_code code, const struct flow *flow,
                    char *arg, struct ofpbuf *ofpacts)
 {
@@ -375,6 +393,10 @@ parse_named_action(enum ofputil_action_code code, const 
struct flow *flow,
         tunnel->tun_id = str_to_u64(arg);
         break;
 
+    case OFPUTIL_NXAST_WRITE_METADATA:
+        parse_metadata(ofpacts, arg);
+        break;
+
     case OFPUTIL_NXAST_SET_QUEUE:
         ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg);
         break;
diff --git a/lib/ofp-util.def b/lib/ofp-util.def
index 974cd8f..e5aa046 100644
--- a/lib/ofp-util.def
+++ b/lib/ofp-util.def
@@ -58,6 +58,8 @@ NXAST_ACTION(NXAST_EXIT,           nx_action_header,       0, 
"exit")
 NXAST_ACTION(NXAST_DEC_TTL,        nx_action_header,       0, "dec_ttl")
 NXAST_ACTION(NXAST_FIN_TIMEOUT,    nx_action_fin_timeout,  0, "fin_timeout")
 NXAST_ACTION(NXAST_CONTROLLER,     nx_action_controller,   0, "controller")
+NXAST_ACTION(NXAST_WRITE_METADATA, nx_action_write_metadata, 0,
+             "write_metadata")
 
 #undef OFPAT10_ACTION
 #undef OFPAT11_ACTION
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 703de50..ba2a393 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -578,6 +578,7 @@ bool ofputil_frag_handling_from_string(const char *, enum 
ofp_config_flags *);
  * OFPUTIL_OFPAT10_ENQUEUE
  * OFPUTIL_NXAST_RESUBMIT
  * OFPUTIL_NXAST_SET_TUNNEL
+ * OFPUTIL_NXAST_SET_METADATA
  * OFPUTIL_NXAST_SET_QUEUE
  * OFPUTIL_NXAST_POP_QUEUE
  * OFPUTIL_NXAST_REG_MOVE
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 2451d44..c6754a5 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5381,6 +5381,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len,
     const struct ofport_dpif *port;
     bool was_evictable = true;
     const struct ofpact *a;
+    const struct ofpact_metadata *om;
 
     port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
     if (port && !may_receive(port, ctx)) {
@@ -5476,6 +5477,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
ofpacts_len,
             ctx->flow.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
             break;
 
+        case OFPACT_WRITE_METADATA:
+            om = ofpact_get_WRITE_METADATA(a);
+            ctx->flow.metadata &= htonll(~om->mask);
+            ctx->flow.metadata |= htonll(om->metadata & om->mask);
+            break;
+
         case OFPACT_SET_QUEUE:
             xlate_set_queue_action(ctx, ofpact_get_SET_QUEUE(a)->queue_id);
             break;
@@ -5559,6 +5566,7 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     ctx->flow = *flow;
     ctx->base_flow = ctx->flow;
     ctx->base_flow.tun_id = 0;
+    ctx->base_flow.metadata = 0;
     ctx->base_flow.vlan_tci = initial_tci;
     ctx->rule = rule;
     ctx->packet = packet;
diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at
index ba8d309..044430c 100644
--- a/tests/ofp-actions.at
+++ b/tests/ofp-actions.at
@@ -1,7 +1,7 @@
 AT_BANNER([OpenFlow actions])
 
 AT_SETUP([OpenFlow 1.0 action translation])
-AT_KEYWORDS([OF1.0])
+AT_KEYWORDS([ofp-actions OF1.0])
 AT_DATA([test-data], [dnl
 # actions=LOCAL
 0000 0008 fffe 04d2
@@ -69,6 +69,12 @@ ffff 0018 00002320 0009 000000000000 c426384d49c53d60
 # actions=set_tunnel64:0x885f3298
 ffff 0018 00002320 0009 000000000000 00000000885f3298
 
+# actions=write_metadata:0xfedcba9876543210
+ffff 0020 00002320 0015 000000000000 fedcba9876543210 ffffffffffffffff
+
+# actions=write_metadata:0xfedcba9876543210/0xffff0000ffff0000
+ffff 0020 00002320 0015 000000000000 fedcba9876543210 ffff0000ffff0000
+
 # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
 
@@ -121,7 +127,7 @@ AT_CHECK(
 AT_CLEANUP
 
 AT_SETUP([OpenFlow 1.1 action translation])
-AT_KEYWORDS([OF1.1])
+AT_KEYWORDS([ofp-actions OF1.1])
 AT_DATA([test-data], [dnl
 # actions=LOCAL
 0000 0010 fffffffe 04d2 000000000000
@@ -183,6 +189,43 @@ ffff 0018 00002320 0009 000000000000 c426384d49c53d60
 # actions=set_tunnel64:0x885f3298
 ffff 0018 00002320 0009 000000000000 00000000885f3298
 
+dnl OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express the NXAST_WRITE_METADATA
+dnl action instead, so parse-ofp11-actions will recognise and drop this action.
+# actions=write_metadata:0xfedcba9876543210
+#  0: ff -> (none)
+#  1: ff -> (none)
+#  2: 00 -> (none)
+#  3: 20 -> (none)
+#  4: 00 -> (none)
+#  5: 00 -> (none)
+#  6: 23 -> (none)
+#  7: 20 -> (none)
+#  8: 00 -> (none)
+#  9: 15 -> (none)
+# 10: 00 -> (none)
+# 11: 00 -> (none)
+# 12: 00 -> (none)
+# 13: 00 -> (none)
+# 14: 00 -> (none)
+# 15: 00 -> (none)
+# 16: fe -> (none)
+# 17: dc -> (none)
+# 18: ba -> (none)
+# 19: 98 -> (none)
+# 20: 76 -> (none)
+# 21: 54 -> (none)
+# 22: 32 -> (none)
+# 23: 10 -> (none)
+# 24: ff -> (none)
+# 25: ff -> (none)
+# 26: ff -> (none)
+# 27: ff -> (none)
+# 28: ff -> (none)
+# 29: ff -> (none)
+# 30: ff -> (none)
+# 31: ff -> (none)
+ffff 0020 00002320 0015 000000000000 fedcba9876543210 ffffffffffffffff
+
 # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
 
@@ -235,7 +278,7 @@ AT_CHECK(
 AT_CLEANUP
 
 AT_SETUP([OpenFlow 1.1 instruction translation])
-AT_KEYWORDS([OF1.1])
+AT_KEYWORDS([ofp-actions OF1.1])
 AT_DATA([test-data], [dnl
 # actions=LOCAL
 0004 0018 00000000 dnl
@@ -269,10 +312,12 @@ dnl Goto-Table not supported yet.
 # bad OF1.1 instructions: OFPBIC_UNSUP_INST
 0001 0008 01 000000
 
-dnl Write-Metadata not supported yet.
-# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+# actions=write_metadata:0xfedcba9876543210
 0002 0018 00000000 fedcba9876543210 ffffffffffffffff
 
+# actions=write_metadata:0xfedcba9876543210/0xff00ff00ff00ff00
+0002 0018 00000000 fedcba9876543210 ff00ff00ff00ff00
+
 dnl Write-Metadata too short.
 # bad OF1.1 instructions: OFPBIC_BAD_LEN
 0002 0010 00000000 fedcba9876543210
diff --git a/tests/ofproto.at b/tests/ofproto.at
index d703fa8..4d423bd 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -723,6 +723,8 @@ AT_CAPTURE_FILE([monitor.log])
 
 # Send a packet-out with a load action to set some metadata, and forward to 
controller
 AT_CHECK([ovs-ofctl packet-out br0 none 
'load(0xfafafafa5a5a5a5a->OXM_OF_METADATA[[0..63]]), controller' 
'0001020304050010203040501234'])
+AT_CHECK([ovs-ofctl packet-out br0 none 'write_metadata(0xfafafafa5a5a5a5a), 
controller' '0001020304050010203040501234'])
+AT_CHECK([ovs-ofctl packet-out br0 none 
'write_metadata(0x1234ffff5678ffff/0xffff0000ffff0000), controller' 
'0001020304050010203040501234'])
 
 # Stop the monitor and check its output.
 ovs-appctl -t ovs-ofctl ofctl/barrier
@@ -731,6 +733,10 @@ ovs-appctl -t ovs-ofctl exit
 AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
 NXT_PACKET_IN: total_len=14 in_port=NONE tun_id=0x0 
metadata=0xfafafafa5a5a5a5a reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 
reg5=0x0 reg6=0x0 reg7=0x0 (via action) data_len=14 (unbuffered)
 priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)
+NXT_PACKET_IN: total_len=14 in_port=NONE tun_id=0x0 
metadata=0xfafafafa5a5a5a5a reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 
reg5=0x0 reg6=0x0 reg7=0x0 (via action) data_len=14 (unbuffered)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)
+NXT_PACKET_IN: total_len=14 in_port=NONE tun_id=0x0 
metadata=0x1234000056780000 reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 
reg5=0x0 reg6=0x0 reg7=0x0 (via action) data_len=14 (unbuffered)
+priority:0,tunnel:0,metadata:0,in_port:0000,tci(0) 
mac(00:10:20:30:40:50->00:01:02:03:04:05) type:1234 proto:0 tos:0 ttl:0 
ip(0.0.0.0->0.0.0.0)
 OFPT_BARRIER_REPLY:
 ])
 
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 3ca217b..8353841 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -577,6 +577,14 @@ When this field is specified in \fBadd-flow\fR, 
\fBadd-flows\fR,
 extension to OpenFlow, which as of this writing is only known to be
 implemented by Open vSwitch.
 .
+.IP \fBmetadata=\fIvalue\fR[\fB/\fImask\fR]
+Matches \fIvalue\fR either exactly or with optional \fImask\fR in the metadata
+field. \fIvalue\fR and \fImask\fR are 64-bit integers, by default in decimal
+(use a \fB0x\fR prefix to specify hexadecimal). Arbitrary \fImask\fR values
+are allowed: a 1-bit in \fImask\fR indicates that the corresponding bit in
+\fIvalue\fR must match exactly, and a 0-bit wildcards that bit. Matching on
+metadata was added in Open vSwitch 1.8.
+.
 .PP
 The following shorthand notations are also available:
 .
@@ -867,6 +875,14 @@ Sets the IPv4 ToS/DSCP field to \fItos\fR.  Valid values 
are between 0 and
 255, inclusive.  Note that the two lower reserved bits are never
 modified.
 .
+.IP \fBwrite_metadata\fB:\fIvalue\fR[/\fImask\fR]
+Updates the metadata field for the flow. If \fImask\fR is omitted, the
+metadata field is set exactly to \fIvalue\fR; if \fImask\fR is specified, then
+a 1-bit in \fImask\fR indicates that the corresponding bit in the metadata
+field will be replaced with the corresponding bit from \fIvalue\fR. Both
+\fIvalue\fR and \fImask\fR are 64-bit values that are decimal by default; use
+a \fB0x\fR prefix to specify them in hexadecimal. This action was added in Open
+vSwitch 1.8.
 .RE
 .IP
 The following actions are Nicira vendor extensions that, as of this writing, 
are
-- 
1.7.2.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to