diff --git a/SOURCES/openvswitch-2.13.0.patch b/SOURCES/openvswitch-2.13.0.patch index 52914f6..8257742 100644 --- a/SOURCES/openvswitch-2.13.0.patch +++ b/SOURCES/openvswitch-2.13.0.patch @@ -87173,8 +87173,44 @@ index 409286ab15..61d5cf9782 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 4407f9c97a..4ad5c510e9 100644 +index 4407f9c97a..0189a1ae82 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); @@ -87186,6 +87222,15 @@ index 4407f9c97a..4ad5c510e9 100644 static void ctx_trigger_freeze(struct xlate_ctx *ctx) +@@ -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 @@ -1516,15 +1516,32 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, return NULL; } @@ -87223,7 +87268,61 @@ index 4407f9c97a..4ad5c510e9 100644 } } -@@ -3076,6 +3093,7 @@ xlate_normal(struct xlate_ctx *ctx) +@@ -1618,7 +1635,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; +@@ -1640,6 +1657,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) + { +@@ -3000,12 +3034,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. */ +@@ -3076,6 +3112,7 @@ xlate_normal(struct xlate_ctx *ctx) xlate_report(ctx, OFT_DETAIL, "MLD query, flooding"); xlate_normal_flood(ctx, in_xbundle, &xvlan); } @@ -87231,7 +87330,7 @@ index 4407f9c97a..4ad5c510e9 100644 } else { if (is_ip_local_multicast(flow, wc)) { /* RFC4541: section 2.1.2, item 2: Packets with a dst IP -@@ -3198,12 +3216,11 @@ compose_sample_action(struct xlate_ctx *ctx, +@@ -3198,12 +3235,11 @@ compose_sample_action(struct xlate_ctx *ctx, odp_port_t odp_port = ofp_port_to_odp_port( ctx->xbridge, ctx->xin->flow.in_port.ofp_port); uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port); @@ -87249,7 +87348,7 @@ index 4407f9c97a..4ad5c510e9 100644 if (is_sample) { nl_msg_end_nested(ctx->odp_actions, actions_offset); nl_msg_end_nested(ctx->odp_actions, sample_offset); -@@ -3248,7 +3265,9 @@ compose_ipfix_action(struct xlate_ctx *ctx, odp_port_t output_odp_port) +@@ -3248,7 +3284,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; @@ -87260,7 +87359,7 @@ index 4407f9c97a..4ad5c510e9 100644 return; } -@@ -3572,7 +3591,7 @@ propagate_tunnel_data_to_flow(struct xlate_ctx *ctx, struct eth_addr dmac, +@@ -3572,7 +3610,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, @@ -87269,7 +87368,7 @@ index 4407f9c97a..4ad5c510e9 100644 { struct netdev_tnl_build_header_params tnl_params; struct ovs_action_push_tnl tnl_push_data; -@@ -3702,7 +3721,7 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport, +@@ -3702,7 +3740,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; @@ -87278,7 +87377,7 @@ index 4407f9c97a..4ad5c510e9 100644 /* Similar to the stats update in revalidation, the x_cache entries * are populated by the previous translation are used to update the -@@ -3796,7 +3815,7 @@ xlate_flow_is_protected(const struct xlate_ctx *ctx, const struct flow *flow, co +@@ -3796,7 +3834,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, @@ -87287,7 +87386,7 @@ index 4407f9c97a..4ad5c510e9 100644 { struct flow *flow = &ctx->xin->flow; struct flow old_flow = ctx->xin->flow; -@@ -3838,8 +3857,9 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, +@@ -3838,8 +3876,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)) { @@ -87298,7 +87397,7 @@ index 4407f9c97a..4ad5c510e9 100644 if (!ctx->freezing) { xlate_action_set(ctx); } -@@ -3854,7 +3874,7 @@ patch_port_output(struct xlate_ctx *ctx, const struct xport *in_dev, +@@ -3854,7 +3893,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, @@ -87307,7 +87406,7 @@ index 4407f9c97a..4ad5c510e9 100644 ctx->mirrors = old_mirrors2; ctx->base_flow = old_base_flow; ctx->odp_actions->size = old_size; -@@ -4071,7 +4091,21 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, +@@ -4071,7 +4110,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)) { @@ -87330,7 +87429,7 @@ index 4407f9c97a..4ad5c510e9 100644 } } -@@ -4081,7 +4115,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, struct flow *flow, +@@ -4081,7 +4134,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, @@ -87339,7 +87438,7 @@ index 4407f9c97a..4ad5c510e9 100644 { const struct xport *xport = get_ofp_port(ctx->xbridge, ofp_port); struct flow_wildcards *wc = ctx->wc; -@@ -4118,7 +4152,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4118,7 +4171,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"); } @@ -87348,7 +87447,7 @@ index 4407f9c97a..4ad5c510e9 100644 return; } -@@ -4203,7 +4237,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, +@@ -4203,7 +4256,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. */ @@ -87358,7 +87457,7 @@ index 4407f9c97a..4ad5c510e9 100644 flow->tunnel = flow_tnl; /* Restore tunnel metadata */ } else if (terminate_native_tunnel(ctx, flow, wc, -@@ -4796,7 +4831,7 @@ put_controller_user_action(struct xlate_ctx *ctx, +@@ -4796,7 +4850,7 @@ put_controller_user_action(struct xlate_ctx *ctx, ctx->xin->flow.in_port.ofp_port); uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port); odp_put_userspace_action(pid, &cookie, sizeof cookie, ODPP_NONE, @@ -87367,7 +87466,7 @@ index 4407f9c97a..4ad5c510e9 100644 } static void -@@ -6123,11 +6158,32 @@ static void +@@ -6123,11 +6177,32 @@ static void compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, bool is_last_action) { @@ -87378,7 +87477,7 @@ index 4407f9c97a..4ad5c510e9 100644 + if (ofc->zone_src.field) { + union mf_subvalue value; + memset(&value, 0xff, sizeof(value)); - ++ + zone = mf_get_subfield(&ofc->zone_src, &ctx->xin->flow); + if (ctx->xin->frozen_state) { + /* If the upcall is a resume of a recirculation, we only need to @@ -87396,14 +87495,14 @@ index 4407f9c97a..4ad5c510e9 100644 + } else { + zone = ofc->zone_imm; + } -+ + + size_t ct_offset; + ovs_u128 old_ct_label_mask = ctx->wc->masks.ct_label; + uint32_t old_ct_mark_mask = ctx->wc->masks.ct_mark; /* Ensure that any prior actions are applied before composing the new * conntrack action. */ xlate_commit_actions(ctx); -@@ -6139,11 +6195,6 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc, +@@ -6139,11 +6214,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); @@ -87415,7 +87514,7 @@ index 4407f9c97a..4ad5c510e9 100644 ct_offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_CT); if (ofc->flags & NX_CT_F_COMMIT) { -@@ -6278,6 +6329,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6278,6 +6348,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. */ @@ -87423,7 +87522,7 @@ index 4407f9c97a..4ad5c510e9 100644 ctx->exit = false; offset_attr = nl_msg_start_nested( -@@ -6302,7 +6354,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, +@@ -6302,7 +6373,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx, ctx->was_mpls = old_was_mpls; ctx->conntracked = old_conntracked; ctx->xin->flow = old_flow; @@ -87432,7 +87531,7 @@ index 4407f9c97a..4ad5c510e9 100644 } static void -@@ -6680,13 +6732,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -6680,13 +6751,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, return; } @@ -87448,7 +87547,7 @@ index 4407f9c97a..4ad5c510e9 100644 if (ctx->error) { break; -@@ -6694,7 +6747,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -6694,7 +6766,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, recirc_for_mpls(a, ctx); @@ -87457,7 +87556,7 @@ index 4407f9c97a..4ad5c510e9 100644 /* Check if need to store the remaining actions for later * execution. */ if (ctx->freezing) { -@@ -7085,17 +7138,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, +@@ -7085,17 +7157,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, break; case OFPACT_CHECK_PKT_LARGER: { @@ -87481,7 +87580,7 @@ index 4407f9c97a..4ad5c510e9 100644 break; } } -@@ -7519,7 +7573,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) +@@ -7519,7 +7592,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) /* Restore pipeline metadata. May change flow's in_port and other * metadata to the values that existed when freezing was triggered. */ @@ -87491,7 +87590,7 @@ index 4407f9c97a..4ad5c510e9 100644 /* Restore stack, if any. */ if (state->stack) { -@@ -7571,14 +7626,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) +@@ -7571,14 +7645,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout) ctx.error = XLATE_INVALID_TUNNEL_METADATA; goto exit; } @@ -87507,11 +87606,34 @@ index 4407f9c97a..4ad5c510e9 100644 flow->tunnel.metadata.tab = ofproto_get_tun_tab( &ctx.xbridge->ofproto->up); } +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 d3cb392077..b86076cfe3 100644 +index d3cb392077..d8189814b5 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c -@@ -1381,6 +1381,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); +@@ -1381,6 +1377,24 @@ check_ct_timeout_policy(struct dpif_backer *backer) return !error; } @@ -87536,7 +87658,7 @@ index d3cb392077..b86076cfe3 100644 /* Tests whether 'backer''s datapath supports the * OVS_ACTION_ATTR_CHECK_PKT_LEN action. */ static bool -@@ -1580,6 +1598,7 @@ check_support(struct dpif_backer *backer) +@@ -1580,6 +1594,7 @@ 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); @@ -87544,7 +87666,26 @@ index d3cb392077..b86076cfe3 100644 /* Flow fields. */ backer->rt_support.odp.ct_state = check_ct_state(backer); -@@ -2298,6 +2317,12 @@ set_ipfix( +@@ -1653,9 +1668,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); +@@ -1757,8 +1769,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) { +@@ -2298,6 +2308,12 @@ set_ipfix( dpif_ipfix_unref(di); ofproto->ipfix = NULL; } @@ -87557,7 +87698,47 @@ index d3cb392077..b86076cfe3 100644 } return 0; -@@ -5375,6 +5400,8 @@ ct_add_timeout_policy_to_dpif(struct dpif *dpif, +@@ -4376,12 +4392,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; + } +@@ -4412,12 +4430,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. */ +@@ -5375,6 +5395,8 @@ ct_add_timeout_policy_to_dpif(struct dpif *dpif, struct ct_dpif_timeout_policy cdtp; struct simap_node *node; @@ -87566,7 +87747,7 @@ index d3cb392077..b86076cfe3 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); -@@ -5563,6 +5590,7 @@ get_datapath_cap(const char *datapath_type, struct smap *cap) +@@ -5563,6 +5585,7 @@ get_datapath_cap(const char *datapath_type, struct smap *cap) smap_add(cap, "ct_timeout", s.ct_timeout ? "true" : "false"); smap_add(cap, "explicit_drop_action", s.explicit_drop_action ? "true" :"false"); @@ -87574,7 +87755,24 @@ index d3cb392077..b86076cfe3 100644 } /* Gets timeout policy name in 'backer' based on 'zone', 'dl_type' and -@@ -6335,6 +6363,7 @@ ofproto_unixctl_dpif_show_dp_features(struct unixctl_conn *conn, +@@ -5717,15 +5740,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 +@@ -6335,6 +6350,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)); @@ -87599,7 +87797,7 @@ index c9d5df34b0..4d1f126910 100644 /* Stores the various features which the corresponding backer supports. */ diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h -index afecb24cba..dab7b37fe0 100644 +index afecb24cba..2fc29ccf9c 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -66,6 +66,7 @@ struct bfd_cfg; @@ -87620,7 +87818,16 @@ index afecb24cba..dab7b37fe0 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; @@ -87629,7 +87836,7 @@ index afecb24cba..dab7b37fe0 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 08830d8371..c2d554e46e 100644 +index 08830d8371..0f92df4f36 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -213,6 +213,8 @@ static void ofproto_rule_insert__(struct ofproto *, struct rule *) @@ -87650,7 +87857,15 @@ index 08830d8371..c2d554e46e 100644 ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name); ofproto->min_mtu = INT_MAX; cmap_init(&ofproto->groups); -@@ -961,7 +965,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) { +@@ -961,7 +966,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); @@ -87659,7 +87874,7 @@ index 08830d8371..c2d554e46e 100644 class->get_datapath_cap(datapath_type, dp_cap); } } -@@ -974,7 +978,7 @@ ofproto_ct_set_zone_timeout_policy(const char *datapath_type, uint16_t zone_id, +@@ -974,7 +979,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); @@ -87668,7 +87883,7 @@ index 08830d8371..c2d554e46e 100644 class->ct_set_zone_timeout_policy(datapath_type, zone_id, timeout_policy); } -@@ -986,7 +990,7 @@ ofproto_ct_del_zone_timeout_policy(const char *datapath_type, uint16_t zone_id) +@@ -986,7 +991,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); @@ -87677,7 +87892,7 @@ index 08830d8371..c2d554e46e 100644 class->ct_del_zone_timeout_policy(datapath_type, zone_id); } -@@ -1635,6 +1639,7 @@ ofproto_flush__(struct ofproto *ofproto) +@@ -1635,6 +1640,7 @@ ofproto_flush__(struct ofproto *ofproto) } ofproto_group_delete_all__(ofproto); meter_delete_all(ofproto); @@ -87685,7 +87900,7 @@ index 08830d8371..c2d554e46e 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'. */ -@@ -1686,6 +1691,11 @@ ofproto_destroy__(struct ofproto *ofproto) +@@ -1686,12 +1692,41 @@ ofproto_destroy__(struct ofproto *ofproto) ovs_assert(hmap_is_empty(&ofproto->learned_cookies)); hmap_destroy(&ofproto->learned_cookies); @@ -87697,7 +87912,77 @@ index 08830d8371..c2d554e46e 100644 ofproto->ofproto_class->dealloc(ofproto); } -@@ -1882,6 +1892,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) +@@ -1699,6 +1734,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) +@@ -1730,8 +1785,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 +@@ -1882,6 +1936,9 @@ ofproto_run(struct ofproto *p) connmgr_run(p->connmgr, handle_openflow); @@ -87707,7 +87992,27 @@ index 08830d8371..c2d554e46e 100644 return error; } -@@ -4440,6 +4453,20 @@ rule_criteria_destroy(struct rule_criteria *criteria) +@@ -2919,6 +2976,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); + } + +@@ -3059,6 +3119,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); + } + +@@ -4440,6 +4503,20 @@ rule_criteria_destroy(struct rule_criteria *criteria) criteria->version = OVS_VERSION_NOT_REMOVED; /* Mark as destroyed. */ } @@ -87728,7 +88033,23 @@ index 08830d8371..c2d554e46e 100644 /* Schedules postponed removal of rules, destroys 'rules'. */ static void remove_rules_postponed(struct rule_collection *rules) -@@ -5836,7 +5863,7 @@ modify_flows_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, +@@ -5247,10 +5324,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; + } +@@ -5836,7 +5918,7 @@ modify_flows_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, } } learned_cookies_flush(ofproto, &dead_cookies); @@ -87737,7 +88058,7 @@ index 08830d8371..c2d554e46e 100644 } return error; -@@ -5944,7 +5971,7 @@ delete_flows_finish__(struct ofproto *ofproto, +@@ -5944,7 +6026,7 @@ delete_flows_finish__(struct ofproto *ofproto, learned_cookies_dec(ofproto, rule_get_actions(rule), &dead_cookies); } @@ -87746,7 +88067,7 @@ index 08830d8371..c2d554e46e 100644 learned_cookies_flush(ofproto, &dead_cookies); } -@@ -6077,8 +6104,8 @@ ofproto_rule_send_removed(struct rule *rule) +@@ -6077,8 +6159,8 @@ ofproto_rule_send_removed(struct rule *rule) fr.hard_timeout = rule->hard_timeout; ovs_mutex_unlock(&rule->mutex); rule->ofproto->ofproto_class->rule_get_stats(rule, &stats, &used); @@ -87757,7 +88078,29 @@ index 08830d8371..c2d554e46e 100644 connmgr_send_flow_removed(connmgr, &fr); ovs_mutex_unlock(&ofproto_mutex); } -@@ -7970,6 +7997,7 @@ ofproto_flow_mod_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, +@@ -7315,8 +7397,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; + } +@@ -7353,6 +7440,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; +@@ -7970,6 +8058,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; @@ -87765,7 +88108,7 @@ index 08830d8371..c2d554e46e 100644 bool check_buffer_id = false; -@@ -8107,6 +8135,33 @@ ofproto_flow_mod_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, +@@ -8107,6 +8196,33 @@ ofproto_flow_mod_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm, return error; } @@ -87799,7 +88142,7 @@ index 08830d8371..c2d554e46e 100644 /* Commit phases (all while locking ofproto_mutex): * * 1. Begin: Gather resources and make changes visible in the next version. -@@ -8168,6 +8223,10 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) +@@ -8168,6 +8284,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; @@ -87810,7 +88153,7 @@ index 08830d8371..c2d554e46e 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 -@@ -8176,6 +8235,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) +@@ -8176,6 +8296,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; @@ -87820,7 +88163,7 @@ index 08830d8371..c2d554e46e 100644 error = ofproto_packet_out_start(ofproto, &be->opo); } else { OVS_NOT_REACHED(); -@@ -8186,6 +8248,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) +@@ -8186,6 +8309,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) } } @@ -87830,7 +88173,7 @@ index 08830d8371..c2d554e46e 100644 if (error) { /* Send error referring to the original message. */ ofconn_send_error(ofconn, be->msg, error); -@@ -8194,14 +8259,23 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags) +@@ -8194,14 +8320,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) { @@ -87854,6 +88197,21 @@ index 08830d8371..c2d554e46e 100644 } else { /* 4. Finish. */ LIST_FOR_EACH (be, node, &bundle->msg_list) { +diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h +index bac4a1c21f..3115bcae88 100644 +--- a/ofproto/ofproto.h ++++ b/ofproto/ofproto.h +@@ -561,6 +561,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/automake.mk b/ovsdb/automake.mk index b895f42925..446d6c1362 100644 --- a/ovsdb/automake.mk diff --git a/SPECS/openvswitch2.13.spec b/SPECS/openvswitch2.13.spec index 0c57c58..d95442b 100644 --- a/SPECS/openvswitch2.13.spec +++ b/SPECS/openvswitch2.13.spec @@ -59,7 +59,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.13.0 -Release: 164%{?commit0:.%{date}git%{shortcommit0}}%{?commit1:dpdk%{shortcommit1}}%{?dist} +Release: 165%{?commit0:.%{date}git%{shortcommit0}}%{?commit1:dpdk%{shortcommit1}}%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -715,6 +715,13 @@ exit 0 %endif %changelog +* Mon Mar 07 2022 Open vSwitch CI - 2.13.0-165 +- Merging upstream branch-2.13 [RH git: 2b7b5c6551] + Commit list: + c9069aa183 ofproto: Use xlate map for uuid lookups. + 43e943141e ofproto: Add refcount to ofproto to fix ofproto use-after-free. + + * Sat Mar 05 2022 Open vSwitch CI - 2.13.0-164 - Merging upstream branch-2.13 [RH git: e6b652172d] Commit list: