2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

ofp-actions: Implement writing to metadata field

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@wand.net.nz>
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Joe Stringer 2012-10-19 02:37:37 +09:00 committed by Ben Pfaff
parent 9908606290
commit 4cceacb94c
10 changed files with 272 additions and 15 deletions

1
NEWS
View File

@ -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-ofctl:
- Commands and actions that accept port numbers now also accept keywords
that represent those ports (such as LOCAL, NONE, and ALL). This is

View File

@ -303,6 +303,7 @@ enum nx_action_subtype {
NXAST_FIN_TIMEOUT, /* struct nx_action_fin_timeout */
NXAST_CONTROLLER, /* struct nx_action_controller */
NXAST_DEC_TTL_CNT_IDS, /* struct nx_action_cnt_ids */
NXAST_WRITE_METADATA, /* struct nx_action_write_metadata */
};
/* Header for Nicira-defined actions. */
@ -2195,4 +2196,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 zeros[6]; /* Must be zero. */
ovs_be64 metadata; /* Metadata register. */
ovs_be64 mask; /* Metadata mask. */
};
OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32);
#endif /* openflow/nicira-ext.h */

View File

@ -135,6 +135,23 @@ controller_from_openflow(const struct nx_action_controller *nac,
oc->reason = nac->reason;
}
static enum ofperr
metadata_from_nxast(const struct nx_action_write_metadata *nawm,
struct ofpbuf *out)
{
struct ofpact_metadata *om;
if (!is_all_zeros(nawm->zeros, sizeof nawm->zeros)) {
return OFPERR_NXBRC_MUST_BE_ZERO;
}
om = ofpact_put_WRITE_METADATA(out);
om->metadata = nawm->metadata;
om->mask = nawm->mask;
return 0;
}
static void
note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out)
{
@ -276,6 +293,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;
@ -297,6 +315,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;
error = metadata_from_nxast(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);
@ -567,6 +590,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);
}
@ -972,7 +1001,17 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
ofpact_put_CLEAR_ACTIONS(ofpacts);
}
/* TODO:XXX Write-Actions */
/* 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 = ofpact_put_WRITE_METADATA(ofpacts);
om->metadata = oiwm->metadata;
om->mask = oiwm->metadata_mask;
}
if (insts[OVSINST_OFPIT11_GOTO_TABLE]) {
const struct ofp11_instruction_goto_table *oigt;
struct ofpact_goto_table *ogt;
@ -983,12 +1022,12 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
ogt->table_id = oigt->table_id;
}
if (insts[OVSINST_OFPIT11_WRITE_METADATA] ||
insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {
if (insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {
error = OFPERR_OFPBIC_UNSUP_INST;
goto exit;
}
error = ofpacts_verify(ofpacts->data, ofpacts->size);
exit:
if (error) {
ofpbuf_clear(ofpacts);
@ -1063,6 +1102,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
return 0;
case OFPACT_CLEAR_ACTIONS:
case OFPACT_WRITE_METADATA:
case OFPACT_GOTO_TABLE:
return 0;
@ -1089,6 +1129,35 @@ 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");
/* should be OFPERR_OFPET_BAD_ACTION? */
return OFPERR_OFPBAC_UNSUPPORTED_ORDER;
} 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. */
@ -1134,6 +1203,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 = om->metadata;
nawm->mask = om->mask;
}
static void
ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out)
{
@ -1232,6 +1312,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);
@ -1384,6 +1468,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:
@ -1502,6 +1587,10 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out);
break;
case OFPACT_WRITE_METADATA:
/* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
break;
case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE:
NOT_REACHED();
@ -1566,7 +1655,7 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
/* TODO:XXX Write-Actions */
/* TODO:XXX Write-Metadata */
if (a->type == OFPACT_CLEAR_ACTIONS) {
instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
} else if (a->type == OFPACT_GOTO_TABLE) {
@ -1575,6 +1664,14 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
oigt = instruction_put_OFPIT11_GOTO_TABLE(openflow);
oigt->table_id = ofpact_get_GOTO_TABLE(a)->table_id;
memset(oigt->pad, 0, sizeof oigt->pad);
} 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 = om->metadata;
oiwm->metadata_mask = om->mask;
} else if (!ofpact_is_instruction(a)) {
/* Apply-actions */
const size_t ofs = openflow->size;
@ -1625,6 +1722,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:
@ -1724,6 +1822,7 @@ ofpact_format(const struct ofpact *a, struct ds *s)
const struct ofpact_resubmit *resubmit;
const struct ofpact_autopath *autopath;
const struct ofpact_controller *controller;
const struct ofpact_metadata *metadata;
const struct ofpact_tunnel *tunnel;
uint16_t port;
@ -1909,6 +2008,17 @@ ofpact_format(const struct ofpact *a, struct ds *s)
OVSINST_OFPIT11_CLEAR_ACTIONS));
break;
case OFPACT_WRITE_METADATA:
metadata = ofpact_get_WRITE_METADATA(a);
ds_put_format(s, "%s:%#"PRIx64,
ofpact_instruction_name_from_type(
OVSINST_OFPIT11_WRITE_METADATA),
ntohll(metadata->metadata));
if (metadata->mask != htonll(UINT64_MAX)) {
ds_put_format(s, "/%#"PRIx64, ntohll(metadata->mask));
}
break;
case OFPACT_GOTO_TABLE:
ds_put_format(s, "%s:%"PRIu8,
ofpact_instruction_name_from_type(
@ -1936,7 +2046,6 @@ ofpacts_format(const struct ofpact *ofpacts, size_t ofpacts_len,
}
/* TODO:XXX write-actions */
/* TODO:XXX write-metadata */
ofpact_format(a, string);
}
}

View File

@ -90,7 +90,8 @@
DEFINE_OFPACT(EXIT, ofpact_null, ofpact) \
\
/* Instructions */ \
/* TODO:XXX Write-Actions, Write-Metadata */ \
/* TODO:XXX Write-Actions */ \
DEFINE_OFPACT(WRITE_METADATA, ofpact_metadata, ofpact) \
DEFINE_OFPACT(CLEAR_ACTIONS, ofpact_null, ofpact) \
DEFINE_OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact)
@ -333,6 +334,15 @@ struct ofpact_fin_timeout {
uint16_t fin_hard_timeout;
};
/* OFPACT_WRITE_METADATA.
*
* Used for NXAST_WRITE_METADATA. */
struct ofpact_metadata {
struct ofpact ofpact;
ovs_be64 metadata;
ovs_be64 mask;
};
/* OFPACT_RESUBMIT.
*
* Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */
@ -441,6 +451,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. */
void ofpacts_put_openflow10(const struct ofpact[], size_t ofpacts_len,
@ -583,8 +594,9 @@ enum {
static inline bool
ofpact_is_instruction(const struct ofpact *a)
{
/* TODO:XXX Write-Actions, Write-Metadata */
/* TODO:XXX Write-Actions */
return a->type == OFPACT_CLEAR_ACTIONS
|| a->type == OFPACT_WRITE_METADATA
|| a->type == OFPACT_GOTO_TABLE;
}

View File

@ -360,6 +360,24 @@ set_field_parse(const char *arg, struct ofpbuf *ofpacts)
free(orig);
}
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 = htonll(str_to_u64(mask + 1));
} else {
om->mask = htonll(UINT64_MAX);
}
om->metadata = htonll(str_to_u64(arg));
}
static void
parse_named_action(enum ofputil_action_code code, const struct flow *flow,
char *arg, struct ofpbuf *ofpacts)
@ -465,6 +483,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;
@ -560,6 +582,7 @@ static void
str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
{
char *pos, *act, *arg;
enum ofperr error;
int n_actions;
pos = str;
@ -570,6 +593,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");
}
ofpact_pad(ofpacts);
}
@ -577,6 +606,8 @@ static void
parse_named_instruction(enum ovs_instruction_type type,
char *arg, struct ofpbuf *ofpacts)
{
enum ofperr error;
switch (type) {
case OVSINST_OFPIT11_APPLY_ACTIONS:
NOT_REACHED(); /* This case is handled by str_to_inst_ofpacts() */
@ -592,8 +623,7 @@ parse_named_instruction(enum ovs_instruction_type type,
break;
case OVSINST_OFPIT11_WRITE_METADATA:
/* TODO:XXX */
ovs_fatal(0, "instruction write-metadata is not supported yet");
parse_metadata(ofpacts, arg);
break;
case OVSINST_OFPIT11_GOTO_TABLE: {
@ -606,6 +636,13 @@ 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");
}
}
static void

View File

@ -60,6 +60,8 @@ 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_DEC_TTL_CNT_IDS, nx_action_cnt_ids, 1, NULL)
NXAST_ACTION(NXAST_WRITE_METADATA, nx_action_write_metadata, 0,
"write_metadata")
#undef OFPAT10_ACTION
#undef OFPAT11_ACTION

View File

@ -540,6 +540,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

View File

@ -5460,6 +5460,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;
@ -5608,6 +5609,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
*/
break;
case OFPACT_WRITE_METADATA:
metadata = ofpact_get_WRITE_METADATA(a);
ctx->flow.metadata &= ~metadata->mask;
ctx->flow.metadata |= metadata->metadata & metadata->mask;
break;
case OFPACT_GOTO_TABLE: {
/* TODO:XXX remove recursion */
/* It is assumed that goto-table is last action */

View File

@ -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 0016 000000000000 fedcba9876543210 ffffffffffffffff
# actions=write_metadata:0xfedcba9876543210/0xffff0000ffff0000
ffff 0020 00002320 0016 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
@ -125,7 +131,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
@ -190,6 +196,53 @@ 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: 16 -> (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 0016 000000000000 fedcba9876543210 ffffffffffffffff
dnl Write-Metadata duplicated.
& ofp_actions|WARN|duplicate write_metadata instruction specified
# bad OF1.1 actions: OFPBAC_UNSUPPORTED_ORDER
ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff
dnl Write-Metadata in wrong position.
& ofp_actions|WARN|write_metadata instruction must be specified after other instructions/actions
# bad OF1.1 actions: OFPBAC_UNSUPPORTED_ORDER
ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff ffff 0010 00002320 0002 0000 12345678
# 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
@ -251,7 +304,7 @@ AT_CHECK(
AT_CLEANUP
AT_SETUP([OpenFlow 1.1 instruction translation])
AT_KEYWORDS([OF1.1 instruction])
AT_KEYWORDS([OF1.1 instruction ofp-actions])
AT_DATA([test-data], [dnl
# actions=LOCAL
0004 0018 00000000 dnl
@ -303,10 +356,14 @@ dnl Goto-Table 1
# actions=goto_table:1
0001 0008 01 000000
dnl Write-Metadata not supported yet.
# bad OF1.1 instructions: OFPBIC_UNSUP_INST
dnl Write-Metadata.
# actions=write_metadata:0xfedcba9876543210
0002 0018 00000000 fedcba9876543210 ffffffffffffffff
dnl Write-Metadata with mask.
# 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
@ -315,6 +372,15 @@ dnl Write-Metadata too long.
# bad OF1.1 instructions: OFPBIC_BAD_LEN
0002 0020 00000000 fedcba9876543210 ffffffffffffffff 0000000000000000
dnl Write-Metadata duplicated.
# bad OF1.1 instructions: OFPIT_BAD_INSTRUCTION
0002 0018 00000000 fedcba9876543210 ff00ff00ff00ff00 0002 0018 00000000 fedcba9876543210 ff00ff00ff00ff00
dnl Write-Metadata in wrong position.
& ofp_actions|WARN|write_metadata instruction must be specified after other instructions/actions
# bad OF1.1 instructions: OFPBAC_UNSUPPORTED_ORDER
0001 0008 01 000000 0002 0018 00000000 fedcba9876543210 ffffffffffffffff
dnl Write-Actions not supported yet.
# bad OF1.1 instructions: OFPBIC_UNSUP_INST
0003 0008 01 000000

View File

@ -919,7 +919,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
@ -1148,6 +1147,14 @@ to \fBactions=\fR field.
.IP \fBclear_actions\fR
Clears all the actions in the action set immediately.
.
.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