From patchwork Tue Mar 7 17:39:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yi-Hung Wei X-Patchwork-Id: 736315 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3vd3nr5NSvz9s9Y for ; Wed, 8 Mar 2017 04:40:00 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="tDU7UJBX"; dkim-atps=neutral Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 5C040BC1; Tue, 7 Mar 2017 17:39:58 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 3DB9EB93 for ; Tue, 7 Mar 2017 17:39:57 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f68.google.com (mail-pg0-f68.google.com [74.125.83.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 2758B13E for ; Tue, 7 Mar 2017 17:39:50 +0000 (UTC) Received: by mail-pg0-f68.google.com with SMTP id 187so733714pgb.2 for ; Tue, 07 Mar 2017 09:39:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=7Mup73jhegOx36HFoXEZ9hrsvPb6IKiagrakkqCMTws=; b=tDU7UJBXrELRjxj3PcDftBXyl5ariEJBCpd7hNiPj+Pq0VRK/aR40yx2gQI7FQQ1Xn Us5MapfXiDHnGr01iDUbdMUzbABTBSB+4Bi2FE1GQH7OXdEeOdgRWraXDDkkZ+EbeTP8 lgD0Y8xDvNH2U85H+Qnm2aXUl7QxBcX+EG7EE82QzChyoOhcfuuR508ZYmO3sThyDw73 k0gSsMQYWJOEx9CL7EKrMmZwVXDCMh2S+B2iNXGxoA7NuVssp6VtZ20TDUdzWDe07+w6 E9PBrLeWL2BGSGekddHCqZ923KA66SRl5Alx2mrEhy9BQjR2eaVwC1IV8w6gPAXlr+uk tjuA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=7Mup73jhegOx36HFoXEZ9hrsvPb6IKiagrakkqCMTws=; b=Jv+qRmvfBz6+phKE/BylfSONKPqTd3MqkR+24AQ6DFUF+6WBHcwrFj8eEwpNOGKfca I2RDesosrExGEwqDNoEpXCWUTspBeeno1CL/o5l6Wy3oSQNJCRmUZ31PiMsn4vMch3s3 3+4PP0P9YuLn5Vxm45BeNp2d7gjfCazdXUBSQvEuRLDalPmz3xdb24gVEVfN9nkvuPGH OFkZACMn0SUTG8URls4opParW2HvFY/vHaLjVzt2liLc255SNGCW8usG6DblRUDI9/k0 v/5lMtm1ndIRCjG2iOkhQ6/SOD3lRuAuhODkSg28sCdrbujDZjrkSAFjNJtafPEW/Dgu aXGA== X-Gm-Message-State: AMke39nlVWE5X4dz8yPc9FVV3SPEjrsP7s+v/2ZbaT8xY3AL0DuJzZZRZkn9i3lReX0gwg== X-Received: by 10.84.234.8 with SMTP id m8mr2056170plk.25.1488908388874; Tue, 07 Mar 2017 09:39:48 -0800 (PST) Received: from sc9-mailhost2.vmware.com ([208.91.1.34]) by smtp.gmail.com with ESMTPSA id a78sm1086901pfc.25.2017.03.07.09.39.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 07 Mar 2017 09:39:47 -0800 (PST) From: Yi-Hung Wei To: dev@openvswitch.org Date: Tue, 7 Mar 2017 09:39:01 -0800 Message-Id: <1488908341-42514-2-git-send-email-yihung.wei@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488908341-42514-1-git-send-email-yihung.wei@gmail.com> References: <1488908341-42514-1-git-send-email-yihung.wei@gmail.com> X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH 2/2] ofproto: Add ref counting for variable length mf_fields. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Currently, a controller may potentially trigger a segmentation fault if it accidentally removes a TLV mapping that is still used by an active flow. To resolve this issue, in this patch, we maintain reference counting for each dynamically allocated variable length mf_fields, so that vswitchd can use this information to properly remove a TLV mapping, and to return an error if the controller tries to remove a TLV mapping that is still used by any active flow. To keep track of the usage of tun_metadata for each flow, two 'uint64_t' bitmaps are introduce for the flow match and flow action respectively. We use 'uint64_t' as a bitmap since the 64 geneve TLV tunnel metadata are the only available variable length mf_fields for now. We shall adopt general bitmap when more variable length mf_fields are introduced. The bitmaps are configured during the flow decoding process, and vswitchd use these bitmaps to increase or decrease the ref counting when the flow is created or deleted. VMWare-BZ: #1768370 Fixes: 04f48a68c428 ("ofp-actions: Fix variable length meta-flow OXMs.") Suggested-by: Jarno Rajahalme Suggested-by: Joe Stringer Signed-off-by: Yi-Hung Wei --- build-aux/extract-ofp-actions | 9 +- include/openvswitch/ofp-actions.h | 3 +- include/openvswitch/ofp-errors.h | 4 + include/openvswitch/ofp-util.h | 1 + lib/learn.c | 6 ++ lib/meta-flow.c | 196 +++++++++++++++++++++++++++++++------- lib/ofp-actions.c | 156 ++++++++++++++++++------------ lib/ofp-util.c | 21 ++-- lib/vl-mff-map.h | 10 +- ofproto/ofproto-provider.h | 4 + ofproto/ofproto.c | 39 ++++++-- ovn/controller/pinctrl.c | 6 +- tests/tunnel.at | 76 ++++++++++++++- utilities/ovs-ofctl.c | 2 +- 14 files changed, 404 insertions(+), 129 deletions(-) diff --git a/build-aux/extract-ofp-actions b/build-aux/extract-ofp-actions index 184447b99422..0062ab881dd5 100755 --- a/build-aux/extract-ofp-actions +++ b/build-aux/extract-ofp-actions @@ -322,7 +322,8 @@ def extract_ofp_actions(fn, definitions): static enum ofperr ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw, enum ofp_version version, uint64_t arg, - 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) { switch (raw) {\ """ @@ -343,7 +344,7 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw, else: arg = "arg" if arg_vl_mff_map: - print " return decode_%s(%s, version, vl_mff_map, out);" % (enum, arg) + print " return decode_%s(%s, version, vl_mff_map, tlv_bitmap, out);" % (enum, arg) else: print " return decode_%s(%s, version, out);" % (enum, arg) print @@ -365,7 +366,7 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw, else: prototype += "%s, enum ofp_version, " % base_argtype if arg_vl_mff_map: - prototype += 'const struct vl_mff_map *, ' + prototype += 'const struct vl_mff_map *, uint64_t *, ' prototype += "struct ofpbuf *);" print prototype @@ -374,7 +375,7 @@ static enum ofperr ofpact_decode(const struct ofp_action_header *, enum ofp_raw_action_type raw, enum ofp_version version, uint64_t arg, const struct vl_mff_map *vl_mff_map, - struct ofpbuf *out); + uint64_t *tlv_bitmap, struct ofpbuf *out); """ if __name__ == '__main__': diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h index 88f573dcd74e..808715e9b1a4 100644 --- a/include/openvswitch/ofp-actions.h +++ b/include/openvswitch/ofp-actions.h @@ -946,13 +946,14 @@ enum ofperr ofpacts_pull_openflow_actions(struct ofpbuf *openflow, unsigned int actions_len, enum ofp_version version, const struct vl_mff_map *, + uint64_t *, 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); + uint64_t *, 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 81825817e843..a5bba8619bcb 100644 --- a/include/openvswitch/ofp-errors.h +++ b/include/openvswitch/ofp-errors.h @@ -772,6 +772,10 @@ enum ofperr { * to be mapped is the same as one assigned to a different field. */ OFPERR_NXTTMFC_DUP_ENTRY, + /* NX1.0-1.1(1,537), NX1.2+(38). Attempted to delete a TLV mapping that + * is used by any active flow. */ + OFPERR_NXTTMFC_INVALID_TLV_DEL, + /* ## ---------- ## */ /* ## NXT_RESUME ## */ /* ## ---------- ## */ diff --git a/include/openvswitch/ofp-util.h b/include/openvswitch/ofp-util.h index e73a942a3e15..7cb9e7fd32bd 100644 --- a/include/openvswitch/ofp-util.h +++ b/include/openvswitch/ofp-util.h @@ -326,6 +326,7 @@ struct ofputil_flow_mod { uint16_t importance; /* Eviction precedence. */ struct ofpact *ofpacts; /* Series of "struct ofpact"s. */ size_t ofpacts_len; /* Length of ofpacts, in bytes. */ + uint64_t ofpacts_tlv_bitmap; /* 1-bit for each present TLV in 'ofpacts'. */ }; enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *, diff --git a/lib/learn.c b/lib/learn.c index ce52c35f297a..0e86f1629d74 100644 --- a/lib/learn.c +++ b/lib/learn.c @@ -29,6 +29,7 @@ #include "openvswitch/ofp-errors.h" #include "openvswitch/ofp-util.h" #include "openvswitch/ofpbuf.h" +#include "vl-mff-map.h" #include "unaligned.h" @@ -107,6 +108,8 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, fm->importance = 0; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; + fm->match.flow.tunnel.metadata.present.map = 0; + fm->ofpacts_tlv_bitmap = 0; fm->flags = 0; if (learn->flags & NX_LEARN_F_SEND_FLOW_REM) { fm->flags |= OFPUTIL_FF_SEND_FLOW_REM; @@ -136,6 +139,8 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, switch (spec->dst_type) { case NX_LEARN_DST_MATCH: mf_write_subfield(&spec->dst, &value, &fm->match); + mf_vl_mff_set_tlv_bitmap( + spec->dst.field, &fm->match.flow.tunnel.metadata.present.map); break; case NX_LEARN_DST_LOAD: @@ -145,6 +150,7 @@ learn_execute(const struct ofpact_learn *learn, const struct flow *flow, spec->n_bits); bitwise_one(ofpact_set_field_mask(sf), spec->dst.field->n_bytes, spec->dst.ofs, spec->n_bits); + mf_vl_mff_set_tlv_bitmap(spec->dst.field, &fm->ofpacts_tlv_bitmap); break; case NX_LEARN_DST_OUTPUT: diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 40704e628aaa..7807b3055f5b 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -27,6 +27,8 @@ #include "openvswitch/dynamic-string.h" #include "nx-match.h" #include "openvswitch/ofp-util.h" +#include "ofproto/ofproto-provider.h" +#include "ovs-atomic.h" #include "ovs-rcu.h" #include "ovs-thread.h" #include "packets.h" @@ -2646,6 +2648,7 @@ field_array_set(enum mf_field_id id, const union mf_value *value, * 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. */ }; @@ -2655,17 +2658,25 @@ mf_field_hash(uint32_t key) return hash_int(key, 0); } -void -mf_vl_mff_map_clear(struct vl_mff_map *vl_mff_map) +enum ofperr +mf_vl_mff_map_clear(struct vl_mff_map *vl_mff_map, bool clear) OVS_REQUIRES(vl_mff_map->mutex) { struct vl_mf_field *vmf; 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); + if (clear) { + cmap_remove(&vl_mff_map->cmap, &vmf->cmap_node, + mf_field_hash(vmf->mf.id)); + ovsrcu_postpone(free, vmf); + } else { + if (ovs_refcount_read(&vmf->ref_cnt) != 1) { + return OFPERR_NXTTMFC_INVALID_TLV_DEL; + } + } } + + return 0; } static struct vl_mf_field * @@ -2697,53 +2708,100 @@ mf_get_vl_mff(const struct mf_field *mff, 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 del) 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; - } + struct vl_mf_field *vmf; + unsigned int idx; 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, - mf_field_hash(idx)); - break; - - case NXTTMC_DELETE: - vmf = mf_get_vl_mff__(idx, vl_mff_map); - if (vmf) { + vmf = mf_get_vl_mff__(idx, vl_mff_map); + if (vmf) { + if (del == true) { cmap_remove(&vl_mff_map->cmap, &vmf->cmap_node, mf_field_hash(idx)); ovsrcu_postpone(free, vmf); + } else { + if (ovs_refcount_read(&vmf->ref_cnt) != 1) { + return OFPERR_NXTTMFC_INVALID_TLV_DEL; + } } - break; + } + } + + return 0; +} + +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; +} - case NXTTMC_CLEAR: - default: - OVS_NOT_REACHED(); +/* 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(). + * 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) +{ + enum ofperr error; + + switch (ttm->command) { + case NXTTMC_ADD: + return mf_vl_mff_map_add(vl_mff_map, ttm); + + case NXTTMC_DELETE: + error = mf_vl_mff_map_del(vl_mff_map, ttm, false); + if (error) { + return error; } + return mf_vl_mff_map_del(vl_mff_map, ttm, true); + + case NXTTMC_CLEAR: + error = mf_vl_mff_map_clear(vl_mff_map, false); + if (error) { + return error; + } + return mf_vl_mff_map_clear(vl_mff_map, true); + + default: + OVS_NOT_REACHED(); } return 0; @@ -2756,3 +2814,67 @@ mf_vl_mff_invalid(const struct mf_field *mff, const struct vl_mff_map *map) { 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) { + ULLONG_SET1(*tlv_bitmap, mff->id - MFF_TUN_METADATA0); + } +} + +/* If the 'mff' is a valid variable length mf_field, udpates the 'tlv_bitmap'. + * Returns OFPERR_NXFMFC_INVALID_TLV_FIELD if the variable length mf_field + * is invalid. */ +enum ofperr +mf_check_vl_mff(const struct mf_field *mff, const struct vl_mff_map *map, + uint64_t *tlv_bitmap) +{ + if (mf_vl_mff_invalid(mff, map)) { + return OFPERR_NXFMFC_INVALID_TLV_FIELD; + } + mf_vl_mff_set_tlv_bitmap(mff, tlv_bitmap); + + return 0; +} + +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_add_ref_cnt_from_rule(const struct rule *rule) +{ + mf_vl_mff_ref_cnt_mod(&rule->ofproto->vl_mff_map, rule->match_tlv_bitmap, + true); + mf_vl_mff_ref_cnt_mod(&rule->ofproto->vl_mff_map, rule->ofpacts_tlv_bitmap, + true); +} + +void +mf_vl_mff_remove_ref_cnt_from_rule(const struct rule *rule) +{ + mf_vl_mff_ref_cnt_mod(&rule->ofproto->vl_mff_map, rule->match_tlv_bitmap, + false); + mf_vl_mff_ref_cnt_mod(&rule->ofproto->vl_mff_map, rule->ofpacts_tlv_bitmap, + false); +} diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index ce80f57e8df3..584e5cd4e847 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -405,7 +405,7 @@ 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, - 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, @@ -1117,13 +1117,20 @@ struct nx_action_output_reg2 { }; OFP_ASSERT(sizeof(struct nx_action_output_reg2) == 24); +#define CHECK_VL_MFF(FIELD, VL_MFF_MAP, BITMAP, ERR) \ +ERR = mf_check_vl_mff(FIELD, VL_MFF_MAP, BITMAP); \ +if (ERR) { \ + return ERR; \ +} + 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) + 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; @@ -1136,9 +1143,7 @@ decode_NXAST_RAW_OUTPUT_REG(const struct nx_action_output_reg *naor, 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; - } + CHECK_VL_MFF(output_reg->src.field, vl_mff_map, tlv_bitmap, error); return mf_check_src(&output_reg->src, NULL); } @@ -1147,7 +1152,7 @@ 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) + uint64_t *tlv_bitmap, struct ofpbuf *out) { struct ofpact_output_reg *output_reg; output_reg = ofpact_put_OUTPUT_REG(out); @@ -1164,6 +1169,8 @@ decode_NXAST_RAW_OUTPUT_REG2(const struct nx_action_output_reg2 *naor, if (error) { return error; } + mf_vl_mff_set_tlv_bitmap(output_reg->src.field, tlv_bitmap); + if (!is_all_zeros(b.data, b.size)) { return OFPERR_NXBRC_MUST_BE_ZERO; } @@ -1286,7 +1293,8 @@ OFP_ASSERT(sizeof(struct nx_action_bundle) == 32); 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; @@ -1326,9 +1334,7 @@ decode_bundle(bool load, const struct nx_action_bundle *nab, 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; - } + CHECK_VL_MFF(bundle->dst.field, vl_mff_map, tlv_bitmap, error); if (bundle->dst.n_bits < 16) { VLOG_WARN_RL(&rl, "bundle_load action requires at least 16 bit " @@ -1369,16 +1375,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, 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 @@ -2282,7 +2288,7 @@ 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) + uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) { struct ofpact_reg_move *move = ofpact_put_REG_MOVE(ofpacts); move->ofpact.raw = ONFACT_RAW13_COPY_FIELD; @@ -2298,10 +2304,13 @@ decode_copy_field__(ovs_be16 src_offset, ovs_be16 dst_offset, ovs_be16 n_bits, if (error) { return error; } + mf_vl_mff_set_tlv_bitmap(move->src.field, tlv_bitmap); + error = nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL); if (error) { return error; } + mf_vl_mff_set_tlv_bitmap(move->dst.field, tlv_bitmap); if (!is_all_zeros(b.data, b.size)) { return OFPERR_NXBRC_MUST_BE_ZERO; @@ -2314,31 +2323,31 @@ 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) + 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); move->ofpact.raw = NXAST_RAW_REG_MOVE; @@ -2354,10 +2363,13 @@ decode_NXAST_RAW_REG_MOVE(const struct nx_action_reg_move *narm, if (error) { return error; } + mf_vl_mff_set_tlv_bitmap(move->src.field, tlv_bitmap); + error = nx_pull_header(&b, vl_mff_map, &move->dst.field, NULL); if (error) { return error; } + mf_vl_mff_set_tlv_bitmap(move->dst.field, tlv_bitmap); if (!is_all_zeros(b.data, b.size)) { return OFPERR_NXBRC_MUST_BE_ZERO; @@ -2481,7 +2493,7 @@ 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, 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)); @@ -2495,6 +2507,8 @@ decode_ofpat_set_field(const struct ofp12_action_set_field *oasf, ? OFPERR_OFPBAC_BAD_SET_MASK : error); } + mf_vl_mff_set_tlv_bitmap(field, tlv_bitmap); + if (!may_mask) { memset(&mask, 0xff, field->n_bytes); } @@ -2540,25 +2554,26 @@ 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) + 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; @@ -2566,9 +2581,7 @@ decode_NXAST_RAW_REG_LOAD(const struct nx_action_reg_load *narl, 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; - } + CHECK_VL_MFF(dst.field, vl_mff_map, tlv_bitmap, error); error = mf_check_dst(&dst, NULL); if (error) { @@ -2596,7 +2609,7 @@ 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) + uint64_t *tlv_bitmap, struct ofpbuf *out) { struct ofpbuf b = ofpbuf_const_initializer(eah, ntohs(eah->len)); ofpbuf_pull(&b, OBJECT_OFFSETOF(eah, pad)); @@ -2607,6 +2620,8 @@ decode_NXAST_RAW_REG_LOAD2(const struct ext_action_header *eah, if (error) { return error; } + mf_vl_mff_set_tlv_bitmap(field, tlv_bitmap); + if (!is_all_zeros(b.data, b.size)) { return OFPERR_OFPBAC_BAD_SET_ARGUMENT; } @@ -3109,7 +3124,7 @@ 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, + const struct vl_mff_map *vl_mff_map, uint64_t *tlv_bitmap, struct ofpact_stack *stack_action) { stack_action->subfield.ofs = ntohs(nasp->offset); @@ -3121,6 +3136,8 @@ decode_stack_action(const struct nx_action_stack *nasp, if (error) { return error; } + mf_vl_mff_set_tlv_bitmap(stack_action->subfield.field, tlv_bitmap); + stack_action->subfield.n_bits = ntohs(*(const ovs_be16 *) b.data); ofpbuf_pull(&b, 2); if (!is_all_zeros(b.data, b.size)) { @@ -3134,10 +3151,11 @@ 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) + 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); } @@ -3145,10 +3163,11 @@ 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) + 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); } @@ -4279,14 +4298,14 @@ get_be32(const void **pp) 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) { + enum ofperr error; + 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; - } + CHECK_VL_MFF(sf->field, vl_mff_map, tlv_bitmap, error); return 0; } @@ -4319,7 +4338,7 @@ 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) + uint64_t *tlv_bitmap, struct ofpbuf *ofpacts) { struct ofpact_learn *learn; const void *p, *end; @@ -4384,7 +4403,8 @@ decode_NXAST_RAW_LEARN(const struct nx_action_learn *nal, 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; } @@ -4399,7 +4419,8 @@ 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) { - 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; } @@ -4649,11 +4670,12 @@ 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) + 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); @@ -4665,9 +4687,7 @@ decode_NXAST_RAW_MULTIPATH(const struct nx_action_multipath *nam, 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; - } + CHECK_VL_MFF(mp->dst.field, vl_mff_map, tlv_bitmap, error); if (!flow_hash_fields_valid(mp->fields)) { VLOG_WARN_RL(&rl, "unsupported fields %d", (int) mp->fields); @@ -4855,7 +4875,7 @@ static enum ofperr 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; @@ -4869,7 +4889,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, 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); @@ -5316,7 +5336,7 @@ OFP_ASSERT(sizeof(struct nx_action_conntrack) == 24); 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; @@ -5325,9 +5345,7 @@ decode_ct_zone(const struct nx_action_conntrack *nac, 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; - } + CHECK_VL_MFF(out->zone_src.field, vl_mff_map, tlv_bitmap, error); error = mf_check_src(&out->zone_src, NULL); if (error) { @@ -5350,13 +5368,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, - 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); conntrack->flags = ntohs(nac->flags); - int error = decode_ct_zone(nac, conntrack, vl_mff_map); + int error = decode_ct_zone(nac, conntrack, vl_mff_map, tlv_bitmap); if (error) { goto out; } @@ -5370,7 +5389,8 @@ 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, vl_mff_map); + out, OFPACT_CT, vl_mff_map, + tlv_bitmap); if (error) { goto out; } @@ -6256,7 +6276,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, - 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) { @@ -6268,7 +6289,7 @@ 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, vl_mff_map, - ofpacts); + ofpacts_tlv_bitmap, ofpacts); } if (error) { @@ -6286,7 +6307,8 @@ ofpacts_pull_openflow_actions__(struct ofpbuf *openflow, 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; @@ -6306,7 +6328,8 @@ ofpacts_pull_openflow_actions__(struct ofpbuf *openflow, 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; @@ -6342,11 +6365,13 @@ ofpacts_pull_openflow_actions(struct ofpbuf *openflow, 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); } /* OpenFlow 1.1 actions. */ @@ -6586,13 +6611,15 @@ 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, + 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; @@ -6891,6 +6918,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, 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; @@ -6902,7 +6930,8 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow, 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) { @@ -6946,7 +6975,7 @@ 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, vl_mff_map, - ofpacts); + ofpacts_tlv_bitmap, ofpacts); if (error) { goto exit; } @@ -6966,7 +6995,8 @@ 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, vl_mff_map, ofpacts); + version, vl_mff_map, + ofpacts_tlv_bitmap, ofpacts); if (error) { goto exit; } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index f7da90b276f9..96b4f8d22333 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -1726,8 +1726,11 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm, return OFPERR_OFPFMFC_BAD_COMMAND; } + fm->ofpacts_tlv_bitmap = 0; error = ofpacts_pull_openflow_instructions(&b, b.size, oh->version, - vl_mff_map, ofpacts); + vl_mff_map, + &fm->ofpacts_tlv_bitmap, + ofpacts); if (error) { return error; } @@ -3009,7 +3012,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, } if (ofpacts_pull_openflow_instructions(msg, instructions_len, oh->version, - NULL, ofpacts)) { + NULL, NULL, ofpacts)) { VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad instructions"); return EINVAL; } @@ -4034,7 +4037,7 @@ parse_actions_property(struct ofpbuf *property, enum ofp_version version, } return ofpacts_pull_openflow_actions(property, property->size, - version, NULL, ofpacts); + version, NULL, NULL, ofpacts); } /* This is like ofputil_decode_packet_in(), except that it decodes the @@ -4189,7 +4192,8 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po, } error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len), - oh->version, NULL, ofpacts); + oh->version, NULL, NULL, + ofpacts); if (error) { return error; } @@ -4201,7 +4205,8 @@ 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, NULL, ofpacts); + oh->version, NULL, NULL, + ofpacts); if (error) { return error; } @@ -6743,7 +6748,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, - NULL, ofpacts); + NULL, NULL, ofpacts); if (error) { return error; } @@ -8727,7 +8732,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, NULL, &ofpacts); + version, NULL, NULL, &ofpacts); if (error) { ofpbuf_uninit(&ofpacts); ofputil_bucket_list_destroy(buckets); @@ -8801,7 +8806,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, - NULL, &ofpacts); + NULL, NULL, &ofpacts); if (err) { goto err; } diff --git a/lib/vl-mff-map.h b/lib/vl-mff-map.h index 1c29385782ec..a47b8aa8a6f9 100644 --- a/lib/vl-mff-map.h +++ b/lib/vl-mff-map.h @@ -20,6 +20,8 @@ #include "cmap.h" #include "openvswitch/thread.h" +struct rule; + /* 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. */ @@ -29,7 +31,7 @@ struct vl_mff_map { }; /* Variable length fields. */ -void mf_vl_mff_map_clear(struct vl_mff_map *vl_mff_map) +enum ofperr mf_vl_mff_map_clear(struct vl_mff_map *vl_mff_map, bool) 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 *) @@ -37,5 +39,9 @@ enum ofperr mf_vl_mff_map_mod_from_tun_metadata( 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 *); - +void mf_vl_mff_set_tlv_bitmap(const struct mf_field *, uint64_t *); +enum ofperr mf_check_vl_mff(const struct mf_field *, const struct vl_mff_map *, + uint64_t *); +void mf_vl_mff_add_ref_cnt_from_rule(const struct rule *); +void mf_vl_mff_remove_ref_cnt_from_rule(const struct rule *); #endif /* vl-mff-map.h */ diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 7d3e929f21e3..dab74e3a195f 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -423,6 +423,10 @@ struct rule { /* Must hold 'mutex' for both read/write, 'ofproto_mutex' not needed. */ long long int modified OVS_GUARDED; /* Time of last modification. */ + + /* 1-bit for each present TLV in flow match / action. */ + uint64_t match_tlv_bitmap; + uint64_t ofpacts_tlv_bitmap; }; void ofproto_rule_ref(struct rule *); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 699c37cd5c3e..cf4db291e12a 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -228,6 +228,8 @@ static enum ofperr ofproto_rule_create(struct ofproto *, struct cls_rule *, uint16_t importance, const struct ofpact *ofpacts, size_t ofpacts_len, + uint64_t match_tlv_bitmap, + uint64_t ofpacts_tlv_bitmap, struct rule **new_rule) OVS_NO_THREAD_SAFETY_ANALYSIS; @@ -1580,12 +1582,6 @@ ofproto_destroy__(struct ofproto *ofproto) 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); @@ -1603,6 +1599,12 @@ ofproto_destroy__(struct ofproto *ofproto) } free(ofproto->tables); + ovs_mutex_lock(&ofproto->vl_mff_map.mutex); + mf_vl_mff_map_clear(&ofproto->vl_mff_map, true); + ovs_mutex_unlock(&ofproto->vl_mff_map.mutex); + cmap_destroy(&ofproto->vl_mff_map.cmap); + ovs_mutex_destroy(&ofproto->vl_mff_map.mutex); + ovs_assert(hindex_is_empty(&ofproto->cookies)); hindex_destroy(&ofproto->cookies); @@ -2829,6 +2831,7 @@ rule_destroy_cb(struct rule *rule) ofproto_rule_send_removed(rule); } rule->ofproto->ofproto_class->rule_destruct(rule); + mf_vl_mff_remove_ref_cnt_from_rule(rule); ofproto_rule_destroy__(rule); } @@ -4741,7 +4744,9 @@ add_flow_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, fm->new_cookie, fm->idle_timeout, fm->hard_timeout, fm->flags, fm->importance, fm->ofpacts, - fm->ofpacts_len, &ofm->temp_rule); + fm->ofpacts_len, + fm->match.flow.tunnel.metadata.present.map, + fm->ofpacts_tlv_bitmap, &ofm->temp_rule); if (error) { return error; } @@ -4856,6 +4861,7 @@ ofproto_rule_create(struct ofproto *ofproto, struct cls_rule *cr, uint16_t idle_timeout, uint16_t hard_timeout, enum ofputil_flow_mod_flags flags, uint16_t importance, const struct ofpact *ofpacts, size_t ofpacts_len, + uint64_t match_tlv_bitmap, uint64_t ofpacts_tlv_bitmap, struct rule **new_rule) OVS_NO_THREAD_SAFETY_ANALYSIS { @@ -4906,6 +4912,9 @@ ofproto_rule_create(struct ofproto *ofproto, struct cls_rule *cr, } rule->state = RULE_INITIALIZED; + rule->match_tlv_bitmap = match_tlv_bitmap; + rule->ofpacts_tlv_bitmap = ofpacts_tlv_bitmap; + mf_vl_mff_add_ref_cnt_from_rule(rule); *new_rule = rule; return 0; @@ -5003,6 +5012,8 @@ ofproto_flow_mod_learn_refresh(struct ofproto_flow_mod *ofm) rule->importance, rule->actions->ofpacts, rule->actions->ofpacts_len, + rule->match_tlv_bitmap, + rule->ofpacts_tlv_bitmap, &ofm->temp_rule); ovs_mutex_unlock(&rule->mutex); if (!error) { @@ -5263,6 +5274,11 @@ modify_flows_start__(struct ofproto *ofproto, struct ofproto_flow_mod *ofm) cls_rule_destroy(CONST_CAST(struct cls_rule *, &temp->cr)); cls_rule_clone(CONST_CAST(struct cls_rule *, &temp->cr), &old_rule->cr); + if (temp->match_tlv_bitmap != old_rule->match_tlv_bitmap) { + mf_vl_mff_remove_ref_cnt_from_rule(temp); + temp->match_tlv_bitmap = old_rule->match_tlv_bitmap; + mf_vl_mff_add_ref_cnt_from_rule(temp); + } *CONST_CAST(uint8_t *, &temp->table_id) = old_rule->table_id; rule_collection_add(new_rules, temp); first = false; @@ -5276,6 +5292,8 @@ modify_flows_start__(struct ofproto *ofproto, struct ofproto_flow_mod *ofm) temp->importance, temp->actions->ofpacts, temp->actions->ofpacts_len, + old_rule->match_tlv_bitmap, + temp->ofpacts_tlv_bitmap, &new_rule); if (!error) { rule_collection_add(new_rules, new_rule); @@ -7784,14 +7802,15 @@ handle_tlv_table_mod(struct ofconn *ofconn, const struct ofp_header *oh) old_tab = ovsrcu_get_protected(struct tun_table *, &ofproto->metadata_tab); error = tun_metadata_table_mod(&ttm, old_tab, &new_tab); 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); } + if (!error) { + ovsrcu_set(&ofproto->metadata_tab, new_tab); + tun_metadata_postpone_free(old_tab); + } ofputil_uninit_tlv_table(&ttm.mappings); return error; diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index 0380c8481ecf..890b47fe0d4f 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -168,7 +168,8 @@ pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md, reload_metadata(&ofpacts, md); enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size, - version, NULL, &ofpacts); + version, NULL, 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)", @@ -1398,7 +1399,8 @@ 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, NULL, &ofpacts); + version, NULL, 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/tunnel.at b/tests/tunnel.at index 1ba209dd4ce7..b9e9e21bfb3f 100644 --- a/tests/tunnel.at +++ b/tests/tunnel.at @@ -535,7 +535,81 @@ AT_CHECK([tail -2 stdout], [0], Datapath actions: 2 ]) -AT_CHECK([ovs-ofctl del-tlv-map br0]) +AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], +[0], [dnl +NXST_FLOW reply: + tun_metadata3=0x1234567890abcdef actions=output:2 +]) + +dnl A TLV mapping should not be removed if any active flow uses the mapping. +AT_CHECK([ovs-ofctl del-tlv-map br0], [1], [], [dnl +OFPT_ERROR (xid=0x4): NXTTMFC_INVALID_TLV_DEL +NXT_TLV_TABLE_MOD (xid=0x4): + CLEAR +]) + +AT_CHECK([ovs-ofctl del-flows br0], [0]) +AT_CHECK([ovs-ofctl del-tlv-map br0], [0]) + +dnl Flow modification +AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=1,len=4}->tun_metadata0"]) +AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=2,len=4}->tun_metadata1"]) +AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=3,len=4}->tun_metadata2"]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=1 actions=multipath(eth_src,50,modulo_n,1,0,tun_metadata0[[0..31]])"]) +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=push:tun_metadata1[[0..31]],clone(move:tun_metadata2[[0..31]]->reg0[[0..31]])"]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=1 actions=output:4"]) +AT_CHECK([ovs-ofctl del-tlv-map br0 "{class=0xffff,type=3,len=4}->tun_metadata0"]) + +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2 actions=push:tun_metadata2[[0..31]]"]) +AT_CHECK([ovs-ofctl del-tlv-map br0 "{class=0xffff,type=2,len=4}->tun_metadata1"]) +AT_CHECK([ovs-ofctl del-tlv-map br0 "{class=0xffff,type=3,len=4}->tun_metadata2"], [1], [], [dnl +OFPT_ERROR (xid=0x4): NXTTMFC_INVALID_TLV_DEL +NXT_TLV_TABLE_MOD (xid=0x4): + DEL mapping table: + class type length match field + ----- ---- ------ ----------- + 0xffff 0x3 4 tun_metadata2 +]) + +AT_CHECK([ovs-ofctl del-flows br0], [0]) +AT_CHECK([ovs-ofctl del-tlv-map br0], [0]) + +dnl Learn action +AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=1,len=4}->tun_metadata1"]) +AT_CHECK([ovs-ofctl add-tlv-map br0 "{class=0xffff,type=2,len=4}->tun_metadata2"]) +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2, eth_src=00:00:00:00:00:01 actions=learn(tun_metadata1[[0..31]]=reg1, output:NXM_OF_IN_PORT[[]])"]) +AT_CHECK([ovs-ofctl add-flow br0 "in_port=2, eth_src=00:00:00:00:00:02 actions=learn(reg1[[0..31]]=0xFF, load:reg1[[0..31]]->tun_metadata2[[0..31]])"]) +flow1="in_port(2),eth(src=00:00:00:00:00:01,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0800)" +flow2="in_port(2),eth(src=00:00:00:00:00:02,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0800)" +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow1" -generate], [0], [stdout]) +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow2" -generate], [0], [stdout]) + +dnl Delete flows with learn action +AT_CHECK([ovs-ofctl del-flows br0 "in_port=2"]) + +AT_CHECK([ovs-ofctl del-tlv-map br0 "{class=0xffff,type=1,len=4}->tun_metadata1"], [1], [], [dnl +OFPT_ERROR (xid=0x4): NXTTMFC_INVALID_TLV_DEL +NXT_TLV_TABLE_MOD (xid=0x4): + DEL mapping table: + class type length match field + ----- ---- ------ ----------- + 0xffff 0x1 4 tun_metadata1 +]) +AT_CHECK([ovs-ofctl del-flows br0 "tun_metadata1"]) +AT_CHECK([ovs-ofctl del-tlv-map br0 "{class=0xffff,type=1,len=4}->tun_metadata1"]) + +AT_CHECK([ovs-ofctl del-tlv-map br0 "{class=0xffff,type=2,len=4}->tun_metadata2"], [1], [], [dnl +OFPT_ERROR (xid=0x4): NXTTMFC_INVALID_TLV_DEL +NXT_TLV_TABLE_MOD (xid=0x4): + DEL mapping table: + class type length match field + ----- ---- ------ ----------- + 0xffff 0x2 4 tun_metadata2 +]) +AT_CHECK([ovs-ofctl del-flows br0 "reg1=0xFF"]) +AT_CHECK([ovs-ofctl del-tlv-map br0], [0]) OVS_VSWITCHD_STOP AT_CLEANUP diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 7b214ebbaacd..6f684d28c9d1 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -3876,7 +3876,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, NULL, &ofpacts); + &of_in, of_in.size, version, NULL, NULL, &ofpacts); if (!error && instructions) { /* Verify actions, enforce consistency. */ enum ofputil_protocol protocol;