[ovs-dev] [PATCH v3] ofp-actions: Implement writing to metadata field
Joe Stringer
joe at wand.net.nz
Tue Aug 14 12:28:47 UTC 2012
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 <joe at wand.net.nz>
---
v3:
- New function ofpacts_verify() which makes sure that the internal ofpacts
struct is correct after all parsing has been completed. At the moment, this
just means making sure that any write_metadata instructions(/actions) are
specified last. Looking for comments on this as my solution to the problems
from v2.
(explanation here: http://openvswitch.org/pipermail/dev/2012-July/018956.html)
- Rebased against current master + yamahata-san's v4 ofp-instructions patchset
from August 2.
(begins here: http://openvswitch.org/pipermail/dev/2012-August/019902.html)
---
NEWS | 1 +
include/openflow/nicira-ext.h | 15 ++++++
lib/ofp-actions.c | 108 ++++++++++++++++++++++++++++++++++++++---
lib/ofp-actions.h | 14 +++++-
lib/ofp-parse.c | 46 +++++++++++++++--
lib/ofp-util.def | 2 +
lib/ofp-util.h | 1 +
ofproto/ofproto-dpif.c | 8 +++
tests/ofp-actions.at | 57 ++++++++++++++++++++--
utilities/ovs-ofctl.8.in | 17 ++++++-
10 files changed, 247 insertions(+), 22 deletions(-)
diff --git a/NEWS b/NEWS
index d673b74..2b9c8fb 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ post-v1.8.0
- OpenFlow:
- Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
fields in IPv6 neighbor discovery messages, and IPv6 flow label.
+ - Adds support for writing to the metadata field for a flow.
- ovs-dpctl
- Support requesting the port number with the "port_no" option in
the "add-if" command.
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 4fc2049..15f69c9 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -294,6 +294,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. */
@@ -2153,4 +2154,18 @@ struct nx_flow_monitor_cancel {
};
OFP_ASSERT(sizeof(struct nx_flow_monitor_cancel) == 4);
+/* 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 4bb02b5..e169b3d 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);
@@ -512,6 +529,12 @@ ofpacts_pull_actions(struct ofpbuf *openflow, unsigned int actions_len,
error = translate(actions, actions_len / OFP_ACTION_ALIGN, ofpacts);
if (error) {
ofpbuf_clear(ofpacts);
+ return error;
+ }
+
+ error = ofpacts_verify(ofpacts->data, ofpacts->size);
+ if (error) {
+ ofpbuf_clear(ofpacts);
}
return error;
}
@@ -938,7 +961,17 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
goto exit;
}
}
- /* TODO:XXX Write-Metadata */
+ 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);
+ }
if (insts[OVSINST_OFPIT11_GOTO_TABLE]) {
const struct ofp11_instruction_goto_table *oigt;
struct ofpact_goto_table *ogt;
@@ -952,11 +985,6 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
ogt->table_id = oigt->table_id;
}
- if (insts[OVSINST_OFPIT11_WRITE_METADATA]) {
- error = OFPERR_OFPBIC_UNSUP_INST;
- goto exit;
- }
-
exit:
if (error) {
ofpbuf_clear(ofpacts);
@@ -1032,6 +1060,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
case OFPACT_CLEAR_ACTIONS:
case OFPACT_WRITE_ACTIONS:
+ case OFPACT_WRITE_METADATA:
case OFPACT_GOTO_TABLE:
return 0;
@@ -1058,6 +1087,33 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
return 0;
}
+
+/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
+ * in the appropriate order as defined by the OpenFlow spec. */
+enum ofperr
+ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len) {
+ const struct ofpact *a;
+ const struct ofpact_metadata *om = NULL;
+
+ OFPACT_FOR_EACH(a, ofpacts, ofpacts_len) {
+ if (om) {
+ if (a->type == OFPACT_WRITE_METADATA) {
+ VLOG_WARN("Duplicate write_metadata instruction specified.");
+ return OFPERR_NXBIC_DUP_TYPE;
+ } else {
+ VLOG_WARN("write_metadata instruction must be specified after "
+ "other instructions/actions.");
+ return OFPERR_OFPBAC_UNSUPPORTED_ORDER;
+ }
+ }
+
+ if (a->type == OFPACT_WRITE_METADATA) {
+ om = (const struct ofpact_metadata *) a;
+ }
+ }
+
+ return 0;
+}
/* Converting ofpacts to Nicira OpenFlow extensions. */
@@ -1104,6 +1160,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;
@@ -1178,6 +1245,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);
@@ -1331,6 +1402,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:
@@ -1438,6 +1510,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_CLEAR_ACTIONS:
case OFPACT_WRITE_ACTIONS:
case OFPACT_GOTO_TABLE:
@@ -1515,7 +1591,6 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
ofs = 0;
}
- /* TODO:XXX Write-Metadata */
if (a->type == OFPACT_CLEAR_ACTIONS) {
struct ofp11_instruction *oi;
oi = instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
@@ -1524,6 +1599,14 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
in_instruction = true;
ofs = openflow->size;
instruction_put_OFPIT11_WRITE_ACTIONS(openflow);
+ } else if (a->type == OFPACT_WRITE_METADATA) {
+ const struct ofpact_metadata *om;
+ struct ofp11_instruction_write_metadata *oiwm;
+ om = ofpact_get_WRITE_METADATA(a);
+ oiwm = instruction_put_OFPIT11_WRITE_METADATA(openflow);
+ oiwm->metadata = htonll(om->metadata);
+ oiwm->metadata_mask = htonll(om->mask);
+ memset(oiwm->pad, 0, sizeof oiwm->pad);
} else if (a->type == OFPACT_GOTO_TABLE) {
struct ofp11_instruction_goto_table *oigt;
oigt = instruction_put_OFPIT11_GOTO_TABLE(openflow);
@@ -1577,6 +1660,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:
@@ -1836,6 +1920,7 @@ ofpact_format(const struct ofpact *a, struct ds *s)
case OFPACT_CLEAR_ACTIONS:
case OFPACT_WRITE_ACTIONS:
+ case OFPACT_WRITE_METADATA:
case OFPACT_GOTO_TABLE:
NOT_REACHED();
}
@@ -1890,7 +1975,6 @@ ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len,
n_actions = 0;
}
- /* TODO:XXX write-metadata */
if (a->type == OFPACT_CLEAR_ACTIONS) {
ds_put_format(string, "%s", ofpact_instruction_name_from_type(
OVSINST_OFPIT11_CLEAR_ACTIONS));
@@ -1899,6 +1983,14 @@ ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len,
OVSINST_OFPIT11_WRITE_ACTIONS));
in_instruction = true;
n_actions = 0;
+ } else if (a->type == OFPACT_WRITE_METADATA) {
+ const struct ofpact_metadata *metadata;
+ metadata = ofpact_get_WRITE_METADATA(a);
+ ds_put_format(string, "write_metadata:%#"PRIx64,
+ metadata->metadata);
+ if (metadata->mask != UINT64_MAX) {
+ ds_put_format(string, "/%#"PRIx64, metadata->mask);
+ }
} else if (a->type == OFPACT_GOTO_TABLE) {
ds_put_format(string, "%s:%"PRIu8,
ofpact_instruction_name_from_type(
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 272b8e8..a16c04a 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -90,7 +90,7 @@
DEFINE_OFPACT(EXIT, ofpact_null, ofpact) \
\
/* Instructions */ \
- /* TODO:XXX Write-Metadata */ \
+ DEFINE_OFPACT(WRITE_METADATA, ofpact_metadata, ofpact) \
DEFINE_OFPACT(CLEAR_ACTIONS, ofpact_null, ofpact) \
DEFINE_OFPACT(WRITE_ACTIONS, ofpact_null, ofpact) \
DEFINE_OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact)
@@ -311,6 +311,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. */
@@ -408,6 +417,7 @@ enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
struct ofpbuf *ofpacts);
enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len,
const struct flow *, int max_ports);
+enum ofperr ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len);
/* Converting ofpacts to OpenFlow. */
enum ofperr ofpacts_put_openflow10(const struct ofpact[], size_t ofpacts_len,
@@ -551,9 +561,9 @@ enum {
static inline bool
ofpact_is_instruction(const struct ofpact *a)
{
- /* TODO:XXX Write-Metadata */
return a->type == OFPACT_CLEAR_ACTIONS
|| a->type == OFPACT_WRITE_ACTIONS
+ || a->type == OFPACT_WRITE_METADATA
|| a->type == OFPACT_GOTO_TABLE;
}
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 9e5264e..51520e2 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;
@@ -442,6 +464,7 @@ str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
{
char *pos, *act, *arg;
int n_actions;
+ enum ofperr error;
pos = str;
n_actions = 0;
@@ -468,6 +491,12 @@ str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
}
n_actions++;
}
+
+ error = ofpacts_verify(ofpacts->data, ofpacts->size);
+ if (error) {
+ ovs_fatal(0, "Incorrect action ordering: %s", ofperr_to_string(error));
+ }
+
ofpact_pad(ofpacts);
}
@@ -476,6 +505,8 @@ parse_named_instruction(enum ovs_instruction_type type,
const struct flow *flow,
char *arg, struct ofpbuf *ofpacts)
{
+ enum ofperr error;
+
switch (type) {
case OVSINST_OFPIT11_APPLY_ACTIONS:
str_to_ofpacts(flow, arg, ofpacts);
@@ -491,7 +522,7 @@ parse_named_instruction(enum ovs_instruction_type type,
break;
case OVSINST_OFPIT11_WRITE_METADATA:
- NOT_REACHED(); /* TODO:XXX */
+ parse_metadata(ofpacts, arg);
break;
case OVSINST_OFPIT11_GOTO_TABLE: {
@@ -504,6 +535,14 @@ parse_named_instruction(enum ovs_instruction_type type,
break;
}
}
+
+ /* If write_metadata is specified as an action AND an instruction, ofpacts
+ could be invalid. */
+ error = ofpacts_verify(ofpacts->data, ofpacts->size);
+ if (error) {
+ ovs_fatal(0, "Incorrect instruction ordering: %s",
+ ofperr_to_string(error));
+ }
}
static void
@@ -536,11 +575,6 @@ str_to_inst_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
prev_type = type;
}
- /* TODO:XXX */
- if (inst_args[OVSINST_OFPIT11_WRITE_METADATA]) {
- ovs_fatal(0, "instruction write-metadata is not supported yet");
- }
-
for (type = 0; type < N_OVS_INSTRUCTIONS; type++) {
if (inst_args[type]) {
parse_named_instruction(type, flow, inst_args[type], ofpacts);
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 b9d71f0..79c0c74 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -525,6 +525,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 93b96cf..b4f0714 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -5427,6 +5427,7 @@ 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;
if (ctx->exit) {
break;
@@ -5575,6 +5576,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
NOT_REACHED(); /* TODO:XXX */
break;
+ case OFPACT_WRITE_METADATA:
+ metadata = ofpact_get_WRITE_METADATA(a);
+ ctx->flow.metadata &= htonll(~metadata->mask);
+ ctx->flow.metadata |= htonll(metadata->metadata & metadata->mask);
+ break;
+
case OFPACT_GOTO_TABLE: {
/* TODO:XXX remove recursion */
/* It is assumed that goto-table is last action */
@@ -5608,6 +5615,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 41e4fb5..9208617 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
+# instructions=write_metadata:0xfedcba9876543210
+ffff 0020 00002320 0015 000000000000 fedcba9876543210 ffffffffffffffff
+
+# instructions=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.
+# instructions=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
@@ -277,10 +320,14 @@ dnl Goto-Table 1
# instructions=goto_table:1
0001 0008 01 000000
-dnl Write-Metadata not supported yet.
-# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+dnl Write-Metadata.
+# instructions=write_metadata:0xfedcba9876543210
0002 0018 00000000 fedcba9876543210 ffffffffffffffff
+dnl Write-Metadata with mask.
+# instructions=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/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 22fc530..2254fdb 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -614,6 +614,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:
.
@@ -903,7 +911,6 @@ Sets the TCP or UDP destination port to \fIport\fR.
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.
-.
.RE
.IP
The following actions are Nicira vendor extensions that, as of this writing, are
@@ -1129,6 +1136,14 @@ Clears all the actions in the action set immediately.
Merges the specified actions(s) into the current actions set.
The syntax of actions are same to \fBactions=\fR field.
.
+.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.
+.
.IP \fBgoto_table\fR:\fItable\fR
Indicates the next table in the process pipeline.
.RE
--
1.7.2.5
More information about the dev
mailing list