diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch
index c5bcbb1..9dcb483 100644
--- a/SOURCES/openvswitch-2.17.0.patch
+++ b/SOURCES/openvswitch-2.17.0.patch
@@ -52191,7 +52191,7 @@ index 66016eb099..7425dd44e7 100644
      /* Statistics. */
      struct dp_netdev_flow_stats stats;
 diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
-index 9f35713ef5..b9cafc2737 100644
+index 9f35713ef5..0b543cf222 100644
 --- a/lib/dpif-netdev.c
 +++ b/lib/dpif-netdev.c
 @@ -93,7 +93,8 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev);
@@ -52563,8 +52563,16 @@ index 9f35713ef5..b9cafc2737 100644
          }
      }
  #endif
+@@ -9495,6 +9527,7 @@ dpif_netdev_bond_stats_get(struct dpif *dpif, uint32_t bond_id,
+ const struct dpif_class dpif_netdev_class = {
+     "netdev",
+     true,                       /* cleanup_required */
++    true,                       /* synced_dp_layers */
+     dpif_netdev_init,
+     dpif_netdev_enumerate,
+     dpif_netdev_port_open_type,
 diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
-index 71e35ccdda..484545cfb8 100644
+index 71e35ccdda..6977888bb4 100644
 --- a/lib/dpif-netlink.c
 +++ b/lib/dpif-netlink.c
 @@ -85,7 +85,7 @@ enum { MAX_PORTS = USHRT_MAX };
@@ -52782,8 +52790,35 @@ index 71e35ccdda..484545cfb8 100644
          return true;
      }
  
+@@ -4416,6 +4495,7 @@ dpif_netlink_cache_set_size(struct dpif *dpif_, uint32_t level, uint32_t size)
+ const struct dpif_class dpif_netlink_class = {
+     "system",
+     false,                      /* cleanup_required */
++    false,                      /* synced_dp_layers */
+     NULL,                       /* init */
+     dpif_netlink_enumerate,
+     NULL,
+diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
+index 12477a24fe..b8ead8a02a 100644
+--- a/lib/dpif-provider.h
++++ b/lib/dpif-provider.h
+@@ -127,6 +127,14 @@ struct dpif_class {
+      * datapaths that can not exist without it (e.g. netdev datapath).  */
+     bool cleanup_required;
+ 
++    /* If 'true' the specific dpif implementation synchronizes the various
++     * datapath implementation layers, i.e., the dpif's layer in combination
++     * with the underlying netdev offload layers. For example, dpif-netlink
++     * does not sync its kernel flows with the tc ones, i.e., only one gets
++     * installed. On the other hand, dpif-netdev installs both flows,
++     * internally keeps track of both, and represents them as one. */
++    bool synced_dp_layers;
++
+     /* Called when the dpif provider is registered, typically at program
+      * startup.  Returning an error from this function will prevent any
+      * datapath with this class from being created.
 diff --git a/lib/dpif.c b/lib/dpif.c
-index 40f5fe4460..fe4db83fbf 100644
+index 40f5fe4460..3305401fe0 100644
 --- a/lib/dpif.c
 +++ b/lib/dpif.c
 @@ -1213,7 +1213,7 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
@@ -52795,6 +52830,28 @@ index 40f5fe4460..fe4db83fbf 100644
                  odp_put_tunnel_action(&md->tunnel, &execute_actions, NULL);
              }
              ofpbuf_put(&execute_actions, action, NLA_ALIGN(action->nla_len));
+@@ -2109,3 +2109,9 @@ dpif_cache_set_size(struct dpif *dpif, uint32_t level, uint32_t size)
+            ? dpif->dpif_class->cache_set_size(dpif, level, size)
+            : EOPNOTSUPP;
+ }
++
++bool
++dpif_synced_dp_layers(struct dpif *dpif)
++{
++    return dpif->dpif_class->synced_dp_layers;
++}
+diff --git a/lib/dpif.h b/lib/dpif.h
+index 6cb4dae6d8..129cbf6a1d 100644
+--- a/lib/dpif.h
++++ b/lib/dpif.h
+@@ -939,6 +939,7 @@ int dpif_get_pmds_for_port(const struct dpif * dpif, odp_port_t port_no,
+ char *dpif_get_dp_version(const struct dpif *);
+ bool dpif_supports_tnl_push_pop(const struct dpif *);
+ bool dpif_supports_explicit_drop_action(const struct dpif *);
++bool dpif_synced_dp_layers(struct dpif *);
+ 
+ /* Log functions. */
+ struct vlog_module;
 diff --git a/lib/dynamic-string.c b/lib/dynamic-string.c
 index fd0127ed17..8e9555a630 100644
 --- a/lib/dynamic-string.c
@@ -55193,6 +55250,35 @@ index 8237a85ddb..13ab06d116 100644
      bool recirc_id_shared_with_tc;  /* Indicates whever tc chains will be in
                                       * sync with datapath recirc ids. */
  
+diff --git a/lib/netdev-windows.c b/lib/netdev-windows.c
+index 4ad45ffa1b..3fad501e3e 100644
+--- a/lib/netdev-windows.c
++++ b/lib/netdev-windows.c
+@@ -156,6 +156,7 @@ netdev_windows_system_construct(struct netdev *netdev_)
+     struct netdev_windows_netdev_info info;
+     struct ofpbuf *buf;
+     int ret;
++    const char    *type = NULL;
+ 
+     /* Query the attributes and runtime status of the netdev. */
+     ret = query_netdev(netdev_get_name(&netdev->up), &info, &buf);
+@@ -167,6 +168,16 @@ netdev_windows_system_construct(struct netdev *netdev_)
+     }
+     ofpbuf_delete(buf);
+ 
++    /* Don't create netdev if ovs-type is "internal"
++     * but the type of netdev->up is "system". */
++    type = netdev_get_type(&netdev->up);
++    if (type && !strcmp(type, "system") &&
++        (info.ovs_type == OVS_VPORT_TYPE_INTERNAL)) {
++        VLOG_DBG("construct device %s, ovs_type: %u failed",
++                 netdev_get_name(&netdev->up), info.ovs_type);
++        return 1;
++    }
++
+     netdev->change_seq = 1;
+     netdev->dev_type = info.ovs_type;
+     netdev->port_no = info.port_no;
 diff --git a/lib/netdev.c b/lib/netdev.c
 index 8305f6c427..c797783782 100644
 --- a/lib/netdev.c
@@ -58954,10 +59040,41 @@ index 78a54c715d..109940ad2a 100644
              oftrace_node_destroy(node);
          }
 diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
-index 57f94df544..59126b9014 100644
+index 57f94df544..308876d38c 100644
 --- a/ofproto/ofproto-dpif-upcall.c
 +++ b/ofproto/ofproto-dpif-upcall.c
-@@ -362,6 +362,10 @@ static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc,
+@@ -47,17 +47,20 @@
+ 
+ #define UPCALL_MAX_BATCH 64
+ #define REVALIDATE_MAX_BATCH 50
++#define UINT64_THREE_QUARTERS (UINT64_MAX / 4 * 3)
+ 
+ VLOG_DEFINE_THIS_MODULE(ofproto_dpif_upcall);
+ 
+ COVERAGE_DEFINE(dumped_duplicate_flow);
+ COVERAGE_DEFINE(dumped_new_flow);
+ COVERAGE_DEFINE(handler_duplicate_upcall);
+-COVERAGE_DEFINE(upcall_ukey_contention);
+-COVERAGE_DEFINE(upcall_ukey_replace);
+ COVERAGE_DEFINE(revalidate_missed_dp_flow);
++COVERAGE_DEFINE(ukey_dp_change);
++COVERAGE_DEFINE(ukey_invalid_stat_reset);
+ COVERAGE_DEFINE(upcall_flow_limit_hit);
+ COVERAGE_DEFINE(upcall_flow_limit_kill);
++COVERAGE_DEFINE(upcall_ukey_contention);
++COVERAGE_DEFINE(upcall_ukey_replace);
+ 
+ /* A thread that reads upcalls from dpif, forwards each upcall's packet,
+  * and possibly sets up a kernel flow as a cache. */
+@@ -287,6 +290,7 @@ struct udpif_key {
+ 
+     struct ovs_mutex mutex;                   /* Guards the following. */
+     struct dpif_flow_stats stats OVS_GUARDED; /* Last known stats.*/
++    const char *dp_layer OVS_GUARDED;         /* Last known dp_layer. */
+     long long int created OVS_GUARDED;        /* Estimate of creation time. */
+     uint64_t dump_seq OVS_GUARDED;            /* Tracks udpif->dump_seq. */
+     uint64_t reval_seq OVS_GUARDED;           /* Tracks udpif->reval_seq. */
+@@ -362,6 +366,10 @@ static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc,
                                       const char *argv[], void *aux);
  static void upcall_unixctl_purge(struct unixctl_conn *conn, int argc,
                                   const char *argv[], void *aux);
@@ -58968,7 +59085,7 @@ index 57f94df544..59126b9014 100644
  
  static struct udpif_key *ukey_create_from_upcall(struct upcall *,
                                                   struct flow_wildcards *);
-@@ -434,6 +438,10 @@ udpif_init(void)
+@@ -434,6 +442,10 @@ udpif_init(void)
                                   upcall_unixctl_dump_wait, NULL);
          unixctl_command_register("revalidator/purge", "", 0, 0,
                                   upcall_unixctl_purge, NULL);
@@ -58979,7 +59096,33 @@ index 57f94df544..59126b9014 100644
          ovsthread_once_done(&once);
      }
  }
-@@ -1868,6 +1876,7 @@ try_ukey_replace(struct umap *umap, struct udpif_key *old_ukey,
+@@ -771,6 +783,17 @@ udpif_get_n_flows(struct udpif *udpif)
+         atomic_store_relaxed(&udpif->n_flows_timestamp, now);
+         dpif_get_dp_stats(udpif->dpif, &stats);
+         flow_count = stats.n_flows;
++
++        if (!dpif_synced_dp_layers(udpif->dpif)) {
++            /* If the dpif layer does not sync the flows, we need to include
++             * the hardware offloaded flows separately. */
++            uint64_t hw_flows;
++
++            if (!dpif_get_n_offloaded_flows(udpif->dpif, &hw_flows)) {
++                flow_count += hw_flows;
++            }
++        }
++
+         atomic_store_relaxed(&udpif->n_flows, flow_count);
+         ovs_mutex_unlock(&udpif->n_flows_mutex);
+     } else {
+@@ -1746,6 +1769,7 @@ ukey_create__(const struct nlattr *key, size_t key_len,
+     ukey->created = ukey->flow_time = time_msec();
+     memset(&ukey->stats, 0, sizeof ukey->stats);
+     ukey->stats.used = used;
++    ukey->dp_layer = NULL;
+     ukey->xcache = NULL;
+ 
+     ukey->offloaded = false;
+@@ -1868,6 +1892,7 @@ try_ukey_replace(struct umap *umap, struct udpif_key *old_ukey,
              ovs_mutex_lock(&new_ukey->mutex);
              cmap_replace(&umap->cmap, &old_ukey->cmap_node,
                           &new_ukey->cmap_node, new_ukey->hash);
@@ -58987,7 +59130,60 @@ index 57f94df544..59126b9014 100644
              ovsrcu_postpone(ukey_delete__, old_ukey);
              transition_ukey(old_ukey, UKEY_DELETED);
              transition_ukey(new_ukey, UKEY_VISIBLE);
-@@ -2853,7 +2862,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
+@@ -2321,6 +2346,13 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
+                     ? stats->n_bytes - ukey->stats.n_bytes
+                     : 0);
+ 
++    if (stats->n_packets < ukey->stats.n_packets &&
++        ukey->stats.n_packets < UINT64_THREE_QUARTERS) {
++        /* Report cases where the packet counter is lower than the previous
++         * instance, but exclude the potential wrapping of an uint64_t. */
++        COVERAGE_INC(ukey_invalid_stat_reset);
++    }
++
+     if (need_revalidate) {
+         if (should_revalidate(udpif, push.n_packets, ukey->stats.used)) {
+             if (!ukey->xcache) {
+@@ -2434,6 +2466,15 @@ push_dp_ops(struct udpif *udpif, struct ukey_op *ops, size_t n_ops)
+             push->tcp_flags = stats->tcp_flags | op->ukey->stats.tcp_flags;
+             push->n_packets = stats->n_packets - op->ukey->stats.n_packets;
+             push->n_bytes = stats->n_bytes - op->ukey->stats.n_bytes;
++
++            if (stats->n_packets < op->ukey->stats.n_packets &&
++                op->ukey->stats.n_packets < UINT64_THREE_QUARTERS) {
++                /* Report cases where the packet counter is lower than the
++                 * previous instance, but exclude the potential wrapping of an
++                 * uint64_t. */
++                COVERAGE_INC(ukey_invalid_stat_reset);
++            }
++
+             ovs_mutex_unlock(&op->ukey->mutex);
+         } else {
+             push = stats;
+@@ -2738,6 +2779,22 @@ revalidate(struct revalidator *revalidator)
+                 continue;
+             }
+ 
++            ukey->offloaded = f->attrs.offloaded;
++            if (!ukey->dp_layer
++                || (!dpif_synced_dp_layers(udpif->dpif)
++                    && strcmp(ukey->dp_layer, f->attrs.dp_layer))) {
++
++                if (ukey->dp_layer) {
++                    /* The dp_layer has changed this is probably due to an
++                     * earlier revalidate cycle moving it to/from hw offload.
++                     * In this case we should reset the ukey stored statistics,
++                     * as they are from the deleted DP flow. */
++                    COVERAGE_INC(ukey_dp_change);
++                    memset(&ukey->stats, 0, sizeof ukey->stats);
++                }
++                ukey->dp_layer = f->attrs.dp_layer;
++            }
++
+             already_dumped = ukey->dump_seq == dump_seq;
+             if (already_dumped) {
+                 /* The flow has already been handled during this flow dump
+@@ -2853,7 +2910,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
                  } else {
                      struct dpif_flow_stats stats;
                      COVERAGE_INC(revalidate_missed_dp_flow);
@@ -58996,7 +59192,7 @@ index 57f94df544..59126b9014 100644
                      result = revalidate_ukey(udpif, ukey, &stats, &odp_actions,
                                               reval_seq, &recircs, false);
                  }
-@@ -3099,6 +3108,31 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED,
+@@ -3099,6 +3156,31 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED,
      unixctl_command_reply(conn, "");
  }
  
@@ -66955,7 +67151,7 @@ index d21fd777dd..c37852b216 100644
  
  OVS_VSWITCHD_STOP
 diff --git a/tests/system-offloads-traffic.at b/tests/system-offloads-traffic.at
-index 80bc1dd5c3..9f50f3b01d 100644
+index 80bc1dd5c3..84bab88be2 100644
 --- a/tests/system-offloads-traffic.at
 +++ b/tests/system-offloads-traffic.at
 @@ -90,7 +90,7 @@ AT_CHECK([tc -o -s -d filter show dev ovs-p0 ingress |
@@ -66976,14 +67172,16 @@ index 80bc1dd5c3..9f50f3b01d 100644
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
-@@ -168,3 +168,67 @@ matchall
+@@ -168,3 +168,131 @@ matchall
  ])
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
 +
 +
 +AT_SETUP([offloads - simulated flow action update])
-+OVS_TRAFFIC_VSWITCHD_START([], [], [-- set Open_vSwitch . other_config:hw-offload=true])
++OVS_TRAFFIC_VSWITCHD_START()
++
++AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
 +
 +ADD_NAMESPACES(at_ns0, at_ns1)
 +
@@ -67044,6 +67242,68 @@ index 80bc1dd5c3..9f50f3b01d 100644
 +
 +OVS_TRAFFIC_VSWITCHD_STOP
 +AT_CLEANUP
++
++
++AT_SETUP([offloads - offload flow to none-offload])
++OVS_TRAFFIC_VSWITCHD_START()
++
++AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:hw-offload=true])
++
++ADD_NAMESPACES(at_ns0, at_ns1)
++
++ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
++ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
++
++AT_DATA([flows.txt], [dnl
++add in_port=ovs-p0,actions=ovs-p1
++add in_port=ovs-p1,actions=ovs-p0
++])
++AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
++
++NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
++10 packets transmitted, 10 received, 0% packet loss, time 0ms
++])
++
++AT_CHECK([ovs-appctl dpctl/dump-flows type=tc | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl
++recirc_id(<recirc>),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:756, used:0.0s, actions:3
++recirc_id(<recirc>),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:756, used:0.0s, actions:2
++])
++
++dnl Here we use an output action with truncate, which will force a kernel flow.
++AT_DATA([flows2.txt], [dnl
++modify in_port=ovs-p0,actions=output(port=ovs-p1, max_len=128)
++modify in_port=ovs-p1,actions=output(port=ovs-p0, max_len=128)
++])
++AT_CHECK([ovs-ofctl add-flows br0 flows2.txt])
++AT_CHECK([ovs-appctl revalidator/wait], [0])
++
++NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
++10 packets transmitted, 10 received, 0% packet loss, time 0ms
++])
++
++AT_CHECK([ovs-appctl dpctl/dump-flows type=ovs | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl
++recirc_id(<recirc>),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:980, used:0.0s, actions:trunc(128),3
++recirc_id(<recirc>),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:980, used:0.0s, actions:trunc(128),2
++])
++
++AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
++AT_CHECK([ovs-appctl revalidator/wait], [0])
++
++NS_CHECK_EXEC([at_ns0], [ping -q -c 10 -i 0.1 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
++10 packets transmitted, 10 received, 0% packet loss, time 0ms
++])
++
++AT_CHECK([ovs-appctl dpctl/dump-flows type=tc | grep "eth_type(0x0800)" | sort | strip_recirc | strip_used], [0], [dnl
++recirc_id(<recirc>),in_port(2),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:840, used:0.0s, actions:3
++recirc_id(<recirc>),in_port(3),eth(),eth_type(0x0800),ipv4(frag=no), packets:10, bytes:840, used:0.0s, actions:2
++])
++
++AT_CHECK([ovs-appctl coverage/read-counter ukey_invalid_stat_reset], [0], [dnl
++0
++])
++
++OVS_TRAFFIC_VSWITCHD_STOP
++AT_CLEANUP
 diff --git a/tests/system-route.at b/tests/system-route.at
 index 1714273e35..270956d13f 100644
 --- a/tests/system-route.at
diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec
index 8f789bb..903d5e9 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: 79%{?dist}
+Release: 80%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -749,6 +749,14 @@ exit 0
 %endif
 
 %changelog
+* Tue Mar 07 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-80
+- Merging upstream branch-2.17 [RH git: b12915ee23]
+    Commit list:
+    7aa314c9c2 netdev-windows: Add checking when creating netdev with system type on Windows
+    215278bded ofproto-dpif-upcall: Include hardware offloaded flows in total flows.
+    4a3f8845e9 ofproto-dpif-upcall: Reset ukey's last stats value if the datapath changed.
+
+
 * Thu Mar 02 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-79
 - Merging upstream branch-2.17 [RH git: 3da76b1dd5]
     Commit list: