diff --git a/build-aux/extract-ofp-actions b/build-aux/extract-ofp-actions index 3a7234943..184447b99 100755 --- a/build-aux/extract-ofp-actions +++ b/build-aux/extract-ofp-actions @@ -123,7 +123,13 @@ def extract_ofp_actions(fn, definitions): fatal("unexpected syntax between actions") dsts = m.group(1) - argtype = m.group(2).strip().replace('.', '', 1) + argtypes = m.group(2).strip().replace('.', '', 1) + + if 'VLMFF' in argtypes: + arg_vl_mff_map = True + else: + arg_vl_mff_map = False + argtype = argtypes.replace('VLMFF', '', 1).rstrip() get_line() m = re.match(r'\s+(([A-Z]+)_RAW([0-9]*)_([A-Z0-9_]+)),?', line) @@ -210,17 +216,18 @@ def extract_ofp_actions(fn, definitions): else: max_length = min_length - info = {"enum": enum, # 0 - "deprecation": deprecation, # 1 - "file_name": file_name, # 2 - "line_number": line_number, # 3 - "min_length": min_length, # 4 - "max_length": max_length, # 5 - "arg_ofs": arg_ofs, # 6 - "arg_len": arg_len, # 7 - "base_argtype": base_argtype, # 8 - "version": version, # 9 - "type": type_} # 10 + info = {"enum": enum, # 0 + "deprecation": deprecation, # 1 + "file_name": file_name, # 2 + "line_number": line_number, # 3 + "min_length": min_length, # 4 + "max_length": max_length, # 5 + "arg_ofs": arg_ofs, # 6 + "arg_len": arg_len, # 7 + "base_argtype": base_argtype, # 8 + "arg_vl_mff_map": arg_vl_mff_map, # 9 + "version": version, # 10 + "type": type_} # 11 domain[vendor][type_][version] = info enums.setdefault(enum, []) @@ -314,7 +321,8 @@ def extract_ofp_actions(fn, definitions): print """\ static enum ofperr ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw, - enum ofp_version version, uint64_t arg, struct ofpbuf *out) + enum ofp_version version, uint64_t arg, + const struct vl_mff_map *vl_mff_map, struct ofpbuf *out) { switch (raw) {\ """ @@ -322,6 +330,7 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw, enum = versions[0]["enum"] print " case %s:" % enum base_argtype = versions[0]["base_argtype"] + arg_vl_mff_map = versions[0]["arg_vl_mff_map"] if base_argtype == 'void': print " return decode_%s(out);" % enum else: @@ -333,7 +342,10 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw, arg = "%s(arg)" % hton else: arg = "arg" - print " return decode_%s(%s, version, out);" % (enum, arg) + if arg_vl_mff_map: + print " return decode_%s(%s, version, vl_mff_map, out);" % (enum, arg) + else: + print " return decode_%s(%s, version, out);" % (enum, arg) print print """\ default: @@ -346,11 +358,14 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw, enum = versions[0]["enum"] prototype = "static enum ofperr decode_%s(" % enum base_argtype = versions[0]["base_argtype"] + arg_vl_mff_map = versions[0]["arg_vl_mff_map"] if base_argtype != 'void': if base_argtype.startswith('struct'): prototype += "const %s *, enum ofp_version, " % base_argtype else: prototype += "%s, enum ofp_version, " % base_argtype + if arg_vl_mff_map: + prototype += 'const struct vl_mff_map *, ' prototype += "struct ofpbuf *);" print prototype @@ -358,7 +373,8 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw, static enum ofperr ofpact_decode(const struct ofp_action_header *, enum ofp_raw_action_type raw, enum ofp_version version, - uint64_t arg, struct ofpbuf *out); + uint64_t arg, const struct vl_mff_map *vl_mff_map, + struct ofpbuf *out); """ if __name__ == '__main__': diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields index 333d90ec3..40f1bb287 100755 --- a/build-aux/extract-ofp-fields +++ b/build-aux/extract-ofp-fields @@ -334,7 +334,7 @@ def make_meta_flow(meta_flow_h): rw = 'true' else: rw = 'false' - output += [" %s, %s, %s, %s," + output += [" %s, %s, %s, %s, false," % (f['mask'], f['string'], PREREQS[f['prereqs']], rw)] oxm = f['OXM'] @@ -386,7 +386,7 @@ def make_meta_flow(meta_flow_h): else: output += [" -1, /* not usable for prefix lookup */"] - output += ["},"] + output += [" {OVSRCU_INITIALIZER(NULL)},},"] for oline in output: print(oline) diff --git a/include/openvswitch/meta-flow.h b/include/openvswitch/meta-flow.h index 6db4bcc62..d5c097179 100644 --- a/include/openvswitch/meta-flow.h +++ b/include/openvswitch/meta-flow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2011-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,13 +23,16 @@ #include #include #include +#include "cmap.h" #include "openvswitch/flow.h" #include "openvswitch/ofp-errors.h" #include "openvswitch/packets.h" +#include "openvswitch/thread.h" #include "openvswitch/util.h" struct ds; struct match; +struct ofputil_tlv_table_mod; /* Open vSwitch fields * =================== @@ -1751,6 +1754,7 @@ struct mf_field { enum mf_string string; enum mf_prereqs prereqs; bool writable; /* May be written by actions? */ + bool mapped; /* Variable length mf_field is mapped. */ /* Usable protocols. * @@ -1770,6 +1774,9 @@ struct mf_field { int flow_be32ofs; /* Field's be32 offset in "struct flow", if prefix tree * lookup is supported for the field, or -1. */ + + /* For variable length mf_fields only. In ofproto->vl_mff_map->cmap. */ + struct cmap_node cmap_node; }; /* The representation of a field's value. */ @@ -1846,6 +1853,14 @@ union mf_subvalue { }; BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue)); +/* Variable length mf_fields mapping map. This is a single writer, + * multiple-reader hash table that a writer must hold the following mutex + * to access this map. */ +struct vl_mff_map { + struct cmap cmap; /* Contains 'struct mf_field' */ + struct ovs_mutex mutex; +}; + bool mf_subvalue_intersect(const union mf_subvalue *a_value, const union mf_subvalue *a_mask, const union mf_subvalue *b_value, @@ -1973,4 +1988,13 @@ void mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s); void field_array_set(enum mf_field_id id, const union mf_value *, struct field_array *); +/* Variable length fields. */ +void mf_vl_mff_map_clear(struct vl_mff_map *vl_mff_map) + OVS_REQUIRES(vl_mff_map->mutex); +enum ofperr mf_vl_mff_map_mod_from_tun_metadata( + struct vl_mff_map *vl_mff_map, const struct ofputil_tlv_table_mod *) + OVS_REQUIRES(vl_mff_map->mutex); +const struct mf_field * mf_get_vl_mff(const struct mf_field *, + const struct vl_mff_map *); +bool mf_vl_mff_invalid(const struct mf_field *, const struct vl_mff_map *); #endif /* meta-flow.h */ diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h index 8ca787aae..a3783c2b8 100644 --- a/include/openvswitch/ofp-actions.h +++ b/include/openvswitch/ofp-actions.h @@ -943,11 +943,14 @@ struct ofpact_unroll_xlate { enum ofperr ofpacts_pull_openflow_actions(struct ofpbuf *openflow, unsigned int actions_len, enum ofp_version version, + const struct vl_mff_map *, struct ofpbuf *ofpacts); -enum ofperr ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, - unsigned int instructions_len, - enum ofp_version version, - struct ofpbuf *ofpacts); +enum ofperr +ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, + unsigned int instructions_len, + enum ofp_version version, + const struct vl_mff_map *vl_mff_map, + struct ofpbuf *ofpacts); enum ofperr ofpacts_check(struct ofpact[], size_t ofpacts_len, struct flow *, ofp_port_t max_ports, uint8_t table_id, uint8_t n_tables, diff --git a/include/openvswitch/ofp-errors.h b/include/openvswitch/ofp-errors.h index a37890991..81825817e 100644 --- a/include/openvswitch/ofp-errors.h +++ b/include/openvswitch/ofp-errors.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2008-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -395,6 +395,10 @@ enum ofperr { * nxt_flow_mod_table_id extension is enabled. */ OFPERR_NXFMFC_BAD_TABLE_ID, + /* NX1.0-1.1(1,536), NX1.2+(37). Attempted to add a flow with an invalid + * variable length meta-flow field. */ + OFPERR_NXFMFC_INVALID_TLV_FIELD, + /* ## ---------------------- ## */ /* ## OFPET_GROUP_MOD_FAILED ## */ /* ## ---------------------- ## */ diff --git a/include/openvswitch/ofp-util.h b/include/openvswitch/ofp-util.h index 62530e8da..dd254e6eb 100644 --- a/include/openvswitch/ofp-util.h +++ b/include/openvswitch/ofp-util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2008-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -331,6 +331,7 @@ enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *, const struct ofp_header *, enum ofputil_protocol, const struct tun_table *, + const struct vl_mff_map *, struct ofpbuf *ofpacts, ofp_port_t max_port, uint8_t max_table); diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 6fc8ff98f..b92950bd5 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2011-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ #include "openvswitch/dynamic-string.h" #include "nx-match.h" #include "openvswitch/ofp-util.h" +#include "ovs-rcu.h" #include "ovs-thread.h" #include "packets.h" #include "random.h" @@ -2639,3 +2640,109 @@ field_array_set(enum mf_field_id id, const union mf_value *value, memcpy(fa->values + offset, value, value_size); } + +static inline uint32_t +mf_field_hash(uint32_t key) +{ + return hash_int(key, 0); +} + +void +mf_vl_mff_map_clear(struct vl_mff_map *vl_mff_map) + OVS_REQUIRES(vl_mff_map->mutex) +{ + struct mf_field *mf; + + CMAP_FOR_EACH (mf, cmap_node, &vl_mff_map->cmap) { + cmap_remove(&vl_mff_map->cmap, &mf->cmap_node, mf_field_hash(mf->id)); + ovsrcu_postpone(free, mf); + } +} + +static struct mf_field * +mf_get_vl_mff__(uint32_t id, const struct vl_mff_map *vl_mff_map) +{ + struct mf_field *field; + + CMAP_FOR_EACH_WITH_HASH (field, cmap_node, mf_field_hash(id), + &vl_mff_map->cmap) { + if (field->id == id) { + return field; + } + } + + return NULL; +} + +/* If 'mff' is a variable length field, looks up 'vl_mff_map', returns a + * pointer to the variable length meta-flow field corresponding to 'mff'. + * Returns NULL if no mapping is existed for 'mff'. */ +const struct mf_field * +mf_get_vl_mff(const struct mf_field *mff, + const struct vl_mff_map *vl_mff_map) +{ + if (mff && mff->variable_len && vl_mff_map) { + return mf_get_vl_mff__(mff->id, vl_mff_map); + } + + 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) + OVS_REQUIRES(vl_mff_map->mutex) +{ + struct ofputil_tlv_map *tlv_map; + + if (ttm->command == NXTTMC_CLEAR) { + mf_vl_mff_map_clear(vl_mff_map); + return 0; + } + + LIST_FOR_EACH (tlv_map, list_node, &ttm->mappings) { + unsigned int idx = MFF_TUN_METADATA0 + tlv_map->index; + struct mf_field *mf; + + if (idx >= MFF_TUN_METADATA0 + TUN_METADATA_NUM_OPTS) { + return OFPERR_NXTTMFC_BAD_FIELD_IDX; + } + + switch (ttm->command) { + case NXTTMC_ADD: + mf = xmalloc(sizeof *mf); + *mf = mf_fields[idx]; + mf->n_bytes = tlv_map->option_len; + mf->n_bits = tlv_map->option_len * 8; + mf->mapped = true; + + cmap_insert(&vl_mff_map->cmap, &mf->cmap_node, mf_field_hash(idx)); + break; + + case NXTTMC_DELETE: + mf = mf_get_vl_mff__(idx, vl_mff_map); + if (mf) { + cmap_remove(&vl_mff_map->cmap, &mf->cmap_node, + mf_field_hash(idx)); + ovsrcu_postpone(free, mf); + } + break; + + case NXTTMC_CLEAR: + default: + OVS_NOT_REACHED(); + } + } + + return 0; +} + +/* Returns true if a variable length meta-flow field 'mff' is not mapped in + * the 'vl_mff_map'. */ +bool +mf_vl_mff_invalid(const struct mf_field *mff, const struct vl_mff_map *map) +{ + return map && mff && mff->variable_len && !mff->mapped; +} diff --git a/lib/nx-match.c b/lib/nx-match.c index a7589ff8a..e9d649bf7 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -231,19 +231,42 @@ mf_nxm_header(enum mf_field_id id) return is_experimenter_oxm(oxm) ? 0 : oxm >> 32; } +/* Returns the 32-bit OXM or NXM header to use for field 'mff'. If 'mff' is + * a mapped variable length mf_field, update the header with the configured + * length of 'mff'. Returns 0 if 'mff' cannot be expressed with a 32-bit NXM + * or OXM header.*/ +uint32_t +nxm_header_from_mff(const struct mf_field *mff) +{ + uint64_t oxm = mf_oxm_header(mff->id, 0); + + if (mff->mapped) { + oxm = nxm_no_len(oxm) | ((uint64_t) mff->n_bytes << 32); + } + + return is_experimenter_oxm(oxm) ? 0 : oxm >> 32; +} + static const struct mf_field * -mf_from_oxm_header(uint64_t header) +mf_from_oxm_header(uint64_t header, const struct vl_mff_map *vl_mff_map) { const struct nxm_field *f = nxm_field_by_header(header); - return f ? mf_from_id(f->id) : NULL; + + if (f) { + const struct mf_field *mff = mf_from_id(f->id); + const struct mf_field *vl_mff = mf_get_vl_mff(mff, vl_mff_map); + return vl_mff ? vl_mff : mff; + } else { + return NULL; + } } /* Returns the "struct mf_field" that corresponds to NXM or OXM header * 'header', or NULL if 'header' doesn't correspond to any known field. */ const struct mf_field * -mf_from_nxm_header(uint32_t header) +mf_from_nxm_header(uint32_t header, const struct vl_mff_map *vl_mff_map) { - return mf_from_oxm_header((uint64_t) header << 32); + return mf_from_oxm_header((uint64_t) header << 32, vl_mff_map); } /* Returns the width of the data for a field with the given 'header', in @@ -286,7 +309,8 @@ is_cookie_pseudoheader(uint64_t header) } static enum ofperr -nx_pull_header__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, +nx_pull_header__(struct ofpbuf *b, bool allow_cookie, + const struct vl_mff_map *vl_mff_map, uint64_t *header, const struct mf_field **field) { if (b->size < 4) { @@ -310,11 +334,13 @@ nx_pull_header__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, ofpbuf_pull(b, nxm_header_len(*header)); if (field) { - *field = mf_from_oxm_header(*header); + *field = mf_from_oxm_header(*header, vl_mff_map); if (!*field && !(allow_cookie && is_cookie_pseudoheader(*header))) { VLOG_DBG_RL(&rl, "OXM header "NXM_HEADER_FMT" is unknown", NXM_HEADER_ARGS(*header)); return OFPERR_OFPBMC_BAD_FIELD; + } else if (mf_vl_mff_invalid(*field, vl_mff_map)) { + return OFPERR_NXFMFC_INVALID_TLV_FIELD; } } @@ -350,7 +376,8 @@ copy_entry_value(const struct mf_field *field, union mf_value *value, } static enum ofperr -nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, +nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, + const struct vl_mff_map *vl_mff_map, uint64_t *header, const struct mf_field **field_, union mf_value *value, union mf_value *mask) { @@ -360,7 +387,8 @@ nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, const uint8_t *payload; int width; - header_error = nx_pull_header__(b, allow_cookie, header, &field); + header_error = nx_pull_header__(b, allow_cookie, vl_mff_map, header, + &field); if (header_error && header_error != OFPERR_OFPBMC_BAD_FIELD) { return header_error; } @@ -414,12 +442,13 @@ nx_pull_entry__(struct ofpbuf *b, bool allow_cookie, uint64_t *header, * errors (with OFPERR_OFPBMC_BAD_MASK). */ enum ofperr -nx_pull_entry(struct ofpbuf *b, const struct mf_field **field, - union mf_value *value, union mf_value *mask) +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 header; - return nx_pull_entry__(b, false, &header, field, value, mask); + return nx_pull_entry__(b, false, vl_mff_map, &header, field, value, mask); } /* Attempts to pull an NXM or OXM header from the beginning of 'b'. If @@ -433,12 +462,13 @@ nx_pull_entry(struct ofpbuf *b, const struct mf_field **field, * errors (with OFPERR_OFPBMC_BAD_MASK). */ enum ofperr -nx_pull_header(struct ofpbuf *b, const struct mf_field **field, bool *masked) +nx_pull_header(struct ofpbuf *b, const struct vl_mff_map *vl_mff_map, + const struct mf_field **field, bool *masked) { enum ofperr error; uint64_t header; - error = nx_pull_header__(b, false, &header, field); + error = nx_pull_header__(b, false, vl_mff_map, &header, field); if (masked) { *masked = !error && nxm_hasmask(header); } else if (!error && nxm_hasmask(header)) { @@ -455,7 +485,8 @@ nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie, enum ofperr error; uint64_t header; - error = nx_pull_entry__(b, allow_cookie, &header, field, value, mask); + error = nx_pull_entry__(b, allow_cookie, NULL, &header, field, value, + mask); if (error) { return error; } @@ -668,7 +699,8 @@ oxm_pull_field_array(const void *fields_data, size_t fields_len, enum ofperr error; uint64_t header; - error = nx_pull_entry__(&b, false, &header, &field, &value, NULL); + error = nx_pull_entry__(&b, false, NULL, &header, &field, &value, + NULL); if (error) { VLOG_DBG_RL(&rl, "error pulling field array field"); return error; @@ -1267,6 +1299,16 @@ nx_put_header(struct ofpbuf *b, enum mf_field_id field, nx_put_header__(b, mf_oxm_header(field, version), masked); } +void nx_put_mff_header(struct ofpbuf *b, const struct mf_field *mff, + enum ofp_version version, bool masked) +{ + if (mff->mapped) { + nx_put_header_len(b, mff->id, version, masked, mff->n_bytes); + } else { + nx_put_header(b, mff->id, version, masked); + } +} + static void nx_put_header_len(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, bool masked, size_t n_bytes) @@ -1281,18 +1323,17 @@ nx_put_header_len(struct ofpbuf *b, enum mf_field_id field, } void -nx_put_entry(struct ofpbuf *b, - enum mf_field_id field, enum ofp_version version, - const union mf_value *value, const union mf_value *mask) +nx_put_entry(struct ofpbuf *b, const struct mf_field *mff, + enum ofp_version version, const union mf_value *value, + const union mf_value *mask) { - const struct mf_field *mf = mf_from_id(field); bool masked; int len, offset; - len = mf_field_len(mf, value, mask, &masked); - offset = mf->n_bytes - len; + len = mf_field_len(mff, value, mask, &masked); + offset = mff->n_bytes - len; - nx_put_header_len(b, field, version, masked, len); + nx_put_header_len(b, mff->id, version, masked, len); ofpbuf_put(b, &value->u8 + offset, len); if (masked) { ofpbuf_put(b, &mask->u8 + offset, len); @@ -1319,7 +1360,7 @@ nx_match_to_string(const uint8_t *p, unsigned int match_len) uint64_t header; int value_len; - error = nx_pull_entry__(&b, true, &header, NULL, &value, &mask); + error = nx_pull_entry__(&b, true, NULL, &header, NULL, &value, &mask); if (error) { break; } @@ -1505,7 +1546,7 @@ nx_match_from_string_raw(const char *s, struct ofpbuf *b) b->header = ofpbuf_put_uninit(b, nxm_header_len(header)); s = ofpbuf_put_hex(b, s, &n); if (n != nxm_field_bytes(header)) { - const struct mf_field *field = mf_from_oxm_header(header); + const struct mf_field *field = mf_from_oxm_header(header, NULL); if (field && field->variable_len) { if (n <= field->n_bytes) { diff --git a/lib/nx-match.h b/lib/nx-match.h index 0ba9f5e35..c3432d70e 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc. + * Copyright (c) 2010-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,17 +76,20 @@ int oxm_put_field_array(struct ofpbuf *, const struct field_array *, /* Decoding and encoding OXM/NXM headers (just a field ID) or entries (a field * ID followed by a value and possibly a mask). */ -enum ofperr nx_pull_entry(struct ofpbuf *, const struct mf_field **, - union mf_value *value, union mf_value *mask); -enum ofperr nx_pull_header(struct ofpbuf *, const struct mf_field **, - bool *masked); +enum ofperr nx_pull_entry(struct ofpbuf *, const struct vl_mff_map *, + const struct mf_field **, union mf_value *value, + union mf_value *mask); +enum ofperr nx_pull_header(struct ofpbuf *, const struct vl_mff_map *, + const struct mf_field **, bool *masked); void nxm_put__(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version, const void *value, const void *mask, size_t n_bytes); -void nx_put_entry(struct ofpbuf *, enum mf_field_id, enum ofp_version, +void nx_put_entry(struct ofpbuf *, const struct mf_field *, enum ofp_version, const union mf_value *value, const union mf_value *mask); void nx_put_header(struct ofpbuf *, enum mf_field_id, enum ofp_version, bool masked); +void nx_put_mff_header(struct ofpbuf *, const struct mf_field *, + enum ofp_version, bool); /* NXM and OXM protocol headers values. * @@ -95,7 +98,9 @@ void nx_put_header(struct ofpbuf *, enum mf_field_id, enum ofp_version, * the nx_*() functions should be preferred because they can support the 64-bit * "experimenter" OXM format (even though it is not yet implemented). */ uint32_t mf_nxm_header(enum mf_field_id); -const struct mf_field *mf_from_nxm_header(uint32_t nxm_header); +uint32_t nxm_header_from_mff(const struct mf_field *); +const struct mf_field *mf_from_nxm_header(uint32_t nxm_header, + const struct vl_mff_map *); char *nx_match_to_string(const uint8_t *, unsigned int match_len); char *oxm_match_to_string(const struct ofpbuf *, unsigned int match_len); diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index cf1ad0fa9..11ab69217 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -114,6 +114,12 @@ OFP_ASSERT(sizeof(struct ext_action_header) == 16); * # "void": The action is just a (standard or vendor extension) * header. * + * # Optionally, one may add "VLMFF" in the end of the second part if + * the Openflow action may use a variable length meta-flow field + * (i.e. tun_metadata). Adding "VLMFF" will pass the per-switch based + * variable length meta-flow field mapping map (struct vl_mff_map) to + * the corresponding action decoding function. + * * - Optional additional text enclosed in square brackets is commentary for * the human reader. */ @@ -226,26 +232,26 @@ enum ofp_raw_action_type { /* NX1.0+(21): struct nx_action_cnt_ids, ... */ NXAST_RAW_DEC_TTL_CNT_IDS, - /* OF1.2-1.4(25): struct ofp12_action_set_field, ... */ + /* OF1.2-1.4(25): struct ofp12_action_set_field, ... VLMFF */ OFPAT_RAW12_SET_FIELD, - /* OF1.5+(25): struct ofp12_action_set_field, ... */ + /* OF1.5+(25): struct ofp12_action_set_field, ... VLMFF */ OFPAT_RAW15_SET_FIELD, - /* NX1.0-1.4(7): struct nx_action_reg_load. + /* NX1.0-1.4(7): struct nx_action_reg_load. VLMFF * * [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 ext_action_header, ... + /* NX1.0-1.4(33): struct ext_action_header, ... VLMFF * * [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, ... */ + /* OF1.5+(28): struct ofp15_action_copy_field, ... VLMFF */ OFPAT_RAW15_COPY_FIELD, - /* ONF1.3-1.4(3200): struct onf_action_copy_field, ... */ + /* ONF1.3-1.4(3200): struct onf_action_copy_field, ... VLMFF */ ONFACT_RAW13_COPY_FIELD, - /* NX1.0-1.4(6): struct nx_action_reg_move, ... */ + /* NX1.0-1.4(6): struct nx_action_reg_move, ... VLMFF */ NXAST_RAW_REG_MOVE, /* ## ------------------------- ## */ @@ -270,20 +276,20 @@ enum ofp_raw_action_type { /* NX1.0+(8): struct nx_action_note, ... */ NXAST_RAW_NOTE, - /* NX1.0+(10): struct nx_action_multipath. */ + /* NX1.0+(10): struct nx_action_multipath. VLMFF */ NXAST_RAW_MULTIPATH, /* NX1.0+(12): struct nx_action_bundle, ... */ NXAST_RAW_BUNDLE, - /* NX1.0+(13): struct nx_action_bundle, ... */ + /* NX1.0+(13): struct nx_action_bundle, ... VLMFF */ NXAST_RAW_BUNDLE_LOAD, - /* NX1.0+(15): struct nx_action_output_reg. */ + /* NX1.0+(15): struct nx_action_output_reg. VLMFF */ NXAST_RAW_OUTPUT_REG, - /* NX1.0+(32): struct nx_action_output_reg2. */ + /* NX1.0+(32): struct nx_action_output_reg2. VLMFF */ NXAST_RAW_OUTPUT_REG2, - /* NX1.0+(16): struct nx_action_learn, ... */ + /* NX1.0+(16): struct nx_action_learn, ... VLMFF */ NXAST_RAW_LEARN, /* NX1.0+(17): void. */ @@ -300,10 +306,10 @@ enum ofp_raw_action_type { /* NX1.0+(22): struct nx_action_write_metadata. */ NXAST_RAW_WRITE_METADATA, - /* NX1.0+(27): struct nx_action_stack. */ + /* NX1.0+(27): struct nx_action_stack. VLMFF */ NXAST_RAW_STACK_PUSH, - /* NX1.0+(28): struct nx_action_stack. */ + /* NX1.0+(28): struct nx_action_stack. VLMFF */ NXAST_RAW_STACK_POP, /* NX1.0+(29): struct nx_action_sample. */ @@ -316,7 +322,7 @@ enum ofp_raw_action_type { /* NX1.0+(34): struct nx_action_conjunction. */ NXAST_RAW_CONJUNCTION, - /* NX1.0+(35): struct nx_action_conntrack, ... */ + /* NX1.0+(35): struct nx_action_conntrack, ... VLMFF */ NXAST_RAW_CT, /* NX1.0+(36): struct nx_action_nat, ... */ @@ -325,7 +331,7 @@ enum ofp_raw_action_type { /* NX1.0+(39): struct nx_action_output_trunc. */ NXAST_RAW_OUTPUT_TRUNC, - /* NX1.0+(42): struct ext_action_header, ... */ + /* NX1.0+(42): struct ext_action_header, ... VLMFF */ NXAST_RAW_CLONE, /* NX1.0+(43): void. */ @@ -397,7 +403,8 @@ static char *OVS_WARN_UNUSED_RESULT ofpacts_parse( static enum ofperr ofpacts_pull_openflow_actions__( struct ofpbuf *openflow, unsigned int actions_len, enum ofp_version version, uint32_t allowed_ovsinsts, - struct ofpbuf *ofpacts, enum ofpact_type outer_action); + struct ofpbuf *ofpacts, enum ofpact_type outer_action, + const struct vl_mff_map *vl_mff_map); static char * OVS_WARN_UNUSED_RESULT ofpacts_parse_copy( const char *s_, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols, @@ -1112,6 +1119,7 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg2) == 24); static enum ofperr 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) { struct ofpact_output_reg *output_reg; @@ -1122,17 +1130,22 @@ 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.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; + } + return mf_check_src(&output_reg->src, NULL); } static enum ofperr 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) { struct ofpact_output_reg *output_reg; @@ -1145,7 +1158,8 @@ decode_NXAST_RAW_OUTPUT_REG2(const struct nx_action_output_reg2 *naor, struct ofpbuf b = ofpbuf_const_initializer(naor, ntohs(naor->len)); ofpbuf_pull(&b, OBJECT_OFFSETOF(naor, pad)); - enum ofperr error = nx_pull_header(&b, &output_reg->src.field, NULL); + enum ofperr error = nx_pull_header(&b, vl_mff_map, &output_reg->src.field, + NULL); if (error) { return error; } @@ -1174,14 +1188,14 @@ encode_OUTPUT_REG(const struct ofpact_output_reg *output_reg, naor->max_len = htons(output_reg->max_len); out->size = size - sizeof naor->pad; - nx_put_header(out, output_reg->src.field->id, 0, false); + nx_put_mff_header(out, output_reg->src.field, 0, false); out->size = 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->src = htonl(nxm_header_from_mff(output_reg->src.field)); naor->max_len = htons(output_reg->max_len); } } @@ -1271,7 +1285,7 @@ OFP_ASSERT(sizeof(struct nx_action_bundle) == 32); static enum ofperr decode_bundle(bool load, const struct nx_action_bundle *nab, - struct ofpbuf *ofpacts) + const struct vl_mff_map *vl_mff_map, struct ofpbuf *ofpacts) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); struct ofpact_bundle *bundle; @@ -1308,9 +1322,12 @@ decode_bundle(bool load, const struct nx_action_bundle *nab, } if (load) { - bundle->dst.field = mf_from_nxm_header(ntohl(nab->dst)); + 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; + } if (bundle->dst.n_bits < 16) { VLOG_WARN_RL(&rl, "bundle_load action requires at least 16 bit " @@ -1351,15 +1368,16 @@ decode_NXAST_RAW_BUNDLE(const struct nx_action_bundle *nab, enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) { - return decode_bundle(false, nab, out); + return decode_bundle(false, nab, 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) { - return decode_bundle(true, nab, out); + return decode_bundle(true, nab, vl_mff_map, out); } static void @@ -1384,7 +1402,7 @@ encode_BUNDLE(const struct ofpact_bundle *bundle, if (bundle->dst.field) { nab->ofs_nbits = nxm_encode_ofs_nbits(bundle->dst.ofs, bundle->dst.n_bits); - nab->dst = htonl(mf_nxm_header(bundle->dst.field->id)); + nab->dst = htonl(nxm_header_from_mff(bundle->dst.field)); } slaves = ofpbuf_put_zeros(out, slaves_len); @@ -2262,6 +2280,7 @@ OFP_ASSERT(sizeof(struct nx_action_reg_move) == 16); static enum ofperr 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) { struct ofpact_reg_move *move = ofpact_put_REG_MOVE(ofpacts); @@ -2274,11 +2293,11 @@ decode_copy_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits, struct ofpbuf b = ofpbuf_const_initializer(action, ntohs(action_len)); ofpbuf_pull(&b, oxm_offset); - enum ofperr error = nx_pull_header(&b, &move->src.field, NULL); + enum ofperr error = nx_pull_header(&b, vl_mff_map, &move->src.field, NULL); if (error) { return error; } - error = nx_pull_header(&b, &move->dst.field, NULL); + error = nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL); if (error) { return error; } @@ -2293,26 +2312,31 @@ decode_copy_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits, static enum ofperr 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) { return decode_copy_field__(oacf->src_offset, oacf->dst_offset, oacf->n_bits, oacf, oacf->len, - OBJECT_OFFSETOF(oacf, pad2), ofpacts); + OBJECT_OFFSETOF(oacf, pad2), vl_mff_map, + 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) { return decode_copy_field__(oacf->src_offset, oacf->dst_offset, oacf->n_bits, oacf, oacf->len, - OBJECT_OFFSETOF(oacf, pad3), ofpacts); + OBJECT_OFFSETOF(oacf, pad3), vl_mff_map, + 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) { struct ofpact_reg_move *move = ofpact_put_REG_MOVE(ofpacts); @@ -2325,14 +2349,15 @@ decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm, struct ofpbuf b = ofpbuf_const_initializer(narm, ntohs(narm->len)); ofpbuf_pull(&b, sizeof *narm); - enum ofperr error = nx_pull_header(&b, &move->src.field, NULL); + enum ofperr error = nx_pull_header(&b, vl_mff_map, &move->src.field, NULL); if (error) { return error; } - error = nx_pull_header(&b, &move->dst.field, NULL); + error = nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL); if (error) { return error; } + if (!is_all_zeros(b.data, b.size)) { return OFPERR_NXBRC_MUST_BE_ZERO; } @@ -2357,8 +2382,8 @@ encode_REG_MOVE(const struct ofpact_reg_move *move, copy->src_offset = htons(move->src.ofs); copy->dst_offset = htons(move->dst.ofs); out->size = out->size - 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); + nx_put_mff_header(out, move->src.field, ofp_version, false); + nx_put_mff_header(out, move->dst.field, 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); @@ -2366,15 +2391,15 @@ encode_REG_MOVE(const struct ofpact_reg_move *move, copy->src_offset = htons(move->src.ofs); copy->dst_offset = htons(move->dst.ofs); out->size = out->size - 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); + nx_put_mff_header(out, move->src.field, ofp_version, false); + nx_put_mff_header(out, move->dst.field, ofp_version, false); } else { 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); - nx_put_header(out, move->src.field->id, 0, false); - nx_put_header(out, move->dst.field->id, 0, false); + nx_put_mff_header(out, move->src.field, 0, false); + nx_put_mff_header(out, move->dst.field, 0, false); } pad_ofpat(out, start_ofs); } @@ -2454,14 +2479,15 @@ OFP_ASSERT(sizeof(struct nx_action_reg_load) == 24); static enum ofperr decode_ofpat_set_field(const struct ofp12_action_set_field *oasf, - bool may_mask, struct ofpbuf *ofpacts) + bool may_mask, const struct vl_mff_map *vl_mff_map, + 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, &field, &value, + enum ofperr error = nx_pull_entry(&b, vl_mff_map, &field, &value, may_mask ? &mask : NULL); if (error) { return (error == OFPERR_OFPBMC_BAD_MASK @@ -2512,30 +2538,37 @@ decode_ofpat_set_field(const struct ofp12_action_set_field *oasf, static enum ofperr 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) { - return decode_ofpat_set_field(oasf, false, ofpacts); + return decode_ofpat_set_field(oasf, false, vl_mff_map, 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) { - return decode_ofpat_set_field(oasf, true, ofpacts); + return decode_ofpat_set_field(oasf, true, vl_mff_map, 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) { struct mf_subfield dst; enum ofperr error; - dst.field = mf_from_nxm_header(ntohl(narl->dst)); + 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_check_dst(&dst, NULL); if (error) { return error; @@ -2561,6 +2594,7 @@ decode_NXAST_RAW_REG_LOAD(const struct nx_action_reg_load *narl, static enum ofperr 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) { struct ofpbuf b = ofpbuf_const_initializer(eah, ntohs(eah->len)); @@ -2568,7 +2602,7 @@ decode_NXAST_RAW_REG_LOAD2(const struct ext_action_header *eah, union mf_value value, mask; const struct mf_field *field; - enum ofperr error = nx_pull_entry(&b, &field, &value, &mask); + enum ofperr error = nx_pull_entry(&b, vl_mff_map, &field, &value, &mask); if (error) { return error; } @@ -2599,7 +2633,7 @@ put_set_field(struct ofpbuf *openflow, enum ofp_version ofp_version, oasf = put_OFPAT12_SET_FIELD(openflow); openflow->size = openflow->size - sizeof oasf->pad; - nx_put_entry(openflow, field, ofp_version, &value, NULL); + nx_put_entry(openflow, mf_from_id(field), ofp_version, &value, NULL); pad_ofpat(openflow, start_ofs); } @@ -2611,7 +2645,7 @@ put_reg_load(struct ofpbuf *openflow, 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->dst = htonl(nxm_header_from_mff(dst->field)); narl->value = htonll(value); } @@ -2653,7 +2687,7 @@ set_field_to_nxast(const struct ofpact_set_field *sf, struct ofpbuf *openflow) eah = put_NXAST_REG_LOAD2(openflow); openflow->size = openflow->size - sizeof eah->pad; - nx_put_entry(openflow, sf->field->id, 0, sf->value, + nx_put_entry(openflow, sf->field, 0, sf->value, ofpact_set_field_mask(sf)); pad_ofpat(openflow, start_ofs); } else { @@ -2799,7 +2833,7 @@ set_field_to_set_field(const struct ofpact_set_field *sf, oasf = put_OFPAT12_SET_FIELD(out); out->size = out->size - sizeof oasf->pad; - nx_put_entry(out, sf->field->id, ofp_version, sf->value, + nx_put_entry(out, sf->field, ofp_version, sf->value, ofpact_set_field_mask(sf)); pad_ofpat(out, start_ofs); } @@ -3074,14 +3108,15 @@ OFP_ASSERT(sizeof(struct nx_action_stack) == 24); static enum ofperr decode_stack_action(const struct nx_action_stack *nasp, + const struct vl_mff_map *vl_mff_map, struct ofpact_stack *stack_action) { 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, &stack_action->subfield.field, - NULL); + enum ofperr error = nx_pull_header(&b, vl_mff_map, + &stack_action->subfield.field, NULL); if (error) { return error; } @@ -3097,20 +3132,22 @@ decode_stack_action(const struct nx_action_stack *nasp, static enum ofperr 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) { struct ofpact_stack *push = ofpact_put_STACK_PUSH(ofpacts); - enum ofperr error = decode_stack_action(nasp, push); + enum ofperr error = decode_stack_action(nasp, vl_mff_map, push); return error ? error : nxm_stack_push_check(push, NULL); } static enum ofperr 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) { struct ofpact_stack *pop = ofpact_put_STACK_POP(ofpacts); - enum ofperr error = decode_stack_action(nasp, pop); + enum ofperr error = decode_stack_action(nasp, vl_mff_map, pop); return error ? error : nxm_stack_pop_check(pop, NULL); } @@ -3125,7 +3162,7 @@ encode_STACK_op(const struct ofpact_stack *stack_action, 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); + nx_put_mff_header(&b, stack_action->subfield.field, 0, false); n_bits = htons(stack_action->subfield.n_bits); ofpbuf_put(&b, &n_bits, sizeof n_bits); } @@ -4239,12 +4276,17 @@ get_be32(const void **pp) return value; } -static void -get_subfield(int n_bits, const void **p, struct mf_subfield *sf) +static enum ofperr +get_subfield(int n_bits, const void **p, struct mf_subfield *sf, + const struct vl_mff_map *vl_mff_map) { - sf->field = mf_from_nxm_header(ntohl(get_be32(p))); + sf->field = mf_from_nxm_header(ntohl(get_be32(p)), vl_mff_map); 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; } static unsigned int @@ -4275,6 +4317,7 @@ learn_min_len(uint16_t header) static enum ofperr 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) { struct ofpact_learn *learn; @@ -4338,8 +4381,12 @@ decode_NXAST_RAW_LEARN(const struct nx_action_learn *nal, /* Get the source. */ const uint8_t *imm = NULL; unsigned int imm_bytes = 0; + enum ofperr error; if (spec->src_type == NX_LEARN_SRC_FIELD) { - get_subfield(spec->n_bits, &p, &spec->src); + error = get_subfield(spec->n_bits, &p, &spec->src, vl_mff_map); + if (error) { + return error; + } } else { int p_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16); p = (const uint8_t *) p + p_bytes; @@ -4351,7 +4398,10 @@ decode_NXAST_RAW_LEARN(const struct nx_action_learn *nal, /* Get the destination. */ if (spec->dst_type == NX_LEARN_DST_MATCH || spec->dst_type == NX_LEARN_DST_LOAD) { - get_subfield(spec->n_bits, &p, &spec->dst); + error = get_subfield(spec->n_bits, &p, &spec->dst, vl_mff_map); + if (error) { + return error; + } } if (imm) { @@ -4418,7 +4468,7 @@ encode_LEARN(const struct ofpact_learn *learn, put_u16(out, spec->n_bits | spec->dst_type | spec->src_type); if (spec->src_type == NX_LEARN_SRC_FIELD) { - put_u32(out, mf_nxm_header(spec->src.field->id)); + put_u32(out, nxm_header_from_mff(spec->src.field)); put_u16(out, spec->src.ofs); } else { size_t n_dst_bytes = 2 * DIV_ROUND_UP(spec->n_bits, 16); @@ -4431,7 +4481,7 @@ encode_LEARN(const struct ofpact_learn *learn, if (spec->dst_type == NX_LEARN_DST_MATCH || spec->dst_type == NX_LEARN_DST_LOAD) { - put_u32(out, mf_nxm_header(spec->dst.field->id)); + put_u32(out, nxm_header_from_mff(spec->dst.field)); put_u16(out, spec->dst.ofs); } } @@ -4597,6 +4647,7 @@ OFP_ASSERT(sizeof(struct nx_action_multipath) == 32); static enum ofperr 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) { uint32_t n_links = ntohs(nam->max_link) + 1; @@ -4609,10 +4660,14 @@ decode_NXAST_RAW_MULTIPATH(const struct nx_action_multipath *nam, 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)); + 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; + } + if (!flow_hash_fields_valid(mp->fields)) { VLOG_WARN_RL(&rl, "unsupported fields %d", (int) mp->fields); return OFPERR_OFPBAC_BAD_ARGUMENT; @@ -4643,7 +4698,7 @@ encode_MULTIPATH(const struct ofpact_multipath *mp, nam->max_link = htons(mp->max_link); nam->arg = htonl(mp->arg); nam->ofs_nbits = nxm_encode_ofs_nbits(mp->dst.ofs, mp->dst.n_bits); - nam->dst = htonl(mf_nxm_header(mp->dst.field->id)); + nam->dst = htonl(nxm_header_from_mff(mp->dst.field)); } static char * OVS_WARN_UNUSED_RESULT @@ -4797,8 +4852,9 @@ format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a, struct ds *s) static enum ofperr decode_NXAST_RAW_CLONE(const struct ext_action_header *eah, - enum ofp_version ofp_version, - struct ofpbuf *out) + enum ofp_version ofp_version, + const struct vl_mff_map *vl_mff_map, + struct ofpbuf *out) { int error; struct ofpbuf openflow; @@ -4812,7 +4868,7 @@ decode_NXAST_RAW_CLONE(const struct ext_action_header *eah, error = ofpacts_pull_openflow_actions__(&openflow, openflow.size, ofp_version, 1u << OVSINST_OFPIT11_APPLY_ACTIONS, - out, 0); + out, 0, vl_mff_map); clone = ofpbuf_push_uninit(out, sizeof *clone); out->header = &clone->ofpact; ofpact_finish_CLONE(out, &clone); @@ -5258,14 +5314,20 @@ OFP_ASSERT(sizeof(struct nx_action_conntrack) == 24); static enum ofperr decode_ct_zone(const struct nx_action_conntrack *nac, - struct ofpact_conntrack *out) + struct ofpact_conntrack *out, + const struct vl_mff_map *vl_mff_map) { if (nac->zone_src) { enum ofperr error; - out->zone_src.field = mf_from_nxm_header(ntohl(nac->zone_src)); + 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_check_src(&out->zone_src, NULL); if (error) { return error; @@ -5286,13 +5348,14 @@ decode_ct_zone(const struct nx_action_conntrack *nac, static enum ofperr decode_NXAST_RAW_CT(const struct nx_action_conntrack *nac, - enum ofp_version ofp_version, struct ofpbuf *out) + enum ofp_version ofp_version, + const struct vl_mff_map *vl_mff_map, struct ofpbuf *out) { const size_t ct_offset = ofpacts_pull(out); struct ofpact_conntrack *conntrack = ofpact_put_CT(out); conntrack->flags = ntohs(nac->flags); - int error = decode_ct_zone(nac, conntrack); + int error = decode_ct_zone(nac, conntrack, vl_mff_map); if (error) { goto out; } @@ -5306,7 +5369,7 @@ decode_NXAST_RAW_CT(const struct nx_action_conntrack *nac, error = ofpacts_pull_openflow_actions__(&openflow, openflow.size, ofp_version, 1u << OVSINST_OFPIT11_APPLY_ACTIONS, - out, OFPACT_CT); + out, OFPACT_CT, vl_mff_map); if (error) { goto out; } @@ -5347,7 +5410,7 @@ encode_CT(const struct ofpact_conntrack *conntrack, nac = put_NXAST_CT(out); nac->flags = htons(conntrack->flags); if (conntrack->zone_src.field) { - nac->zone_src = htonl(mf_nxm_header(conntrack->zone_src.field->id)); + nac->zone_src = htonl(nxm_header_from_mff(conntrack->zone_src.field)); nac->zone_ofs_nbits = nxm_encode_ofs_nbits(conntrack->zone_src.ofs, conntrack->zone_src.n_bits); } else { @@ -6191,7 +6254,8 @@ log_bad_action(const struct ofp_action_header *actions, size_t actions_len, static enum ofperr ofpacts_decode(const void *actions, size_t actions_len, - enum ofp_version ofp_version, struct ofpbuf *ofpacts) + enum ofp_version ofp_version, + const struct vl_mff_map *vl_mff_map, struct ofpbuf *ofpacts) { struct ofpbuf openflow = ofpbuf_const_initializer(actions, actions_len); while (openflow.size) { @@ -6202,7 +6266,8 @@ ofpacts_decode(const void *actions, size_t actions_len, error = ofpact_pull_raw(&openflow, ofp_version, &raw, &arg); if (!error) { - error = ofpact_decode(action, raw, ofp_version, arg, ofpacts); + error = ofpact_decode(action, raw, ofp_version, arg, vl_mff_map, + ofpacts); } if (error) { @@ -6219,7 +6284,8 @@ ofpacts_pull_openflow_actions__(struct ofpbuf *openflow, enum ofp_version version, uint32_t allowed_ovsinsts, struct ofpbuf *ofpacts, - enum ofpact_type outer_action) + enum ofpact_type outer_action, + const struct vl_mff_map *vl_mff_map) { const struct ofp_action_header *actions; size_t orig_size = ofpacts->size; @@ -6239,7 +6305,7 @@ ofpacts_pull_openflow_actions__(struct ofpbuf *openflow, return OFPERR_OFPBRC_BAD_LEN; } - error = ofpacts_decode(actions, actions_len, version, ofpacts); + error = ofpacts_decode(actions, actions_len, version, vl_mff_map, ofpacts); if (error) { ofpacts->size = orig_size; return error; @@ -6274,11 +6340,12 @@ enum ofperr ofpacts_pull_openflow_actions(struct ofpbuf *openflow, unsigned int actions_len, enum ofp_version version, + const struct vl_mff_map *vl_mff_map, struct ofpbuf *ofpacts) { return ofpacts_pull_openflow_actions__(openflow, actions_len, version, 1u << OVSINST_OFPIT11_APPLY_ACTIONS, - ofpacts, 0); + ofpacts, 0, vl_mff_map); } /* OpenFlow 1.1 actions. */ @@ -6517,13 +6584,14 @@ ofpacts_execute_action_set(struct ofpbuf *action_list, static enum ofperr 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, struct ofpbuf *out) { enum ofperr error; struct ofpact *a; size_t start = out->size; - error = ofpacts_decode(in, n_in, version, out); + error = ofpacts_decode(in, n_in, version, vl_mff_map, out); if (error) { return error; @@ -6821,6 +6889,7 @@ enum ofperr ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, unsigned int instructions_len, enum ofp_version version, + const struct vl_mff_map *vl_mff_map, struct ofpbuf *ofpacts) { const struct ofp11_instruction *instructions; @@ -6832,7 +6901,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, return ofpacts_pull_openflow_actions__(openflow, instructions_len, version, (1u << N_OVS_INSTRUCTIONS) - 1, - ofpacts, 0); + ofpacts, 0, vl_mff_map); } if (instructions_len % OFP11_INSTRUCTION_ALIGN != 0) { @@ -6875,7 +6944,8 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS], &actions, &actions_len); - error = ofpacts_decode(actions, actions_len, version, ofpacts); + error = ofpacts_decode(actions, actions_len, version, vl_mff_map, + ofpacts); if (error) { goto exit; } @@ -6895,7 +6965,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, get_actions_from_instruction(insts[OVSINST_OFPIT11_WRITE_ACTIONS], &actions, &actions_len); error = ofpacts_decode_for_action_set(actions, actions_len, - version, ofpacts); + version, vl_mff_map, ofpacts); if (error) { goto exit; } diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 7719e5c19..f7f7df26f 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2008-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -797,7 +797,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity) protocol = ofputil_protocol_set_tid(protocol, true); ofpbuf_init(&ofpacts, 64); - error = ofputil_decode_flow_mod(&fm, oh, protocol, NULL, &ofpacts, + error = ofputil_decode_flow_mod(&fm, oh, protocol, NULL, NULL, &ofpacts, OFPP_MAX, 255); if (error) { ofpbuf_uninit(&ofpacts); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index b5e294bff..0c9343ec4 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2008-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1571,6 +1571,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, const struct ofp_header *oh, enum ofputil_protocol protocol, const struct tun_table *tun_table, + const struct vl_mff_map *vl_mff_map, struct ofpbuf *ofpacts, ofp_port_t max_port, uint8_t max_table) { @@ -1723,8 +1724,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, return OFPERR_OFPFMFC_BAD_COMMAND; } - error = ofpacts_pull_openflow_instructions(&b, b.size, - oh->version, ofpacts); + error = ofpacts_pull_openflow_instructions(&b, b.size, oh->version, + vl_mff_map, ofpacts); if (error) { return error; } @@ -2996,7 +2997,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, } if (ofpacts_pull_openflow_instructions(msg, instructions_len, oh->version, - ofpacts)) { + NULL, ofpacts)) { VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad instructions"); return EINVAL; } @@ -4017,7 +4018,7 @@ parse_actions_property(struct ofpbuf *property, enum ofp_version version, } return ofpacts_pull_openflow_actions(property, property->size, - version, ofpacts); + version, NULL, ofpacts); } /* This is like ofputil_decode_packet_in(), except that it decodes the @@ -4170,7 +4171,7 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po, } error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len), - oh->version, ofpacts); + oh->version, NULL, ofpacts); if (error) { return error; } @@ -4182,7 +4183,7 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po, po->in_port = u16_to_ofp(ntohs(opo->in_port)); error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len), - oh->version, ofpacts); + oh->version, NULL, ofpacts); if (error) { return error; } @@ -5156,7 +5157,7 @@ parse_oxms(struct ofpbuf *payload, bool loose, enum ofperr error; bool hasmask; - error = nx_pull_header(payload, &field, &hasmask); + error = nx_pull_header(payload, NULL, &field, &hasmask); if (!error) { bitmap_set1(hasmask ? masked.bm : exact.bm, field->id); } else if (error != OFPERR_OFPBMC_BAD_FIELD || !loose) { @@ -6723,7 +6724,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update, actions_len = length - sizeof *nfuf - ROUND_UP(match_len, 8); error = ofpacts_pull_openflow_actions(msg, actions_len, oh->version, - ofpacts); + NULL, ofpacts); if (error) { return error; } @@ -8707,7 +8708,7 @@ ofputil_pull_ofp11_buckets(struct ofpbuf *msg, size_t buckets_length, ofpbuf_init(&ofpacts, 0); error = ofpacts_pull_openflow_actions(msg, ob_len - sizeof *ob, - version, &ofpacts); + version, NULL, &ofpacts); if (error) { ofpbuf_uninit(&ofpacts); ofputil_bucket_list_destroy(buckets); @@ -8781,7 +8782,7 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length, buckets_length -= ob_len; err = ofpacts_pull_openflow_actions(msg, actions_len, version, - &ofpacts); + NULL, &ofpacts); if (err) { goto err; } diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 3739ebce7..eb3237568 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2009-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +59,7 @@ struct bfd_cfg; struct meter; struct ofoperation; struct ofproto_packet_out; +struct vl_mff_map; extern struct ovs_mutex ofproto_mutex; @@ -126,6 +127,10 @@ struct ofproto { /* Tunnel TLV mapping table. */ OVSRCU_TYPE(struct tun_table *) metadata_tab; + + /* Variable length mf_field mapping. Stores all configured variable length + * meta-flow fields (struct mf_field) in a switch. */ + struct vl_mff_map vl_mff_map; }; void ofproto_init_tables(struct ofproto *, int n_tables); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 0b5e0fa8e..9234b5625 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2016 Nicira, Inc. + * Copyright (c) 2009-2017 Nicira, Inc. * Copyright (c) 2010 Jean Tourrilhes - HP-Labs. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -531,6 +531,9 @@ ofproto_create(const char *datapath_name, const char *datapath_type, } ovsrcu_set(&ofproto->metadata_tab, tun_metadata_alloc(NULL)); + ovs_mutex_init(&ofproto->vl_mff_map.mutex); + cmap_init(&ofproto->vl_mff_map.cmap); + error = ofproto->ofproto_class->construct(ofproto); if (error) { VLOG_ERR("failed to open datapath %s: %s", @@ -1571,6 +1574,13 @@ ofproto_destroy__(struct ofproto *ofproto) hmap_remove(&all_ofprotos, &ofproto->hmap_node); tun_metadata_free(ovsrcu_get_protected(struct tun_table *, &ofproto->metadata_tab)); + + ovs_mutex_lock(&ofproto->vl_mff_map.mutex); + mf_vl_mff_map_clear(&ofproto->vl_mff_map); + ovs_mutex_unlock(&ofproto->vl_mff_map.mutex); + cmap_destroy(&ofproto->vl_mff_map.cmap); + ovs_mutex_destroy(&ofproto->vl_mff_map.mutex); + free(ofproto->name); free(ofproto->type); free(ofproto->mfr_desc); @@ -5707,7 +5717,8 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh) ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub); error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn), - ofproto_get_tun_tab(ofproto), &ofpacts, + ofproto_get_tun_tab(ofproto), + &ofproto->vl_mff_map, &ofpacts, u16_to_ofp(ofproto->max_ports), ofproto->n_tables); if (!error) { @@ -7707,7 +7718,7 @@ handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh) error = ofputil_decode_flow_mod(&fm, badd.msg, ofconn_get_protocol(ofconn), ofproto_get_tun_tab(ofproto), - &ofpacts, + &ofproto->vl_mff_map, &ofpacts, u16_to_ofp(ofproto->max_ports), ofproto->n_tables); if (!error) { @@ -7767,6 +7778,11 @@ handle_tlv_table_mod(struct ofconn *ofconn, const struct ofp_header *oh) if (!error) { ovsrcu_set(&ofproto->metadata_tab, new_tab); tun_metadata_postpone_free(old_tab); + + ovs_mutex_lock(&ofproto->vl_mff_map.mutex); + error = mf_vl_mff_map_mod_from_tun_metadata(&ofproto->vl_mff_map, + &ttm); + ovs_mutex_unlock(&ofproto->vl_mff_map.mutex); } ofputil_uninit_tlv_table(&ttm.mappings); diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index 7320a8412..0cdbf87cf 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -1,4 +1,5 @@ /* Copyright (c) 2015, 2016 Red Hat, Inc. + * Copyright (c) 2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -166,7 +167,8 @@ pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md, enum ofp_version version = rconn_get_version(swconn); reload_metadata(&ofpacts, md); - enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size, version, &ofpacts); + enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size, + version, NULL, &ofpacts); if (error) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "failed to parse arp actions (%s)", @@ -202,7 +204,7 @@ pinctrl_handle_put_dhcp_opts( /* Parse result field. */ const struct mf_field *f; - enum ofperr ofperr = nx_pull_header(userdata, &f, NULL); + enum ofperr ofperr = nx_pull_header(userdata, NULL, &f, NULL); if (ofperr) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "bad result OXM (%s)", ofperr_to_string(ofperr)); @@ -493,7 +495,7 @@ pinctrl_handle_put_dhcpv6_opts( /* Parse result field. */ const struct mf_field *f; - enum ofperr ofperr = nx_pull_header(userdata, &f, NULL); + enum ofperr ofperr = nx_pull_header(userdata, NULL, &f, NULL); if (ofperr) { VLOG_WARN_RL(&rl, "bad result OXM (%s)", ofperr_to_string(ofperr)); goto exit; @@ -1396,7 +1398,7 @@ pinctrl_handle_nd_na(const struct flow *ip_flow, const struct match *md, reload_metadata(&ofpacts, md); enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size, - version, &ofpacts); + version, NULL, &ofpacts); if (error) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "failed to parse actions for 'na' (%s)", diff --git a/tests/ofproto.at b/tests/ofproto.at index ad8df2835..c899ec80c 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -5685,3 +5685,128 @@ NXST_FLOW reply: OVS_VSWITCHD_STOP AT_CLEANUP + +AT_SETUP([ofproto - flow mod with tunnel metadata]) +AT_KEYWORDS([ofp-actions]) +OVS_VSWITCHD_START + +AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=0,len=4}->tun_metadata0"]) +AT_CHECK([ovs-ofctl add-flow br0 "in_port=1 actions=move:tun_metadata0[[0..31]]->NXM_NX_REG0[[]]"]) + +dnl Check the length of tun_metadata0 in the replied OXM header. +dnl Ignore the first 0x50 bytes of hex dump from the reply msg since the NXM +dnl header that describes the tunnel metadata starts at offset 0x50. +AT_CHECK([ovs-ofctl dump-flows br0 -mmmm], [0], [stdout]) +AT_CHECK([sed -e 's/duration=[[0-9.]]*s/duration=?s/' -e 's/idle_age=[[0-9]]*/idle_age=?/' -e '/^000000[[0-4]]0 / d' stdout], [0], [dnl +NXST_FLOW reply (xid=0x4): + cookie=0x0, duration=?s, table=0, n_packets=0, n_bytes=0, idle_age=?, in_port=1 actions=move:NXM_NX_TUN_METADATA0[[0..31]]->NXM_NX_REG0[[]] +00000050 ff ff 00 18 00 00 23 20-00 06 00 20 00 00 00 00 |......# ... ....| +00000060 00 01 50 04 00 01 00 04- |..P..... | +]) + +dnl Check actions that may use tun_metadata +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=move:tun_metadata1[[0..31]]->NXM_NX_REG0[[]]"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=move:tun_metadata0[[32..63]]->NXM_NX_REG0[[]]"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=push:tun_metadata1[[0..31]]"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=pop:tun_metadata0[[32..63]]"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=3, actions=load:0x11223344->tun_metadata1"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=output:tun_metadata1[[0..31]]"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=output:tun_metadata0[[32..63]]"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=multipath(eth_src,50,modulo_n,1,0,tun_metadata1[[0..31]])"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=multipath(eth_src,50,modulo_n,1,0,tun_metadata0[[32..63]])"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=bundle_load(eth_src,50,hrw,ofport,tun_metadata1[[0..31]], slaves:4,8)"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=bundle_load(eth_src,50,hrw,ofport,tun_metadata0[[32..63]], slaves:4,8)"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=learn(tun_metadata1[[0..31]]=reg0[[0..31]])"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=learn(tun_metadata0[[32..63]]=reg0[[0..31]])"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=clone(move:tun_metadata1[[0..31]]->reg0[[0..31]])"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=clone(move:tun_metadata0[[32..63]]->reg0[[0..31]])"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl add-flow br0 "ip actions=ct(commit,zone=tun_metadata1[[0..15]],exec(set_field:0x01->ct_mark))"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "ip actions=ct(commit,zone=tun_metadata0[[32..47]],exec(set_field:0x01->ct_mark))"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl add-flow br0 "ip actions=ct(commit,zone=1,exec(move:tun_metadata1[[0..31]]->ct_mark))"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: NXFMFC_INVALID_TLV_FIELD +]) + +AT_CHECK([ovs-ofctl add-flow br0 "ip actions=ct(commit,zone=1,exec(move:tun_metadata0[[32..63]]->ct_mark))"], [1], [], [stderr]) +AT_CHECK([strip_xids < stderr | sed '/FLOW_MOD/,$d'], [0], [dnl +OFPT_ERROR: OFPBAC_BAD_SET_LEN +]) + +AT_CHECK([ovs-ofctl dump-flows br0], [0], [stdout]) +AT_CHECK([sed -e 's/duration=[[0-9.]]*s/duration=?s/' -e 's/idle_age=[[0-9]]*/idle_age=?/' stdout], [0], [dnl +NXST_FLOW reply (xid=0x4): + cookie=0x0, duration=?s, table=0, n_packets=0, n_bytes=0, idle_age=?, in_port=1 actions=move:NXM_NX_TUN_METADATA0[[0..31]]->NXM_NX_REG0[[]] +]) + +OVS_VSWITCHD_STOP(["/NXFMFC_INVALID_TLV_FIELD/d +/tun_metadata0/d +/OFPBAC_BAD_SET_LEN/d"]) +AT_CLEANUP diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index e4935d5e0..4e1162329 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. + * Copyright (c) 2008-2017 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -3871,7 +3871,7 @@ ofctl_parse_actions__(const char *version_s, bool instructions) error = (instructions ? ofpacts_pull_openflow_instructions : ofpacts_pull_openflow_actions)( - &of_in, of_in.size, version, &ofpacts); + &of_in, of_in.size, version, NULL, &ofpacts); if (!error && instructions) { /* Verify actions, enforce consistency. */ enum ofputil_protocol protocol;