#include "openvswitch/dynamic-string.h"
#include "nx-match.h"
#include "openvswitch/ofp-util.h"
+#include "ovs-atomic.h"
#include "ovs-rcu.h"
#include "ovs-thread.h"
#include "packets.h"
* struct vl_mff_map.*/
struct vl_mf_field {
struct mf_field mf;
+ struct ovs_refcount ref_cnt;
struct cmap_node cmap_node; /* In ofproto->vl_mff_map->cmap. */
};
return hash_int(key, 0);
}
-void
-mf_vl_mff_map_clear(struct vl_mff_map *vl_mff_map)
+static void
+vmf_delete(struct vl_mf_field *vmf)
+{
+ if (ovs_refcount_unref(&vmf->ref_cnt) == 1) {
+ /* Postpone as this function is typically called immediately
+ * after removing from cmap. */
+ ovsrcu_postpone(free, vmf);
+ } else {
+ VLOG_WARN_RL(&rl,
+ "Attempted to delete VMF %s but refcount is nonzero!",
+ vmf->mf.name);
+ }
+}
+
+enum ofperr
+mf_vl_mff_map_clear(struct vl_mff_map *vl_mff_map, bool force)
OVS_REQUIRES(vl_mff_map->mutex)
{
struct vl_mf_field *vmf;
+ if (!force) {
+ CMAP_FOR_EACH (vmf, cmap_node, &vl_mff_map->cmap) {
+ if (ovs_refcount_read(&vmf->ref_cnt) != 1) {
+ return OFPERR_NXTTMFC_INVALID_TLV_DEL;
+ }
+ }
+ }
+
CMAP_FOR_EACH (vmf, cmap_node, &vl_mff_map->cmap) {
cmap_remove(&vl_mff_map->cmap, &vmf->cmap_node,
mf_field_hash(vmf->mf.id));
- ovsrcu_postpone(free, vmf);
+ vmf_delete(vmf);
}
+
+ return 0;
}
static struct vl_mf_field *
return NULL;
}
-/* Updates the tun_metadata mf_field in 'vl_mff_map' according to 'ttm'.
- * This function is supposed to be invoked after tun_metadata_table_mod(). */
-enum ofperr
-mf_vl_mff_map_mod_from_tun_metadata(struct vl_mff_map *vl_mff_map,
- const struct ofputil_tlv_table_mod *ttm)
+static enum ofperr
+mf_vl_mff_map_del(struct vl_mff_map *vl_mff_map,
+ const struct ofputil_tlv_table_mod *ttm, bool force)
OVS_REQUIRES(vl_mff_map->mutex)
{
struct ofputil_tlv_map *tlv_map;
+ struct vl_mf_field *vmf;
+ unsigned int idx;
- if (ttm->command == NXTTMC_CLEAR) {
- mf_vl_mff_map_clear(vl_mff_map);
- return 0;
+ if (!force) {
+ LIST_FOR_EACH (tlv_map, list_node, &ttm->mappings) {
+ idx = MFF_TUN_METADATA0 + tlv_map->index;
+ if (idx >= MFF_TUN_METADATA0 + TUN_METADATA_NUM_OPTS) {
+ return OFPERR_NXTTMFC_BAD_FIELD_IDX;
+ }
+
+ vmf = mf_get_vl_mff__(idx, vl_mff_map);
+ if (vmf && ovs_refcount_read(&vmf->ref_cnt) != 1) {
+ return OFPERR_NXTTMFC_INVALID_TLV_DEL;
+ }
+ }
}
LIST_FOR_EACH (tlv_map, list_node, &ttm->mappings) {
- unsigned int idx = MFF_TUN_METADATA0 + tlv_map->index;
- struct vl_mf_field *vmf;
-
+ idx = MFF_TUN_METADATA0 + tlv_map->index;
if (idx >= MFF_TUN_METADATA0 + TUN_METADATA_NUM_OPTS) {
return OFPERR_NXTTMFC_BAD_FIELD_IDX;
}
- switch (ttm->command) {
- case NXTTMC_ADD:
- vmf = xmalloc(sizeof *vmf);
- vmf->mf = mf_fields[idx];
- vmf->mf.n_bytes = tlv_map->option_len;
- vmf->mf.n_bits = tlv_map->option_len * 8;
- vmf->mf.mapped = true;
-
- cmap_insert(&vl_mff_map->cmap, &vmf->cmap_node,
+ vmf = mf_get_vl_mff__(idx, vl_mff_map);
+ if (vmf) {
+ cmap_remove(&vl_mff_map->cmap, &vmf->cmap_node,
mf_field_hash(idx));
- break;
+ vmf_delete(vmf);
+ }
+ }
- case NXTTMC_DELETE:
- vmf = mf_get_vl_mff__(idx, vl_mff_map);
- if (vmf) {
- cmap_remove(&vl_mff_map->cmap, &vmf->cmap_node,
- mf_field_hash(idx));
- ovsrcu_postpone(free, vmf);
- }
- break;
+ return 0;
+}
- case NXTTMC_CLEAR:
- default:
- OVS_NOT_REACHED();
+static enum ofperr
+mf_vl_mff_map_add(struct vl_mff_map *vl_mff_map,
+ const struct ofputil_tlv_table_mod *ttm)
+ OVS_REQUIRES(vl_mff_map->mutex)
+{
+ struct ofputil_tlv_map *tlv_map;
+ struct vl_mf_field *vmf;
+ unsigned int idx;
+
+ LIST_FOR_EACH (tlv_map, list_node, &ttm->mappings) {
+ idx = MFF_TUN_METADATA0 + tlv_map->index;
+ if (idx >= MFF_TUN_METADATA0 + TUN_METADATA_NUM_OPTS) {
+ return OFPERR_NXTTMFC_BAD_FIELD_IDX;
}
+
+ vmf = xmalloc(sizeof *vmf);
+ vmf->mf = mf_fields[idx];
+ vmf->mf.n_bytes = tlv_map->option_len;
+ vmf->mf.n_bits = tlv_map->option_len * 8;
+ vmf->mf.mapped = true;
+ ovs_refcount_init(&vmf->ref_cnt);
+
+ cmap_insert(&vl_mff_map->cmap, &vmf->cmap_node,
+ mf_field_hash(idx));
+ }
+
+ return 0;
+}
+
+/* Updates the tun_metadata mf_field in 'vl_mff_map' according to 'ttm'.
+ * This function must be invoked after tun_metadata_table_mod().
+ * Returns OFPERR_NXTTMFC_BAD_FIELD_IDX, if the index for the vl_mf_field is
+ * invalid.
+ * Returns OFPERR_NXTTMFC_INVALID_TLV_DEL, if 'ttm' tries to delete an
+ * vl_mf_field that is still used by any active flow.*/
+enum ofperr
+mf_vl_mff_map_mod_from_tun_metadata(struct vl_mff_map *vl_mff_map,
+ const struct ofputil_tlv_table_mod *ttm)
+ OVS_REQUIRES(vl_mff_map->mutex)
+{
+ switch (ttm->command) {
+ case NXTTMC_ADD:
+ return mf_vl_mff_map_add(vl_mff_map, ttm);
+
+ case NXTTMC_DELETE:
+ return mf_vl_mff_map_del(vl_mff_map, ttm, false);
+
+ case NXTTMC_CLEAR:
+ return mf_vl_mff_map_clear(vl_mff_map, false);
+
+ default:
+ OVS_NOT_REACHED();
}
return 0;
{
return map && mff && mff->variable_len && !mff->mapped;
}
+
+void
+mf_vl_mff_set_tlv_bitmap(const struct mf_field *mff, uint64_t *tlv_bitmap)
+{
+ if (mff && mff->mapped) {
+ ovs_assert(mf_is_tun_metadata(mff));
+ ULLONG_SET1(*tlv_bitmap, mff->id - MFF_TUN_METADATA0);
+ }
+}
+
+static void
+mf_vl_mff_ref_cnt_mod(const struct vl_mff_map *map, uint64_t tlv_bitmap,
+ bool ref)
+{
+ struct vl_mf_field *vmf;
+ int i;
+
+ if (map) {
+ ULLONG_FOR_EACH_1 (i, tlv_bitmap) {
+ vmf = mf_get_vl_mff__(i + MFF_TUN_METADATA0, map);
+ if (vmf) {
+ if (ref) {
+ ovs_refcount_ref(&vmf->ref_cnt);
+ } else {
+ ovs_refcount_unref(&vmf->ref_cnt);
+ }
+ } else {
+ VLOG_WARN("Invalid TLV index %d.", i);
+ }
+ }
+ }
+}
+
+void
+mf_vl_mff_ref(const struct vl_mff_map *map, uint64_t tlv_bitmap)
+{
+ mf_vl_mff_ref_cnt_mod(map, tlv_bitmap, true);
+}
+
+void
+mf_vl_mff_unref(const struct vl_mff_map *map, uint64_t tlv_bitmap)
+{
+ mf_vl_mff_ref_cnt_mod(map, tlv_bitmap, false);
+}
+
+enum ofperr
+mf_vl_mff_nx_pull_header(struct ofpbuf *b, const struct vl_mff_map *vl_mff_map,
+ const struct mf_field **field, bool *masked,
+ uint64_t *tlv_bitmap)
+{
+ enum ofperr error = nx_pull_header(b, vl_mff_map, field, masked);
+ if (error) {
+ return error;
+ }
+
+ mf_vl_mff_set_tlv_bitmap(*field, tlv_bitmap);
+ return 0;
+}
+
+enum ofperr
+mf_vl_mff_nx_pull_entry(struct ofpbuf *b, const struct vl_mff_map *vl_mff_map,
+ const struct mf_field **field, union mf_value *value,
+ union mf_value *mask, uint64_t *tlv_bitmap)
+{
+ enum ofperr error = nx_pull_entry(b, vl_mff_map, field, value, mask);
+ if (error) {
+ return error;
+ }
+
+ mf_vl_mff_set_tlv_bitmap(*field, tlv_bitmap);
+ return 0;
+}
+
+enum ofperr
+mf_vl_mff_mf_from_nxm_header(uint32_t header,
+ const struct vl_mff_map *vl_mff_map,
+ const struct mf_field **field,
+ uint64_t *tlv_bitmap)
+{
+ *field = mf_from_nxm_header(header, vl_mff_map);
+ if (mf_vl_mff_invalid(*field, vl_mff_map)) {
+ return OFPERR_NXFMFC_INVALID_TLV_FIELD;
+ }
+
+ mf_vl_mff_set_tlv_bitmap(*field, tlv_bitmap);
+ return 0;
+}
struct ofpbuf *openflow, unsigned int actions_len,
enum ofp_version version, uint32_t allowed_ovsinsts,
struct ofpbuf *ofpacts, enum ofpact_type outer_action,
- const struct vl_mff_map *vl_mff_map);
+ const struct vl_mff_map *vl_mff_map, uint64_t *ofpacts_tlv_bitmap);
static char * OVS_WARN_UNUSED_RESULT ofpacts_parse_copy(
const char *s_, struct ofpbuf *ofpacts,
enum ofputil_protocol *usable_protocols,
decode_NXAST_RAW_OUTPUT_REG(const struct nx_action_output_reg *naor,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *out)
+ uint64_t *tlv_bitmap, struct ofpbuf *out)
{
struct ofpact_output_reg *output_reg;
+ enum ofperr error;
if (!is_all_zeros(naor->zero, sizeof naor->zero)) {
return OFPERR_OFPBAC_BAD_ARGUMENT;
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), vl_mff_map);
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);
-
- if (mf_vl_mff_invalid(output_reg->src.field, vl_mff_map)) {
- return OFPERR_NXFMFC_INVALID_TLV_FIELD;
+ error = mf_vl_mff_mf_from_nxm_header(ntohl(naor->src), vl_mff_map,
+ &output_reg->src.field, tlv_bitmap);
+ if (error) {
+ return error;
}
return mf_check_src(&output_reg->src, NULL);
decode_NXAST_RAW_OUTPUT_REG2(const struct nx_action_output_reg2 *naor,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *out)
+ uint64_t *tlv_bitmap, struct ofpbuf *out)
{
struct ofpact_output_reg *output_reg;
+ enum ofperr error;
+
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);
struct ofpbuf b = ofpbuf_const_initializer(naor, ntohs(naor->len));
ofpbuf_pull(&b, OBJECT_OFFSETOF(naor, pad));
- enum ofperr error = nx_pull_header(&b, vl_mff_map, &output_reg->src.field,
- NULL);
+ error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &output_reg->src.field,
+ NULL, tlv_bitmap);
if (error) {
return error;
}
+
if (!is_all_zeros(b.data, b.size)) {
return OFPERR_NXBRC_MUST_BE_ZERO;
}
static enum ofperr
decode_bundle(bool load, const struct nx_action_bundle *nab,
- const struct vl_mff_map *vl_mff_map, struct ofpbuf *ofpacts)
+ const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap,
+ struct ofpbuf *ofpacts)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
struct ofpact_bundle *bundle;
}
if (load) {
- bundle->dst.field = mf_from_nxm_header(ntohl(nab->dst), vl_mff_map);
bundle->dst.ofs = nxm_decode_ofs(nab->ofs_nbits);
bundle->dst.n_bits = nxm_decode_n_bits(nab->ofs_nbits);
- if (mf_vl_mff_invalid(bundle->dst.field, vl_mff_map)) {
- return OFPERR_NXFMFC_INVALID_TLV_FIELD;
+ error = mf_vl_mff_mf_from_nxm_header(ntohl(nab->dst), vl_mff_map,
+ &bundle->dst.field, tlv_bitmap);
+ if (error) {
+ return error;
}
if (bundle->dst.n_bits < 16) {
enum ofp_version ofp_version OVS_UNUSED,
struct ofpbuf *out)
{
- return decode_bundle(false, nab, NULL, out);
+ return decode_bundle(false, nab, NULL, NULL, out);
}
static enum ofperr
decode_NXAST_RAW_BUNDLE_LOAD(const struct nx_action_bundle *nab,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *out)
+ uint64_t *tlv_bitmap, struct ofpbuf *out)
{
- return decode_bundle(true, nab, vl_mff_map, out);
+ return decode_bundle(true, nab, vl_mff_map, tlv_bitmap, out);
}
static void
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,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
struct ofpact_reg_move *move = ofpact_put_REG_MOVE(ofpacts);
+ enum ofperr error;
+
move->ofpact.raw = ONFACT_RAW13_COPY_FIELD;
move->src.ofs = ntohs(src_offset);
move->src.n_bits = ntohs(n_bits);
struct ofpbuf b = ofpbuf_const_initializer(action, ntohs(action_len));
ofpbuf_pull(&b, oxm_offset);
- enum ofperr error = nx_pull_header(&b, vl_mff_map, &move->src.field, NULL);
+ error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &move->src.field, NULL,
+ tlv_bitmap);
if (error) {
return error;
}
- error = nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL);
+ error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL,
+ tlv_bitmap);
if (error) {
return error;
}
decode_OFPAT_RAW15_COPY_FIELD(const struct ofp15_action_copy_field *oacf,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
return decode_copy_field__(oacf->src_offset, oacf->dst_offset,
oacf->n_bits, oacf, oacf->len,
OBJECT_OFFSETOF(oacf, pad2), vl_mff_map,
- ofpacts);
+ tlv_bitmap, ofpacts);
}
static enum ofperr
decode_ONFACT_RAW13_COPY_FIELD(const struct onf_action_copy_field *oacf,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
return decode_copy_field__(oacf->src_offset, oacf->dst_offset,
oacf->n_bits, oacf, oacf->len,
OBJECT_OFFSETOF(oacf, pad3), vl_mff_map,
- ofpacts);
+ tlv_bitmap, ofpacts);
}
static enum ofperr
decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
struct ofpact_reg_move *move = ofpact_put_REG_MOVE(ofpacts);
+ enum ofperr error;
+
move->ofpact.raw = NXAST_RAW_REG_MOVE;
move->src.ofs = ntohs(narm->src_ofs);
move->src.n_bits = ntohs(narm->n_bits);
struct ofpbuf b = ofpbuf_const_initializer(narm, ntohs(narm->len));
ofpbuf_pull(&b, sizeof *narm);
- enum ofperr error = nx_pull_header(&b, vl_mff_map, &move->src.field, NULL);
+ error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &move->src.field, NULL,
+ tlv_bitmap);
if (error) {
return error;
}
- error = nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL);
+
+ error = mf_vl_mff_nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL,
+ tlv_bitmap);
if (error) {
return error;
}
static enum ofperr
decode_ofpat_set_field(const struct ofp12_action_set_field *oasf,
bool may_mask, const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
struct ofpbuf b = ofpbuf_const_initializer(oasf, ntohs(oasf->len));
ofpbuf_pull(&b, OBJECT_OFFSETOF(oasf, pad));
union mf_value value, mask;
const struct mf_field *field;
- enum ofperr error = nx_pull_entry(&b, vl_mff_map, &field, &value,
- may_mask ? &mask : NULL);
+ enum ofperr error;
+ error = mf_vl_mff_nx_pull_entry(&b, vl_mff_map, &field, &value,
+ may_mask ? &mask : NULL, tlv_bitmap);
if (error) {
return (error == OFPERR_OFPBMC_BAD_MASK
? OFPERR_OFPBAC_BAD_SET_MASK
: error);
}
+
if (!may_mask) {
memset(&mask, 0xff, field->n_bytes);
}
decode_OFPAT_RAW12_SET_FIELD(const struct ofp12_action_set_field *oasf,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
- return decode_ofpat_set_field(oasf, false, vl_mff_map, ofpacts);
+ return decode_ofpat_set_field(oasf, false, vl_mff_map, tlv_bitmap,
+ ofpacts);
}
static enum ofperr
decode_OFPAT_RAW15_SET_FIELD(const struct ofp12_action_set_field *oasf,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
- return decode_ofpat_set_field(oasf, true, vl_mff_map, ofpacts);
+ return decode_ofpat_set_field(oasf, true, vl_mff_map, tlv_bitmap, ofpacts);
}
static enum ofperr
decode_NXAST_RAW_REG_LOAD(const struct nx_action_reg_load *narl,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *out)
+ uint64_t *tlv_bitmap, struct ofpbuf *out)
{
struct mf_subfield dst;
enum ofperr error;
- dst.field = mf_from_nxm_header(ntohl(narl->dst), vl_mff_map);
dst.ofs = nxm_decode_ofs(narl->ofs_nbits);
dst.n_bits = nxm_decode_n_bits(narl->ofs_nbits);
- if (mf_vl_mff_invalid(dst.field, vl_mff_map)) {
- return OFPERR_NXFMFC_INVALID_TLV_FIELD;
+ error = mf_vl_mff_mf_from_nxm_header(ntohl(narl->dst), vl_mff_map,
+ &dst.field, tlv_bitmap);
+ if (error) {
+ return error;
}
error = mf_check_dst(&dst, NULL);
decode_NXAST_RAW_REG_LOAD2(const struct ext_action_header *eah,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *out)
+ uint64_t *tlv_bitmap, struct ofpbuf *out)
{
struct ofpbuf b = ofpbuf_const_initializer(eah, ntohs(eah->len));
ofpbuf_pull(&b, OBJECT_OFFSETOF(eah, pad));
union mf_value value, mask;
const struct mf_field *field;
- enum ofperr error = nx_pull_entry(&b, vl_mff_map, &field, &value, &mask);
+ enum ofperr error;
+ error = mf_vl_mff_nx_pull_entry(&b, vl_mff_map, &field, &value, &mask,
+ tlv_bitmap);
if (error) {
return error;
}
+
if (!is_all_zeros(b.data, b.size)) {
return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
}
static enum ofperr
decode_stack_action(const struct nx_action_stack *nasp,
- const struct vl_mff_map *vl_mff_map,
+ const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap,
struct ofpact_stack *stack_action)
{
+ enum ofperr error;
stack_action->subfield.ofs = ntohs(nasp->offset);
struct ofpbuf b = ofpbuf_const_initializer(nasp, sizeof *nasp);
ofpbuf_pull(&b, OBJECT_OFFSETOF(nasp, pad));
- enum ofperr error = nx_pull_header(&b, vl_mff_map,
- &stack_action->subfield.field, NULL);
+ error = mf_vl_mff_nx_pull_header(&b, vl_mff_map,
+ &stack_action->subfield.field, NULL,
+ tlv_bitmap);
if (error) {
return error;
}
+
stack_action->subfield.n_bits = ntohs(*(const ovs_be16 *) b.data);
ofpbuf_pull(&b, 2);
if (!is_all_zeros(b.data, b.size)) {
decode_NXAST_RAW_STACK_PUSH(const struct nx_action_stack *nasp,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
struct ofpact_stack *push = ofpact_put_STACK_PUSH(ofpacts);
- enum ofperr error = decode_stack_action(nasp, vl_mff_map, push);
+ enum ofperr error = decode_stack_action(nasp, vl_mff_map, tlv_bitmap,
+ push);
return error ? error : nxm_stack_push_check(push, NULL);
}
decode_NXAST_RAW_STACK_POP(const struct nx_action_stack *nasp,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
struct ofpact_stack *pop = ofpact_put_STACK_POP(ofpacts);
- enum ofperr error = decode_stack_action(nasp, vl_mff_map, pop);
+ enum ofperr error = decode_stack_action(nasp, vl_mff_map, tlv_bitmap,
+ pop);
return error ? error : nxm_stack_pop_check(pop, NULL);
}
static enum ofperr
get_subfield(int n_bits, const void **p, struct mf_subfield *sf,
- const struct vl_mff_map *vl_mff_map)
+ const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap)
{
- sf->field = mf_from_nxm_header(ntohl(get_be32(p)), vl_mff_map);
+ enum ofperr error;
+
+ error = mf_vl_mff_mf_from_nxm_header(ntohl(get_be32(p)), vl_mff_map,
+ &sf->field, tlv_bitmap);
sf->ofs = ntohs(get_be16(p));
sf->n_bits = n_bits;
- if (mf_vl_mff_invalid(sf->field, vl_mff_map)) {
- return OFPERR_NXFMFC_INVALID_TLV_FIELD;
- }
- return 0;
+ return error;
}
static unsigned int
decode_NXAST_RAW_LEARN(const struct nx_action_learn *nal,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *ofpacts)
+ uint64_t *tlv_bitmap, struct ofpbuf *ofpacts)
{
struct ofpact_learn *learn;
const void *p, *end;
unsigned int imm_bytes = 0;
enum ofperr error;
if (spec->src_type == NX_LEARN_SRC_FIELD) {
- error = get_subfield(spec->n_bits, &p, &spec->src, vl_mff_map);
+ error = get_subfield(spec->n_bits, &p, &spec->src, vl_mff_map,
+ tlv_bitmap);
if (error) {
return error;
}
/* Get the destination. */
if (spec->dst_type == NX_LEARN_DST_MATCH ||
spec->dst_type == NX_LEARN_DST_LOAD) {
- error = get_subfield(spec->n_bits, &p, &spec->dst, vl_mff_map);
+ error = get_subfield(spec->n_bits, &p, &spec->dst, vl_mff_map,
+ tlv_bitmap);
if (error) {
return error;
}
decode_NXAST_RAW_MULTIPATH(const struct nx_action_multipath *nam,
enum ofp_version ofp_version OVS_UNUSED,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *out)
+ uint64_t *tlv_bitmap, struct ofpbuf *out)
{
uint32_t n_links = ntohs(nam->max_link) + 1;
size_t min_n_bits = log_2_ceil(n_links);
struct ofpact_multipath *mp;
+ enum ofperr error;
mp = ofpact_put_MULTIPATH(out);
mp->fields = ntohs(nam->fields);
mp->algorithm = ntohs(nam->algorithm);
mp->max_link = ntohs(nam->max_link);
mp->arg = ntohl(nam->arg);
- mp->dst.field = mf_from_nxm_header(ntohl(nam->dst), vl_mff_map);
mp->dst.ofs = nxm_decode_ofs(nam->ofs_nbits);
mp->dst.n_bits = nxm_decode_n_bits(nam->ofs_nbits);
-
- if (mf_vl_mff_invalid(mp->dst.field, vl_mff_map)) {
- return OFPERR_NXFMFC_INVALID_TLV_FIELD;
+ error = mf_vl_mff_mf_from_nxm_header(ntohl(nam->dst), vl_mff_map,
+ &mp->dst.field, tlv_bitmap);
+ if (error) {
+ return error;
}
if (!flow_hash_fields_valid(mp->fields)) {
decode_NXAST_RAW_CLONE(const struct ext_action_header *eah,
enum ofp_version ofp_version,
const struct vl_mff_map *vl_mff_map,
- struct ofpbuf *out)
+ uint64_t *tlv_bitmap, struct ofpbuf *out)
{
int error;
struct ofpbuf openflow;
error = ofpacts_pull_openflow_actions__(&openflow, openflow.size,
ofp_version,
1u << OVSINST_OFPIT11_APPLY_ACTIONS,
- out, 0, vl_mff_map);
+ out, 0, vl_mff_map, tlv_bitmap);
clone = ofpbuf_push_uninit(out, sizeof *clone);
out->header = &clone->ofpact;
ofpact_finish_CLONE(out, &clone);
static enum ofperr
decode_ct_zone(const struct nx_action_conntrack *nac,
struct ofpact_conntrack *out,
- const struct vl_mff_map *vl_mff_map)
+ const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap)
{
if (nac->zone_src) {
enum ofperr error;
- out->zone_src.field = mf_from_nxm_header(ntohl(nac->zone_src),
- vl_mff_map);
out->zone_src.ofs = nxm_decode_ofs(nac->zone_ofs_nbits);
out->zone_src.n_bits = nxm_decode_n_bits(nac->zone_ofs_nbits);
- if (mf_vl_mff_invalid(out->zone_src.field, vl_mff_map)) {
- return OFPERR_NXFMFC_INVALID_TLV_FIELD;
+ error = mf_vl_mff_mf_from_nxm_header(ntohl(nac->zone_src),
+ vl_mff_map, &out->zone_src.field,
+ tlv_bitmap);
+ if (error) {
+ return error;
}
error = mf_check_src(&out->zone_src, NULL);
static enum ofperr
decode_NXAST_RAW_CT(const struct nx_action_conntrack *nac,
enum ofp_version ofp_version,
- const struct vl_mff_map *vl_mff_map, struct ofpbuf *out)
+ const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap,
+ struct ofpbuf *out)
{
const size_t ct_offset = ofpacts_pull(out);
struct ofpact_conntrack *conntrack = ofpact_put_CT(out);
goto out;
}
- error = decode_ct_zone(nac, conntrack, vl_mff_map);
+ error = decode_ct_zone(nac, conntrack, vl_mff_map, tlv_bitmap);
if (error) {
goto out;
}
error = ofpacts_pull_openflow_actions__(&openflow, openflow.size,
ofp_version,
1u << OVSINST_OFPIT11_APPLY_ACTIONS,
- out, OFPACT_CT, vl_mff_map);
+ out, OFPACT_CT, vl_mff_map,
+ tlv_bitmap);
if (error) {
goto out;
}
static enum ofperr
ofpacts_decode(const void *actions, size_t actions_len,
enum ofp_version ofp_version,
- const struct vl_mff_map *vl_mff_map, struct ofpbuf *ofpacts)
+ const struct vl_mff_map *vl_mff_map,
+ uint64_t *ofpacts_tlv_bitmap, struct ofpbuf *ofpacts)
{
struct ofpbuf openflow = ofpbuf_const_initializer(actions, actions_len);
while (openflow.size) {
error = ofpact_pull_raw(&openflow, ofp_version, &raw, &arg);
if (!error) {
error = ofpact_decode(action, raw, ofp_version, arg, vl_mff_map,
- ofpacts);
+ ofpacts_tlv_bitmap, ofpacts);
}
if (error) {
uint32_t allowed_ovsinsts,
struct ofpbuf *ofpacts,
enum ofpact_type outer_action,
- const struct vl_mff_map *vl_mff_map)
+ const struct vl_mff_map *vl_mff_map,
+ uint64_t *ofpacts_tlv_bitmap)
{
const struct ofp_action_header *actions;
size_t orig_size = ofpacts->size;
return OFPERR_OFPBRC_BAD_LEN;
}
- error = ofpacts_decode(actions, actions_len, version, vl_mff_map, ofpacts);
+ error = ofpacts_decode(actions, actions_len, version, vl_mff_map,
+ ofpacts_tlv_bitmap, ofpacts);
if (error) {
ofpacts->size = orig_size;
return error;
* you should call ofpacts_pull_openflow_instructions() instead of this
* function.
*
+ * 'vl_mff_map' and 'ofpacts_tlv_bitmap' are optional. If 'vl_mff_map' is
+ * provided, it is used to get variable length mf_fields with configured
+ * length in the actions. If an action uses a variable length mf_field,
+ * 'ofpacts_tlv_bitmap' is updated accordingly for ref counting. If
+ * 'vl_mff_map' is not provided, the default mf_fields with maximum length
+ * will be used.
+ *
* The parsed actions are valid generically, but they may not be valid in a
* specific context. For example, port numbers up to OFPP_MAX are valid
* generically, but specific datapaths may only support port numbers in a
unsigned int actions_len,
enum ofp_version version,
const struct vl_mff_map *vl_mff_map,
+ uint64_t *ofpacts_tlv_bitmap,
struct ofpbuf *ofpacts)
{
return ofpacts_pull_openflow_actions__(openflow, actions_len, version,
1u << OVSINST_OFPIT11_APPLY_ACTIONS,
- ofpacts, 0, vl_mff_map);
+ ofpacts, 0, vl_mff_map,
+ ofpacts_tlv_bitmap);
}
\f
/* OpenFlow 1.1 actions. */
ofpacts_decode_for_action_set(const struct ofp_action_header *in,
size_t n_in, enum ofp_version version,
const struct vl_mff_map *vl_mff_map,
+ uint64_t *ofpacts_tlv_bitmap,
struct ofpbuf *out)
{
enum ofperr error;
struct ofpact *a;
size_t start = out->size;
- error = ofpacts_decode(in, n_in, version, vl_mff_map, out);
+ error = ofpacts_decode(in, n_in, version, vl_mff_map, ofpacts_tlv_bitmap,
+ out);
if (error) {
return error;
unsigned int instructions_len,
enum ofp_version version,
const struct vl_mff_map *vl_mff_map,
+ uint64_t *ofpacts_tlv_bitmap,
struct ofpbuf *ofpacts)
{
const struct ofp11_instruction *instructions;
return ofpacts_pull_openflow_actions__(openflow, instructions_len,
version,
(1u << N_OVS_INSTRUCTIONS) - 1,
- ofpacts, 0, vl_mff_map);
+ ofpacts, 0, vl_mff_map,
+ ofpacts_tlv_bitmap);
}
if (instructions_len % OFP11_INSTRUCTION_ALIGN != 0) {
get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS],
&actions, &actions_len);
error = ofpacts_decode(actions, actions_len, version, vl_mff_map,
- ofpacts);
+ ofpacts_tlv_bitmap, ofpacts);
if (error) {
goto exit;
}
get_actions_from_instruction(insts[OVSINST_OFPIT11_WRITE_ACTIONS],
&actions, &actions_len);
error = ofpacts_decode_for_action_set(actions, actions_len,
- version, vl_mff_map, ofpacts);
+ version, vl_mff_map,
+ ofpacts_tlv_bitmap, ofpacts);
if (error) {
goto exit;
}