diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch
index bcd2de4..57f33d5 100644
--- a/SOURCES/openvswitch-2.17.0.patch
+++ b/SOURCES/openvswitch-2.17.0.patch
@@ -55182,7 +55182,7 @@ index 9845e8d3fe..6fa27d1dda 100644
      }
  
 diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c
-index fb108c0d50..eea8fadc0e 100644
+index fb108c0d50..ad7c0f199f 100644
 --- a/lib/netdev-offload.c
 +++ b/lib/netdev-offload.c
 @@ -182,6 +182,7 @@ netdev_assign_flow_api(struct netdev *netdev)
@@ -55235,6 +55235,265 @@ index fb108c0d50..eea8fadc0e 100644
  }
  
  int
+@@ -408,11 +426,13 @@ netdev_set_hw_info(struct netdev *netdev, int type, int val)
+ }
+ 
+ /* Protects below port hashmaps. */
+-static struct ovs_rwlock netdev_hmap_rwlock = OVS_RWLOCK_INITIALIZER;
++static struct ovs_rwlock ifindex_to_port_rwlock = OVS_RWLOCK_INITIALIZER;
++static struct ovs_rwlock port_to_netdev_rwlock
++    OVS_ACQ_BEFORE(ifindex_to_port_rwlock) = OVS_RWLOCK_INITIALIZER;
+ 
+-static struct hmap port_to_netdev OVS_GUARDED_BY(netdev_hmap_rwlock)
++static struct hmap port_to_netdev OVS_GUARDED_BY(port_to_netdev_rwlock)
+     = HMAP_INITIALIZER(&port_to_netdev);
+-static struct hmap ifindex_to_port OVS_GUARDED_BY(netdev_hmap_rwlock)
++static struct hmap ifindex_to_port OVS_GUARDED_BY(ifindex_to_port_rwlock)
+     = HMAP_INITIALIZER(&ifindex_to_port);
+ 
+ struct port_to_netdev_data {
+@@ -429,12 +449,12 @@ struct port_to_netdev_data {
+  */
+ bool
+ netdev_any_oor(void)
+-    OVS_EXCLUDED(netdev_hmap_rwlock)
++    OVS_EXCLUDED(port_to_netdev_rwlock)
+ {
+     struct port_to_netdev_data *data;
+     bool oor = false;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
+         struct netdev *dev = data->netdev;
+ 
+@@ -443,7 +463,7 @@ netdev_any_oor(void)
+             break;
+         }
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ 
+     return oor;
+ }
+@@ -517,13 +537,13 @@ netdev_ports_flow_flush(const char *dpif_type)
+ {
+     struct port_to_netdev_data *data;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
+         if (netdev_get_dpif_type(data->netdev) == dpif_type) {
+             netdev_flow_flush(data->netdev);
+         }
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ }
+ 
+ void
+@@ -533,7 +553,7 @@ netdev_ports_traverse(const char *dpif_type,
+ {
+     struct port_to_netdev_data *data;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
+         if (netdev_get_dpif_type(data->netdev) == dpif_type) {
+             if (cb(data->netdev, data->dpif_port.port_no, aux)) {
+@@ -541,7 +561,7 @@ netdev_ports_traverse(const char *dpif_type,
+             }
+         }
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ }
+ 
+ struct netdev_flow_dump **
+@@ -552,7 +572,7 @@ netdev_ports_flow_dump_create(const char *dpif_type, int *ports, bool terse)
+     int count = 0;
+     int i = 0;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
+         if (netdev_get_dpif_type(data->netdev) == dpif_type) {
+             count++;
+@@ -571,7 +591,7 @@ netdev_ports_flow_dump_create(const char *dpif_type, int *ports, bool terse)
+             i++;
+         }
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ 
+     *ports = i;
+     return dumps;
+@@ -583,15 +603,15 @@ netdev_ports_flow_del(const char *dpif_type, const ovs_u128 *ufid,
+ {
+     struct port_to_netdev_data *data;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
+         if (netdev_get_dpif_type(data->netdev) == dpif_type
+             && !netdev_flow_del(data->netdev, ufid, stats)) {
+-            ovs_rwlock_unlock(&netdev_hmap_rwlock);
++            ovs_rwlock_unlock(&port_to_netdev_rwlock);
+             return 0;
+         }
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ 
+     return ENOENT;
+ }
+@@ -604,16 +624,16 @@ netdev_ports_flow_get(const char *dpif_type, struct match *match,
+ {
+     struct port_to_netdev_data *data;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
+         if (netdev_get_dpif_type(data->netdev) == dpif_type
+             && !netdev_flow_get(data->netdev, match, actions,
+                                 ufid, stats, attrs, buf)) {
+-            ovs_rwlock_unlock(&netdev_hmap_rwlock);
++            ovs_rwlock_unlock(&port_to_netdev_rwlock);
+             return 0;
+         }
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+     return ENOENT;
+ }
+ 
+@@ -625,7 +645,7 @@ netdev_ports_hash(odp_port_t port, const char *dpif_type)
+ 
+ static struct port_to_netdev_data *
+ netdev_ports_lookup(odp_port_t port_no, const char *dpif_type)
+-    OVS_REQ_RDLOCK(netdev_hmap_rwlock)
++    OVS_REQ_RDLOCK(port_to_netdev_rwlock)
+ {
+     struct port_to_netdev_data *data;
+ 
+@@ -649,9 +669,9 @@ netdev_ports_insert(struct netdev *netdev, struct dpif_port *dpif_port)
+ 
+     ovs_assert(dpif_type);
+ 
+-    ovs_rwlock_wrlock(&netdev_hmap_rwlock);
++    ovs_rwlock_wrlock(&port_to_netdev_rwlock);
+     if (netdev_ports_lookup(dpif_port->port_no, dpif_type)) {
+-        ovs_rwlock_unlock(&netdev_hmap_rwlock);
++        ovs_rwlock_unlock(&port_to_netdev_rwlock);
+         return EEXIST;
+     }
+ 
+@@ -661,14 +681,16 @@ netdev_ports_insert(struct netdev *netdev, struct dpif_port *dpif_port)
+ 
+     if (ifindex >= 0) {
+         data->ifindex = ifindex;
++        ovs_rwlock_wrlock(&ifindex_to_port_rwlock);
+         hmap_insert(&ifindex_to_port, &data->ifindex_node, ifindex);
++        ovs_rwlock_unlock(&ifindex_to_port_rwlock);
+     } else {
+         data->ifindex = -1;
+     }
+ 
+     hmap_insert(&port_to_netdev, &data->portno_node,
+                 netdev_ports_hash(dpif_port->port_no, dpif_type));
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ 
+     netdev_init_flow_api(netdev);
+ 
+@@ -681,12 +703,12 @@ netdev_ports_get(odp_port_t port_no, const char *dpif_type)
+     struct port_to_netdev_data *data;
+     struct netdev *ret = NULL;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     data = netdev_ports_lookup(port_no, dpif_type);
+     if (data) {
+         ret = netdev_ref(data->netdev);
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ 
+     return ret;
+ }
+@@ -697,19 +719,21 @@ netdev_ports_remove(odp_port_t port_no, const char *dpif_type)
+     struct port_to_netdev_data *data;
+     int ret = ENOENT;
+ 
+-    ovs_rwlock_wrlock(&netdev_hmap_rwlock);
++    ovs_rwlock_wrlock(&port_to_netdev_rwlock);
+     data = netdev_ports_lookup(port_no, dpif_type);
+     if (data) {
+         dpif_port_destroy(&data->dpif_port);
+         netdev_close(data->netdev); /* unref and possibly close */
+         hmap_remove(&port_to_netdev, &data->portno_node);
+         if (data->ifindex >= 0) {
++            ovs_rwlock_wrlock(&ifindex_to_port_rwlock);
+             hmap_remove(&ifindex_to_port, &data->ifindex_node);
++            ovs_rwlock_unlock(&ifindex_to_port_rwlock);
+         }
+         free(data);
+         ret = 0;
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ 
+     return ret;
+ }
+@@ -721,7 +745,7 @@ netdev_ports_get_n_flows(const char *dpif_type, odp_port_t port_no,
+     struct port_to_netdev_data *data;
+     int ret = EOPNOTSUPP;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     data = netdev_ports_lookup(port_no, dpif_type);
+     if (data) {
+         uint64_t thread_n_flows[MAX_OFFLOAD_THREAD_NB] = {0};
+@@ -735,7 +759,7 @@ netdev_ports_get_n_flows(const char *dpif_type, odp_port_t port_no,
+             }
+         }
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+     return ret;
+ }
+ 
+@@ -745,14 +769,14 @@ netdev_ifindex_to_odp_port(int ifindex)
+     struct port_to_netdev_data *data;
+     odp_port_t ret = 0;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&ifindex_to_port_rwlock);
+     HMAP_FOR_EACH_WITH_HASH (data, ifindex_node, ifindex, &ifindex_to_port) {
+         if (data->ifindex == ifindex) {
+             ret = data->dpif_port.port_no;
+             break;
+         }
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&ifindex_to_port_rwlock);
+ 
+     return ret;
+ }
+@@ -770,11 +794,11 @@ netdev_ports_flow_init(void)
+ {
+     struct port_to_netdev_data *data;
+ 
+-    ovs_rwlock_rdlock(&netdev_hmap_rwlock);
++    ovs_rwlock_rdlock(&port_to_netdev_rwlock);
+     HMAP_FOR_EACH (data, portno_node, &port_to_netdev) {
+        netdev_init_flow_api(data->netdev);
+     }
+-    ovs_rwlock_unlock(&netdev_hmap_rwlock);
++    ovs_rwlock_unlock(&port_to_netdev_rwlock);
+ }
+ 
+ void
 diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h
 index 8237a85ddb..13ab06d116 100644
 --- a/lib/netdev-offload.h
@@ -59365,10 +59624,18 @@ index 114aff8ea3..0fc6d2ea60 100644
      enum xc_type type;
      union {
 diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
-index 578cbfe581..ae5e29de7f 100644
+index 578cbfe581..a212cd3698 100644
 --- a/ofproto/ofproto-dpif-xlate.c
 +++ b/ofproto/ofproto-dpif-xlate.c
-@@ -865,7 +865,7 @@ xlate_xbridge_init(struct xlate_cfg *xcfg, struct xbridge *xbridge)
+@@ -66,6 +66,7 @@
+ #include "tunnel.h"
+ #include "util.h"
+ #include "uuid.h"
++#include "vlan-bitmap.h"
+ 
+ COVERAGE_DEFINE(xlate_actions);
+ COVERAGE_DEFINE(xlate_actions_oversize);
+@@ -865,7 +866,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,
@@ -59377,7 +59644,19 @@ index 578cbfe581..ae5e29de7f 100644
  }
  
  static void
-@@ -1222,13 +1222,13 @@ xlate_txn_start(void)
+@@ -1017,7 +1018,10 @@ xlate_xbundle_set(struct xbundle *xbundle,
+     xbundle->qinq_ethtype = qinq_ethtype;
+     xbundle->vlan = vlan;
+     xbundle->trunks = trunks;
+-    xbundle->cvlans = cvlans;
++    if (!vlan_bitmap_equal(xbundle->cvlans, cvlans)) {
++        free(xbundle->cvlans);
++        xbundle->cvlans = vlan_bitmap_clone(cvlans);
++    }
+     xbundle->use_priority_tags = use_priority_tags;
+     xbundle->floodable = floodable;
+     xbundle->protected = protected;
+@@ -1222,13 +1226,13 @@ xlate_txn_start(void)
  static void
  xlate_xcfg_free(struct xlate_cfg *xcfg)
  {
@@ -59393,7 +59672,7 @@ index 578cbfe581..ae5e29de7f 100644
          xlate_xbridge_remove(xcfg, xbridge);
      }
  
-@@ -1282,18 +1282,18 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
+@@ -1282,18 +1286,18 @@ xlate_ofproto_set(struct ofproto_dpif *ofproto, const char *name,
  static void
  xlate_xbridge_remove(struct xlate_cfg *xcfg, struct xbridge *xbridge)
  {
@@ -59416,7 +59695,15 @@ index 578cbfe581..ae5e29de7f 100644
          xlate_xbundle_remove(xcfg, xbundle);
      }
  
-@@ -1515,7 +1515,7 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer,
+@@ -1369,6 +1373,7 @@ xlate_xbundle_remove(struct xlate_cfg *xcfg, struct xbundle *xbundle)
+     ovs_list_remove(&xbundle->list_node);
+     bond_unref(xbundle->bond);
+     lacp_unref(xbundle->lacp);
++    free(xbundle->cvlans);
+     free(xbundle->name);
+     free(xbundle);
+ }
+@@ -1515,7 +1520,7 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer,
          if (OVS_UNLIKELY(!recirc_id_node)) {
              if (errorp) {
                  *errorp = xasprintf("no recirculation data for recirc_id "
@@ -59425,7 +59712,7 @@ index 578cbfe581..ae5e29de7f 100644
              }
              return NULL;
          }
-@@ -1556,8 +1556,8 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer,
+@@ -1556,8 +1561,8 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer,
          if (errorp) {
              *errorp = (tnl_port_should_receive(flow)
                         ? xstrdup("no OpenFlow tunnel port for this packet")
@@ -59436,7 +59723,7 @@ index 578cbfe581..ae5e29de7f 100644
          }
          return NULL;
      }
-@@ -1639,7 +1639,7 @@ xbridge_lookup(struct xlate_cfg *xcfg, const struct ofproto_dpif *ofproto)
+@@ -1639,7 +1644,7 @@ xbridge_lookup(struct xlate_cfg *xcfg, const struct ofproto_dpif *ofproto)
  
      xbridges = &xcfg->xbridges;
  
@@ -59445,7 +59732,7 @@ index 578cbfe581..ae5e29de7f 100644
                               xbridges) {
          if (xbridge->ofproto == ofproto) {
              return xbridge;
-@@ -1661,6 +1661,23 @@ xbridge_lookup_by_uuid(struct xlate_cfg *xcfg, const struct uuid *uuid)
+@@ -1661,6 +1666,23 @@ xbridge_lookup_by_uuid(struct xlate_cfg *xcfg, const struct uuid *uuid)
      return NULL;
  }
  
@@ -59469,7 +59756,7 @@ index 578cbfe581..ae5e29de7f 100644
  static struct xbundle *
  xbundle_lookup(struct xlate_cfg *xcfg, const struct ofbundle *ofbundle)
  {
-@@ -1894,8 +1911,8 @@ group_is_alive(const struct xlate_ctx *ctx, uint32_t group_id, int depth)
+@@ -1894,8 +1916,8 @@ group_is_alive(const struct xlate_ctx *ctx, uint32_t group_id, int depth)
  #define MAX_LIVENESS_RECURSION 128 /* Arbitrary limit */
  
  static bool
@@ -59480,7 +59767,7 @@ index 578cbfe581..ae5e29de7f 100644
  {
      if (depth >= MAX_LIVENESS_RECURSION) {
          xlate_report_error(ctx, "bucket chaining exceeded %d links",
-@@ -1903,6 +1920,12 @@ bucket_is_alive(const struct xlate_ctx *ctx,
+@@ -1903,6 +1925,12 @@ bucket_is_alive(const struct xlate_ctx *ctx,
          return false;
      }
  
@@ -59493,7 +59780,7 @@ index 578cbfe581..ae5e29de7f 100644
      return (!ofputil_bucket_has_liveness(bucket)
              || (bucket->watch_port != OFPP_ANY
                 && bucket->watch_port != OFPP_CONTROLLER
-@@ -1943,7 +1966,7 @@ group_first_live_bucket(const struct xlate_ctx *ctx,
+@@ -1943,7 +1971,7 @@ group_first_live_bucket(const struct xlate_ctx *ctx,
  {
      struct ofputil_bucket *bucket;
      LIST_FOR_EACH (bucket, list_node, &group->up.buckets) {
@@ -59502,7 +59789,7 @@ index 578cbfe581..ae5e29de7f 100644
              return bucket;
          }
          xlate_report_bucket_not_live(ctx, bucket);
-@@ -1962,7 +1985,7 @@ group_best_live_bucket(const struct xlate_ctx *ctx,
+@@ -1962,7 +1990,7 @@ group_best_live_bucket(const struct xlate_ctx *ctx,
  
      struct ofputil_bucket *bucket;
      LIST_FOR_EACH (bucket, list_node, &group->up.buckets) {
@@ -59511,7 +59798,7 @@ index 578cbfe581..ae5e29de7f 100644
              uint32_t score =
                  (hash_int(bucket->bucket_id, basis) & 0xffff) * bucket->weight;
              if (score >= best_score) {
-@@ -2125,9 +2148,14 @@ mirror_packet(struct xlate_ctx *ctx, struct xbundle *xbundle,
+@@ -2125,9 +2153,14 @@ mirror_packet(struct xlate_ctx *ctx, struct xbundle *xbundle,
          int snaplen;
  
          /* Get the details of the mirror represented by the rightmost 1-bit. */
@@ -59529,7 +59816,7 @@ index 578cbfe581..ae5e29de7f 100644
  
  
          /* If this mirror selects on the basis of VLAN, and it does not select
-@@ -2444,9 +2472,18 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
+@@ -2444,9 +2477,18 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
              /* In case recirculation is not actually in use, 'xr.recirc_id'
               * will be set to '0', since a valid 'recirc_id' can
               * not be zero.  */
@@ -59551,7 +59838,7 @@ index 578cbfe581..ae5e29de7f 100644
              if (xr.recirc_id) {
                  /* Use recirculation instead of output. */
                  use_recirc = true;
-@@ -3015,7 +3052,7 @@ xlate_normal(struct xlate_ctx *ctx)
+@@ -3015,7 +3057,7 @@ xlate_normal(struct xlate_ctx *ctx)
      bool is_grat_arp = is_gratuitous_arp(flow, wc);
      if (ctx->xin->allow_side_effects
          && flow->packet_type == htonl(PT_ETH)
@@ -59560,7 +59847,7 @@ index 578cbfe581..ae5e29de7f 100644
      ) {
          update_learning_table(ctx, in_xbundle, flow->dl_src, vlan,
                                is_grat_arp);
-@@ -3024,12 +3061,14 @@ xlate_normal(struct xlate_ctx *ctx)
+@@ -3024,12 +3066,14 @@ xlate_normal(struct xlate_ctx *ctx)
          struct xc_entry *entry;
  
          /* Save just enough info to update mac learning table later. */
@@ -59581,7 +59868,7 @@ index 578cbfe581..ae5e29de7f 100644
      }
  
      /* Determine output bundle. */
-@@ -3048,7 +3087,6 @@ xlate_normal(struct xlate_ctx *ctx)
+@@ -3048,7 +3092,6 @@ xlate_normal(struct xlate_ctx *ctx)
               */
              ctx->xout->slow |= SLOW_ACTION;
  
@@ -59589,7 +59876,7 @@ index 578cbfe581..ae5e29de7f 100644
              if (mcast_snooping_is_membership(flow->tp_src) ||
                  mcast_snooping_is_query(flow->tp_src)) {
                  if (ctx->xin->allow_side_effects && ctx->xin->packet) {
-@@ -3523,6 +3561,9 @@ propagate_tunnel_data_to_flow__(struct flow *dst_flow,
+@@ -3523,6 +3566,9 @@ propagate_tunnel_data_to_flow__(struct flow *dst_flow,
      dst_flow->dl_dst = dmac;
      dst_flow->dl_src = smac;
  
@@ -59599,7 +59886,7 @@ index 578cbfe581..ae5e29de7f 100644
      dst_flow->packet_type = htonl(PT_ETH);
      dst_flow->nw_dst = src_flow->tunnel.ip_dst;
      dst_flow->nw_src = src_flow->tunnel.ip_src;
-@@ -3654,14 +3695,27 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
+@@ -3654,14 +3700,27 @@ native_tunnel_output(struct xlate_ctx *ctx, const struct xport *xport,
  
      err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac);
      if (err) {
@@ -59629,7 +59916,7 @@ index 578cbfe581..ae5e29de7f 100644
          }
          return err;
      }
-@@ -4099,6 +4153,16 @@ xport_has_ip(const struct xport *xport)
+@@ -4099,6 +4158,16 @@ xport_has_ip(const struct xport *xport)
      return n_in6 ? true : false;
  }
  
@@ -59646,7 +59933,7 @@ index 578cbfe581..ae5e29de7f 100644
  static bool
  terminate_native_tunnel(struct xlate_ctx *ctx, const struct xport *xport,
                          struct flow *flow, struct flow_wildcards *wc,
-@@ -4119,9 +4183,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, const struct xport *xport,
+@@ -4119,9 +4188,7 @@ terminate_native_tunnel(struct xlate_ctx *ctx, const struct xport *xport,
          /* If no tunnel port was found and it's about an ARP or ICMPv6 packet,
           * do tunnel neighbor snooping. */
          if (*tnl_port == ODPP_NONE &&
@@ -59657,7 +59944,7 @@ index 578cbfe581..ae5e29de7f 100644
              tnl_neigh_snoop(flow, wc, ctx->xbridge->name,
                              ctx->xin->allow_side_effects);
          } else if (*tnl_port != ODPP_NONE &&
-@@ -4176,6 +4238,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
+@@ -4176,6 +4243,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
          if (xport->pt_mode == NETDEV_PT_LEGACY_L3) {
              flow->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
                                                 ntohs(flow->dl_type));
@@ -59668,7 +59955,7 @@ index 578cbfe581..ae5e29de7f 100644
          }
      }
  
-@@ -4678,7 +4744,7 @@ pick_dp_hash_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+@@ -4678,7 +4749,7 @@ pick_dp_hash_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
          for (int i = 0; i <= hash_mask; i++) {
              struct ofputil_bucket *b =
                      group->hash_map[(dp_hash + i) & hash_mask];
@@ -59677,7 +59964,7 @@ index 578cbfe581..ae5e29de7f 100644
                  return b;
              }
          }
-@@ -5120,6 +5186,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
+@@ -5120,6 +5191,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
      }
  
      ctx->wc->masks.nw_ttl = 0xff;
@@ -59685,7 +59972,7 @@ index 578cbfe581..ae5e29de7f 100644
      if (flow->nw_ttl > 1) {
          flow->nw_ttl--;
          return false;
-@@ -5622,7 +5689,8 @@ xlate_sample_action(struct xlate_ctx *ctx,
+@@ -5622,7 +5694,8 @@ xlate_sample_action(struct xlate_ctx *ctx,
  
      /* Scale the probability from 16-bit to 32-bit while representing
       * the same percentage. */
@@ -59695,7 +59982,7 @@ index 578cbfe581..ae5e29de7f 100644
  
      /* If ofp_port in flow sample action is equel to ofp_port,
       * this sample action is a input port action. */
-@@ -7027,6 +7095,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -7027,6 +7100,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
          case OFPACT_SET_IPV4_SRC:
              if (flow->dl_type == htons(ETH_TYPE_IP)) {
                  memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
@@ -59703,7 +59990,7 @@ index 578cbfe581..ae5e29de7f 100644
                  flow->nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4;
              }
              break;
-@@ -7034,12 +7103,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -7034,12 +7108,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
          case OFPACT_SET_IPV4_DST:
              if (flow->dl_type == htons(ETH_TYPE_IP)) {
                  memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
@@ -59718,7 +60005,7 @@ index 578cbfe581..ae5e29de7f 100644
                  wc->masks.nw_tos |= IP_DSCP_MASK;
                  flow->nw_tos &= ~IP_DSCP_MASK;
                  flow->nw_tos |= ofpact_get_SET_IP_DSCP(a)->dscp;
-@@ -7048,6 +7119,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -7048,6 +7124,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
  
          case OFPACT_SET_IP_ECN:
              if (is_ip_any(flow)) {
@@ -59726,7 +60013,7 @@ index 578cbfe581..ae5e29de7f 100644
                  wc->masks.nw_tos |= IP_ECN_MASK;
                  flow->nw_tos &= ~IP_ECN_MASK;
                  flow->nw_tos |= ofpact_get_SET_IP_ECN(a)->ecn;
-@@ -7056,6 +7128,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -7056,6 +7133,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
  
          case OFPACT_SET_IP_TTL:
              if (is_ip_any(flow)) {
@@ -59734,7 +60021,7 @@ index 578cbfe581..ae5e29de7f 100644
                  wc->masks.nw_ttl = 0xff;
                  flow->nw_ttl = ofpact_get_SET_IP_TTL(a)->ttl;
              }
-@@ -7123,6 +7196,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -7123,6 +7201,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
  
              /* Set the field only if the packet actually has it. */
              if (mf_are_prereqs_ok(mf, flow, wc)) {
@@ -59742,7 +60029,7 @@ index 578cbfe581..ae5e29de7f 100644
                  mf_mask_field_masked(mf, ofpact_set_field_mask(set_field), wc);
                  mf_set_flow_value_masked(mf, set_field->value,
                                           ofpact_set_field_mask(set_field),
-@@ -7179,6 +7253,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+@@ -7179,6 +7258,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
  
          case OFPACT_DEC_TTL:
              wc->masks.nw_ttl = 0xff;
@@ -59750,7 +60037,7 @@ index 578cbfe581..ae5e29de7f 100644
              if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
                  return;
              }
-@@ -7609,6 +7684,43 @@ xlate_wc_finish(struct xlate_ctx *ctx)
+@@ -7609,6 +7689,43 @@ xlate_wc_finish(struct xlate_ctx *ctx)
              ctx->wc->masks.vlans[i].tci = 0;
          }
      }
@@ -59794,7 +60081,7 @@ index 578cbfe581..ae5e29de7f 100644
  }
  
  /* Translates the flow, actions, or rule in 'xin' into datapath actions in
-@@ -7784,6 +7896,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
+@@ -7784,6 +7901,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
          goto exit;
      }
  
@@ -59807,7 +60094,7 @@ index 578cbfe581..ae5e29de7f 100644
      /* Tunnel metadata in udpif format must be normalized before translation. */
      if (flow->tunnel.flags & FLOW_TNL_F_UDPIF) {
          const struct tun_table *tun_tab = ofproto_get_tun_tab(
-@@ -8030,6 +8148,10 @@ exit:
+@@ -8030,6 +8153,10 @@ exit:
          if (xin->odp_actions) {
              ofpbuf_clear(xin->odp_actions);
          }
diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec
index 315fbfc..8c6d57c 100644
--- a/SPECS/openvswitch2.17.spec
+++ b/SPECS/openvswitch2.17.spec
@@ -63,7 +63,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 2.17.0
-Release: 96%{?dist}
+Release: 97%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -749,6 +749,13 @@ exit 0
 %endif
 
 %changelog
+* Wed May 10 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-97
+- Merging upstream branch-2.17 [RH git: 2fe36c053b]
+    Commit list:
+    80b15d1428 netdev-offload: Fix deadlock/recursive use of the netdev_hmap_rwlock rwlock. (#2182541)
+    0d3c27e909 ofproto-dpif-xlate: Fix use-after-free when xlate_actions().
+
+
 * Fri Apr 28 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-96
 - Merging upstream branch-2.17 [RH git: 9de5592f0a]
     Commit list: