summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/bundle.c5
-rw-r--r--lib/learn.c8
-rw-r--r--lib/multipath.c4
-rw-r--r--lib/ofp-actions.c263
4 files changed, 236 insertions, 44 deletions
diff --git a/lib/bundle.c b/lib/bundle.c
index a514ebb64..793eb82a9 100644
--- a/lib/bundle.c
+++ b/lib/bundle.c
@@ -207,6 +207,11 @@ bundle_parse__(const char *s, char **save_ptr,
if (error) {
return error;
}
+
+ if (!mf_nxm_header(bundle->dst.field->id)) {
+ return xasprintf("%s: experimenter OXM field '%s' not supported",
+ s, dst);
+ }
}
return NULL;
diff --git a/lib/learn.c b/lib/learn.c
index c04e1f3bb..e93015c69 100644
--- a/lib/learn.c
+++ b/lib/learn.c
@@ -221,6 +221,10 @@ learn_parse_load_immediate(const char *s, struct ofpact_learn_spec *spec)
if (error) {
return error;
}
+ if (!mf_nxm_header(dst.field->id)) {
+ return xasprintf("%s: experimenter OXM field '%s' not supported",
+ full_s, s);
+ }
if (!bitwise_is_all_zeros(&imm, sizeof imm, dst.n_bits,
(8 * sizeof imm) - dst.n_bits)) {
@@ -269,6 +273,10 @@ learn_parse_spec(const char *orig, char *name, char *value,
if (error) {
return error;
}
+ if (!mf_nxm_header(spec->dst.field->id)) {
+ return xasprintf("%s: experimenter OXM field '%s' not supported",
+ orig, name);
+ }
/* Parse source and check prerequisites. */
if (value[0] != '\0') {
diff --git a/lib/multipath.c b/lib/multipath.c
index 8983c6a09..edd295fe3 100644
--- a/lib/multipath.c
+++ b/lib/multipath.c
@@ -189,6 +189,10 @@ multipath_parse__(struct ofpact_multipath *mp, const char *s_, char *s)
if (error) {
return error;
}
+ if (!mf_nxm_header(mp->dst.field->id)) {
+ return xasprintf("%s: experimenter OXM field '%s' not supported",
+ s, dst);
+ }
if (mp->dst.n_bits < 16 && n_links > (1u << mp->dst.n_bits)) {
return xasprintf("%s: %d-bit destination field has %u possible "
"values, less than specified n_links %d",
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index f5169ff46..7d9ee585a 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -210,10 +210,15 @@ enum ofp_raw_action_type {
* [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. */
+ /* NX1.0-1.4(6): struct nx_action_reg_move, ... */
NXAST_RAW_REG_MOVE,
/* ## ------------------------- ## */
@@ -248,6 +253,8 @@ enum ofp_raw_action_type {
/* 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,
@@ -708,6 +715,27 @@ struct nx_action_output_reg {
};
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)
@@ -719,6 +747,7 @@ decode_NXAST_RAW_OUTPUT_REG(const struct nx_action_output_reg *naor,
}
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);
@@ -727,17 +756,61 @@ decode_NXAST_RAW_OUTPUT_REG(const struct nx_action_output_reg *naor,
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
@@ -1747,10 +1820,12 @@ struct nx_action_reg_move {
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,
@@ -1794,15 +1869,29 @@ 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->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);
}
@@ -1810,11 +1899,9 @@ static void
encode_REG_MOVE(const struct ofpact_reg_move *move,
enum ofp_version ofp_version, struct ofpbuf *out)
{
+ 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);
@@ -1822,17 +1909,15 @@ encode_REG_MOVE(const struct ofpact_reg_move *move,
ofpbuf_set_size(out, ofpbuf_size(out) - sizeof copy->pad);
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
@@ -1921,6 +2006,26 @@ struct nx_action_reg_load {
};
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)
@@ -2028,6 +2133,35 @@ decode_NXAST_RAW_REG_LOAD(const struct nx_action_reg_load *narl,
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_)
@@ -2069,15 +2203,30 @@ next_load_segment(const struct ofpact_set_field *sf,
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);
+ }
}
}
@@ -2220,10 +2369,12 @@ encode_SET_FIELD(const struct ofpact_set_field *sf,
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. */
@@ -2379,19 +2530,36 @@ struct nx_action_stack {
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
@@ -2399,8 +2567,8 @@ decode_NXAST_RAW_STACK_PUSH(const struct nx_action_stack *nasp,
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
@@ -2408,17 +2576,24 @@ decode_NXAST_RAW_STACK_POP(const struct nx_action_stack *nasp,
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