2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 09:58:01 +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: - OpenFlow:
- Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL - Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
fields in IPv6 neighbor discovery messages, and IPv6 flow label. fields in IPv6 neighbor discovery messages, and IPv6 flow label.
- Adds support for writing to the metadata field for a flow.
- ovs-ofctl: - ovs-ofctl:
- Commands and actions that accept port numbers now also accept keywords - Commands and actions that accept port numbers now also accept keywords
that represent those ports (such as LOCAL, NONE, and ALL). This is 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_FIN_TIMEOUT, /* struct nx_action_fin_timeout */
NXAST_CONTROLLER, /* struct nx_action_controller */ NXAST_CONTROLLER, /* struct nx_action_controller */
NXAST_DEC_TTL_CNT_IDS, /* struct nx_action_cnt_ids */ NXAST_DEC_TTL_CNT_IDS, /* struct nx_action_cnt_ids */
NXAST_WRITE_METADATA, /* struct nx_action_write_metadata */
}; };
/* Header for Nicira-defined actions. */ /* Header for Nicira-defined actions. */
@ -2195,4 +2196,18 @@ struct nx_flow_monitor_cancel {
}; };
OFP_ASSERT(sizeof(struct nx_flow_monitor_cancel) == 4); 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 */ #endif /* openflow/nicira-ext.h */

View File

@ -135,6 +135,23 @@ controller_from_openflow(const struct nx_action_controller *nac,
oc->reason = nac->reason; 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 static void
note_from_openflow(const struct nx_action_note *nan, struct ofpbuf *out) 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_set_queue *nasq;
const struct nx_action_note *nan; const struct nx_action_note *nan;
const struct nx_action_set_tunnel64 *nast64; const struct nx_action_set_tunnel64 *nast64;
const struct nx_action_write_metadata *nawm;
struct ofpact_tunnel *tunnel; struct ofpact_tunnel *tunnel;
enum ofperr error = 0; 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); tunnel->tun_id = ntohl(nast->tun_id);
break; 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: case OFPUTIL_NXAST_SET_QUEUE:
nasq = (const struct nx_action_set_queue *) a; nasq = (const struct nx_action_set_queue *) a;
ofpact_put_SET_QUEUE(out)->queue_id = ntohl(nasq->queue_id); 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); 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) { if (error) {
ofpbuf_clear(ofpacts); ofpbuf_clear(ofpacts);
} }
@ -972,7 +1001,17 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
ofpact_put_CLEAR_ACTIONS(ofpacts); ofpact_put_CLEAR_ACTIONS(ofpacts);
} }
/* TODO:XXX Write-Actions */ /* 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]) { if (insts[OVSINST_OFPIT11_GOTO_TABLE]) {
const struct ofp11_instruction_goto_table *oigt; const struct ofp11_instruction_goto_table *oigt;
struct ofpact_goto_table *ogt; struct ofpact_goto_table *ogt;
@ -983,12 +1022,12 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
ogt->table_id = oigt->table_id; ogt->table_id = oigt->table_id;
} }
if (insts[OVSINST_OFPIT11_WRITE_METADATA] || if (insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {
insts[OVSINST_OFPIT11_WRITE_ACTIONS]) {
error = OFPERR_OFPBIC_UNSUP_INST; error = OFPERR_OFPBIC_UNSUP_INST;
goto exit; goto exit;
} }
error = ofpacts_verify(ofpacts->data, ofpacts->size);
exit: exit:
if (error) { if (error) {
ofpbuf_clear(ofpacts); ofpbuf_clear(ofpacts);
@ -1063,6 +1102,7 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
return 0; return 0;
case OFPACT_CLEAR_ACTIONS: case OFPACT_CLEAR_ACTIONS:
case OFPACT_WRITE_METADATA:
case OFPACT_GOTO_TABLE: case OFPACT_GOTO_TABLE:
return 0; return 0;
@ -1089,6 +1129,35 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
return 0; 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. */ /* 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 static void
ofpact_note_to_nxast(const struct ofpact_note *note, struct ofpbuf *out) 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); ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
break; break;
case OFPACT_WRITE_METADATA:
ofpact_write_metadata_to_nxast(ofpact_get_WRITE_METADATA(a), out);
break;
case OFPACT_SET_QUEUE: case OFPACT_SET_QUEUE:
ofputil_put_NXAST_SET_QUEUE(out)->queue_id ofputil_put_NXAST_SET_QUEUE(out)->queue_id
= htonl(ofpact_get_SET_QUEUE(a)->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_REG_LOAD:
case OFPACT_DEC_TTL: case OFPACT_DEC_TTL:
case OFPACT_SET_TUNNEL: case OFPACT_SET_TUNNEL:
case OFPACT_WRITE_METADATA:
case OFPACT_SET_QUEUE: case OFPACT_SET_QUEUE:
case OFPACT_POP_QUEUE: case OFPACT_POP_QUEUE:
case OFPACT_FIN_TIMEOUT: 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); ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out);
break; break;
case OFPACT_WRITE_METADATA:
/* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
break;
case OFPACT_CLEAR_ACTIONS: case OFPACT_CLEAR_ACTIONS:
case OFPACT_GOTO_TABLE: case OFPACT_GOTO_TABLE:
NOT_REACHED(); NOT_REACHED();
@ -1566,7 +1655,7 @@ ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) { OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
/* TODO:XXX Write-Actions */ /* TODO:XXX Write-Actions */
/* TODO:XXX Write-Metadata */
if (a->type == OFPACT_CLEAR_ACTIONS) { if (a->type == OFPACT_CLEAR_ACTIONS) {
instruction_put_OFPIT11_CLEAR_ACTIONS(openflow); instruction_put_OFPIT11_CLEAR_ACTIONS(openflow);
} else if (a->type == OFPACT_GOTO_TABLE) { } 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 = instruction_put_OFPIT11_GOTO_TABLE(openflow);
oigt->table_id = ofpact_get_GOTO_TABLE(a)->table_id; oigt->table_id = ofpact_get_GOTO_TABLE(a)->table_id;
memset(oigt->pad, 0, sizeof oigt->pad); 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)) { } else if (!ofpact_is_instruction(a)) {
/* Apply-actions */ /* Apply-actions */
const size_t ofs = openflow->size; 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_REG_LOAD:
case OFPACT_DEC_TTL: case OFPACT_DEC_TTL:
case OFPACT_SET_TUNNEL: case OFPACT_SET_TUNNEL:
case OFPACT_WRITE_METADATA:
case OFPACT_SET_QUEUE: case OFPACT_SET_QUEUE:
case OFPACT_POP_QUEUE: case OFPACT_POP_QUEUE:
case OFPACT_FIN_TIMEOUT: 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_resubmit *resubmit;
const struct ofpact_autopath *autopath; const struct ofpact_autopath *autopath;
const struct ofpact_controller *controller; const struct ofpact_controller *controller;
const struct ofpact_metadata *metadata;
const struct ofpact_tunnel *tunnel; const struct ofpact_tunnel *tunnel;
uint16_t port; uint16_t port;
@ -1909,6 +2008,17 @@ ofpact_format(const struct ofpact *a, struct ds *s)
OVSINST_OFPIT11_CLEAR_ACTIONS)); OVSINST_OFPIT11_CLEAR_ACTIONS));
break; 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: case OFPACT_GOTO_TABLE:
ds_put_format(s, "%s:%"PRIu8, ds_put_format(s, "%s:%"PRIu8,
ofpact_instruction_name_from_type( 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-actions */
/* TODO:XXX write-metadata */
ofpact_format(a, string); ofpact_format(a, string);
} }
} }

View File

@ -90,7 +90,8 @@
DEFINE_OFPACT(EXIT, ofpact_null, ofpact) \ DEFINE_OFPACT(EXIT, ofpact_null, ofpact) \
\ \
/* Instructions */ \ /* 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(CLEAR_ACTIONS, ofpact_null, ofpact) \
DEFINE_OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact) DEFINE_OFPACT(GOTO_TABLE, ofpact_goto_table, ofpact)
@ -333,6 +334,15 @@ struct ofpact_fin_timeout {
uint16_t fin_hard_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. /* OFPACT_RESUBMIT.
* *
* Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */ * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */
@ -441,6 +451,7 @@ enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
struct ofpbuf *ofpacts); struct ofpbuf *ofpacts);
enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len, enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len,
const struct flow *, int max_ports); const struct flow *, int max_ports);
enum ofperr ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len);
/* Converting ofpacts to OpenFlow. */ /* Converting ofpacts to OpenFlow. */
void ofpacts_put_openflow10(const struct ofpact[], size_t ofpacts_len, void ofpacts_put_openflow10(const struct ofpact[], size_t ofpacts_len,
@ -583,8 +594,9 @@ enum {
static inline bool static inline bool
ofpact_is_instruction(const struct ofpact *a) ofpact_is_instruction(const struct ofpact *a)
{ {
/* TODO:XXX Write-Actions, Write-Metadata */ /* TODO:XXX Write-Actions */
return a->type == OFPACT_CLEAR_ACTIONS return a->type == OFPACT_CLEAR_ACTIONS
|| a->type == OFPACT_WRITE_METADATA
|| a->type == OFPACT_GOTO_TABLE; || a->type == OFPACT_GOTO_TABLE;
} }

View File

@ -360,6 +360,24 @@ set_field_parse(const char *arg, struct ofpbuf *ofpacts)
free(orig); 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 static void
parse_named_action(enum ofputil_action_code code, const struct flow *flow, parse_named_action(enum ofputil_action_code code, const struct flow *flow,
char *arg, struct ofpbuf *ofpacts) 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); tunnel->tun_id = str_to_u64(arg);
break; break;
case OFPUTIL_NXAST_WRITE_METADATA:
parse_metadata(ofpacts, arg);
break;
case OFPUTIL_NXAST_SET_QUEUE: case OFPUTIL_NXAST_SET_QUEUE:
ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg); ofpact_put_SET_QUEUE(ofpacts)->queue_id = str_to_u32(arg);
break; break;
@ -560,6 +582,7 @@ static void
str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts) str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
{ {
char *pos, *act, *arg; char *pos, *act, *arg;
enum ofperr error;
int n_actions; int n_actions;
pos = str; pos = str;
@ -570,6 +593,12 @@ str_to_ofpacts(const struct flow *flow, char *str, struct ofpbuf *ofpacts)
} }
n_actions++; n_actions++;
} }
error = ofpacts_verify(ofpacts->data, ofpacts->size);
if (error) {
ovs_fatal(0, "Incorrect action ordering");
}
ofpact_pad(ofpacts); ofpact_pad(ofpacts);
} }
@ -577,6 +606,8 @@ static void
parse_named_instruction(enum ovs_instruction_type type, parse_named_instruction(enum ovs_instruction_type type,
char *arg, struct ofpbuf *ofpacts) char *arg, struct ofpbuf *ofpacts)
{ {
enum ofperr error;
switch (type) { switch (type) {
case OVSINST_OFPIT11_APPLY_ACTIONS: case OVSINST_OFPIT11_APPLY_ACTIONS:
NOT_REACHED(); /* This case is handled by str_to_inst_ofpacts() */ NOT_REACHED(); /* This case is handled by str_to_inst_ofpacts() */
@ -592,8 +623,7 @@ parse_named_instruction(enum ovs_instruction_type type,
break; break;
case OVSINST_OFPIT11_WRITE_METADATA: case OVSINST_OFPIT11_WRITE_METADATA:
/* TODO:XXX */ parse_metadata(ofpacts, arg);
ovs_fatal(0, "instruction write-metadata is not supported yet");
break; break;
case OVSINST_OFPIT11_GOTO_TABLE: { case OVSINST_OFPIT11_GOTO_TABLE: {
@ -606,6 +636,13 @@ parse_named_instruction(enum ovs_instruction_type type,
break; 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 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_FIN_TIMEOUT, nx_action_fin_timeout, 0, "fin_timeout")
NXAST_ACTION(NXAST_CONTROLLER, nx_action_controller, 0, "controller") 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_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 OFPAT10_ACTION
#undef OFPAT11_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_OFPAT10_ENQUEUE
* OFPUTIL_NXAST_RESUBMIT * OFPUTIL_NXAST_RESUBMIT
* OFPUTIL_NXAST_SET_TUNNEL * OFPUTIL_NXAST_SET_TUNNEL
* OFPUTIL_NXAST_SET_METADATA
* OFPUTIL_NXAST_SET_QUEUE * OFPUTIL_NXAST_SET_QUEUE
* OFPUTIL_NXAST_POP_QUEUE * OFPUTIL_NXAST_POP_QUEUE
* OFPUTIL_NXAST_REG_MOVE * 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) { OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
struct ofpact_controller *controller; struct ofpact_controller *controller;
const struct ofpact_metadata *metadata;
if (ctx->exit) { if (ctx->exit) {
break; break;
@ -5608,6 +5609,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
*/ */
break; 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: { case OFPACT_GOTO_TABLE: {
/* TODO:XXX remove recursion */ /* TODO:XXX remove recursion */
/* It is assumed that goto-table is last action */ /* It is assumed that goto-table is last action */

View File

@ -1,7 +1,7 @@
AT_BANNER([OpenFlow actions]) AT_BANNER([OpenFlow actions])
AT_SETUP([OpenFlow 1.0 action translation]) AT_SETUP([OpenFlow 1.0 action translation])
AT_KEYWORDS([OF1.0]) AT_KEYWORDS([ofp-actions OF1.0])
AT_DATA([test-data], [dnl AT_DATA([test-data], [dnl
# actions=LOCAL # actions=LOCAL
0000 0008 fffe 04d2 0000 0008 fffe 04d2
@ -69,6 +69,12 @@ ffff 0018 00002320 0009 000000000000 c426384d49c53d60
# actions=set_tunnel64:0x885f3298 # actions=set_tunnel64:0x885f3298
ffff 0018 00002320 0009 000000000000 00000000885f3298 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[]) # 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 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
@ -125,7 +131,7 @@ AT_CHECK(
AT_CLEANUP AT_CLEANUP
AT_SETUP([OpenFlow 1.1 action translation]) AT_SETUP([OpenFlow 1.1 action translation])
AT_KEYWORDS([OF1.1]) AT_KEYWORDS([ofp-actions OF1.1])
AT_DATA([test-data], [dnl AT_DATA([test-data], [dnl
# actions=LOCAL # actions=LOCAL
0000 0010 fffffffe 04d2 000000000000 0000 0010 fffffffe 04d2 000000000000
@ -190,6 +196,53 @@ ffff 0018 00002320 0009 000000000000 c426384d49c53d60
# actions=set_tunnel64:0x885f3298 # actions=set_tunnel64:0x885f3298
ffff 0018 00002320 0009 000000000000 00000000885f3298 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[]) # 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 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
@ -251,7 +304,7 @@ AT_CHECK(
AT_CLEANUP AT_CLEANUP
AT_SETUP([OpenFlow 1.1 instruction translation]) AT_SETUP([OpenFlow 1.1 instruction translation])
AT_KEYWORDS([OF1.1 instruction]) AT_KEYWORDS([OF1.1 instruction ofp-actions])
AT_DATA([test-data], [dnl AT_DATA([test-data], [dnl
# actions=LOCAL # actions=LOCAL
0004 0018 00000000 dnl 0004 0018 00000000 dnl
@ -303,10 +356,14 @@ dnl Goto-Table 1
# actions=goto_table:1 # actions=goto_table:1
0001 0008 01 000000 0001 0008 01 000000
dnl Write-Metadata not supported yet. dnl Write-Metadata.
# bad OF1.1 instructions: OFPBIC_UNSUP_INST # actions=write_metadata:0xfedcba9876543210
0002 0018 00000000 fedcba9876543210 ffffffffffffffff 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. dnl Write-Metadata too short.
# bad OF1.1 instructions: OFPBIC_BAD_LEN # bad OF1.1 instructions: OFPBIC_BAD_LEN
0002 0010 00000000 fedcba9876543210 0002 0010 00000000 fedcba9876543210
@ -315,6 +372,15 @@ dnl Write-Metadata too long.
# bad OF1.1 instructions: OFPBIC_BAD_LEN # bad OF1.1 instructions: OFPBIC_BAD_LEN
0002 0020 00000000 fedcba9876543210 ffffffffffffffff 0000000000000000 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. dnl Write-Actions not supported yet.
# bad OF1.1 instructions: OFPBIC_UNSUP_INST # bad OF1.1 instructions: OFPBIC_UNSUP_INST
0003 0008 01 000000 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 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 255, inclusive. Note that the two lower reserved bits are never
modified. modified.
.
.RE .RE
.IP .IP
The following actions are Nicira vendor extensions that, as of this writing, are 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 .IP \fBclear_actions\fR
Clears all the actions in the action set immediately. 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 .IP \fBgoto_table\fR:\fItable\fR
Indicates the next table in the process pipeline. Indicates the next table in the process pipeline.
.RE .RE