/* NX1.0+(7): struct nx_action_reg_load. */
NXAST_RAW_REG_LOAD,
+ /* OF1.5+(28): struct ofp15_action_copy_field. */
+ OFPAT_RAW15_COPY_FIELD,
+ /* NX1.0-1.4(6): struct nx_action_reg_move. */
+ NXAST_RAW_REG_MOVE,
+
/* ## ------------------------- ## */
/* ## Nicira extension actions. ## */
/* ## ------------------------- ## */
/* NX1.0+(5): void. */
NXAST_RAW_POP_QUEUE,
- /* NX1.0+(6): struct nx_action_reg_move. */
- NXAST_RAW_REG_MOVE,
-
/* NX1.0+(8): struct nx_action_note, ... */
NXAST_RAW_NOTE,
ds_put_format(s, "mod_tp_dst:%d", a->port);
}
\f
+/* Action structure for OFPAT_COPY_FIELD. */
+struct ofp15_action_copy_field {
+ ovs_be16 type; /* OFPAT_COPY_FIELD. */
+ ovs_be16 len; /* Length is padded to 64 bits. */
+ ovs_be16 n_bits; /* Number of bits to copy. */
+ ovs_be16 src_offset; /* Starting bit offset in source. */
+ ovs_be16 dst_offset; /* Starting bit offset in destination. */
+ ovs_be16 oxm_id_len; /* Length of oxm_ids. */
+
+ /* OpenFlow allows for experimenter OXM fields whose expression is longer
+ * than a standard 32-bit OXM. Thus, in the OpenFlow specification, the
+ * following is variable-length. Open vSwitch does not yet support
+ * experimenter OXM fields, so until it does we leave these as fixed
+ * size. */
+ ovs_be32 src; /* OXM for source field. */
+ ovs_be32 dst; /* OXM for destination field. */
+ uint8_t pad[4]; /* Must be zero. */
+};
+OFP_ASSERT(sizeof(struct ofp15_action_copy_field) == 24);
+
/* Action structure for NXAST_REG_MOVE.
*
* Copies src[src_ofs:src_ofs+n_bits] to dst[dst_ofs:dst_ofs+n_bits], where
};
OFP_ASSERT(sizeof(struct nx_action_reg_move) == 24);
+static enum ofperr
+decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf,
+ struct ofpbuf *ofpacts)
+{
+ struct ofpact_reg_move *move;
+
+ if (oacf->oxm_id_len != htons(8)) {
+ /* We only support 4-byte OXM IDs so far. */
+ return OFPERR_OFPBAC_BAD_LEN;
+ }
+
+ move = ofpact_put_REG_MOVE(ofpacts);
+ move->src.field = mf_from_nxm_header(ntohl(oacf->src));
+ move->src.ofs = ntohs(oacf->src_offset);
+ move->src.n_bits = ntohs(oacf->n_bits);
+ move->dst.field = mf_from_nxm_header(ntohl(oacf->dst));
+ move->dst.ofs = ntohs(oacf->dst_offset);
+ move->dst.n_bits = ntohs(oacf->n_bits);
+
+ return nxm_reg_move_check(move, NULL);
+}
+
static enum ofperr
decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm,
struct ofpbuf *ofpacts)
static void
encode_REG_MOVE(const struct ofpact_reg_move *move,
- enum ofp_version ofp_version OVS_UNUSED,
- struct ofpbuf *out)
+ enum ofp_version ofp_version, struct ofpbuf *out)
{
- struct nx_action_reg_move *narm;
+ if (ofp_version >= OFP15_VERSION) {
+ struct ofp15_action_copy_field *copy;
+
+ copy = put_OFPAT15_COPY_FIELD(out);
+ copy->n_bits = htons(move->dst.n_bits);
+ copy->src_offset = htons(move->src.ofs);
+ copy->dst_offset = htons(move->dst.ofs);
+ copy->oxm_id_len = htons(8);
+ copy->src = htonl(mf_oxm_header(move->src.field->id, ofp_version));
+ copy->dst = htonl(mf_oxm_header(move->dst.field->id, ofp_version));
+ } else {
+ struct nx_action_reg_move *narm;
- narm = put_NXAST_REG_MOVE(out);
- narm->n_bits = htons(move->dst.n_bits);
- narm->src_ofs = htons(move->src.ofs);
- narm->dst_ofs = htons(move->dst.ofs);
- narm->src = htonl(move->src.field->nxm_header);
- narm->dst = htonl(move->dst.field->nxm_header);
+ narm = put_NXAST_REG_MOVE(out);
+ narm->n_bits = htons(move->dst.n_bits);
+ narm->src_ofs = htons(move->src.ofs);
+ narm->dst_ofs = htons(move->dst.ofs);
+ narm->src = htonl(move->src.field->nxm_header);
+ narm->dst = htonl(move->dst.field->nxm_header);
+ }
}
static char * WARN_UNUSED_RESULT
}
if (NXM_HASMASK(oxm_header)) {
- return OFPERR_OFPBAC_BAD_SET_TYPE;
+ return OFPERR_OFPBAC_BAD_SET_MASK;
}
mf = mf_from_nxm_header(oxm_header);
if (!mf) {
}
\f
static void
-log_bad_action(const struct ofp_action_header *actions, size_t max_actions,
+log_bad_action(const struct ofp_action_header *actions, size_t actions_len,
const struct ofp_action_header *bad_action, enum ofperr error)
{
if (!VLOG_DROP_WARN(&rl)) {
struct ds s;
ds_init(&s);
- ds_put_hex_dump(&s, actions, max_actions * OFP_ACTION_ALIGN, 0, false);
+ ds_put_hex_dump(&s, actions, actions_len, 0, false);
VLOG_WARN("bad action at offset %#"PRIxPTR" (%s):\n%s",
(char *)bad_action - (char *)actions,
ofperr_get_name(error), ds_cstr(&s));
}
if (error) {
- log_bad_action(actions, actions_len * 8, action, error);
+ log_bad_action(actions, actions_len, action, error);
return error;
}
}
/* True if an action sets the value of a field
* in a way that is compatibile with the action set.
+ * The field can be set via either a set or a move action.
* False otherwise. */
static bool
-ofpact_is_set_action(const struct ofpact *a)
+ofpact_is_set_or_move_action(const struct ofpact *a)
{
switch (a->type) {
case OFPACT_SET_FIELD:
case OFPACT_REG_LOAD:
+ case OFPACT_REG_MOVE:
case OFPACT_SET_ETH_DST:
case OFPACT_SET_ETH_SRC:
case OFPACT_SET_IP_DSCP:
case OFPACT_POP_QUEUE:
case OFPACT_PUSH_MPLS:
case OFPACT_PUSH_VLAN:
- case OFPACT_REG_MOVE:
case OFPACT_RESUBMIT:
case OFPACT_SAMPLE:
case OFPACT_STACK_POP:
case OFPACT_PUSH_MPLS:
case OFPACT_PUSH_VLAN:
case OFPACT_REG_LOAD:
+ case OFPACT_REG_MOVE:
case OFPACT_SET_FIELD:
case OFPACT_SET_ETH_DST:
case OFPACT_SET_ETH_SRC:
case OFPACT_NOTE:
case OFPACT_OUTPUT_REG:
case OFPACT_POP_QUEUE:
- case OFPACT_REG_MOVE:
case OFPACT_RESUBMIT:
case OFPACT_SAMPLE:
case OFPACT_STACK_POP:
ofpacts_copy_last(action_list, action_set, OFPACT_PUSH_VLAN);
ofpacts_copy_last(action_list, action_set, OFPACT_DEC_TTL);
ofpacts_copy_last(action_list, action_set, OFPACT_DEC_MPLS_TTL);
- ofpacts_copy_all(action_list, action_set, ofpact_is_set_action);
+ ofpacts_copy_all(action_list, action_set, ofpact_is_set_or_move_action);
ofpacts_copy_last(action_list, action_set, OFPACT_SET_QUEUE);
/* If both OFPACT_GROUP and OFPACT_OUTPUT are present, OpenFlow says that
* all the actions because there's no point in modifying a packet that will
* not be sent anywhere. */
if (!ofpacts_copy_last(action_list, action_set, OFPACT_GROUP) &&
- !ofpacts_copy_last(action_list, action_set, OFPACT_OUTPUT)) {
+ !ofpacts_copy_last(action_list, action_set, OFPACT_OUTPUT) &&
+ !ofpacts_copy_last(action_list, action_set, OFPACT_RESUBMIT)) {
ofpbuf_clear(action_list);
}
}
switch (a->type) {
#define OFPACT(ENUM, STRUCT, MEMBER, NAME) \
case OFPACT_##ENUM: \
- return encode_##ENUM(ofpact_get_##ENUM(a), ofp_version, out);
+ encode_##ENUM(ofpact_get_##ENUM(a), ofp_version, out); \
+ return;
OFPACTS
#undef OFPACT
default: