#include "ofpbuf.h"
#include "unaligned.h"
#include "util.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(ofp_actions);
* [In OpenFlow 1.5, set_field is a superset of reg_load functionality, so
* we drop reg_load.] */
NXAST_RAW_REG_LOAD,
+ /* NX1.0-1.4(33): struct nx_action_reg_load2, ...
+ *
+ * [In OpenFlow 1.5, set_field is a superset of reg_load2 functionality, so
+ * we drop reg_load2.] */
+ NXAST_RAW_REG_LOAD2,
/* OF1.5+(28): struct ofp15_action_copy_field, ... */
OFPAT_RAW15_COPY_FIELD,
- /* NX1.0-1.4(6): struct nx_action_reg_move. */
+ /* ONF1.3-1.4(3200): struct onf_action_copy_field, ... */
+ ONFACT_RAW13_COPY_FIELD,
+ /* NX1.0-1.4(6): struct nx_action_reg_move, ... */
NXAST_RAW_REG_MOVE,
/* ## ------------------------- ## */
/* NX1.0+(15): struct nx_action_output_reg. */
NXAST_RAW_OUTPUT_REG,
+ /* NX1.0+(32): struct nx_action_output_reg2. */
+ NXAST_RAW_OUTPUT_REG2,
/* NX1.0+(16): struct nx_action_learn, ... */
NXAST_RAW_LEARN,
/* NX1.0+(29): struct nx_action_sample. */
NXAST_RAW_SAMPLE,
+
+ /* NX1.0+(34): struct nx_action_conjunction. */
+ NXAST_RAW_CONJUNCTION,
};
/* OpenFlow actions are always a multiple of 8 bytes in length. */
static void *ofpact_put_raw(struct ofpbuf *, enum ofp_version,
enum ofp_raw_action_type, uint64_t arg);
-static char *WARN_UNUSED_RESULT ofpacts_parse(
+static char *OVS_WARN_UNUSED_RESULT ofpacts_parse(
char *str, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols,
bool allow_instructions);
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_OUTPUT(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_GROUP(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
nac->reason = controller->reason;
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_CONTROLLER(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_ENQUEUE(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
};
OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
+/* Action structure for NXAST_OUTPUT_REG2.
+ *
+ * Like the NXAST_OUTPUT_REG but organized so that there is room for a 64-bit
+ * experimenter OXM as 'src'.
+ */
+struct nx_action_output_reg2 {
+ ovs_be16 type; /* OFPAT_VENDOR. */
+ ovs_be16 len; /* 24. */
+ ovs_be32 vendor; /* NX_VENDOR_ID. */
+ ovs_be16 subtype; /* NXAST_OUTPUT_REG2. */
+
+ ovs_be16 ofs_nbits; /* (ofs << 6) | (n_bits - 1). */
+ ovs_be16 max_len; /* Max length to send to controller. */
+
+ /* Followed by:
+ * - 'src', as an OXM/NXM header (either 4 or 8 bytes).
+ * - Enough 0-bytes to pad the action out to 24 bytes. */
+ uint8_t pad[10];
+};
+OFP_ASSERT(sizeof(struct nx_action_output_reg2) == 24);
+
static enum ofperr
decode_NXAST_RAW_OUTPUT_REG(const struct nx_action_output_reg *naor,
struct ofpbuf *out)
}
output_reg = ofpact_put_OUTPUT_REG(out);
+ output_reg->ofpact.raw = NXAST_RAW_OUTPUT_REG;
output_reg->src.field = mf_from_nxm_header(ntohl(naor->src));
output_reg->src.ofs = nxm_decode_ofs(naor->ofs_nbits);
output_reg->src.n_bits = nxm_decode_n_bits(naor->ofs_nbits);
return mf_check_src(&output_reg->src, NULL);
}
+static enum ofperr
+decode_NXAST_RAW_OUTPUT_REG2(const struct nx_action_output_reg2 *naor,
+ struct ofpbuf *out)
+{
+ struct ofpact_output_reg *output_reg;
+ enum ofperr error;
+ struct ofpbuf b;
+
+ output_reg = ofpact_put_OUTPUT_REG(out);
+ output_reg->ofpact.raw = NXAST_RAW_OUTPUT_REG2;
+ output_reg->src.ofs = nxm_decode_ofs(naor->ofs_nbits);
+ output_reg->src.n_bits = nxm_decode_n_bits(naor->ofs_nbits);
+ output_reg->max_len = ntohs(naor->max_len);
+
+ ofpbuf_use_const(&b, naor, ntohs(naor->len));
+ ofpbuf_pull(&b, OBJECT_OFFSETOF(naor, pad));
+ error = nx_pull_header(&b, &output_reg->src.field, NULL);
+ if (error) {
+ return error;
+ }
+ if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) {
+ return OFPERR_NXBRC_MUST_BE_ZERO;
+ }
+
+ return mf_check_src(&output_reg->src, NULL);
+}
+
static void
encode_OUTPUT_REG(const struct ofpact_output_reg *output_reg,
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
- struct nx_action_output_reg *naor = put_NXAST_OUTPUT_REG(out);
+ /* If 'output_reg' came in as an NXAST_RAW_OUTPUT_REG2 action, or if it
+ * cannot be encoded in the older form, encode it as
+ * NXAST_RAW_OUTPUT_REG2. */
+ if (output_reg->ofpact.raw == NXAST_RAW_OUTPUT_REG2
+ || !mf_nxm_header(output_reg->src.field->id)) {
+ struct nx_action_output_reg2 *naor = put_NXAST_OUTPUT_REG2(out);
+ size_t size = ofpbuf_size(out);
+
+ naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs,
+ output_reg->src.n_bits);
+ naor->max_len = htons(output_reg->max_len);
+
+ ofpbuf_set_size(out, size - sizeof naor->pad);
+ nx_put_header(out, output_reg->src.field->id, 0, false);
+ ofpbuf_set_size(out, size);
+ } else {
+ struct nx_action_output_reg *naor = put_NXAST_OUTPUT_REG(out);
- naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs,
- output_reg->src.n_bits);
- naor->src = htonl(mf_nxm_header(output_reg->src.field->id));
- naor->max_len = htons(output_reg->max_len);
+ naor->ofs_nbits = nxm_encode_ofs_nbits(output_reg->src.ofs,
+ output_reg->src.n_bits);
+ naor->src = htonl(mf_nxm_header(output_reg->src.field->id));
+ naor->max_len = htons(output_reg->max_len);
+ }
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_OUTPUT_REG(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_BUNDLE(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
return bundle_parse(arg, ofpacts);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_bundle_load(const char *arg, struct ofpbuf *ofpacts)
{
return bundle_parse_load(arg, ofpacts);
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_set_vlan_vid(char *arg, struct ofpbuf *ofpacts, bool push_vlan_if_needed)
{
struct ofpact_vlan_vid *vlan_vid;
return NULL;
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_VLAN_VID(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_set_vlan_pcp(char *arg, struct ofpbuf *ofpacts, bool push_vlan_if_needed)
{
struct ofpact_vlan_pcp *vlan_pcp;
return NULL;
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_VLAN_PCP(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_STRIP_VLAN(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
return NULL;
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_pop_vlan(struct ofpbuf *ofpacts)
{
ofpact_put_STRIP_VLAN(ofpacts)->ofpact.raw = OFPAT_RAW11_POP_VLAN;
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_PUSH_VLAN(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_ETH_SRC(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
return str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_ETH_DST(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
out);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_IPV4_SRC(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
return str_to_ip(arg, &ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_IPV4_DST(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_IP_DSCP(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_IP_ECN(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_IP_TTL(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
encode_SET_L4_port(l4_port, ofp_version, OFPAT_RAW_SET_TP_DST, field, out);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_L4_SRC_PORT(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
&ofpact_put_SET_L4_SRC_PORT(ofpacts)->port);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_L4_DST_PORT(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
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. */
+ uint8_t pad[2];
/* Followed by:
* - OXM header for source field.
* - OXM header for destination field.
* - Padding with 0-bytes to a multiple of 8 bytes.
- * The "pad" member is the beginning of the above. */
- uint8_t pad[4];
+ * The "pad2" member is the beginning of the above. */
+ uint8_t pad2[4];
};
OFP_ASSERT(sizeof(struct ofp15_action_copy_field) == 16);
+/* Action structure for OpenFlow 1.3 extension copy-field action.. */
+struct onf_action_copy_field {
+ ovs_be16 type; /* OFPAT_EXPERIMENTER. */
+ ovs_be16 len; /* Length is padded to 64 bits. */
+ ovs_be32 experimenter; /* ONF_VENDOR_ID. */
+ ovs_be16 exp_type; /* 3200. */
+ uint8_t pad[2]; /* Not used. */
+ 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. */
+ uint8_t pad2[2]; /* Not used. */
+ /* Followed by:
+ * - OXM header for source field.
+ * - OXM header for destination field.
+ * - Padding with 0-bytes (either 0 or 4 of them) to a multiple of 8 bytes.
+ * The "pad3" member is the beginning of the above. */
+ uint8_t pad3[4]; /* Not used. */
+};
+OFP_ASSERT(sizeof(struct onf_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
ovs_be16 n_bits; /* Number of bits. */
ovs_be16 src_ofs; /* Starting bit offset in source. */
ovs_be16 dst_ofs; /* Starting bit offset in destination. */
- ovs_be32 src; /* Source register. */
- ovs_be32 dst; /* Destination register. */
+ /* Followed by:
+ * - OXM/NXM header for source field (4 or 8 bytes).
+ * - OXM/NXM header for destination field (4 or 8 bytes).
+ * - Padding with 0-bytes to a multiple of 8 bytes, if necessary. */
};
-OFP_ASSERT(sizeof(struct nx_action_reg_move) == 24);
+OFP_ASSERT(sizeof(struct nx_action_reg_move) == 16);
static enum ofperr
-decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf,
- struct ofpbuf *ofpacts)
+decode_copy_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits,
+ const void *action, ovs_be16 action_len, size_t oxm_offset,
+ struct ofpbuf *ofpacts)
{
struct ofpact_reg_move *move;
enum ofperr error;
- size_t orig_size;
struct ofpbuf b;
move = ofpact_put_REG_MOVE(ofpacts);
- move->src.ofs = ntohs(oacf->src_offset);
- move->src.n_bits = ntohs(oacf->n_bits);
- move->dst.ofs = ntohs(oacf->dst_offset);
- move->dst.n_bits = ntohs(oacf->n_bits);
-
- ofpbuf_use_const(&b, oacf, ntohs(oacf->len));
- ofpbuf_pull(&b, offsetof(struct ofp15_action_copy_field, pad));
- orig_size = ofpbuf_size(&b);
+ move->ofpact.raw = ONFACT_RAW13_COPY_FIELD;
+ move->src.ofs = ntohs(src_offset);
+ move->src.n_bits = ntohs(n_bits);
+ move->dst.ofs = ntohs(dst_offset);
+ move->dst.n_bits = ntohs(n_bits);
+
+ ofpbuf_use_const(&b, action, ntohs(action_len));
+ ofpbuf_pull(&b, oxm_offset);
error = nx_pull_header(&b, &move->src.field, NULL);
if (error) {
return error;
if (error) {
return error;
}
- if (orig_size - ofpbuf_size(&b) != ntohs(oacf->oxm_id_len)) {
- return OFPERR_OFPBAC_BAD_LEN;
- }
if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) {
return OFPERR_NXBRC_MUST_BE_ZERO;
return nxm_reg_move_check(move, NULL);
}
+static enum ofperr
+decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf,
+ struct ofpbuf *ofpacts)
+{
+ return decode_copy_field__(oacf->src_offset, oacf->dst_offset,
+ oacf->n_bits, oacf, oacf->len,
+ OBJECT_OFFSETOF(oacf, pad2), ofpacts);
+}
+
+static enum ofperr
+decode_ONFACT_RAW13_COPY_FIELD(const struct onf_action_copy_field *oacf,
+ struct ofpbuf *ofpacts)
+{
+ return decode_copy_field__(oacf->src_offset, oacf->dst_offset,
+ oacf->n_bits, oacf, oacf->len,
+ OBJECT_OFFSETOF(oacf, pad3), ofpacts);
+}
+
static enum ofperr
decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm,
struct ofpbuf *ofpacts)
{
struct ofpact_reg_move *move;
+ enum ofperr error;
+ struct ofpbuf b;
move = ofpact_put_REG_MOVE(ofpacts);
- move->src.field = mf_from_nxm_header(ntohl(narm->src));
+ move->ofpact.raw = NXAST_RAW_REG_MOVE;
move->src.ofs = ntohs(narm->src_ofs);
move->src.n_bits = ntohs(narm->n_bits);
- move->dst.field = mf_from_nxm_header(ntohl(narm->dst));
move->dst.ofs = ntohs(narm->dst_ofs);
move->dst.n_bits = ntohs(narm->n_bits);
+ ofpbuf_use_const(&b, narm, ntohs(narm->len));
+ ofpbuf_pull(&b, sizeof *narm);
+ error = nx_pull_header(&b, &move->src.field, NULL);
+ if (error) {
+ return error;
+ }
+ error = nx_pull_header(&b, &move->dst.field, NULL);
+ if (error) {
+ return error;
+ }
+ if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) {
+ return OFPERR_NXBRC_MUST_BE_ZERO;
+ }
+
return nxm_reg_move_check(move, NULL);
}
encode_REG_MOVE(const struct ofpact_reg_move *move,
enum ofp_version ofp_version, struct ofpbuf *out)
{
+ /* For OpenFlow 1.3, the choice of ONFACT_RAW13_COPY_FIELD versus
+ * NXAST_RAW_REG_MOVE is somewhat difficult. Neither one is guaranteed to
+ * be supported by every OpenFlow 1.3 implementation. It would be ideal to
+ * probe for support. Until we have that ability, we currently prefer
+ * NXAST_RAW_REG_MOVE for backward compatibility with older Open vSwitch
+ * versions. */
+ size_t start_ofs = ofpbuf_size(out);
if (ofp_version >= OFP15_VERSION) {
- struct ofp15_action_copy_field *copy;
- size_t start_ofs = ofpbuf_size(out);
-
- copy = put_OFPAT15_COPY_FIELD(out);
+ struct ofp15_action_copy_field *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);
- ofpbuf_set_size(out, ofpbuf_size(out) - sizeof copy->pad);
+ ofpbuf_set_size(out, ofpbuf_size(out) - sizeof copy->pad2);
+ nx_put_header(out, move->src.field->id, ofp_version, false);
+ nx_put_header(out, move->dst.field->id, ofp_version, false);
+ } else if (ofp_version == OFP13_VERSION
+ && move->ofpact.raw == ONFACT_RAW13_COPY_FIELD) {
+ struct onf_action_copy_field *copy = put_ONFACT13_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);
+ ofpbuf_set_size(out, ofpbuf_size(out) - sizeof copy->pad3);
nx_put_header(out, move->src.field->id, ofp_version, false);
nx_put_header(out, move->dst.field->id, ofp_version, false);
- pad_ofpat(out, start_ofs);
} else {
- struct nx_action_reg_move *narm;
-
- narm = put_NXAST_REG_MOVE(out);
+ struct nx_action_reg_move *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(mf_nxm_header(move->src.field->id));
- narm->dst = htonl(mf_nxm_header(move->dst.field->id));
+ nx_put_header(out, move->src.field->id, 0, false);
+ nx_put_header(out, move->dst.field->id, 0, false);
}
+ pad_ofpat(out, start_ofs);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_REG_MOVE(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
};
OFP_ASSERT(sizeof(struct nx_action_reg_load) == 24);
+/* Action structure for NXAST_REG_LOAD2.
+ *
+ * Compared to OFPAT_SET_FIELD, we can use this to set whole or partial fields
+ * in any OpenFlow version. Compared to NXAST_REG_LOAD, we can use this to set
+ * OXM experimenter fields. */
+struct nx_action_reg_load2 {
+ ovs_be16 type; /* OFPAT_VENDOR. */
+ ovs_be16 len; /* At least 16. */
+ ovs_be32 vendor; /* NX_VENDOR_ID. */
+ ovs_be16 subtype; /* NXAST_SET_FIELD. */
+
+ /* Followed by:
+ * - An NXM/OXM header, value, and optionally a mask.
+ * - Enough 0-bytes to pad out to a multiple of 64 bits.
+ *
+ * The "pad" member is the beginning of the above. */
+ uint8_t pad[6];
+};
+OFP_ASSERT(sizeof(struct nx_action_reg_load2) == 16);
+
static enum ofperr
decode_ofpat_set_field(const struct ofp12_action_set_field *oasf,
bool may_mask, struct ofpbuf *ofpacts)
* a 1-bit in oxm_value and in oxm_mask." */
if (!mf_is_value_valid(sf->field, &sf->value)
|| (sf->field->id == MFF_VLAN_VID
- && (!(sf->mask.be16 & htons(OFPVID12_PRESENT)
- || !(sf->value.be16 & htons(OFPVID12_PRESENT)))))) {
+ && (!(sf->mask.be16 & htons(OFPVID12_PRESENT))
+ || !(sf->value.be16 & htons(OFPVID12_PRESENT))))) {
struct ds ds = DS_EMPTY_INITIALIZER;
mf_format(sf->field, &sf->value, NULL, &ds);
VLOG_WARN_RL(&rl, "Invalid value for set field %s: %s",
return 0;
}
+static enum ofperr
+decode_NXAST_RAW_REG_LOAD2(const struct nx_action_reg_load2 *narl,
+ struct ofpbuf *out)
+{
+ struct ofpact_set_field *sf;
+ enum ofperr error;
+ struct ofpbuf b;
+
+ sf = ofpact_put_SET_FIELD(out);
+ sf->ofpact.raw = NXAST_RAW_REG_LOAD2;
+
+ ofpbuf_use_const(&b, narl, ntohs(narl->len));
+ ofpbuf_pull(&b, OBJECT_OFFSETOF(narl, pad));
+ error = nx_pull_entry(&b, &sf->field, &sf->value, &sf->mask);
+ if (error) {
+ return error;
+ }
+ if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) {
+ return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
+ }
+
+ if (!sf->field->writable) {
+ VLOG_WARN_RL(&rl, "destination field %s is not writable",
+ sf->field->name);
+ return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
+ }
+ return 0;
+}
+
static void
ofpact_put_set_field(struct ofpbuf *openflow, enum ofp_version ofp_version,
enum mf_field_id field, uint64_t value_)
next_load_segment(const struct ofpact_set_field *sf,
struct mf_subfield *dst, uint64_t *value)
{
- int w = sf->field->n_bytes;
+ int n_bits = sf->field->n_bits;
+ int n_bytes = sf->field->n_bytes;
int start = dst->ofs + dst->n_bits;
- if (start < 8 * w) {
+ if (start < n_bits) {
dst->field = sf->field;
- dst->ofs = bitwise_scan(&sf->mask, w, 1, start, 8 * w);
- if (dst->ofs < 8 * w) {
- dst->n_bits = bitwise_scan(&sf->mask, w, 0, dst->ofs + 1,
- MIN(dst->ofs + 64, 8 * w)) - dst->ofs;
- *value = bitwise_get(&sf->value, w, dst->ofs, dst->n_bits);
+ dst->ofs = bitwise_scan(&sf->mask, n_bytes, 1, start, n_bits);
+ if (dst->ofs < n_bits) {
+ dst->n_bits = bitwise_scan(&sf->mask, n_bytes, 0, dst->ofs + 1,
+ MIN(dst->ofs + 64, n_bits)) - dst->ofs;
+ *value = bitwise_get(&sf->value, n_bytes, dst->ofs, dst->n_bits);
return true;
}
}
static void
set_field_to_nxast(const struct ofpact_set_field *sf, struct ofpbuf *openflow)
{
- struct mf_subfield dst;
- uint64_t value;
+ /* If 'sf' cannot be encoded as NXAST_REG_LOAD because it requires an
+ * experimenter OXM (or if it came in as NXAST_REG_LOAD2), encode as
+ * NXAST_REG_LOAD2. Otherwise use NXAST_REG_LOAD, which is backward
+ * compatible. */
+ if (sf->ofpact.raw == NXAST_RAW_REG_LOAD2
+ || !mf_nxm_header(sf->field->id)) {
+ struct nx_action_reg_load2 *narl OVS_UNUSED;
+ size_t start_ofs = ofpbuf_size(openflow);
+
+ narl = put_NXAST_REG_LOAD2(openflow);
+ ofpbuf_set_size(openflow, ofpbuf_size(openflow) - sizeof narl->pad);
+ nx_put_entry(openflow, sf->field->id, 0, &sf->value, &sf->mask);
+ pad_ofpat(openflow, start_ofs);
+ } else {
+ struct mf_subfield dst;
+ uint64_t value;
- dst.ofs = dst.n_bits = 0;
- while (next_load_segment(sf, &dst, &value)) {
- struct nx_action_reg_load *narl = put_NXAST_REG_LOAD(openflow);
- narl->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits);
- narl->dst = htonl(mf_nxm_header(dst.field->id));
- narl->value = htonll(value);
+ dst.ofs = dst.n_bits = 0;
+ while (next_load_segment(sf, &dst, &value)) {
+ struct nx_action_reg_load *narl = put_NXAST_REG_LOAD(openflow);
+ narl->ofs_nbits = nxm_encode_ofs_nbits(dst.ofs, dst.n_bits);
+ narl->dst = htonl(mf_nxm_header(dst.field->id));
+ narl->value = htonll(value);
+ }
}
}
enum ofp_version ofp_version, struct ofpbuf *out)
{
if (ofp_version >= OFP15_VERSION) {
- /* OF1.5+ only has Set-Field (we drop NXAST_REG_LOAD entirely). */
+ /* OF1.5+ only has Set-Field (reg_load is redundant so we drop it
+ * entirely). */
set_field_to_set_field(sf, ofp_version, out);
- } else if (sf->ofpact.raw == NXAST_RAW_REG_LOAD) {
- /* It came in as NXAST_REG_LOAD, send it out the same way. */
+ } else if (sf->ofpact.raw == NXAST_RAW_REG_LOAD ||
+ sf->ofpact.raw == NXAST_RAW_REG_LOAD2) {
+ /* It came in as reg_load, send it out the same way. */
set_field_to_nxast(sf, out);
} else if (ofp_version < OFP12_VERSION) {
/* OpenFlow 1.0 and 1.1 don't have Set-Field. */
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
set_field_parse__(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
{
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_FIELD(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
{
return error;
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_reg_load(char *arg, struct ofpbuf *ofpacts)
{
struct ofpact_set_field *sf = ofpact_put_reg_load(ofpacts);
ovs_be32 vendor; /* NX_VENDOR_ID. */
ovs_be16 subtype; /* NXAST_STACK_PUSH or NXAST_STACK_POP. */
ovs_be16 offset; /* Bit offset into the field. */
- ovs_be32 field; /* The field used for push or pop. */
- ovs_be16 n_bits; /* (n_bits + 1) bits of the field. */
- uint8_t zero[6]; /* Reserved, must be zero. */
+ /* Followed by:
+ * - OXM/NXM header for field to push or pop (4 or 8 bytes).
+ * - ovs_be16 'n_bits', the number of bits to extract from the field.
+ * - Enough 0-bytes to pad out the action to 24 bytes. */
+ uint8_t pad[12]; /* See above. */
};
OFP_ASSERT(sizeof(struct nx_action_stack) == 24);
-static void
+static enum ofperr
decode_stack_action(const struct nx_action_stack *nasp,
struct ofpact_stack *stack_action)
{
- stack_action->subfield.field = mf_from_nxm_header(ntohl(nasp->field));
+ enum ofperr error;
+ struct ofpbuf b;
+
stack_action->subfield.ofs = ntohs(nasp->offset);
- stack_action->subfield.n_bits = ntohs(nasp->n_bits);
+
+ ofpbuf_use_const(&b, nasp, sizeof *nasp);
+ ofpbuf_pull(&b, OBJECT_OFFSETOF(nasp, pad));
+ error = nx_pull_header(&b, &stack_action->subfield.field, NULL);
+ if (error) {
+ return error;
+ }
+ stack_action->subfield.n_bits = ntohs(*(const ovs_be16 *) ofpbuf_data(&b));
+ ofpbuf_pull(&b, 2);
+ if (!is_all_zeros(ofpbuf_data(&b), ofpbuf_size(&b))) {
+ return OFPERR_NXBRC_MUST_BE_ZERO;
+ }
+
+ return 0;
}
static enum ofperr
struct ofpbuf *ofpacts)
{
struct ofpact_stack *push = ofpact_put_STACK_PUSH(ofpacts);
- decode_stack_action(nasp, push);
- return nxm_stack_push_check(push, NULL);
+ enum ofperr error = decode_stack_action(nasp, push);
+ return error ? error : nxm_stack_push_check(push, NULL);
}
static enum ofperr
struct ofpbuf *ofpacts)
{
struct ofpact_stack *pop = ofpact_put_STACK_POP(ofpacts);
- decode_stack_action(nasp, pop);
- return nxm_stack_pop_check(pop, NULL);
+ enum ofperr error = decode_stack_action(nasp, pop);
+ return error ? error : nxm_stack_pop_check(pop, NULL);
}
static void
encode_STACK_op(const struct ofpact_stack *stack_action,
struct nx_action_stack *nasp)
{
+ struct ofpbuf b;
+ ovs_be16 n_bits;
+
nasp->offset = htons(stack_action->subfield.ofs);
- nasp->n_bits = htons(stack_action->subfield.n_bits);
- nasp->field = htonl(mf_nxm_header(stack_action->subfield.field->id));
+
+ ofpbuf_use_stack(&b, nasp, ntohs(nasp->len));
+ ofpbuf_put_uninit(&b, OBJECT_OFFSETOF(nasp, pad));
+ nx_put_header(&b, stack_action->subfield.field->id, 0, false);
+ n_bits = htons(stack_action->subfield.n_bits);
+ ofpbuf_put(&b, &n_bits, sizeof n_bits);
}
static void
encode_STACK_op(stack, put_NXAST_STACK_POP(out));
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_STACK_PUSH(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
return nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_STACK_POP(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
ofpact_update_len(ofpacts, &ids->ofpact);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_DEC_TTL(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_MPLS_LABEL(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_MPLS_TC(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_MPLS_TTL(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
put_OFPAT_DEC_MPLS_TTL(out, ofp_version);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_DEC_MPLS_TTL(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
put_OFPAT_PUSH_MPLS(out, ofp_version, push_mpls->ethertype);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_PUSH_MPLS(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
put_OFPAT_POP_MPLS(out, ofp_version, pop_mpls->ethertype);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_POP_MPLS(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_set_tunnel(char *arg, struct ofpbuf *ofpacts,
enum ofp_raw_action_type raw)
{
return str_to_u64(arg, &tunnel->tun_id);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_TUNNEL(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
put_OFPAT_SET_QUEUE(out, ofp_version, queue->queue_id);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SET_QUEUE(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
put_NXAST_POP_QUEUE(out);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_POP_QUEUE(const char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
naft->fin_hard_timeout = htons(fin_timeout->fin_hard_timeout);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_FIN_TIMEOUT(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_RESUBMIT(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
pad_ofpat(out, start_ofs);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_LEARN(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
learn_format(a, s);
}
\f
+/* Action structure for NXAST_CONJUNCTION. */
+struct nx_action_conjunction {
+ ovs_be16 type; /* OFPAT_VENDOR. */
+ ovs_be16 len; /* At least 16. */
+ ovs_be32 vendor; /* NX_VENDOR_ID. */
+ ovs_be16 subtype; /* See enum ofp_raw_action_type. */
+ uint8_t clause;
+ uint8_t n_clauses;
+ ovs_be32 id;
+};
+OFP_ASSERT(sizeof(struct nx_action_conjunction) == 16);
+
+static void
+add_conjunction(struct ofpbuf *out,
+ uint32_t id, uint8_t clause, uint8_t n_clauses)
+{
+ struct ofpact_conjunction *oc;
+
+ oc = ofpact_put_CONJUNCTION(out);
+ oc->id = id;
+ oc->clause = clause;
+ oc->n_clauses = n_clauses;
+}
+
+static enum ofperr
+decode_NXAST_RAW_CONJUNCTION(const struct nx_action_conjunction *nac,
+ struct ofpbuf *out)
+{
+ if (nac->n_clauses < 2 || nac->n_clauses > 64
+ || nac->clause >= nac->n_clauses) {
+ return OFPERR_NXBAC_BAD_CONJUNCTION;
+ } else {
+ add_conjunction(out, ntohl(nac->id), nac->clause, nac->n_clauses);
+ return 0;
+ }
+}
+
+static void
+encode_CONJUNCTION(const struct ofpact_conjunction *oc,
+ enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
+{
+ struct nx_action_conjunction *nac = put_NXAST_CONJUNCTION(out);
+ nac->clause = oc->clause;
+ nac->n_clauses = oc->n_clauses;
+ nac->id = htonl(oc->id);
+}
+
+static void
+format_CONJUNCTION(const struct ofpact_conjunction *oc, struct ds *s)
+{
+ ds_put_format(s, "conjunction(%"PRIu32",%"PRIu8"/%"PRIu8")",
+ oc->id, oc->clause + 1, oc->n_clauses);
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_CONJUNCTION(const char *arg, struct ofpbuf *ofpacts,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ uint8_t n_clauses;
+ uint8_t clause;
+ uint32_t id;
+ int n;
+
+ if (!ovs_scan(arg, "%"SCNi32" , %"SCNu8" / %"SCNu8" %n",
+ &id, &clause, &n_clauses, &n) || n != strlen(arg)) {
+ return xstrdup("\"conjunction\" syntax is \"conjunction(id,i/n)\"");
+ }
+
+ if (n_clauses < 2) {
+ return xstrdup("conjunction must have at least 2 clauses");
+ } else if (n_clauses > 64) {
+ return xstrdup("conjunction must have at most 64 clauses");
+ } else if (clause < 1) {
+ return xstrdup("clause index must be positive");
+ } else if (clause > n_clauses) {
+ return xstrdup("clause index must be less than or equal to "
+ "number of clauses");
+ }
+
+ add_conjunction(ofpacts, id, clause - 1, n_clauses);
+ return NULL;
+}
+\f
/* Action structure for NXAST_MULTIPATH.
*
* This action performs the following steps in sequence:
nam->dst = htonl(mf_nxm_header(mp->dst.field->id));
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_MULTIPATH(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
nan->len = htons(ofpbuf_size(out) - start_ofs);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_NOTE(const char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
put_NXAST_EXIT(out);
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_EXIT(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_SAMPLE(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_METER(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_CLEAR_ACTIONS(char *arg OVS_UNUSED, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_WRITE_ACTIONS(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_WRITE_METADATA(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
{
}
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_GOTO_TABLE(char *arg, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols OVS_UNUSED)
{
case OFPACT_GOTO_TABLE:
case OFPACT_GROUP:
case OFPACT_LEARN:
+ case OFPACT_CONJUNCTION:
case OFPACT_METER:
case OFPACT_MULTIPATH:
case OFPACT_NOTE:
case OFPACT_EXIT:
case OFPACT_FIN_TIMEOUT:
case OFPACT_LEARN:
+ case OFPACT_CONJUNCTION:
case OFPACT_MULTIPATH:
case OFPACT_NOTE:
case OFPACT_OUTPUT_REG:
case OFPACT_FIN_TIMEOUT:
case OFPACT_RESUBMIT:
case OFPACT_LEARN:
+ case OFPACT_CONJUNCTION:
case OFPACT_MULTIPATH:
case OFPACT_NOTE:
case OFPACT_EXIT:
return 0;
case OFPACT_SET_L4_SRC_PORT:
- if (!is_ip_any(flow) ||
- (flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP
- && flow->nw_proto != IPPROTO_SCTP)) {
- inconsistent_match(usable_protocols);
- }
- /* Note on which transport protocol the port numbers are set.
- * This allows this set action to be converted to an OF1.2 set field
- * action. */
- ofpact_get_SET_L4_SRC_PORT(a)->flow_ip_proto = flow->nw_proto;
- return 0;
-
case OFPACT_SET_L4_DST_PORT:
- if (!is_ip_any(flow) ||
+ if (!is_ip_any(flow) || (flow->nw_frag & FLOW_NW_FRAG_LATER) ||
(flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP
&& flow->nw_proto != IPPROTO_SCTP)) {
inconsistent_match(usable_protocols);
/* Note on which transport protocol the port numbers are set.
* This allows this set action to be converted to an OF1.2 set field
* action. */
- ofpact_get_SET_L4_DST_PORT(a)->flow_ip_proto = flow->nw_proto;
+ if (a->type == OFPACT_SET_L4_SRC_PORT) {
+ ofpact_get_SET_L4_SRC_PORT(a)->flow_ip_proto = flow->nw_proto;
+ } else {
+ ofpact_get_SET_L4_DST_PORT(a)->flow_ip_proto = flow->nw_proto;
+ }
return 0;
case OFPACT_REG_MOVE:
case OFPACT_LEARN:
return learn_check(ofpact_get_LEARN(a), flow);
+ case OFPACT_CONJUNCTION:
+ return 0;
+
case OFPACT_MULTIPATH:
return multipath_check(ofpact_get_MULTIPATH(a), flow);
: 0);
}
-/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
- * in the appropriate order as defined by the OpenFlow spec. */
+/* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are in the
+ * appropriate order as defined by the OpenFlow spec and as required by Open
+ * vSwitch.
+ *
+ * 'allowed_ovsinsts' is a bitmap of OVSINST_* values, in which 1-bits indicate
+ * instructions that are allowed within 'ofpacts[]'. */
static enum ofperr
ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len,
uint32_t allowed_ovsinsts)
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
enum ovs_instruction_type next;
+ if (a->type == OFPACT_CONJUNCTION) {
+ OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+ if (a->type != OFPACT_CONJUNCTION) {
+ VLOG_WARN("when %s action is present, it must be the only "
+ "kind of action used", ofpact_name(a->type));
+ return OFPERR_NXBAC_BAD_CONJUNCTION;
+ }
+ }
+ return 0;
+ }
+
next = ovs_instruction_type_from_ofpact_type(a->type);
if (a > ofpacts
&& (inst == OVSINST_OFPIT11_APPLY_ACTIONS
case OFPACT_FIN_TIMEOUT:
case OFPACT_RESUBMIT:
case OFPACT_LEARN:
+ case OFPACT_CONJUNCTION:
case OFPACT_MULTIPATH:
case OFPACT_NOTE:
case OFPACT_EXIT:
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
ofpact_parse(enum ofpact_type type, char *value, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
{
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
ofpacts_parse__(char *str, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols,
bool allow_instructions)
return NULL;
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
ofpacts_parse(char *str, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols, bool allow_instructions)
{
return error;
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
ofpacts_parse_copy(const char *s_, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols,
bool allow_instructions)
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-char * WARN_UNUSED_RESULT
+char * OVS_WARN_UNUSED_RESULT
ofpacts_parse_actions(const char *s, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
{
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
-char * WARN_UNUSED_RESULT
+char * OVS_WARN_UNUSED_RESULT
ofpacts_parse_instructions(const char *s, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols)
{
};
OFP_ASSERT(sizeof(struct ofp_action_header) == 8);
-/* Header for Nicira-defined actions. */
-struct nx_action_header {
+/* Header for Nicira-defined actions and for ONF vendor extensions.
+ *
+ * This cannot be used as an entirely generic vendor extension action header,
+ * because OpenFlow does not specify the location or size of the action
+ * subtype; it just happens that ONF extensions and Nicira extensions share
+ * this format. */
+struct ext_action_header {
ovs_be16 type; /* OFPAT_VENDOR. */
ovs_be16 len; /* At least 16. */
- ovs_be32 vendor; /* NX_VENDOR_ID. */
+ ovs_be32 vendor; /* NX_VENDOR_ID or ONF_VENDOR_ID. */
ovs_be16 subtype; /* See enum ofp_raw_action_type. */
uint8_t pad[6];
};
-OFP_ASSERT(sizeof(struct nx_action_header) == 16);
+OFP_ASSERT(sizeof(struct ext_action_header) == 16);
static bool
ofpact_hdrs_equal(const struct ofpact_hdrs *a,
if (oah->type == htons(OFPAT_VENDOR)) {
/* Get vendor. */
hdrs.vendor = ntohl(oah->vendor);
- if (hdrs.vendor == NX_VENDOR_ID) {
- /* Get Nicira action type. */
- const struct nx_action_header *nah;
+ if (hdrs.vendor == NX_VENDOR_ID || hdrs.vendor == ONF_VENDOR_ID) {
+ /* Get extension subtype. */
+ const struct ext_action_header *nah;
- nah = ALIGNED_CAST(const struct nx_action_header *, oah);
+ nah = ALIGNED_CAST(const struct ext_action_header *, oah);
if (length < sizeof *nah) {
return OFPERR_OFPBAC_BAD_LEN;
}
}
length = ntohs(oah->len);
+ if (length > ofpbuf_size(buf)) {
+ VLOG_WARN_RL(&rl, "OpenFlow action %s length %u exceeds action buffer "
+ "length %"PRIu32, action->name, length, ofpbuf_size(buf));
+ return OFPERR_OFPBAC_BAD_LEN;
+ }
if (length < action->min_length || length > action->max_length) {
VLOG_WARN_RL(&rl, "OpenFlow action %s length %u not in valid range "
"[%hu,%hu]", action->name, length,
case 0:
break;
- case NX_VENDOR_ID: {
- struct nx_action_header *nah = (struct nx_action_header *) oah;
+ case NX_VENDOR_ID:
+ case ONF_VENDOR_ID: {
+ struct ext_action_header *nah = (struct ext_action_header *) oah;
nah->subtype = htons(hdrs->type);
break;
}