diff --git a/SOURCES/openvswitch-2.16.0.patch b/SOURCES/openvswitch-2.16.0.patch
index 83d99b7..6bd7ae8 100644
--- a/SOURCES/openvswitch-2.16.0.patch
+++ b/SOURCES/openvswitch-2.16.0.patch
@@ -3344,8 +3344,44 @@ index 1c9c720f04..57f94df544 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 a426fcfeb6..aeff3b2679 100644
+index a426fcfeb6..9381affa77 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);
@@ -3357,7 +3393,70 @@ index a426fcfeb6..aeff3b2679 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;
  
@@ -3368,7 +3467,7 @@ index a426fcfeb6..aeff3b2679 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,
@@ -3377,7 +3476,7 @@ index a426fcfeb6..aeff3b2679 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;
  
@@ -3386,7 +3485,7 @@ index a426fcfeb6..aeff3b2679 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,
@@ -3395,7 +3494,7 @@ index a426fcfeb6..aeff3b2679 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)) {
@@ -3406,7 +3505,7 @@ index a426fcfeb6..aeff3b2679 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,
@@ -3415,7 +3514,7 @@ index a426fcfeb6..aeff3b2679 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)) {
@@ -3438,7 +3537,7 @@ index a426fcfeb6..aeff3b2679 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,
@@ -3447,7 +3546,7 @@ index a426fcfeb6..aeff3b2679 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");
         }
@@ -3456,7 +3555,7 @@ index a426fcfeb6..aeff3b2679 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. */
@@ -3466,7 +3565,7 @@ index a426fcfeb6..aeff3b2679 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)
  {
@@ -3477,7 +3576,7 @@ index a426fcfeb6..aeff3b2679 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
@@ -3495,14 +3594,14 @@ index a426fcfeb6..aeff3b2679 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);
-@@ -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);
  
@@ -3514,7 +3613,7 @@ index a426fcfeb6..aeff3b2679 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. */
@@ -3522,7 +3621,7 @@ index a426fcfeb6..aeff3b2679 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;
@@ -3531,7 +3630,7 @@ index a426fcfeb6..aeff3b2679 100644
  }
  
  static void
-@@ -6738,13 +6773,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -6738,13 +6792,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
          return;
      }
  
@@ -3547,7 +3646,7 @@ index a426fcfeb6..aeff3b2679 100644
  
          if (ctx->error) {
              break;
-@@ -6752,7 +6788,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -6752,7 +6807,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
  
          recirc_for_mpls(a, ctx);
  
@@ -3556,7 +3655,7 @@ index a426fcfeb6..aeff3b2679 100644
              /* Check if need to store the remaining actions for later
               * execution. */
              if (ctx->freezing) {
-@@ -7149,17 +7185,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -7149,17 +7204,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
              break;
  
          case OFPACT_CHECK_PKT_LARGER: {
@@ -3580,11 +3679,53 @@ index a426fcfeb6..aeff3b2679 100644
              break;
          }
          }
+diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
+index 851088d794..2ba90e999c 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 cba49a99e1..3239defbdf 100644
+index cba49a99e1..f926d60142 100644
 --- a/ofproto/ofproto-dpif.c
 +++ b/ofproto/ofproto-dpif.c
-@@ -2333,6 +2333,12 @@ set_ipfix(
+@@ -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);
+@@ -1682,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);
+@@ -1782,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) {
+@@ -2333,6 +2324,12 @@ set_ipfix(
              dpif_ipfix_unref(di);
              ofproto->ipfix = NULL;
          }
@@ -3597,7 +3738,64 @@ index cba49a99e1..3239defbdf 100644
      }
  
      return 0;
-@@ -6496,6 +6502,7 @@ ofproto_unixctl_dpif_show_dp_features(struct unixctl_conn *conn,
+@@ -4433,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;
+         }
+@@ -4469,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. */
+@@ -5779,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
+@@ -6496,6 +6489,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));
@@ -3606,7 +3804,7 @@ index cba49a99e1..3239defbdf 100644
  
  static void
 diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
-index 57c7d17cb2..14b909973d 100644
+index 57c7d17cb2..47e96e62e1 100644
 --- a/ofproto/ofproto-provider.h
 +++ b/ofproto/ofproto-provider.h
 @@ -66,6 +66,7 @@ struct bfd_cfg;
@@ -3627,7 +3825,16 @@ index 57c7d17cb2..14b909973d 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;
@@ -3636,7 +3843,7 @@ index 57c7d17cb2..14b909973d 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 bd6103b1c8..56aeac7209 100644
+index bd6103b1c8..7e09a588a2 100644
 --- a/ofproto/ofproto.c
 +++ b/ofproto/ofproto.c
 @@ -213,6 +213,8 @@ static void ofproto_rule_insert__(struct ofproto *, struct rule *)
@@ -3657,7 +3864,15 @@ index bd6103b1c8..56aeac7209 100644
      ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name);
      ofproto->min_mtu = INT_MAX;
      cmap_init(&ofproto->groups);
-@@ -1631,6 +1635,7 @@ ofproto_flush__(struct ofproto *ofproto, bool del)
+@@ -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) {
+@@ -1631,6 +1636,7 @@ ofproto_flush__(struct ofproto *ofproto, bool del)
      }
      ofproto_group_delete_all__(ofproto);
      meter_delete_all(ofproto);
@@ -3665,7 +3880,7 @@ index bd6103b1c8..56aeac7209 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'. */
-@@ -1682,6 +1687,11 @@ ofproto_destroy__(struct ofproto *ofproto)
+@@ -1682,12 +1688,41 @@ ofproto_destroy__(struct ofproto *ofproto)
      ovs_assert(hmap_is_empty(&ofproto->learned_cookies));
      hmap_destroy(&ofproto->learned_cookies);
  
@@ -3677,7 +3892,77 @@ index bd6103b1c8..56aeac7209 100644
      ofproto->ofproto_class->dealloc(ofproto);
  }
  
-@@ -1878,6 +1888,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)
+@@ -1695,6 +1730,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)
+@@ -1726,8 +1781,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
+@@ -1878,6 +1932,9 @@ ofproto_run(struct ofproto *p)
  
      connmgr_run(p->connmgr, handle_openflow);
  
@@ -3687,7 +3972,27 @@ index bd6103b1c8..56aeac7209 100644
      return error;
  }
  
-@@ -4437,6 +4450,20 @@ rule_criteria_destroy(struct rule_criteria *criteria)
+@@ -2916,6 +2973,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);
+ }
+ 
+@@ -3056,6 +3116,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);
+ }
+ 
+@@ -4437,6 +4500,20 @@ rule_criteria_destroy(struct rule_criteria *criteria)
      criteria->version = OVS_VERSION_NOT_REMOVED; /* Mark as destroyed. */
  }
  
@@ -3708,7 +4013,23 @@ index bd6103b1c8..56aeac7209 100644
  /* Schedules postponed removal of rules, destroys 'rules'. */
  static void
  remove_rules_postponed(struct rule_collection *rules)
-@@ -5833,7 +5860,7 @@ modify_flows_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
+@@ -5244,10 +5321,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;
+     }
+@@ -5833,7 +5915,7 @@ modify_flows_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
              }
          }
          learned_cookies_flush(ofproto, &dead_cookies);
@@ -3717,7 +4038,7 @@ index bd6103b1c8..56aeac7209 100644
      }
  
      return error;
-@@ -5941,7 +5968,7 @@ delete_flows_finish__(struct ofproto *ofproto,
+@@ -5941,7 +6023,7 @@ delete_flows_finish__(struct ofproto *ofproto,
              learned_cookies_dec(ofproto, rule_get_actions(rule),
                                  &dead_cookies);
          }
@@ -3726,7 +4047,29 @@ index bd6103b1c8..56aeac7209 100644
  
          learned_cookies_flush(ofproto, &dead_cookies);
      }
-@@ -7967,6 +7994,7 @@ ofproto_flow_mod_init(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
+@@ -7312,8 +7394,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;
+     }
+@@ -7350,6 +7437,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;
+@@ -7967,6 +8055,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;
@@ -3734,7 +4077,7 @@ index bd6103b1c8..56aeac7209 100644
  
      bool check_buffer_id = false;
  
-@@ -8104,6 +8132,33 @@ ofproto_flow_mod_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
+@@ -8104,6 +8193,33 @@ ofproto_flow_mod_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
      return error;
  }
  
@@ -3768,7 +4111,7 @@ index bd6103b1c8..56aeac7209 100644
  /* Commit phases (all while locking ofproto_mutex):
   *
   * 1. Begin: Gather resources and make changes visible in the next version.
-@@ -8165,6 +8220,10 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
+@@ -8165,6 +8281,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;
@@ -3779,7 +4122,7 @@ index bd6103b1c8..56aeac7209 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
-@@ -8173,6 +8232,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
+@@ -8173,6 +8293,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;
@@ -3789,7 +4132,7 @@ index bd6103b1c8..56aeac7209 100644
                      error = ofproto_packet_out_start(ofproto, &be->opo);
                  } else {
                      OVS_NOT_REACHED();
-@@ -8183,6 +8245,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
+@@ -8183,6 +8306,9 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
              }
          }
  
@@ -3799,7 +4142,7 @@ index bd6103b1c8..56aeac7209 100644
          if (error) {
              /* Send error referring to the original message. */
              ofconn_send_error(ofconn, be->msg, error);
-@@ -8191,14 +8256,23 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
+@@ -8191,14 +8317,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) {
@@ -3823,6 +4166,21 @@ index bd6103b1c8..56aeac7209 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/file.c b/ovsdb/file.c
 index 59220824fa..9f44007d97 100644
 --- a/ovsdb/file.c
diff --git a/SPECS/openvswitch2.16.spec b/SPECS/openvswitch2.16.spec
index 5911357..c067704 100644
--- a/SPECS/openvswitch2.16.spec
+++ b/SPECS/openvswitch2.16.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 2.16.0
-Release: 60%{?dist}
+Release: 61%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -699,6 +699,13 @@ exit 0
 %endif
 
 %changelog
+* Mon Mar 07 2022 Open vSwitch CI <ovs-ci@redhat.com> - 2.16.0-61
+- Merging upstream branch-2.16 [RH git: 0e0cf86cf5]
+    Commit list:
+    d5d2bd3c09 ofproto: Use xlate map for uuid lookups.
+    d158b29fb6 ofproto: Add refcount to ofproto to fix ofproto use-after-free.
+
+
 * Sat Mar 05 2022 Open vSwitch CI <ovs-ci@redhat.com> - 2.16.0-60
 - Merging upstream branch-2.16 [RH git: 67312d8bee]
     Commit list: