diff --git a/SOURCES/openvswitch-2.15.0.patch b/SOURCES/openvswitch-2.15.0.patch index 7830a36..4fc4d15 100644 --- a/SOURCES/openvswitch-2.15.0.patch +++ b/SOURCES/openvswitch-2.15.0.patch @@ -22924,8 +22924,44 @@ index 5fae46adfc..c710a5137f 100644 elements += cmap_count(&udpif->ukeys[j].cmap); } ds_put_format(&ds, " %u: (keys %d)\n", revalidator->id, elements); +diff --git a/ofproto/ofproto-dpif-xlate-cache.c b/ofproto/ofproto-dpif-xlate-cache.c +index dcc91cb380..9224ee2e6d 100644 +--- a/ofproto/ofproto-dpif-xlate-cache.c ++++ b/ofproto/ofproto-dpif-xlate-cache.c +@@ -209,6 +209,7 @@ xlate_cache_clear_entry(struct xc_entry *entry) + { + switch (entry->type) { + case XC_TABLE: ++ ofproto_unref(&(entry->table.ofproto->up)); + break; + case XC_RULE: + ofproto_rule_unref(&entry->rule->up); +@@ -231,6 +232,7 @@ xlate_cache_clear_entry(struct xc_entry *entry) + free(entry->learn.ofm); + break; + case XC_NORMAL: ++ ofproto_unref(&(entry->normal.ofproto->up)); + break; + case XC_FIN_TIMEOUT: + /* 'u.fin.rule' is always already held as a XC_RULE, which +diff --git a/ofproto/ofproto-dpif-xlate-cache.h b/ofproto/ofproto-dpif-xlate-cache.h +index 114aff8ea3..0fc6d2ea60 100644 +--- a/ofproto/ofproto-dpif-xlate-cache.h ++++ b/ofproto/ofproto-dpif-xlate-cache.h +@@ -61,9 +61,8 @@ enum xc_type { + * that a flow relates to, although they may be used for other effects as well + * (for instance, refreshing hard timeouts for learned flows). + * +- * An explicit reference is taken to all pointers other than the ones for +- * struct ofproto_dpif. ofproto_dpif pointers are explicitly protected by +- * destroying all xlate caches before the ofproto is destroyed. */ ++ * An explicit reference is taken to all pointers. ++ */ + struct xc_entry { + enum xc_type type; + union { diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c -index 7108c8a301..6a518e59cc 100644 +index 7108c8a301..5425274e99 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -460,7 +460,7 @@ static void xlate_commit_actions(struct xlate_ctx *ctx); @@ -22937,7 +22973,70 @@ index 7108c8a301..6a518e59cc 100644 static void ctx_trigger_freeze(struct xlate_ctx *ctx) -@@ -3272,7 +3272,9 @@ compose_ipfix_action(struct xlate_ctx *ctx, odp_port_t output_odp_port) +@@ -865,7 +865,7 @@ xlate_xbridge_init(struct xlate_cfg *xcfg, struct xbridge *xbridge) + ovs_list_init(&xbridge->xbundles); + hmap_init(&xbridge->xports); + hmap_insert(&xcfg->xbridges, &xbridge->hmap_node, +- hash_pointer(xbridge->ofproto, 0)); ++ uuid_hash(&xbridge->ofproto->uuid)); + } + + static void +@@ -1639,7 +1639,7 @@ xbridge_lookup(struct xlate_cfg *xcfg, const struct ofproto_dpif *ofproto) + + xbridges = &xcfg->xbridges; + +- HMAP_FOR_EACH_IN_BUCKET (xbridge, hmap_node, hash_pointer(ofproto, 0), ++ HMAP_FOR_EACH_IN_BUCKET (xbridge, hmap_node, uuid_hash(&ofproto->uuid), + xbridges) { + if (xbridge->ofproto == ofproto) { + return xbridge; +@@ -1661,6 +1661,23 @@ xbridge_lookup_by_uuid(struct xlate_cfg *xcfg, const struct uuid *uuid) + return NULL; + } + ++struct ofproto_dpif * ++xlate_ofproto_lookup(const struct uuid *uuid) ++{ ++ struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp); ++ struct xbridge *xbridge; ++ ++ if (!xcfg) { ++ return NULL; ++ } ++ ++ xbridge = xbridge_lookup_by_uuid(xcfg, uuid); ++ if (xbridge != NULL) { ++ return xbridge->ofproto; ++ } ++ return NULL; ++} ++ + static struct xbundle * + xbundle_lookup(struct xlate_cfg *xcfg, const struct ofbundle *ofbundle) + { +@@ -3024,12 +3041,14 @@ xlate_normal(struct xlate_ctx *ctx) + struct xc_entry *entry; + + /* Save just enough info to update mac learning table later. */ +- entry = xlate_cache_add_entry(ctx->xin->xcache, XC_NORMAL); +- entry->normal.ofproto = ctx->xbridge->ofproto; +- entry->normal.in_port = flow->in_port.ofp_port; +- entry->normal.dl_src = flow->dl_src; +- entry->normal.vlan = vlan; +- entry->normal.is_gratuitous_arp = is_grat_arp; ++ if (ofproto_try_ref(&ctx->xbridge->ofproto->up)) { ++ entry = xlate_cache_add_entry(ctx->xin->xcache, XC_NORMAL); ++ entry->normal.ofproto = ctx->xbridge->ofproto; ++ entry->normal.in_port = flow->in_port.ofp_port; ++ entry->normal.dl_src = flow->dl_src; ++ entry->normal.vlan = vlan; ++ entry->normal.is_gratuitous_arp = is_grat_arp; ++ } + } + + /* Determine output bundle. */ +@@ -3272,7 +3291,9 @@ compose_ipfix_action(struct xlate_ctx *ctx, odp_port_t output_odp_port) struct dpif_ipfix *ipfix = ctx->xbridge->ipfix; odp_port_t tunnel_out_port = ODPP_NONE; @@ -22948,7 +23047,7 @@ index 7108c8a301..6a518e59cc 100644 return; } -@@ -3598,7 +3600,7 @@ propagate_tunnel_data_to_flow(struct xlate_ctx *ctx, struct eth_addr dmac, +@@ -3598,7 +3619,7 @@ propagate_tunnel_data_to_flow(struct xlate_ctx *ctx, struct eth_addr dmac, static int native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, const struct flow *flow, odp_port_t tunnel_odp_port, @@ -22957,7 +23056,7 @@ index 7108c8a301..6a518e59cc 100644 { struct netdev_tnl_build_header_params tnl_params; struct ovs_action_push_tnl tnl_push_data; -@@ -3728,7 +3730,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, +@@ -3728,7 +3749,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, entry->tunnel_hdr.hdr_size = tnl_push_data.header_len; entry->tunnel_hdr.operation = ADD; @@ -22966,7 +23065,7 @@ index 7108c8a301..6a518e59cc 100644 /* Similar to the stats update in revalidation, the x_cache entries * are populated by the previous translation are used to update the -@@ -3822,7 +3824,7 @@ xlate_flow_is_protected(const struct xlate_ctx *ctx, const struct flow *flow, co +@@ -3822,7 +3843,7 @@ xlate_flow_is_protected(const struct xlate_ctx *ctx, const struct flow *flow, co */ static void patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, @@ -22975,7 +23074,7 @@ index 7108c8a301..6a518e59cc 100644 { struct flow *flow = &ctx->xin->flow; struct flow old_flow = ctx->xin->flow; -@@ -3864,8 +3866,9 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, +@@ -3864,8 +3885,9 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, if (!process_special(ctx, out_dev) && may_receive(out_dev, ctx)) { if (xport_stp_forward_state(out_dev) && xport_rstp_forward_state(out_dev)) { @@ -22986,7 +23085,7 @@ index 7108c8a301..6a518e59cc 100644 if (!ctx->freezing) { xlate_action_set(ctx); } -@@ -3880,7 +3883,7 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, +@@ -3880,7 +3902,7 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, mirror_mask_t old_mirrors2 = ctx->mirrors; xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true, @@ -22995,7 +23094,7 @@ index 7108c8a301..6a518e59cc 100644 ctx->mirrors = old_mirrors2; ctx->base_flow = old_base_flow; ctx->odp_actions->size = old_size; -@@ -4097,7 +4100,21 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, +@@ -4097,7 +4119,21 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, (flow->dl_type == htons(ETH_TYPE_ARP) || flow->nw_proto == IPPROTO_ICMPV6) && is_neighbor_reply_correct(ctx, flow)) { @@ -23018,7 +23117,7 @@ index 7108c8a301..6a518e59cc 100644 } } -@@ -4107,7 +4124,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, +@@ -4107,7 +4143,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, static void compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, const struct xlate_bond_recirc *xr, bool check_stp, @@ -23027,7 +23126,7 @@ index 7108c8a301..6a518e59cc 100644 { const struct xport *xport = get_ofp_port(ctx->xbridge, ofp_port); struct flow_wildcards *wc = ctx->wc; -@@ -4144,7 +4161,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4144,7 +4180,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, if (truncate) { xlate_report_error(ctx, "Cannot truncate output to patch port"); } @@ -23036,7 +23135,7 @@ index 7108c8a301..6a518e59cc 100644 return; } -@@ -4239,7 +4256,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4239,7 +4275,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, xr->recirc_id); } else if (is_native_tunnel) { /* Output to native tunnel port. */ @@ -23046,7 +23145,7 @@ index 7108c8a301..6a518e59cc 100644 flow->tunnel = flow_tnl; /* Restore tunnel metadata */ } else if (terminate_native_tunnel(ctx, flow, wc, -@@ -6177,11 +6195,32 @@ static void +@@ -6177,11 +6214,32 @@ static void compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, bool is_last_action) { @@ -23082,7 +23181,7 @@ index 7108c8a301..6a518e59cc 100644 /* Ensure that any prior actions are applied before composing the new * conntrack action. */ xlate_commit_actions(ctx); -@@ -6193,11 +6232,6 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, +@@ -6193,11 +6251,6 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, do_xlate_actions(ofc->actions, ofpact_ct_get_action_len(ofc), ctx, is_last_action, false); @@ -23094,7 +23193,7 @@ index 7108c8a301..6a518e59cc 100644 ct_offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CT); if (ofc->flags & NX_CT_F_COMMIT) { -@@ -6333,6 +6367,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6333,6 +6386,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, * then ctx->exit would be true. Reset to false so that we can * do flow translation for 'IF_LESS_EQUAL' case. finish_freezing() * would have taken care of Undoing the changes done for freeze. */ @@ -23102,7 +23201,7 @@ index 7108c8a301..6a518e59cc 100644 ctx->exit = false; offset_attr = nl_msg_start_nested( -@@ -6357,7 +6392,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6357,7 +6411,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, ctx->was_mpls = old_was_mpls; ctx->conntracked = old_conntracked; ctx->xin->flow = old_flow; @@ -23111,7 +23210,7 @@ index 7108c8a301..6a518e59cc 100644 } static void -@@ -6736,13 +6771,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -6736,13 +6790,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, return; } @@ -23127,7 +23226,7 @@ index 7108c8a301..6a518e59cc 100644 if (ctx->error) { break; -@@ -6750,7 +6786,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -6750,7 +6805,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, recirc_for_mpls(a, ctx); @@ -23136,7 +23235,7 @@ index 7108c8a301..6a518e59cc 100644 /* Check if need to store the remaining actions for later * execution. */ if (ctx->freezing) { -@@ -7127,7 +7163,9 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7127,7 +7182,9 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_CT_CLEAR: @@ -23147,7 +23246,7 @@ index 7108c8a301..6a518e59cc 100644 break; case OFPACT_NAT: -@@ -7145,17 +7183,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7145,17 +7202,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_CHECK_PKT_LARGER: { @@ -23171,11 +23270,34 @@ index 7108c8a301..6a518e59cc 100644 break; } } +diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h +index 3426a27b2d..e4959ec686 100644 +--- a/ofproto/ofproto-dpif-xlate.h ++++ b/ofproto/ofproto-dpif-xlate.h +@@ -176,6 +176,7 @@ void xlate_ofproto_set(struct ofproto_dpif *, const char *name, struct dpif *, + bool forward_bpdu, bool has_in_band, + const struct dpif_backer_support *support); + void xlate_remove_ofproto(struct ofproto_dpif *); ++struct ofproto_dpif *xlate_ofproto_lookup(const struct uuid *uuid); + + void xlate_bundle_set(struct ofproto_dpif *, struct ofbundle *, + const char *name, enum port_vlan_mode, diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index fd0b2fdea0..ebd8f08e84 100644 +index fd0b2fdea0..1f4c8e00fd 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c -@@ -1389,6 +1389,24 @@ check_ct_timeout_policy(struct dpif_backer *backer) +@@ -215,10 +215,6 @@ struct shash all_dpif_backers = SHASH_INITIALIZER(&all_dpif_backers); + static struct hmap all_ofproto_dpifs_by_name = + HMAP_INITIALIZER(&all_ofproto_dpifs_by_name); + +-/* All existing ofproto_dpif instances, indexed by ->uuid. */ +-static struct hmap all_ofproto_dpifs_by_uuid = +- HMAP_INITIALIZER(&all_ofproto_dpifs_by_uuid); +- + static bool ofproto_use_tnl_push_pop = true; + static void ofproto_unixctl_init(void); + static void ct_zone_config_init(struct dpif_backer *backer); +@@ -1389,6 +1385,24 @@ check_ct_timeout_policy(struct dpif_backer *backer) return !error; } @@ -23200,7 +23322,7 @@ index fd0b2fdea0..ebd8f08e84 100644 /* Tests whether 'backer''s datapath supports the * OVS_ACTION_ATTR_CHECK_PKT_LEN action. */ static bool -@@ -1588,8 +1606,9 @@ check_support(struct dpif_backer *backer) +@@ -1588,8 +1602,9 @@ check_support(struct dpif_backer *backer) backer->rt_support.ct_timeout = check_ct_timeout_policy(backer); backer->rt_support.explicit_drop_action = dpif_supports_explicit_drop_action(backer->dpif); @@ -23211,7 +23333,26 @@ index fd0b2fdea0..ebd8f08e84 100644 /* Flow fields. */ backer->rt_support.odp.ct_state = check_ct_state(backer); -@@ -2314,6 +2333,12 @@ set_ipfix( +@@ -1663,9 +1678,6 @@ construct(struct ofproto *ofproto_) + hmap_insert(&all_ofproto_dpifs_by_name, + &ofproto->all_ofproto_dpifs_by_name_node, + hash_string(ofproto->up.name, 0)); +- hmap_insert(&all_ofproto_dpifs_by_uuid, +- &ofproto->all_ofproto_dpifs_by_uuid_node, +- uuid_hash(&ofproto->uuid)); + memset(&ofproto->stats, 0, sizeof ofproto->stats); + + ofproto_init_tables(ofproto_, N_TABLES); +@@ -1763,8 +1775,6 @@ destruct(struct ofproto *ofproto_, bool del) + + hmap_remove(&all_ofproto_dpifs_by_name, + &ofproto->all_ofproto_dpifs_by_name_node); +- hmap_remove(&all_ofproto_dpifs_by_uuid, +- &ofproto->all_ofproto_dpifs_by_uuid_node); + + OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) { + CLS_FOR_EACH (rule, up.cr, &table->cls) { +@@ -2314,6 +2324,12 @@ set_ipfix( dpif_ipfix_unref(di); ofproto->ipfix = NULL; } @@ -23224,7 +23365,47 @@ index fd0b2fdea0..ebd8f08e84 100644 } return 0; -@@ -5413,6 +5438,8 @@ ct_add_timeout_policy_to_dpif(struct dpif *dpif, +@@ -4414,12 +4430,14 @@ rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto, + atomic_add_relaxed(&tbl->n_matched, stats->n_packets, &orig); + } + if (xcache) { +- struct xc_entry *entry; ++ if (ofproto_try_ref(&ofproto->up)) { ++ struct xc_entry *entry; + +- entry = xlate_cache_add_entry(xcache, XC_TABLE); +- entry->table.ofproto = ofproto; +- entry->table.id = *table_id; +- entry->table.match = true; ++ entry = xlate_cache_add_entry(xcache, XC_TABLE); ++ entry->table.ofproto = ofproto; ++ entry->table.id = *table_id; ++ entry->table.match = true; ++ } + } + return rule; + } +@@ -4450,12 +4468,14 @@ rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto, + stats->n_packets, &orig); + } + if (xcache) { +- struct xc_entry *entry; ++ if (ofproto_try_ref(&ofproto->up)) { ++ struct xc_entry *entry; + +- entry = xlate_cache_add_entry(xcache, XC_TABLE); +- entry->table.ofproto = ofproto; +- entry->table.id = next_id; +- entry->table.match = (rule != NULL); ++ entry = xlate_cache_add_entry(xcache, XC_TABLE); ++ entry->table.ofproto = ofproto; ++ entry->table.id = next_id; ++ entry->table.match = (rule != NULL); ++ } + } + if (rule) { + goto out; /* Match. */ +@@ -5413,6 +5433,8 @@ ct_add_timeout_policy_to_dpif(struct dpif *dpif, struct ct_dpif_timeout_policy cdtp; struct simap_node *node; @@ -23233,7 +23414,7 @@ index fd0b2fdea0..ebd8f08e84 100644 cdtp.id = ct_tp->tp_id; SIMAP_FOR_EACH (node, &ct_tp->tp) { ct_dpif_set_timeout_policy_attr_by_name(&cdtp, node->name, node->data); -@@ -5603,6 +5630,7 @@ get_datapath_cap(const char *datapath_type, struct smap *cap) +@@ -5603,6 +5625,7 @@ get_datapath_cap(const char *datapath_type, struct smap *cap) smap_add(cap, "explicit_drop_action", s.explicit_drop_action ? "true" :"false"); smap_add(cap, "lb_output_action", s.lb_output_action ? "true" : "false"); @@ -23241,7 +23422,24 @@ index fd0b2fdea0..ebd8f08e84 100644 } /* Gets timeout policy name in 'backer' based on 'zone', 'dl_type' and -@@ -6375,6 +6403,7 @@ ofproto_unixctl_dpif_show_dp_features(struct unixctl_conn *conn, +@@ -5757,15 +5780,7 @@ ofproto_dpif_lookup_by_name(const char *name) + struct ofproto_dpif * + ofproto_dpif_lookup_by_uuid(const struct uuid *uuid) + { +- struct ofproto_dpif *ofproto; +- +- HMAP_FOR_EACH_WITH_HASH (ofproto, all_ofproto_dpifs_by_uuid_node, +- uuid_hash(uuid), &all_ofproto_dpifs_by_uuid) { +- if (uuid_equals(&ofproto->uuid, uuid)) { +- return ofproto; +- } +- } +- return NULL; ++ return xlate_ofproto_lookup(uuid); + } + + static void +@@ -6375,6 +6390,7 @@ ofproto_unixctl_dpif_show_dp_features(struct unixctl_conn *conn, dpif_show_support(&ofproto->backer->bt_support, &ds); unixctl_command_reply(conn, ds_cstr(&ds)); @@ -23266,7 +23464,7 @@ index b41c3d82ad..191cfcb0df 100644 /* Stores the various features which the corresponding backer supports. */ diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h -index 9ad2b71d23..3cb1a3bbb6 100644 +index 9ad2b71d23..318407a1b4 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -66,6 +66,7 @@ struct bfd_cfg; @@ -23287,7 +23485,16 @@ index 9ad2b71d23..3cb1a3bbb6 100644 /* Meter table. */ struct ofputil_meter_features meter_features; struct hmap meters; /* uint32_t indexed 'struct meter *'. */ -@@ -1962,6 +1966,7 @@ struct ofproto_flow_mod { +@@ -139,6 +143,8 @@ struct ofproto { + /* 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; ++ /* refcount to this ofproto, held by rule/group/xlate_caches */ ++ struct ovs_refcount refcount; + }; + + void ofproto_init_tables(struct ofproto *, int n_tables); +@@ -1962,6 +1968,7 @@ struct ofproto_flow_mod { bool modify_may_add_flow; bool modify_keep_counts; enum nx_flow_update_event event; @@ -23296,7 +23503,7 @@ index 9ad2b71d23..3cb1a3bbb6 100644 /* These are only used during commit execution. * ofproto_flow_mod_uninit() does NOT clean these up. */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c -index b91517cd25..947d5967c8 100644 +index b91517cd25..d717995ac2 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -213,6 +213,8 @@ static void ofproto_rule_insert__(struct ofproto *, struct rule *) @@ -23317,7 +23524,15 @@ index b91517cd25..947d5967c8 100644 ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name); ofproto->min_mtu = INT_MAX; cmap_init(&ofproto->groups); -@@ -968,7 +972,7 @@ ofproto_get_datapath_cap(const char *datapath_type, struct smap *dp_cap) +@@ -545,6 +549,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, + + ovs_mutex_init(&ofproto->vl_mff_map.mutex); + cmap_init(&ofproto->vl_mff_map.cmap); ++ ovs_refcount_init(&ofproto->refcount); + + error = ofproto->ofproto_class->construct(ofproto); + if (error) { +@@ -968,7 +973,7 @@ ofproto_get_datapath_cap(const char *datapath_type, struct smap *dp_cap) datapath_type = ofproto_normalize_type(datapath_type); const struct ofproto_class *class = ofproto_class_find__(datapath_type); @@ -23326,7 +23541,7 @@ index b91517cd25..947d5967c8 100644 class->get_datapath_cap(datapath_type, dp_cap); } } -@@ -981,7 +985,7 @@ ofproto_ct_set_zone_timeout_policy(const char *datapath_type, uint16_t zone_id, +@@ -981,7 +986,7 @@ ofproto_ct_set_zone_timeout_policy(const char *datapath_type, uint16_t zone_id, datapath_type = ofproto_normalize_type(datapath_type); const struct ofproto_class *class = ofproto_class_find__(datapath_type); @@ -23335,7 +23550,7 @@ index b91517cd25..947d5967c8 100644 class->ct_set_zone_timeout_policy(datapath_type, zone_id, timeout_policy); } -@@ -993,7 +997,7 @@ ofproto_ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) +@@ -993,7 +998,7 @@ ofproto_ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) datapath_type = ofproto_normalize_type(datapath_type); const struct ofproto_class *class = ofproto_class_find__(datapath_type); @@ -23344,7 +23559,7 @@ index b91517cd25..947d5967c8 100644 class->ct_del_zone_timeout_policy(datapath_type, zone_id); } -@@ -1643,6 +1647,7 @@ ofproto_flush__(struct ofproto *ofproto, bool del) +@@ -1643,6 +1648,7 @@ ofproto_flush__(struct ofproto *ofproto, bool del) } ofproto_group_delete_all__(ofproto); meter_delete_all(ofproto); @@ -23352,7 +23567,7 @@ index b91517cd25..947d5967c8 100644 /* XXX: Concurrent handler threads may insert new learned flows based on * learn actions of the now deleted flows right after we release * 'ofproto_mutex'. */ -@@ -1694,6 +1699,11 @@ ofproto_destroy__(struct ofproto *ofproto) +@@ -1694,12 +1700,41 @@ ofproto_destroy__(struct ofproto *ofproto) ovs_assert(hmap_is_empty(&ofproto->learned_cookies)); hmap_destroy(&ofproto->learned_cookies); @@ -23364,7 +23579,77 @@ index b91517cd25..947d5967c8 100644 ofproto->ofproto_class->dealloc(ofproto); } -@@ -1890,6 +1900,9 @@ ofproto_run(struct ofproto *p) +-/* Destroying rules is doubly deferred, must have 'ofproto' around for them. +- * - 1st we defer the removal of the rules from the classifier +- * - 2nd we defer the actual destruction of the rules. */ ++/* ++ * Rule destruction requires ofproto to remain accessible. ++ * Depending on the rule destruction call (shown in below), it can take several ++ * RCU grace periods before the ofproto reference is not needed anymore. ++ * The ofproto destruction callback is thus protected by a refcount, ++ * and such destruction is itself deferred. ++ * ++ * remove_rules_postponed (one grace period) ++ * -> remove_rule_rcu ++ * -> remove_rule_rcu__ ++ * -> ofproto_rule_unref -> ref count != 1 ++ * -> ... more grace periods. ++ * -> rule_destroy_cb (> 2 grace periods) ++ * -> free ++ * ++ * NOTE: The original ofproto destruction is only deferred by two grace ++ * periods to keep ofproto accessible. By using refcount together the ++ * destruction can be deferred for longer time. Now ofproto has 3 states: ++ * ++ * state 1: alive, with refcount >= 1 ++ * state 2: dying, with refcount == 0, however pointer is valid ++ * state 3: died, memory freed, pointer might be dangling. ++ * ++ * We only need to add refcount to certain objects whose destruction can ++ * take several RCU grace periods (rule, group, xlate_cache). Other ++ * references to ofproto must be cleared before the 2 RCU grace periods. ++ */ + static void + ofproto_destroy_defer__(struct ofproto *ofproto) + OVS_EXCLUDED(ofproto_mutex) +@@ -1707,6 +1742,26 @@ ofproto_destroy_defer__(struct ofproto *ofproto) + ovsrcu_postpone(ofproto_destroy__, ofproto); + } + ++void ++ofproto_ref(struct ofproto *ofproto) ++{ ++ ovs_refcount_ref(&ofproto->refcount); ++} ++ ++bool ++ofproto_try_ref(struct ofproto *ofproto) ++{ ++ return ovs_refcount_try_ref_rcu(&ofproto->refcount); ++} ++ ++void ++ofproto_unref(struct ofproto *ofproto) ++{ ++ if (ofproto && ovs_refcount_unref(&ofproto->refcount) == 1) { ++ ovsrcu_postpone(ofproto_destroy_defer__, ofproto); ++ } ++} ++ + void + ofproto_destroy(struct ofproto *p, bool del) + OVS_EXCLUDED(ofproto_mutex) +@@ -1738,8 +1793,7 @@ ofproto_destroy(struct ofproto *p, bool del) + p->connmgr = NULL; + ovs_mutex_unlock(&ofproto_mutex); + +- /* Destroying rules is deferred, must have 'ofproto' around for them. */ +- ovsrcu_postpone(ofproto_destroy_defer__, p); ++ ofproto_unref(p); + } + + /* Destroys the datapath with the respective 'name' and 'type'. With the Linux +@@ -1890,6 +1944,9 @@ ofproto_run(struct ofproto *p) connmgr_run(p->connmgr, handle_openflow); @@ -23374,7 +23659,27 @@ index b91517cd25..947d5967c8 100644 return error; } -@@ -4449,6 +4462,20 @@ rule_criteria_destroy(struct rule_criteria *criteria) +@@ -2928,6 +2985,9 @@ ofproto_rule_destroy__(struct rule *rule) + cls_rule_destroy(CONST_CAST(struct cls_rule *, &rule->cr)); + rule_actions_destroy(rule_get_actions(rule)); + ovs_mutex_destroy(&rule->mutex); ++ /* ofproto_unref() must be called first. It is possible because ofproto ++ * destruction is deferred by an RCU grace period. */ ++ ofproto_unref(rule->ofproto); + rule->ofproto->ofproto_class->rule_dealloc(rule); + } + +@@ -3068,6 +3128,9 @@ group_destroy_cb(struct ofgroup *group) + &group->props)); + ofputil_bucket_list_destroy(CONST_CAST(struct ovs_list *, + &group->buckets)); ++ /* ofproto_unref() must be called first. It is possible because ofproto ++ * destruction is deferred by an RCU grace period. */ ++ ofproto_unref(group->ofproto); + group->ofproto->ofproto_class->group_dealloc(group); + } + +@@ -4449,6 +4512,20 @@ rule_criteria_destroy(struct rule_criteria *criteria) criteria->version = OVS_VERSION_NOT_REMOVED; /* Mark as destroyed. */ } @@ -23395,7 +23700,23 @@ index b91517cd25..947d5967c8 100644 /* Schedules postponed removal of rules, destroys 'rules'. */ static void remove_rules_postponed(struct rule_collection *rules) -@@ -5845,7 +5872,7 @@ modify_flows_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, +@@ -5256,10 +5333,15 @@ ofproto_rule_create(struct ofproto *ofproto, struct cls_rule *cr, + struct rule *rule; + enum ofperr error; + ++ if (!ofproto_try_ref(ofproto)) { ++ return OFPERR_OFPFMFC_UNKNOWN; ++ } ++ + /* Allocate new rule. */ + rule = ofproto->ofproto_class->rule_alloc(); + if (!rule) { + cls_rule_destroy(cr); ++ ofproto_unref(ofproto); + VLOG_WARN_RL(&rl, "%s: failed to allocate a rule.", ofproto->name); + return OFPERR_OFPFMFC_UNKNOWN; + } +@@ -5845,7 +5927,7 @@ modify_flows_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, } } learned_cookies_flush(ofproto, &dead_cookies); @@ -23404,7 +23725,7 @@ index b91517cd25..947d5967c8 100644 } return error; -@@ -5953,7 +5980,7 @@ delete_flows_finish__(struct ofproto *ofproto, +@@ -5953,7 +6035,7 @@ delete_flows_finish__(struct ofproto *ofproto, learned_cookies_dec(ofproto, rule_get_actions(rule), &dead_cookies); } @@ -23413,7 +23734,29 @@ index b91517cd25..947d5967c8 100644 learned_cookies_flush(ofproto, &dead_cookies); } -@@ -7979,6 +8006,7 @@ ofproto_flow_mod_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, +@@ -7324,8 +7406,13 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, + return OFPERR_OFPGMFC_BAD_TYPE; + } + ++ if (!ofproto_try_ref(ofproto)) { ++ return OFPERR_OFPFMFC_UNKNOWN; ++ } ++ + *ofgroup = ofproto->ofproto_class->group_alloc(); + if (!*ofgroup) { ++ ofproto_unref(ofproto); + VLOG_WARN_RL(&rl, "%s: failed to allocate group", ofproto->name); + return OFPERR_OFPGMFC_OUT_OF_GROUPS; + } +@@ -7362,6 +7449,7 @@ init_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm, + &(*ofgroup)->props)); + ofputil_bucket_list_destroy(CONST_CAST(struct ovs_list *, + &(*ofgroup)->buckets)); ++ ofproto_unref(ofproto); + ofproto->ofproto_class->group_dealloc(*ofgroup); + } + return error; +@@ -7979,6 +8067,7 @@ ofproto_flow_mod_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, ofm->criteria.version = OVS_VERSION_NOT_REMOVED; ofm->conjs = NULL; ofm->n_conjs = 0; @@ -23421,7 +23764,7 @@ index b91517cd25..947d5967c8 100644 bool check_buffer_id = false; -@@ -8116,6 +8144,33 @@ ofproto_flow_mod_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, +@@ -8116,6 +8205,33 @@ ofproto_flow_mod_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, return error; } @@ -23455,7 +23798,7 @@ index b91517cd25..947d5967c8 100644 /* Commit phases (all while locking ofproto_mutex): * * 1. Begin: Gather resources and make changes visible in the next version. -@@ -8177,6 +8232,10 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) +@@ -8177,6 +8293,10 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) /* Store the version in which the changes should take * effect. */ be->ofm.version = version; @@ -23466,7 +23809,7 @@ index b91517cd25..947d5967c8 100644 error = ofproto_flow_mod_start(ofproto, &be->ofm); } else if (be->type == OFPTYPE_GROUP_MOD) { /* Store the version in which the changes should take -@@ -8185,6 +8244,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) +@@ -8185,6 +8305,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) error = ofproto_group_mod_start(ofproto, &be->ogm); } else if (be->type == OFPTYPE_PACKET_OUT) { be->opo.version = version; @@ -23476,7 +23819,7 @@ index b91517cd25..947d5967c8 100644 error = ofproto_packet_out_start(ofproto, &be->opo); } else { OVS_NOT_REACHED(); -@@ -8195,6 +8257,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) +@@ -8195,6 +8318,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) } } @@ -23486,7 +23829,7 @@ index b91517cd25..947d5967c8 100644 if (error) { /* Send error referring to the original message. */ ofconn_send_error(ofconn, be->msg, error); -@@ -8203,14 +8268,23 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) +@@ -8203,14 +8329,23 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) /* 2. Revert. Undo all the changes made above. */ LIST_FOR_EACH_REVERSE_CONTINUE(be, node, &bundle->msg_list) { if (be->type == OFPTYPE_FLOW_MOD) { @@ -23510,6 +23853,21 @@ index b91517cd25..947d5967c8 100644 } else { /* 4. Finish. */ LIST_FOR_EACH (be, node, &bundle->msg_list) { +diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h +index b0262da2df..4e15167ab7 100644 +--- a/ofproto/ofproto.h ++++ b/ofproto/ofproto.h +@@ -563,6 +563,10 @@ int ofproto_port_get_cfm_status(const struct ofproto *, + enum ofputil_table_miss ofproto_table_get_miss_config(const struct ofproto *, + uint8_t table_id); + ++void ofproto_ref(struct ofproto *); ++void ofproto_unref(struct ofproto *); ++bool ofproto_try_ref(struct ofproto *); ++ + #ifdef __cplusplus + } + #endif diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c index 72756eb1f2..ba28e36d78 100644 --- a/ovsdb/ovsdb-client.c diff --git a/SPECS/openvswitch2.15.spec b/SPECS/openvswitch2.15.spec index d8c0ae3..d7b50fb 100644 --- a/SPECS/openvswitch2.15.spec +++ b/SPECS/openvswitch2.15.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.15.0 -Release: 80%{?dist} +Release: 81%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -702,6 +702,13 @@ exit 0 %endif %changelog +* Mon Mar 07 2022 Open vSwitch CI - 2.15.0-81 +- Merging upstream branch-2.15 [RH git: a735607890] + Commit list: + 8a58897b56 ofproto: Use xlate map for uuid lookups. + c091911e13 ofproto: Add refcount to ofproto to fix ofproto use-after-free. + + * Sat Mar 05 2022 Open vSwitch CI - 2.15.0-80 - Merging upstream branch-2.15 [RH git: 729a55e204] Commit list: