diff --git a/.openvswitch.metadata b/.openvswitch.metadata
index 53d7d0a..aae65b4 100644
--- a/.openvswitch.metadata
+++ b/.openvswitch.metadata
@@ -1,5 +1,5 @@
 002450621b33c5690060345b0aac25bc2426d675  SOURCES/docutils-0.12.tar.gz
-019c0a80416de57f0820850034e17ce2a4768910  SOURCES/openvswitch-2.17.0.tar.gz
+722b63cd114c21041abda7b38d7f14e46338e3e0  SOURCES/openvswitch-2.17.0.tar.gz
 8509a716f9f936526f64fb23f313c5a9baf2f123  SOURCES/pyelftools-0.27.tar.gz
 d34f96421a86004aa5d26ecf975edefd09f948b1  SOURCES/Pygments-1.4.tar.gz
 3a11f130c63b057532ca37fe49c8967d0cbae1d5  SOURCES/Sphinx-1.2.3.tar.gz
diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch
index d36876f..7720d72 100644
--- a/SOURCES/openvswitch-2.17.0.patch
+++ b/SOURCES/openvswitch-2.17.0.patch
@@ -50900,6 +50900,55 @@ index 228b185c3a..8e6c46a85f 100644
  #ifdef __cplusplus
  }
  #endif
+diff --git a/include/sparse/numa.h b/include/sparse/numa.h
+index 3691a0eaf7..a185972e31 100644
+--- a/include/sparse/numa.h
++++ b/include/sparse/numa.h
+@@ -18,10 +18,21 @@
+ #error "Use this header only with sparse.  It is not a correct implementation."
+ #endif
+ 
+-/* Avoid sparse warning: non-ANSI function declaration of function" */
+-#define numa_get_membind_compat() numa_get_membind_compat(void)
+-#define numa_get_interleave_mask_compat() numa_get_interleave_mask_compat(void)
+-#define numa_get_run_node_mask_compat() numa_get_run_node_mask_compat(void)
++#ifndef __NUMA_H_SPARSE
++#define __NUMA_H_SPARSE 1
+ 
+-/* Get actual <numa.h> definitions for us to annotate and build on. */
+-#include_next<numa.h>
++/* Avoid sparse warning "non-ANSI function declaration of function" with
++ * libnuma < 2.0.13. */
++
++struct bitmask {
++    unsigned long size;
++    unsigned long *maskp;
++};
++
++int numa_available(void);
++struct bitmask *numa_allocate_nodemask(void);
++void numa_bitmask_free(struct bitmask *);
++void numa_set_localalloc(void);
++void numa_set_preferred(int node);
++
++#endif /* <numa.h> for sparse. */
+diff --git a/include/sparse/rte_memcpy.h b/include/sparse/rte_memcpy.h
+index 5cd3f013ea..ec88500242 100644
+--- a/include/sparse/rte_memcpy.h
++++ b/include/sparse/rte_memcpy.h
+@@ -20,11 +20,8 @@
+ #error "Use this header only with sparse.  It is not a correct implementation."
+ #endif
+ 
+-/* Include the same headers as the real rte_memcpy(). */
+-#include <stdio.h>
++#include <stddef.h>
+ #include <stdint.h>
+-#include <string.h>
+-#include <rte_vect.h>
+ 
+ /* Declare the same functions as the real rte_memcpy.h, without defining them.
+  * This gives sparse the information it needs without provoking sparse's
 diff --git a/ipsec/ovs-monitor-ipsec.in b/ipsec/ovs-monitor-ipsec.in
 index a8b0705d9f..631a8fca80 100755
 --- a/ipsec/ovs-monitor-ipsec.in
@@ -53792,7 +53841,7 @@ index 94dc6a9b74..303b99daf4 100644
              .queue = rss_data->queue,
              .key_len = 0,
 diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
-index 9845e8d3fe..057fad412a 100644
+index 9845e8d3fe..19eae7bd20 100644
 --- a/lib/netdev-offload-tc.c
 +++ b/lib/netdev-offload-tc.c
 @@ -44,6 +44,7 @@
@@ -53803,16 +53852,130 @@ index 9845e8d3fe..057fad412a 100644
  
  static struct hmap ufid_to_tc = HMAP_INITIALIZER(&ufid_to_tc);
  static struct hmap tc_to_ufid = HMAP_INITIALIZER(&tc_to_ufid);
-@@ -204,7 +205,7 @@ del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid)
+@@ -62,6 +63,12 @@ struct chain_node {
+     uint32_t chain;
+ };
+ 
++static void parse_tc_flower_to_stats(struct tc_flower *flower,
++                                     struct dpif_flow_stats *stats);
++
++static int get_ufid_adjust_stats(const ovs_u128 *ufid,
++                                 struct dpif_flow_stats *stats);
++
+ static bool
+ is_internal_port(const char *type)
+ {
+@@ -158,6 +165,9 @@ static struct ovs_mutex ufid_lock = OVS_MUTEX_INITIALIZER;
+  * @ufid: ufid assigned to the flow
+  * @id: tc filter id (tcf_id)
+  * @netdev: netdev associated with the tc rule
++ * @adjust_stats: When flow gets updated with new actions, we need to adjust
++ *                the reported stats to include previous values as the hardware
++ *                rule is removed and re-added. This stats copy is used for it.
+  */
+ struct ufid_tc_data {
+     struct hmap_node ufid_to_tc_node;
+@@ -165,6 +175,7 @@ struct ufid_tc_data {
+     ovs_u128 ufid;
+     struct tcf_id id;
+     struct netdev *netdev;
++    struct dpif_flow_stats adjust_stats;
+ };
+ 
+ static void
+@@ -198,13 +209,39 @@ del_ufid_tc_mapping(const ovs_u128 *ufid)
+     ovs_mutex_unlock(&ufid_lock);
+ }
+ 
++static void
++netdev_tc_adjust_stats(struct dpif_flow_stats *stats,
++                       const struct dpif_flow_stats *adjust_stats)
++{
++    /* Do not try to restore the stats->used, as in terse mode dumps TC doesn't
++     * report TCA_ACT_OPTIONS, so the 'lastused' value is not available, hence
++     * we report used as 0.
++     * tcp_flags is not collected by tc, so no need to update it. */
++    stats->n_bytes += adjust_stats->n_bytes;
++    stats->n_packets += adjust_stats->n_packets;
++}
++
+ /* Wrapper function to delete filter and ufid tc mapping */
+ static int
+-del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid)
++del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid,
++                            struct dpif_flow_stats *stats)
  {
++    struct tc_flower flower;
      int err;
  
 -    err = tc_del_filter(id);
++    if (stats) {
++        memset(stats, 0, sizeof *stats);
++        if (!tc_get_flower(id, &flower)) {
++            struct dpif_flow_stats adjust_stats;
++
++            parse_tc_flower_to_stats(&flower, stats);
++            if (!get_ufid_adjust_stats(ufid, &adjust_stats)) {
++                netdev_tc_adjust_stats(stats, &adjust_stats);
++            }
++        }
++    }
++
 +    err = tc_del_flower_filter(id);
      if (!err) {
          del_ufid_tc_mapping(ufid);
      }
-@@ -405,7 +406,7 @@ delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id)
+@@ -214,7 +251,7 @@ del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid)
+ /* Add ufid entry to ufid_to_tc hashmap. */
+ static void
+ add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid,
+-                    struct tcf_id *id)
++                    struct tcf_id *id, struct dpif_flow_stats *stats)
+ {
+     struct ufid_tc_data *new_data = xzalloc(sizeof *new_data);
+     size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0);
+@@ -226,6 +263,9 @@ add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid,
+     new_data->ufid = *ufid;
+     new_data->id = *id;
+     new_data->netdev = netdev_ref(netdev);
++    if (stats) {
++        new_data->adjust_stats = *stats;
++    }
+ 
+     ovs_mutex_lock(&ufid_lock);
+     hmap_insert(&ufid_to_tc, &new_data->ufid_to_tc_node, ufid_hash);
+@@ -257,6 +297,30 @@ get_ufid_tc_mapping(const ovs_u128 *ufid, struct tcf_id *id)
+     return ENOENT;
+ }
+ 
++/* Get adjust_stats from ufid_to_tc hashmap.
++ *
++ * Returns 0 if successful and fills stats with adjust_stats.
++ * Otherwise returns the error.
++*/
++static int
++get_ufid_adjust_stats(const ovs_u128 *ufid, struct dpif_flow_stats *stats)
++{
++    size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0);
++    struct ufid_tc_data *data;
++
++    ovs_mutex_lock(&ufid_lock);
++    HMAP_FOR_EACH_WITH_HASH (data, ufid_to_tc_node, ufid_hash, &ufid_to_tc) {
++        if (ovs_u128_equals(*ufid, data->ufid)) {
++            *stats = data->adjust_stats;
++            ovs_mutex_unlock(&ufid_lock);
++            return 0;
++        }
++    }
++    ovs_mutex_unlock(&ufid_lock);
++
++    return ENOENT;
++}
++
+ /* Find ufid entry in ufid_to_tc hashmap using tcf_id id.
+  * The result is saved in ufid.
+  *
+@@ -405,7 +469,7 @@ delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id)
           */
          HMAP_FOR_EACH_POP (chain_node, node, &map) {
              id->chain = chain_node->chain;
@@ -53821,7 +53984,7 @@ index 9845e8d3fe..057fad412a 100644
              free(chain_node);
          }
      }
-@@ -417,16 +418,16 @@ delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id)
+@@ -417,16 +481,16 @@ delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id)
  static int
  netdev_tc_flow_flush(struct netdev *netdev)
  {
@@ -53841,7 +54004,7 @@ index 9845e8d3fe..057fad412a 100644
          if (!err) {
              del_ufid_tc_mapping_unlocked(&data->ufid);
          }
-@@ -481,10 +482,10 @@ netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump)
+@@ -481,10 +545,10 @@ netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump)
  
  static void
  parse_flower_rewrite_to_netlink_action(struct ofpbuf *buf,
@@ -53855,7 +54018,7 @@ index 9845e8d3fe..057fad412a 100644
  
      for (int type = 0; type < ARRAY_SIZE(set_flower_map); type++) {
          char *put = NULL;
-@@ -550,30 +551,42 @@ flower_tun_opt_to_match(struct match *match, struct tc_flower *flower)
+@@ -550,30 +614,42 @@ flower_tun_opt_to_match(struct match *match, struct tc_flower *flower)
      struct geneve_opt *opt, *opt_mask;
      int len, cnt = 0;
  
@@ -53905,7 +54068,7 @@ index 9845e8d3fe..057fad412a 100644
  }
  
  static void
-@@ -585,8 +598,10 @@ parse_tc_flower_to_stats(struct tc_flower *flower,
+@@ -585,8 +661,10 @@ parse_tc_flower_to_stats(struct tc_flower *flower,
      }
  
      memset(stats, 0, sizeof *stats);
@@ -53918,7 +54081,7 @@ index 9845e8d3fe..057fad412a 100644
      stats->used = flower->lastused;
  }
  
-@@ -616,7 +631,8 @@ parse_tc_flower_terse_to_match(struct tc_flower *flower,
+@@ -616,7 +694,8 @@ parse_tc_flower_terse_to_match(struct tc_flower *flower,
  }
  
  static int
@@ -53928,7 +54091,7 @@ index 9845e8d3fe..057fad412a 100644
                           struct match *match,
                           struct nlattr **actions,
                           struct dpif_flow_stats *stats,
-@@ -803,18 +819,24 @@ parse_tc_flower_to_match(struct tc_flower *flower,
+@@ -803,18 +882,24 @@ parse_tc_flower_to_match(struct tc_flower *flower,
                                            &flower->key.tunnel.ipv6.ipv6_src,
                                            &flower->mask.tunnel.ipv6.ipv6_src);
          }
@@ -53958,7 +54121,7 @@ index 9845e8d3fe..057fad412a 100644
              flower_tun_opt_to_match(match, flower);
          }
      }
-@@ -877,7 +899,7 @@ parse_tc_flower_to_match(struct tc_flower *flower,
+@@ -877,7 +962,7 @@ parse_tc_flower_to_match(struct tc_flower *flower,
              }
              break;
              case TC_ACT_PEDIT: {
@@ -53967,7 +54130,20 @@ index 9845e8d3fe..057fad412a 100644
              }
              break;
              case TC_ACT_ENCAP: {
-@@ -965,13 +987,13 @@ parse_tc_flower_to_match(struct tc_flower *flower,
+@@ -947,7 +1032,11 @@ parse_tc_flower_to_match(struct tc_flower *flower,
+                 ct_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_CT);
+ 
+                 if (action->ct.commit) {
+-                    nl_msg_put_flag(buf, OVS_CT_ATTR_COMMIT);
++                    if (action->ct.force) {
++                        nl_msg_put_flag(buf, OVS_CT_ATTR_FORCE_COMMIT);
++                    } else {
++                        nl_msg_put_flag(buf, OVS_CT_ATTR_COMMIT);
++                    }
+                 }
+ 
+                 if (action->ct.zone) {
+@@ -965,13 +1054,13 @@ parse_tc_flower_to_match(struct tc_flower *flower,
                      struct {
                          ovs_u128 key;
                          ovs_u128 mask;
@@ -53987,7 +54163,14 @@ index 9845e8d3fe..057fad412a 100644
                  }
  
                  if (action->ct.nat_type) {
-@@ -1054,8 +1076,8 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
+@@ -1048,14 +1137,15 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
+                         get_tc_qdisc_hook(netdev));
+ 
+     while (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) {
++        struct dpif_flow_stats adjust_stats;
+         struct tc_flower flower;
+ 
+         if (parse_netlink_to_tc_flower(&nl_flow, &id, &flower, dump->terse)) {
              continue;
          }
  
@@ -53998,7 +54181,32 @@ index 9845e8d3fe..057fad412a 100644
              continue;
          }
  
-@@ -1194,13 +1216,14 @@ parse_put_flow_ct_action(struct tc_flower *flower,
+@@ -1065,6 +1155,10 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump,
+             continue;
+         }
+ 
++        if (!get_ufid_adjust_stats(ufid, &adjust_stats)) {
++            netdev_tc_adjust_stats(stats, &adjust_stats);
++        }
++
+         match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX);
+         match->flow.in_port.odp_port = dump->port;
+         match_set_recirc_id(match, id.chain);
+@@ -1164,7 +1258,12 @@ parse_put_flow_ct_action(struct tc_flower *flower,
+         NL_ATTR_FOR_EACH_UNSAFE (ct_attr, ct_left, ct, ct_len) {
+             switch (nl_attr_type(ct_attr)) {
+                 case OVS_CT_ATTR_COMMIT: {
+-                        action->ct.commit = true;
++                    action->ct.commit = true;
++                }
++                break;
++                case OVS_CT_ATTR_FORCE_COMMIT: {
++                    action->ct.commit = true;
++                    action->ct.force = true;
+                 }
+                 break;
+                 case OVS_CT_ATTR_ZONE: {
+@@ -1194,15 +1293,20 @@ parse_put_flow_ct_action(struct tc_flower *flower,
                  break;
                  case OVS_CT_ATTR_LABELS: {
                      const struct {
@@ -54016,8 +54224,14 @@ index 9845e8d3fe..057fad412a 100644
 +                        get_32aligned_u128(&ct_label->mask);
                  }
                  break;
++                /* The following option we do not support in tc-ct, and should
++                 * not be ignored for proper operation. */
++                case OVS_CT_ATTR_HELPER:
++                    return EOPNOTSUPP;
              }
-@@ -1222,8 +1245,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower,
+         }
+ 
+@@ -1222,8 +1326,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower,
      uint64_t set_stub[1024 / 8];
      struct ofpbuf set_buf = OFPBUF_STUB_INITIALIZER(set_stub);
      char *set_data, *set_mask;
@@ -54028,7 +54242,7 @@ index 9845e8d3fe..057fad412a 100644
      const struct nlattr *attr;
      int i, j, type;
      size_t size;
-@@ -1265,14 +1288,6 @@ parse_put_flow_set_masked_action(struct tc_flower *flower,
+@@ -1265,14 +1369,6 @@ parse_put_flow_set_masked_action(struct tc_flower *flower,
          }
      }
  
@@ -54043,7 +54257,7 @@ index 9845e8d3fe..057fad412a 100644
      if (hasmask && !is_all_zeros(set_mask, size)) {
          VLOG_DBG_RL(&rl, "unsupported sub attribute of set action type %d",
                      type);
-@@ -1281,6 +1296,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower,
+@@ -1281,6 +1377,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower,
      }
  
      ofpbuf_uninit(&set_buf);
@@ -54052,7 +54266,7 @@ index 9845e8d3fe..057fad412a 100644
      return 0;
  }
  
-@@ -1288,6 +1305,7 @@ static int
+@@ -1288,6 +1386,7 @@ static int
  parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action,
                            const struct nlattr *set, size_t set_len)
  {
@@ -54060,7 +54274,7 @@ index 9845e8d3fe..057fad412a 100644
      const struct nlattr *tunnel;
      const struct nlattr *tun_attr;
      size_t tun_left, tunnel_len;
-@@ -1306,6 +1324,7 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action,
+@@ -1306,6 +1405,7 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action,
  
      action->type = TC_ACT_ENCAP;
      action->encap.id_present = false;
@@ -54068,7 +54282,7 @@ index 9845e8d3fe..057fad412a 100644
      flower->action_count++;
      NL_ATTR_FOR_EACH_UNSAFE(tun_attr, tun_left, tunnel, tunnel_len) {
          switch (nl_attr_type(tun_attr)) {
-@@ -1330,6 +1349,18 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action,
+@@ -1330,6 +1430,18 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action,
              action->encap.ttl = nl_attr_get_u8(tun_attr);
          }
          break;
@@ -54087,7 +54301,7 @@ index 9845e8d3fe..057fad412a 100644
          case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: {
              action->encap.ipv6.ipv6_src =
                  nl_attr_get_in6_addr(tun_attr);
-@@ -1354,12 +1385,31 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action,
+@@ -1354,12 +1466,31 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action,
              action->encap.data.present.len = nl_attr_get_size(tun_attr);
          }
          break;
@@ -54119,7 +54333,7 @@ index 9845e8d3fe..057fad412a 100644
  static int
  test_key_and_mask(struct match *match)
  {
-@@ -1442,8 +1492,23 @@ test_key_and_mask(struct match *match)
+@@ -1442,8 +1573,23 @@ test_key_and_mask(struct match *match)
          return EOPNOTSUPP;
      }
  
@@ -54144,7 +54358,7 @@ index 9845e8d3fe..057fad412a 100644
          return EOPNOTSUPP;
      }
  
-@@ -1452,18 +1517,51 @@ test_key_and_mask(struct match *match)
+@@ -1452,18 +1598,51 @@ test_key_and_mask(struct match *match)
  
  static void
  flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl,
@@ -54199,7 +54413,7 @@ index 9845e8d3fe..057fad412a 100644
      len = flower->key.tunnel.metadata.present.len;
      while (len) {
          opt = &flower->key.tunnel.metadata.opts.gnv[cnt];
-@@ -1474,8 +1572,6 @@ flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl,
+@@ -1474,8 +1653,6 @@ flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl,
          cnt += sizeof(struct geneve_opt) / 4 + opt->length;
          len -= sizeof(struct geneve_opt) + opt->length * 4;
      }
@@ -54208,7 +54422,7 @@ index 9845e8d3fe..057fad412a 100644
  }
  
  static void
-@@ -1541,6 +1637,12 @@ parse_match_ct_state_to_flower(struct tc_flower *flower, struct match *match)
+@@ -1541,6 +1718,12 @@ parse_match_ct_state_to_flower(struct tc_flower *flower, struct match *match)
              flower->key.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW);
              flower->mask.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW);
          }
@@ -54221,16 +54435,17 @@ index 9845e8d3fe..057fad412a 100644
      }
  
      if (mask->ct_zone) {
-@@ -1574,7 +1676,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
+@@ -1574,7 +1757,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
      const struct flow *key = &match->flow;
      struct flow *mask = &match->wc.masks;
      const struct flow_tnl *tnl = &match->flow.tunnel;
 -    const struct flow_tnl *tnl_mask = &mask->tunnel;
 +    struct flow_tnl *tnl_mask = &mask->tunnel;
++    struct dpif_flow_stats adjust_stats;
      struct tc_action *action;
      bool recirc_act = false;
      uint32_t block_id = 0;
-@@ -1615,17 +1717,49 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
+@@ -1615,17 +1799,49 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
          flower.key.tunnel.ttl = tnl->ip_ttl;
          flower.key.tunnel.tp_src = tnl->tp_src;
          flower.key.tunnel.tp_dst = tnl->tp_dst;
@@ -54282,7 +54497,7 @@ index 9845e8d3fe..057fad412a 100644
  
      flower.key.eth_type = key->dl_type;
      flower.mask.eth_type = mask->dl_type;
-@@ -1638,7 +1772,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
+@@ -1638,7 +1854,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
  
      if (mask->vlans[0].tpid && eth_type_vlan(key->vlans[0].tpid)) {
          flower.key.encap_eth_type[0] = flower.key.eth_type;
@@ -54291,7 +54506,7 @@ index 9845e8d3fe..057fad412a 100644
          flower.key.eth_type = key->vlans[0].tpid;
          flower.mask.eth_type = mask->vlans[0].tpid;
      }
-@@ -1734,7 +1868,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
+@@ -1734,7 +1950,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
              memset(&mask->arp_tha, 0, sizeof mask->arp_tha);
      }
  
@@ -54300,7 +54515,7 @@ index 9845e8d3fe..057fad412a 100644
          flower.key.ip_proto = key->nw_proto;
          flower.mask.ip_proto = mask->nw_proto;
          mask->nw_proto = 0;
-@@ -1841,7 +1975,25 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
+@@ -1841,7 +2057,25 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
                  VLOG_DBG_RL(&rl, "Can't find netdev for output port %d", port);
                  return ENODEV;
              }
@@ -54326,7 +54541,7 @@ index 9845e8d3fe..057fad412a 100644
              action->out.ingress = is_internal_port(netdev_get_type(outdev));
              action->type = TC_ACT_OUTPUT;
              flower.action_count++;
-@@ -1879,10 +2031,6 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
+@@ -1879,10 +2113,6 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
              if (err) {
                  return err;
              }
@@ -54337,7 +54552,32 @@ index 9845e8d3fe..057fad412a 100644
          } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) {
              const struct nlattr *set = nl_attr_get(nla);
              const size_t set_len = nl_attr_get_size(nla);
-@@ -1989,7 +2137,8 @@ netdev_tc_flow_get(struct netdev *netdev,
+@@ -1929,10 +2159,12 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
+         return EOPNOTSUPP;
+     }
+ 
++    memset(&adjust_stats, 0, sizeof adjust_stats);
+     if (get_ufid_tc_mapping(ufid, &id) == 0) {
+         VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d",
+                     id.handle, id.prio);
+-        info->tc_modify_flow_deleted = !del_filter_and_ufid_mapping(&id, ufid);
++        info->tc_modify_flow_deleted = !del_filter_and_ufid_mapping(
++            &id, ufid, &adjust_stats);
+     }
+ 
+     prio = get_prio_for_tc_flower(&flower);
+@@ -1950,8 +2182,9 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
+     if (!err) {
+         if (stats) {
+             memset(stats, 0, sizeof *stats);
++            netdev_tc_adjust_stats(stats, &adjust_stats);
+         }
+-        add_ufid_tc_mapping(netdev, ufid, &id);
++        add_ufid_tc_mapping(netdev, ufid, &id, &adjust_stats);
+     }
+ 
+     return err;
+@@ -1989,8 +2222,16 @@ netdev_tc_flow_get(struct netdev *netdev,
      }
  
      in_port = netdev_ifindex_to_odp_port(id.ifindex);
@@ -54345,20 +54585,45 @@ index 9845e8d3fe..057fad412a 100644
 +    parse_tc_flower_to_match(netdev, &flower, match, actions,
 +                             stats, attrs, buf, false);
  
++    if (stats) {
++        struct dpif_flow_stats adjust_stats;
++
++        if (!get_ufid_adjust_stats(ufid, &adjust_stats)) {
++            netdev_tc_adjust_stats(stats, &adjust_stats);
++        }
++    }
      match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX);
      match->flow.in_port.odp_port = in_port;
-@@ -2015,9 +2164,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
-     if (stats) {
-         memset(stats, 0, sizeof *stats);
-         if (!tc_get_flower(&id, &flower)) {
+     match_set_recirc_id(match, id.chain);
+@@ -2003,7 +2244,6 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
+                    const ovs_u128 *ufid,
+                    struct dpif_flow_stats *stats)
+ {
+-    struct tc_flower flower;
+     struct tcf_id id;
+     int error;
+ 
+@@ -2012,18 +2252,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
+         return error;
+     }
+ 
+-    if (stats) {
+-        memset(stats, 0, sizeof *stats);
+-        if (!tc_get_flower(&id, &flower)) {
 -            stats->n_packets = get_32aligned_u64(&flower.stats.n_packets);
 -            stats->n_bytes = get_32aligned_u64(&flower.stats.n_bytes);
 -            stats->used = flower.lastused;
-+            parse_tc_flower_to_stats(&flower, stats);
-         }
-     }
+-        }
+-    }
+-
+-    error = del_filter_and_ufid_mapping(&id, ufid);
+-
+-    return error;
++    return del_filter_and_ufid_mapping(&id, ufid, stats);
+ }
  
-@@ -2077,13 +2224,13 @@ probe_multi_mask_per_prio(int ifindex)
+ static int
+@@ -2077,13 +2306,13 @@ probe_multi_mask_per_prio(int ifindex)
  
      id2 = tc_make_tcf_id(ifindex, block_id, prio, TC_INGRESS);
      error = tc_replace_flower(&id2, &flower);
@@ -54374,7 +54639,7 @@ index 9845e8d3fe..057fad412a 100644
  
      multi_mask_per_prio = true;
      VLOG_INFO("probe tc: multiple masks on single tc prio is supported.");
-@@ -2135,7 +2282,7 @@ probe_ct_state_support(int ifindex)
+@@ -2135,7 +2364,7 @@ probe_ct_state_support(int ifindex)
          goto out_del;
      }
  
@@ -54383,7 +54648,7 @@ index 9845e8d3fe..057fad412a 100644
      ct_state_support = OVS_CS_F_NEW |
                         OVS_CS_F_ESTABLISHED |
                         OVS_CS_F_TRACKED |
-@@ -2149,7 +2296,7 @@ probe_ct_state_support(int ifindex)
+@@ -2149,7 +2378,7 @@ probe_ct_state_support(int ifindex)
          goto out_del;
      }
  
@@ -54392,7 +54657,7 @@ index 9845e8d3fe..057fad412a 100644
  
      /* Test for ct_state INVALID support */
      memset(&flower, 0, sizeof flower);
-@@ -2160,7 +2307,7 @@ probe_ct_state_support(int ifindex)
+@@ -2160,7 +2389,7 @@ probe_ct_state_support(int ifindex)
          goto out;
      }
  
@@ -54401,7 +54666,7 @@ index 9845e8d3fe..057fad412a 100644
      ct_state_support |= OVS_CS_F_INVALID;
  
      /* Test for ct_state REPLY support */
-@@ -2176,7 +2323,7 @@ probe_ct_state_support(int ifindex)
+@@ -2176,7 +2405,7 @@ probe_ct_state_support(int ifindex)
      ct_state_support |= OVS_CS_F_REPLY_DIR;
  
  out_del:
@@ -54410,7 +54675,7 @@ index 9845e8d3fe..057fad412a 100644
  out:
      tc_add_del_qdisc(ifindex, false, 0, TC_INGRESS);
      VLOG_INFO("probe tc: supported ovs ct_state bits: 0x%x", ct_state_support);
-@@ -2251,7 +2398,7 @@ netdev_tc_init_flow_api(struct netdev *netdev)
+@@ -2251,7 +2480,7 @@ netdev_tc_init_flow_api(struct netdev *netdev)
  
      /* fallback here if delete chains fail */
      if (!get_chain_supported) {
@@ -54564,6 +54829,36 @@ index 8305f6c427..c797783782 100644
                  netdev->node = shash_add(&netdev_shash, name, netdev);
  
                  /* By default enable one tx and rx queue per netdev. */
+diff --git a/lib/netlink.c b/lib/netlink.c
+index 8204025a56..6215282d6f 100644
+--- a/lib/netlink.c
++++ b/lib/netlink.c
+@@ -570,6 +570,13 @@ nl_msg_put_nested(struct ofpbuf *msg,
+     nl_msg_end_nested(msg, offset);
+ }
+ 
++/* Reset message size to offset. */
++void
++nl_msg_reset_size(struct ofpbuf *msg, size_t offset)
++{
++    msg->size = offset;
++}
++
+ /* If 'buffer' begins with a valid "struct nlmsghdr", pulls the header and its
+  * payload off 'buffer', stores header and payload in 'msg->data' and
+  * 'msg->size', and returns a pointer to the header.
+diff --git a/lib/netlink.h b/lib/netlink.h
+index b97470743e..e9050c31ba 100644
+--- a/lib/netlink.h
++++ b/lib/netlink.h
+@@ -86,6 +86,7 @@ void nl_msg_cancel_nested(struct ofpbuf *, size_t offset);
+ bool nl_msg_end_non_empty_nested(struct ofpbuf *, size_t offset);
+ void nl_msg_put_nested(struct ofpbuf *, uint16_t type,
+                        const void *data, size_t size);
++void nl_msg_reset_size(struct ofpbuf *, size_t offset);
+ 
+ /* Prepending attributes. */
+ void *nl_msg_push_unspec_uninit(struct ofpbuf *, uint16_t type, size_t);
 diff --git a/lib/odp-util.c b/lib/odp-util.c
 index 9a705cffa3..fac4cf3a8c 100644
 --- a/lib/odp-util.c
@@ -56038,7 +56333,7 @@ index a921159667..2fe6c540a7 100644
   * key-value pairs, e.g.
   *
 diff --git a/lib/socket-util.c b/lib/socket-util.c
-index 4f1ffecf5d..38705cc51e 100644
+index 4f1ffecf5d..3eb3a3816b 100644
 --- a/lib/socket-util.c
 +++ b/lib/socket-util.c
 @@ -62,7 +62,8 @@ static bool parse_sockaddr_components(struct sockaddr_storage *ss,
@@ -56130,16 +56425,42 @@ index 4f1ffecf5d..38705cc51e 100644
          error = EAFNOSUPPORT;
          goto exit;
      }
-@@ -660,7 +672,7 @@ inet_parse_passive(const char *target_, int default_port,
+@@ -648,7 +660,8 @@ exit:
+  * zeros '*ss' and returns false. */
+ bool
+ inet_parse_passive(const char *target_, int default_port,
+-                   struct sockaddr_storage *ss)
++                   struct sockaddr_storage *ss,
++                   bool resolve_host, bool *dns_failure)
+ {
+     char *target = xstrdup(target_);
+     char *port, *host;
+@@ -660,7 +673,7 @@ inet_parse_passive(const char *target_, int default_port,
          ok = false;
      } else {
          ok = parse_sockaddr_components(ss, host, port, default_port,
 -                                       target_, true);
-+                                       target_, true, NULL);
++                                       target_, resolve_host, dns_failure);
      }
      if (!ok) {
          memset(ss, 0, sizeof *ss);
-@@ -783,7 +795,8 @@ inet_parse_address(const char *target_, struct sockaddr_storage *ss)
+@@ -698,8 +711,14 @@ inet_open_passive(int style, const char *target, int default_port,
+     struct sockaddr_storage ss;
+     int fd = 0, error;
+     unsigned int yes = 1;
++    bool dns_failure;
+ 
+-    if (!inet_parse_passive(target, default_port, &ss)) {
++    if (!inet_parse_passive(target, default_port, &ss, true, &dns_failure)) {
++        if (dns_failure) {
++            /* DNS failure means asynchronous DNS resolution is in progress,
++             * or that the name does currently not resolve. */
++            return -EAGAIN;
++        }
+         return -EAFNOSUPPORT;
+     }
+     kernel_chooses_port = ss_get_port(&ss) == 0;
+@@ -783,7 +802,8 @@ inet_parse_address(const char *target_, struct sockaddr_storage *ss)
  {
      char *target = xstrdup(target_);
      char *host = unbracket(target);
@@ -56150,10 +56471,10 @@ index 4f1ffecf5d..38705cc51e 100644
          memset(ss, 0, sizeof *ss);
      }
 diff --git a/lib/socket-util.h b/lib/socket-util.h
-index 9ccb7d4cc4..bf66393df9 100644
+index 9ccb7d4cc4..4eec627e3e 100644
 --- a/lib/socket-util.h
 +++ b/lib/socket-util.h
-@@ -49,7 +49,8 @@ ovs_be32 guess_netmask(ovs_be32 ip);
+@@ -49,12 +49,14 @@ ovs_be32 guess_netmask(ovs_be32 ip);
  void inet_parse_host_port_tokens(char *s, char **hostp, char **portp);
  void inet_parse_port_host_tokens(char *s, char **portp, char **hostp);
  bool inet_parse_active(const char *target, int default_port,
@@ -56163,6 +56484,13 @@ index 9ccb7d4cc4..bf66393df9 100644
  int inet_open_active(int style, const char *target, int default_port,
                       struct sockaddr_storage *ssp, int *fdp, uint8_t dscp);
  
+ bool inet_parse_passive(const char *target, int default_port,
+-                        struct sockaddr_storage *ssp);
++                        struct sockaddr_storage *ssp,
++                        bool resolve_host, bool *dns_failure);
+ int inet_open_passive(int style, const char *target, int default_port,
+                       struct sockaddr_storage *ssp, uint8_t dscp,
+                       bool kernel_print_port);
 diff --git a/lib/sset.c b/lib/sset.c
 index b2e3f43ec9..6fbaa9d60d 100644
 --- a/lib/sset.c
@@ -56324,7 +56652,7 @@ index fcaddf10ad..71039e24f1 100644
  
  /* Attempts to guess the content type of a stream whose first few bytes were
 diff --git a/lib/tc.c b/lib/tc.c
-index adb2d3182a..485e4834f8 100644
+index adb2d3182a..7298ce6901 100644
 --- a/lib/tc.c
 +++ b/lib/tc.c
 @@ -84,6 +84,11 @@ struct flower_key_to_pedit {
@@ -56526,7 +56854,32 @@ index adb2d3182a..485e4834f8 100644
      action->type = TC_ACT_PEDIT;
  
      return 0;
-@@ -1314,8 +1343,8 @@ nl_parse_act_gact(struct nlattr *options, struct tc_flower *flower)
+@@ -1305,7 +1334,23 @@ get_user_hz(void)
+ static void
+ nl_parse_tcf(const struct tcf_t *tm, struct tc_flower *flower)
+ {
+-    flower->lastused = time_msec() - (tm->lastuse * 1000 / get_user_hz());
++    uint64_t lastused;
++
++    /* On creation both tm->install and tm->lastuse are set to jiffies
++     * by the kernel. So if both values are the same, the flow has not been
++     * used yet.
++     *
++     * Note that tm->firstuse can not be used due to some kernel bug, i.e.,
++     * hardware offloaded flows do not update tm->firstuse. */
++    if (tm->lastuse == tm->install) {
++        lastused = 0;
++    } else {
++        lastused = time_msec() - (tm->lastuse * 1000 / get_user_hz());
++    }
++
++    if (flower->lastused < lastused) {
++        flower->lastused = lastused;
++    }
+ }
+ 
+ static int
+@@ -1314,8 +1359,8 @@ nl_parse_act_gact(struct nlattr *options, struct tc_flower *flower)
      struct nlattr *gact_attrs[ARRAY_SIZE(gact_policy)];
      const struct tc_gact *p;
      struct nlattr *gact_parms;
@@ -56536,7 +56889,7 @@ index adb2d3182a..485e4834f8 100644
  
      if (!nl_parse_nested(options, gact_policy, gact_attrs,
                           ARRAY_SIZE(gact_policy))) {
-@@ -1335,8 +1364,9 @@ nl_parse_act_gact(struct nlattr *options, struct tc_flower *flower)
+@@ -1335,8 +1380,9 @@ nl_parse_act_gact(struct nlattr *options, struct tc_flower *flower)
          return EINVAL;
      }
  
@@ -56548,7 +56901,7 @@ index adb2d3182a..485e4834f8 100644
  
      return 0;
  }
-@@ -1357,9 +1387,9 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
+@@ -1357,9 +1403,9 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
      struct nlattr *mirred_attrs[ARRAY_SIZE(mirred_policy)];
      const struct tc_mirred *m;
      const struct nlattr *mirred_parms;
@@ -56559,7 +56912,7 @@ index adb2d3182a..485e4834f8 100644
  
      if (!nl_parse_nested(options, mirred_policy, mirred_attrs,
                           ARRAY_SIZE(mirred_policy))) {
-@@ -1387,8 +1417,8 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
+@@ -1387,8 +1433,8 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
      action->type = TC_ACT_OUTPUT;
  
      mirred_tm = mirred_attrs[TCA_MIRRED_TM];
@@ -56570,7 +56923,7 @@ index adb2d3182a..485e4834f8 100644
  
      return 0;
  }
-@@ -1487,7 +1517,9 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
+@@ -1487,7 +1533,9 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
                  if (ipv4_max) {
                      ovs_be32 addr = nl_attr_get_be32(ipv4_max);
  
@@ -56581,7 +56934,7 @@ index adb2d3182a..485e4834f8 100644
                  }
              } else if (ipv6_min) {
                  action->ct.range.ip_family = AF_INET6;
-@@ -1496,7 +1528,9 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
+@@ -1496,7 +1544,9 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
                  if (ipv6_max) {
                      struct in6_addr addr = nl_attr_get_in6_addr(ipv6_max);
  
@@ -56592,7 +56945,7 @@ index adb2d3182a..485e4834f8 100644
                  }
              }
  
-@@ -1504,6 +1538,10 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
+@@ -1504,6 +1554,10 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
                  action->ct.range.port.min = nl_attr_get_be16(port_min);
                  if (port_max) {
                      action->ct.range.port.max = nl_attr_get_be16(port_max);
@@ -56603,7 +56956,7 @@ index adb2d3182a..485e4834f8 100644
                  }
              }
          }
-@@ -1698,24 +1736,89 @@ static const struct nl_policy act_policy[] = {
+@@ -1698,24 +1752,89 @@ static const struct nl_policy act_policy[] = {
      [TCA_ACT_STATS] = { .type = NL_A_NESTED, .optional = false, },
  };
  
@@ -56702,7 +57055,7 @@ index adb2d3182a..485e4834f8 100644
      int err = 0;
  
      if (!nl_parse_nested(action, act_policy, action_attrs,
-@@ -1763,21 +1866,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower,
+@@ -1763,21 +1882,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower,
          flower->act_cookie.len = nl_attr_get_size(act_cookie);
      }
  
@@ -56726,7 +57079,7 @@ index adb2d3182a..485e4834f8 100644
  }
  
  #define TCA_ACT_MIN_PRIO 1
-@@ -1964,14 +2054,21 @@ tc_dump_tc_chain_start(struct tcf_id *id, struct nl_dump *dump)
+@@ -1964,14 +2070,21 @@ tc_dump_tc_chain_start(struct tcf_id *id, struct nl_dump *dump)
  }
  
  int
@@ -56749,7 +57102,7 @@ index adb2d3182a..485e4834f8 100644
  int
  tc_get_flower(struct tcf_id *id, struct tc_flower *flower)
  {
-@@ -1980,6 +2077,7 @@ tc_get_flower(struct tcf_id *id, struct tc_flower *flower)
+@@ -1980,6 +2093,7 @@ tc_get_flower(struct tcf_id *id, struct tc_flower *flower)
      int error;
  
      request_from_tcf_id(id, 0, RTM_GETTFILTER, NLM_F_ECHO, &request);
@@ -56757,7 +57110,7 @@ index adb2d3182a..485e4834f8 100644
      error = tc_transact(&request, &reply);
      if (error) {
          return error;
-@@ -2399,14 +2497,14 @@ nl_msg_put_act_flags(struct ofpbuf *request) {
+@@ -2399,14 +2513,14 @@ nl_msg_put_act_flags(struct ofpbuf *request) {
   * first_word_mask/last_word_mask - the mask to use for the first/last read
   * (as we read entire words). */
  static void
@@ -56775,7 +57128,7 @@ index adb2d3182a..485e4834f8 100644
  
      max_offset = m->offset + m->size;
      start_offset = ROUND_DOWN(m->offset, 4);
-@@ -2473,7 +2571,8 @@ csum_update_flag(struct tc_flower *flower,
+@@ -2473,7 +2587,8 @@ csum_update_flag(struct tc_flower *flower,
  
  static int
  nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,
@@ -56785,7 +57138,7 @@ index adb2d3182a..485e4834f8 100644
  {
      struct {
          struct tc_pedit sel;
-@@ -2497,12 +2596,12 @@ nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,
+@@ -2497,12 +2612,12 @@ nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,
              continue;
          }
  
@@ -56801,7 +57154,7 @@ index adb2d3182a..485e4834f8 100644
  
              if (j == 0) {
                  mask_word &= first_word_mask;
-@@ -2556,6 +2655,29 @@ nl_msg_put_flower_acts_release(struct ofpbuf *request, uint16_t act_index)
+@@ -2556,6 +2671,29 @@ nl_msg_put_flower_acts_release(struct ofpbuf *request, uint16_t act_index)
      nl_msg_end_nested(request, act_offset);
  }
  
@@ -56831,7 +57184,7 @@ index adb2d3182a..485e4834f8 100644
  static int
  nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
  {
-@@ -2572,20 +2694,22 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
+@@ -2572,20 +2710,22 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
  
          action = flower->actions;
          for (i = 0; i < flower->action_count; i++, action++) {
@@ -56860,7 +57213,7 @@ index adb2d3182a..485e4834f8 100644
                  }
              }
              break;
-@@ -2792,13 +2916,16 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
+@@ -2792,13 +2932,16 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
      struct in6_addr *ipv6_dst_mask = &flower->mask.tunnel.ipv6.ipv6_dst;
      struct in6_addr *ipv6_src = &flower->key.tunnel.ipv6.ipv6_src;
      struct in6_addr *ipv6_dst = &flower->key.tunnel.ipv6.ipv6_dst;
@@ -56878,7 +57231,7 @@ index adb2d3182a..485e4834f8 100644
  
      if (ipv4_dst_mask || ipv4_src_mask) {
          nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
-@@ -2824,8 +2951,15 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
+@@ -2824,8 +2967,15 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
          nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TTL, ttl);
          nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TTL_MASK, ttl_mask);
      }
@@ -56895,7 +57248,7 @@ index adb2d3182a..485e4834f8 100644
      }
      if (id_mask) {
          nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_KEY_ID, id);
-@@ -2914,13 +3048,13 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
+@@ -2914,13 +3064,13 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
              FLOWER_PUT_MASKED_VALUE(icmp_code, TCA_FLOWER_KEY_ICMPV6_CODE);
              FLOWER_PUT_MASKED_VALUE(icmp_type, TCA_FLOWER_KEY_ICMPV6_TYPE);
          }
@@ -56914,7 +57267,7 @@ index adb2d3182a..485e4834f8 100644
      if (host_eth_type == ETH_P_IP) {
              FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_src, TCA_FLOWER_KEY_IPV4_SRC);
              FLOWER_PUT_MASKED_VALUE(ipv4.ipv4_dst, TCA_FLOWER_KEY_IPV4_DST);
-@@ -2993,12 +3127,79 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
+@@ -2993,12 +3143,79 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
      return 0;
  }
  
@@ -56995,7 +57348,7 @@ index adb2d3182a..485e4834f8 100644
          return false;
      }
  
-@@ -3011,8 +3212,8 @@ cmp_tc_flower_match_action(const struct tc_flower *a,
+@@ -3011,8 +3228,8 @@ cmp_tc_flower_match_action(const struct tc_flower *a,
          uint8_t key_b = ((uint8_t *)&b->key)[i] & mask;
  
          if (key_a != key_b) {
@@ -57006,7 +57359,7 @@ index adb2d3182a..485e4834f8 100644
              return false;
          }
      }
-@@ -3022,14 +3223,15 @@ cmp_tc_flower_match_action(const struct tc_flower *a,
+@@ -3022,14 +3239,15 @@ cmp_tc_flower_match_action(const struct tc_flower *a,
      const struct tc_action *action_b = b->actions;
  
      if (a->action_count != b->action_count) {
@@ -57026,7 +57379,7 @@ index adb2d3182a..485e4834f8 100644
          }
      }
 diff --git a/lib/tc.h b/lib/tc.h
-index a147ca461d..55bed0853a 100644
+index a147ca461d..35068cbd89 100644
 --- a/lib/tc.h
 +++ b/lib/tc.h
 @@ -256,11 +256,23 @@ struct tc_action {
@@ -57053,7 +57406,15 @@ index a147ca461d..55bed0853a 100644
  enum tc_offloaded_state {
      TC_OFFLOADED_STATE_UNDEFINED,
      TC_OFFLOADED_STATE_IN_HW,
-@@ -330,15 +342,10 @@ struct tc_flower {
+@@ -307,7 +319,6 @@ static inline bool
+ is_tcf_id_eq(struct tcf_id *id1, struct tcf_id *id2)
+ {
+     return id1->prio == id2->prio
+-           && id1->handle == id2->handle
+            && id1->handle == id2->handle
+            && id1->hook == id2->hook
+            && id1->block_id == id2->block_id
+@@ -330,15 +341,10 @@ struct tc_flower {
      int action_count;
      struct tc_action actions[TCA_ACT_MAX_NUM];
  
@@ -57071,7 +57432,7 @@ index a147ca461d..55bed0853a 100644
      uint32_t csum_update_flags;
  
      bool tunnel;
-@@ -352,15 +359,9 @@ struct tc_flower {
+@@ -352,15 +358,9 @@ struct tc_flower {
      enum tc_offload_policy tc_policy;
  };
  
@@ -57905,7 +58266,7 @@ index 78a54c715d..109940ad2a 100644
              oftrace_node_destroy(node);
          }
 diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
-index 57f94df544..fe47090584 100644
+index 57f94df544..adb53f8031 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,
@@ -57930,7 +58291,15 @@ index 57f94df544..fe47090584 100644
          ovsthread_once_done(&once);
      }
  }
-@@ -3099,6 +3107,31 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED,
+@@ -1868,6 +1876,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);
++            new_ukey->dump_seq = old_ukey->dump_seq;
+             ovsrcu_postpone(ukey_delete__, old_ukey);
+             transition_ukey(old_ukey, UKEY_DELETED);
+             transition_ukey(new_ukey, UKEY_VISIBLE);
+@@ -3099,6 +3108,31 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED,
      unixctl_command_reply(conn, "");
  }
  
@@ -57999,7 +58368,7 @@ 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..8a28b29d4c 100644
+index 578cbfe581..97614ec4d7 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)
@@ -58321,7 +58690,7 @@ index 578cbfe581..8a28b29d4c 100644
  
      /* If ofp_port in flow sample action is equel to ofp_port,
       * this sample action is a input port action. */
-@@ -7609,6 +7676,10 @@ xlate_wc_finish(struct xlate_ctx *ctx)
+@@ -7609,6 +7676,43 @@ xlate_wc_finish(struct xlate_ctx *ctx)
              ctx->wc->masks.vlans[i].tci = 0;
          }
      }
@@ -58329,10 +58698,43 @@ index 578cbfe581..8a28b29d4c 100644
 +    if (!flow_tnl_dst_is_set(&ctx->xin->upcall_flow->tunnel)) {
 +        memset(&ctx->wc->masks.tunnel, 0, sizeof ctx->wc->masks.tunnel);
 +    }
++}
++
++/* This will optimize the odp actions generated. For now, it will remove
++ * trailing clone actions that are unnecessary. */
++static void
++xlate_optimize_odp_actions(struct xlate_in *xin)
++{
++    struct ofpbuf *actions = xin->odp_actions;
++    struct nlattr *last_action = NULL;
++    struct nlattr *a;
++    int left;
++
++    if (!actions) {
++        return;
++    }
++
++    /* Find the last action in the set. */
++    NL_ATTR_FOR_EACH (a, left, actions->data, actions->size) {
++        last_action = a;
++    }
++
++    /* Remove the trailing clone() action, by directly embedding the nested
++     * actions. */
++    if (last_action && nl_attr_type(last_action) == OVS_ACTION_ATTR_CLONE) {
++        void *dest;
++
++        nl_msg_reset_size(actions,
++                          (unsigned char *) last_action -
++                          (unsigned char *) actions->data);
++
++        dest = nl_msg_put_uninit(actions, nl_attr_get_size(last_action));
++        memmove(dest, nl_attr_get(last_action), nl_attr_get_size(last_action));
++    }
  }
  
  /* Translates the flow, actions, or rule in 'xin' into datapath actions in
-@@ -7784,6 +7855,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
+@@ -7784,6 +7888,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
          goto exit;
      }
  
@@ -58345,6 +58747,17 @@ index 578cbfe581..8a28b29d4c 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 +8140,10 @@ exit:
+         if (xin->odp_actions) {
+             ofpbuf_clear(xin->odp_actions);
+         }
++    } else {
++        /* In the non-error case, see if we can further optimize the datapath
++         * rules by removing redundant (clone) actions. */
++        xlate_optimize_odp_actions(xin);
+     }
+ 
+     /* Install drop action if datapath supports explicit drop action. */
 diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
 index 851088d794..2ba90e999c 100644
 --- a/ofproto/ofproto-dpif-xlate.h
@@ -58965,7 +59378,7 @@ index 9f44007d97..ca80c28235 100644
              break;
          }
 diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
-index 351c39d8aa..916a1f414e 100644
+index 351c39d8aa..17868f5b72 100644
 --- a/ovsdb/jsonrpc-server.c
 +++ b/ovsdb/jsonrpc-server.c
 @@ -197,9 +197,9 @@ ovsdb_jsonrpc_server_remove_db(struct ovsdb_jsonrpc_server *svr,
@@ -58992,7 +59405,60 @@ index 351c39d8aa..916a1f414e 100644
          struct ovsdb_jsonrpc_remote *remote = node->data;
          struct ovsdb_jsonrpc_options *options
              = shash_find_data(new_remotes, node->name);
-@@ -585,9 +585,9 @@ ovsdb_jsonrpc_session_set_options(struct ovsdb_jsonrpc_session *session,
+@@ -267,25 +267,36 @@ ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *svr,
+     int error;
+ 
+     error = jsonrpc_pstream_open(name, &listener, options->dscp);
+-    if (error && error != EAFNOSUPPORT) {
+-        VLOG_ERR_RL(&rl, "%s: listen failed: %s", name, ovs_strerror(error));
+-        return NULL;
+-    }
++    switch (error) {
++    case 0:
++    case EAFNOSUPPORT:
++        remote = xmalloc(sizeof *remote);
++        remote->server = svr;
++        remote->listener = listener;
++        ovs_list_init(&remote->sessions);
++        remote->dscp = options->dscp;
++        remote->read_only = options->read_only;
++        remote->role = nullable_xstrdup(options->role);
++        shash_add(&svr->remotes, name, remote);
++        if (!listener) {
++            /* Not a listener, attempt creation of active jsonrpc session. */
++            ovsdb_jsonrpc_session_create(remote,
++                                         jsonrpc_session_open(name, true),
++                                         svr->read_only || remote->read_only);
++        }
++        return remote;
+ 
+-    remote = xmalloc(sizeof *remote);
+-    remote->server = svr;
+-    remote->listener = listener;
+-    ovs_list_init(&remote->sessions);
+-    remote->dscp = options->dscp;
+-    remote->read_only = options->read_only;
+-    remote->role = nullable_xstrdup(options->role);
+-    shash_add(&svr->remotes, name, remote);
++    case EAGAIN:
++        VLOG_DBG_RL(&rl, "%s: listen failed: "
++                         "DNS resolution in progress or host not found", name);
++        return NULL;
+ 
+-    if (!listener) {
+-        ovsdb_jsonrpc_session_create(remote, jsonrpc_session_open(name, true),
+-                                      svr->read_only || remote->read_only);
++    default:
++        VLOG_ERR_RL(&rl, "%s: listen failed: %s", name,
++                    ovs_strerror(error));
++        return NULL;
+     }
+-    return remote;
++    OVS_NOT_REACHED();
+ }
+ 
+ static void
+@@ -585,9 +596,9 @@ ovsdb_jsonrpc_session_set_options(struct ovsdb_jsonrpc_session *session,
  static void
  ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *remote)
  {
@@ -59004,7 +59470,7 @@ index 351c39d8aa..916a1f414e 100644
          int error = ovsdb_jsonrpc_session_run(s);
          if (error) {
              ovsdb_jsonrpc_session_close(s);
-@@ -642,9 +642,9 @@ ovsdb_jsonrpc_session_get_memory_usage_all(
+@@ -642,9 +653,9 @@ ovsdb_jsonrpc_session_get_memory_usage_all(
  static void
  ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *remote)
  {
@@ -59016,7 +59482,7 @@ index 351c39d8aa..916a1f414e 100644
          ovsdb_jsonrpc_session_close(s);
      }
  }
-@@ -660,9 +660,9 @@ static void
+@@ -660,9 +671,9 @@ static void
  ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote *remote,
                                      bool force, const char *comment)
  {
@@ -59028,7 +59494,7 @@ index 351c39d8aa..916a1f414e 100644
          if (force || !s->db_change_aware) {
              jsonrpc_session_force_reconnect(s->js);
              if (comment && jsonrpc_session_is_connected(s->js)) {
-@@ -909,9 +909,9 @@ error:
+@@ -909,9 +920,9 @@ error:
  static void
  ovsdb_jsonrpc_session_unlock_all(struct ovsdb_jsonrpc_session *s)
  {
@@ -59040,7 +59506,7 @@ index 351c39d8aa..916a1f414e 100644
          ovsdb_jsonrpc_session_unlock__(waiter);
      }
  }
-@@ -1198,8 +1198,8 @@ static void
+@@ -1198,8 +1209,8 @@ static void
  ovsdb_jsonrpc_trigger_remove__(struct ovsdb_jsonrpc_session *s,
                                 struct ovsdb *db)
  {
@@ -59051,7 +59517,7 @@ index 351c39d8aa..916a1f414e 100644
          if (!db || t->trigger.db == db) {
              ovsdb_jsonrpc_trigger_complete(t);
          }
-@@ -1226,8 +1226,8 @@ ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *s)
+@@ -1226,8 +1237,8 @@ ovsdb_jsonrpc_trigger_complete_all(struct ovsdb_jsonrpc_session *s)
  static void
  ovsdb_jsonrpc_trigger_complete_done(struct ovsdb_jsonrpc_session *s)
  {
@@ -59062,7 +59528,7 @@ index 351c39d8aa..916a1f414e 100644
          ovsdb_jsonrpc_trigger_complete(trigger);
      }
  }
-@@ -1688,8 +1688,8 @@ ovsdb_jsonrpc_monitor_preremove_db(struct ovsdb_jsonrpc_session *s,
+@@ -1688,8 +1699,8 @@ ovsdb_jsonrpc_monitor_preremove_db(struct ovsdb_jsonrpc_session *s,
  {
      ovs_assert(db);
  
@@ -59073,7 +59539,7 @@ index 351c39d8aa..916a1f414e 100644
          if (m->db == db) {
              ovsdb_jsonrpc_monitor_destroy(m, true);
          }
-@@ -1700,9 +1700,9 @@ ovsdb_jsonrpc_monitor_preremove_db(struct ovsdb_jsonrpc_session *s,
+@@ -1700,9 +1711,9 @@ ovsdb_jsonrpc_monitor_preremove_db(struct ovsdb_jsonrpc_session *s,
  static void
  ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s)
  {
@@ -61922,7 +62388,7 @@ index 757cf7186e..fe475e7b38 100644
 +
 +AT_CLEANUP
 diff --git a/tests/nsh.at b/tests/nsh.at
-index 4d49f12017..91ded1445d 100644
+index 4d49f12017..6b7b6856f2 100644
 --- a/tests/nsh.at
 +++ b/tests/nsh.at
 @@ -27,7 +27,7 @@ AT_CHECK([
@@ -62015,6 +62481,26 @@ index 4d49f12017..91ded1445d 100644
  
  bridge("br0")
  -------------
+@@ -724,7 +724,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789))
++recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3000,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(4789)
+ tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3000,si=255), packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x1)
+ tunnel(tun_id=0x0,src=30.0.0.1,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x1),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
+ ])
+@@ -778,8 +778,8 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789))
+-tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(spi=0x3020,si=255), packets:1, bytes:108, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789))
++recirc_id(0),in_port(4),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20/255.255.255.248,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,push_nsh(flags=0,ttl=63,mdtype=1,np=1,spi=0x3020,si=255,c1=0x0,c2=0x0,c3=0x0,c4=0x0),tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(4789)
++tunnel(tun_id=0x0,src=20.0.0.1,dst=20.0.0.2,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(spi=0x3020,si=255), packets:1, bytes:108, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=11:22:33:44:55:66),set(nsh(spi=0x3020,si=254)),pop_eth,tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.3,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000004,vni=0x0)),out_port(2)),set(ipv4(src=30.0.0.2,dst=30.0.0.3)),tnl_pop(4789)
+ tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0),in_port(4789),packet_type(ns=1,id=0x894f),eth_type(0x894f),nsh(np=1,spi=0x3020,si=254), packets:1, bytes:108, used:0.0s, actions:pop_nsh(),recirc(0x2)
+ tunnel(tun_id=0x0,src=30.0.0.2,dst=30.0.0.3,flags(-df-csum+key)),recirc_id(0x2),in_port(4789),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:03),6
+ ])
 diff --git a/tests/odp.at b/tests/odp.at
 index 4d08c59ca6..fce6a4f2bc 100644
 --- a/tests/odp.at
@@ -62133,7 +62619,7 @@ index 2c7e163bd6..7be6628c34 100644
  AT_CLEANUP
  
 diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
-index 7c2edeb9d4..bc981f8fc6 100644
+index 7c2edeb9d4..cc5340f376 100644
 --- a/tests/ofproto-dpif.at
 +++ b/tests/ofproto-dpif.at
 @@ -29,6 +29,58 @@ AT_CHECK([ovs-appctl revalidator/wait])
@@ -63503,7 +63989,48 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP(["/stack underflow/d"])
-@@ -9855,7 +10054,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+@@ -8717,6 +8916,40 @@ AT_CHECK([tail -1 stdout], [0],
+ OVS_VSWITCHD_STOP
+ AT_CLEANUP
+ 
++AT_SETUP([ofproto-dpif - patch ports - no additional clone])
++OVS_VSWITCHD_START(
++  [add-port br0 p0 -- set Interface p0 type=dummy ofport_request=1 -- dnl
++   add-port br0 p1 -- set Interface p1 type=patch dnl
++                                       options:peer=p2 ofport_request=2 -- dnl
++   add-br br1 -- dnl
++   set bridge br1 other-config:hwaddr=aa:66:aa:66:00:00 -- dnl
++   set bridge br1 datapath-type=dummy other-config:datapath-id=1234 dnl
++                  fail-mode=secure -- dnl
++   add-port br1 p2 -- set Interface p2 type=patch dnl
++                                       options:peer=p1 -- dnl
++   add-port br1 p3 -- set Interface p3 type=dummy ofport_request=3])
++
++AT_DATA([flows-br0.txt], [dnl
++priority=10,tcp,action=push:NXM_OF_IN_PORT[],resubmit(,65),pop:NXM_OF_IN_PORT[]
++table=65,priority=10,ip,in_port=p0,action=p1
++])
++
++AT_DATA([flows-br1.txt], [dnl
++priority=100,in_port=p2,tcp,ct_state=-trk,action=ct(table=0,zone=1)
++priority=100,in_port=p2,tcp,ct_state=+trk+est,ct_zone=1,action=p3
++])
++
++AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt])
++AT_CHECK([ovs-ofctl --bundle add-flows br1 flows-br1.txt])
++
++AT_CHECK([ovs-appctl ofproto/trace br0 in_port=p0,tcp --ct-next 'trk,est' | dnl
++          grep  "Datapath actions:" | grep -q clone],
++         [1], [], [],
++         [ovs-appctl ofproto/trace br0 in_port=p0,tcp --ct-next 'trk,est'])
++
++OVS_TRAFFIC_VSWITCHD_STOP
++AT_CLEANUP
++
+ dnl ----------------------------------------------------------------------
+ AT_BANNER([ofproto-dpif -- megaflows])
+ 
+@@ -9855,7 +10088,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
  
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via no_match) data_len=86 (unbuffered)
@@ -63512,7 +64039,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -9906,7 +10105,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+@@ -9906,7 +10139,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
  
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via action) data_len=86 (unbuffered)
@@ -63521,7 +64048,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -10166,10 +10365,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10166,10 +10399,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output. We only see the latter two packets, not the first.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x0 total_len=106 reg0=0x1,reg1=0x4d2,reg2=0x1,reg3=0x1,reg4=0x1,in_port=1 (via action) data_len=106 (unbuffered)
@@ -63534,7 +64061,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl -P nxt_packet_in --detach --no-chdir --pidfile 2> ofctl_monitor.log])
-@@ -10187,10 +10386,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10187,10 +10420,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output. We should see both packets
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x0 total_len=106 reg0=0x1,reg1=0x4d2,reg2=0x1,reg3=0x1,reg4=0x1,in_port=1 (via action) data_len=106 (unbuffered)
@@ -63547,7 +64074,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -10239,10 +10438,10 @@ dnl Note that the first packet doesn't have the ct_state bits set. This
+@@ -10239,10 +10472,10 @@ dnl Note that the first packet doesn't have the ct_state bits set. This
  dnl happens because the ct_state field is available only after recirc.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered)
@@ -63560,7 +64087,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl -P nxt_packet_in --detach --no-chdir --pidfile 2> ofctl_monitor.log])
-@@ -10261,10 +10460,10 @@ dnl Note that the first packet doesn't have the ct_state bits set. This
+@@ -10261,10 +10494,10 @@ dnl Note that the first packet doesn't have the ct_state bits set. This
  dnl happens because the ct_state field is available only after recirc.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered)
@@ -63573,7 +64100,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  dnl
-@@ -10320,9 +10519,9 @@ dnl Note that the first packet doesn't have the ct_state bits set. This
+@@ -10320,9 +10553,9 @@ dnl Note that the first packet doesn't have the ct_state bits set. This
  dnl happens because the ct_state field is available only after recirc.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=126 in_port=1 (via action) data_len=126 (unbuffered)
@@ -63585,7 +64112,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -10433,7 +10632,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10433,7 +10666,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output. Only one reply must be there
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=106 ct_state=est|rpl|trk,ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ip,in_port=2 (via action) data_len=106 (unbuffered)
@@ -63594,7 +64121,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  dnl
  OFPT_ECHO_REQUEST (xid=0x0): 0 bytes of payload
  ])
-@@ -10467,7 +10666,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10467,7 +10700,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 ct_state=inv|trk,ipv6,in_port=2 (via action) data_len=86 (unbuffered)
@@ -63603,7 +64130,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -10523,16 +10722,16 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10523,16 +10756,16 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output. We only see the latter two packets (for each zone), not the first.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered)
@@ -63624,7 +64151,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -10579,10 +10778,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10579,10 +10812,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output. We only see the latter two packets, not the first.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered)
@@ -63637,7 +64164,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -10629,10 +10828,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10629,10 +10862,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output. We only see the first and the last packet
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=47 ct_state=new|trk,ct_nw_src=172.16.0.1,ct_nw_dst=172.16.0.2,ct_nw_proto=17,ct_tp_src=41614,ct_tp_dst=5555,ip,in_port=1 (via action) data_len=47 (unbuffered)
@@ -63650,7 +64177,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -10681,19 +10880,19 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10681,19 +10914,19 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered)
@@ -63675,7 +64202,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -10738,10 +10937,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -10738,10 +10971,10 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=106 ct_state=est|rpl|trk,ct_label=0x1,ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2,ct_nw_proto=17,ct_tp_src=1,ct_tp_dst=2,ip,in_port=2 (via action) data_len=106 (unbuffered)
@@ -63688,7 +64215,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -11152,16 +11351,16 @@ dnl Note that the first packet doesn't have the ct_state bits set. This
+@@ -11152,16 +11385,16 @@ dnl Note that the first packet doesn't have the ct_state bits set. This
  dnl happens because the ct_state field is available only after recirc.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=106 in_port=1 (via action) data_len=106 (unbuffered)
@@ -63709,7 +64236,7 @@ index 7c2edeb9d4..bc981f8fc6 100644
  ])
  
  dnl The next test verifies that ct_clear at the datapath only gets executed
-@@ -11235,13 +11434,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+@@ -11235,13 +11468,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
  dnl Check this output.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=106 ct_state=est|rpl|trk,ct_nw_src=10.1.2.100,ct_nw_dst=10.1.2.200,ct_nw_proto=17,ct_tp_src=6,ct_tp_dst=6,ip,in_port=2 (via action) data_len=106 (unbuffered)
@@ -64928,6 +65455,105 @@ index 876cb836cd..4a183bf186 100644
              --remote=ptcp:0:127.0.0.1                             dnl
              db.tmp], [0], [stdout], [stderr])
  PARSE_LISTENING_PORT([listener.log], [BAD_TCP_PORT])
+diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at
+index 054dcc9ccf..3b5c66fe52 100644
+--- a/tests/packet-type-aware.at
++++ b/tests/packet-type-aware.at
+@@ -326,7 +326,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys))
++recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys)
+ tunnel(src=30.0.0.1,dst=30.0.0.3,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:03)),n3
+ ])
+ 
+@@ -344,7 +344,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(gre_sys))
++recirc_id(0),in_port(n1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=20.0.0.1,dst=20.0.0.2)),tnl_pop(gre_sys)
+ tunnel(src=20.0.0.1,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=46:1e:7d:1a:95:a1),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:02)),n2
+ ])
+ 
+@@ -362,7 +362,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys))
++recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
+ tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=3a:6d:d2:09:9c:ab),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no), packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:01)),n1
+ ])
+ 
+@@ -380,8 +380,8 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys))
+-tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys))
++recirc_id(0),in_port(n2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
++tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.30,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:03,src=aa:55:00:00:00:01,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.3,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p1)),set(ipv4(src=30.0.0.1,dst=30.0.0.3)),tnl_pop(gre_sys)
+ tunnel(src=30.0.0.1,dst=30.0.0.3,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=1e:2c:e9:2a:66:9e),eth_type(0x0800),ipv4(dst=192.168.10.30,frag=no), packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:03)),n3
+ ])
+ 
+@@ -399,9 +399,9 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
++recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
+ tunnel(src=10.0.0.2,dst=10.0.0.1,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,frag=no), packets:1, bytes:84, used:0.0s, actions:push_eth(src=00:00:00:00:00:00,dst=aa:55:aa:55:00:01),n1
+-tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:84, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys))
++tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.10,tos=0/0x3,frag=no), packets:1, bytes:84, used:0.0s, actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:01,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=20.0.0.2,dst=20.0.0.1,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p2)),set(ipv4(src=10.0.0.2,dst=10.0.0.1)),tnl_pop(gre_sys)
+ ])
+ 
+ # Clear up megaflow cache
+@@ -418,7 +418,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
++recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
+ tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=0,id=0),eth(dst=46:1e:7d:1a:95:a1),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:98, used:0.0s, actions:set(eth(dst=aa:55:aa:55:00:02)),n2
+ ])
+ 
+@@ -504,7 +504,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
++recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys)
+ tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),eth_type(0x0800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop
+ ])
+ 
+@@ -726,7 +726,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2)
++recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2
+ ])
+ 
+ AT_CHECK([
+@@ -814,7 +814,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2)
++recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2
+ ])
+ 
+ AT_CHECK([
+@@ -892,7 +892,7 @@ ovs-appctl time/warp 1000
+ AT_CHECK([
+     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
+ ], [0], [flow-dump from the main thread:
+-recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:n1,pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2)
++recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:n1,pop_eth,tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=de:af:be:ef:ba:be,src=aa:55:00:00:00:02,dl_type=0x0800),ipv4(src=10.0.0.1,dst=10.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br2)),n2
+ ])
+ 
+ AT_CHECK([
 diff --git a/tests/pmd.at b/tests/pmd.at
 index a2f9d34a2a..a2832b544c 100644
 --- a/tests/pmd.at
@@ -65399,8 +66025,21 @@ index 86d633ac4f..f0aaae63eb 100644
  # VSCTL_ADD_DATAPATH_TABLE()
  #
  # Create system datapath table "system" for kernel tests in ovsdb
+diff --git a/tests/system-layer3-tunnels.at b/tests/system-layer3-tunnels.at
+index d21fd777dd..c37852b216 100644
+--- a/tests/system-layer3-tunnels.at
++++ b/tests/system-layer3-tunnels.at
+@@ -147,7 +147,7 @@ AT_CHECK([tail -1 stdout], [0],
+ dnl Check GRE tunnel push
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(3),eth(dst=f9:bc:12:44:34:b6,src=af:55:aa:55:00:03),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.92,proto=1,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4),header(size=38,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:03,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(2)),1)
++  [Datapath actions: tnl_push(tnl_port(4),header(size=38,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:03,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x6558))),out_port(2)),1
+ ])
+ 
+ OVS_VSWITCHD_STOP
 diff --git a/tests/system-offloads-traffic.at b/tests/system-offloads-traffic.at
-index 80bc1dd5c3..14a332f5ed 100644
+index 80bc1dd5c3..9f50f3b01d 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 |
@@ -65421,6 +66060,74 @@ index 80bc1dd5c3..14a332f5ed 100644
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
+@@ -168,3 +168,67 @@ 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])
++
++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,br0
++add in_port=ovs-p1,actions=ovs-p0,br0
++])
++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 | grep "eth_type(0x0800)" | sort | dnl
++          strip_recirc | strip_used | dnl
++          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:756/bytes:882/'],
++          [0], [dnl
++recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:882, used:0.0s, actions:3,1
++recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:882, used:0.0s, actions:2,1
++])
++
++AT_DATA([flows2.txt], [dnl
++modify in_port=ovs-p0,actions=ovs-p1
++modify in_port=ovs-p1,actions=ovs-p0
++])
++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 | grep "eth_type(0x0800)" | sort | dnl
++          strip_recirc | strip_used | dnl
++          sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:1596/bytes:1862/'],
++          [0], [dnl
++recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:19, bytes:1862, used:0.0s, actions:3
++recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:19, bytes:1862, used:0.0s, actions: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 | grep "eth_type(0x0800)" | sort | dnl
++          strip_recirc | strip_used | dnl
++          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:2436/bytes:2842/'],
++          [0], [dnl
++recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:29, bytes:2842, used:0.0s, actions:3,1
++recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:29, bytes:2842, used:0.0s, actions:2,1
++])
++
++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
@@ -65440,7 +66147,7 @@ index 1714273e35..270956d13f 100644
  dnl Delete ip address.
  AT_CHECK([ip addr del 10.0.0.17/24 dev p1-route], [0], [stdout])
 diff --git a/tests/system-traffic.at b/tests/system-traffic.at
-index f22d86e466..4808e78de3 100644
+index f22d86e466..d4c34c1291 100644
 --- a/tests/system-traffic.at
 +++ b/tests/system-traffic.at
 @@ -192,6 +192,46 @@ NS_CHECK_EXEC([at_ns0], [ping6 -s 3200 -q -c 3 -i 0.3 -w 2 fc00:1::2 | FORMAT_PI
@@ -65836,7 +66543,77 @@ index f22d86e466..4808e78de3 100644
  ])
  
  OVS_TRAFFIC_VSWITCHD_STOP
-@@ -1765,10 +1917,10 @@ dnl p1(at_ns1) interface
+@@ -1738,6 +1890,69 @@ masks-cache:size:256
+ OVS_TRAFFIC_VSWITCHD_STOP
+ AT_CLEANUP
+ 
++AT_SETUP([datapath - simulated flow action update])
++OVS_TRAFFIC_VSWITCHD_START()
++
++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,br0
++add in_port=ovs-p1,actions=ovs-p0,br0
++])
++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 | grep "eth_type(0x0800)" | sort | dnl
++          strip_recirc | strip_used | dnl
++          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:756/bytes:882/'],
++          [0], [dnl
++recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:882, used:0.0s, actions:3,1
++recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:9, bytes:882, used:0.0s, actions:2,1
++])
++
++AT_DATA([flows2.txt], [dnl
++modify in_port=ovs-p0,actions=ovs-p1
++modify in_port=ovs-p1,actions=ovs-p0
++])
++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 | grep "eth_type(0x0800)" | sort | dnl
++          strip_recirc | strip_used | dnl
++          sed -e 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:1596/bytes:1862/'],
++          [0], [dnl
++recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:19, bytes:1862, used:0.0s, actions:3
++recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:19, bytes:1862, used:0.0s, actions: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 | grep "eth_type(0x0800)" | sort | dnl
++          strip_recirc | strip_used | dnl
++          sed 's/,packet_type(ns=[[0-9]]*,id=[[0-9]]*),/,/;s/,eth(),/,/;s/bytes:2436/bytes:2842/'],
++          [0], [dnl
++recirc_id(<recirc>),in_port(2),eth_type(0x0800),ipv4(frag=no), packets:29, bytes:2842, used:0.0s, actions:3,1
++recirc_id(<recirc>),in_port(3),eth_type(0x0800),ipv4(frag=no), packets:29, bytes:2842, used:0.0s, actions:2,1
++])
++
++OVS_TRAFFIC_VSWITCHD_STOP
++AT_CLEANUP
++
+ AT_BANNER([MPLS])
+ 
+ AT_SETUP([mpls - encap header dp-support])
+@@ -1765,10 +1980,10 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
  
  dnl Check the expected mpls encapsulated packet on the egress interface
@@ -65851,7 +66628,7 @@ index f22d86e466..4808e78de3 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -1797,10 +1949,10 @@ dnl p1(at_ns1) interface
+@@ -1797,10 +2012,10 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
  
  dnl Check the expected mpls encapsulated packet on the egress interface
@@ -65866,7 +66643,7 @@ index f22d86e466..4808e78de3 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -1830,10 +1982,10 @@ dnl p1(at_ns1) interface
+@@ -1830,10 +2045,10 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
  
  dnl Check the expected mpls encapsulated packet on the egress interface
@@ -65881,7 +66658,7 @@ index f22d86e466..4808e78de3 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -1862,10 +2014,10 @@ dnl p1(at_ns1) interface
+@@ -1862,10 +2077,10 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
  
  dnl Check the expected mpls encapsulated packet on the egress interface
@@ -65896,7 +66673,7 @@ index f22d86e466..4808e78de3 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -1896,13 +2048,13 @@ dnl p1(at_ns1) interface
+@@ -1896,13 +2111,13 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 00 00 00 00 00 02 00 00 00 00 00 01 88 47 00 00 21 40 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
  
  dnl Check the expected decapsulated on the egress interface
@@ -65917,7 +66694,7 @@ index f22d86e466..4808e78de3 100644
  
  
  OVS_TRAFFIC_VSWITCHD_STOP
-@@ -1933,15 +2085,51 @@ dnl p1(at_ns1) interface
+@@ -1933,15 +2148,51 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 00 00 00 00 00 02 00 00 00 00 00 01 88 47 00 00 21 40 36 b1 ee 7c 01 02 36 b1 ee 7c 01 03 08 00 45 00 00 54 03 44 40 00 40 01 21 61 0a 01 01 01 0a 01 01 02 08 00 ef ac 7c e4 00 03 5b 2c 1f 61 00 00 00 00 50 0b 02 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37  > /dev/null])
  
  dnl Check the expected decapsulated on the egress interface
@@ -65976,7 +66753,7 @@ index f22d86e466..4808e78de3 100644
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
-@@ -1985,9 +2173,9 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+@@ -1985,9 +2236,9 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
  dnl Check this output. We only see the latter two packets, not the first.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN2 (xid=0x0): total_len=42 in_port=1 (via action) data_len=42 (unbuffered)
@@ -65988,7 +66765,7 @@ index f22d86e466..4808e78de3 100644
  ])
  
  OVS_TRAFFIC_VSWITCHD_STOP
-@@ -2033,9 +2221,9 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+@@ -2033,9 +2284,9 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
  dnl Check this output. We only see the latter two packets, not the first.
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
  NXT_PACKET_IN2 (xid=0x0): cookie=0x0 total_len=42 in_port=1 (via action) data_len=42 (unbuffered)
@@ -66000,7 +66777,7 @@ index f22d86e466..4808e78de3 100644
  ])
  
  dnl
-@@ -2980,6 +3168,15 @@ NXST_FLOW reply:
+@@ -2980,6 +3231,15 @@ NXST_FLOW reply:
   table=1, priority=100,ct_state=+est+trk,in_port=1 actions=output:2
  ])
  
@@ -66016,7 +66793,7 @@ index f22d86e466..4808e78de3 100644
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
-@@ -3140,11 +3337,11 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+@@ -3140,11 +3400,11 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
  dnl Check this output. We only see the latter two packets, not the first.
  AT_CHECK([cat ofctl_monitor.log | grep -v ff02 | grep -v fe80 | grep -v no_match], [0], [dnl
  NXT_PACKET_IN2 (xid=0x0): table_id=1 cookie=0x0 total_len=75 ct_state=inv|trk,ip,in_port=2 (via action) data_len=75 (unbuffered)
@@ -66031,7 +66808,7 @@ index f22d86e466..4808e78de3 100644
  ])
  
  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1)], [0], [dnl
-@@ -3345,6 +3542,11 @@ AT_CHECK([ovs-ofctl bundle br0 bundle.txt])
+@@ -3345,6 +3605,11 @@ AT_CHECK([ovs-ofctl bundle br0 bundle.txt])
  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl
  ])
  
@@ -66043,7 +66820,7 @@ index f22d86e466..4808e78de3 100644
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
-@@ -4100,15 +4302,15 @@ action=normal
+@@ -4100,15 +4365,15 @@ action=normal
  
  AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt])
  
@@ -66062,7 +66839,7 @@ index f22d86e466..4808e78de3 100644
  "1616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161610a, actions=ct(table=1)"])
  
  AT_CHECK([ovs-appctl dpctl/dump-flows | head -2 | tail -1 | grep -q -e ["]udp[(]src=5001["]])
-@@ -5384,7 +5586,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=
+@@ -5384,7 +5649,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=
  udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=<cleared>,dport=<cleared>),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=<cleared>,dport=<cleared>),mark=1
  ])
  
@@ -66071,7 +66848,7 @@ index f22d86e466..4808e78de3 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -6134,7 +6336,7 @@ sleep 1
+@@ -6134,7 +6399,7 @@ sleep 1
  dnl UDP packets from ns0->ns1 should solicit "destination unreachable" response.
  NS_CHECK_EXEC([at_ns0], [bash -c "echo a | nc -6 $NC_EOF_OPT -u fc00::2 1"])
  
@@ -66080,7 +66857,7 @@ index f22d86e466..4808e78de3 100644
  
  AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl
  udp,orig=(src=fc00::1,dst=fc00::2,sport=<cleared>,dport=<cleared>),reply=(src=fc00::2,dst=fc00::240,sport=<cleared>,dport=<cleared>)
-@@ -6454,7 +6656,7 @@ on_exit 'ovs-appctl revalidator/purge'
+@@ -6454,7 +6719,7 @@ on_exit 'ovs-appctl revalidator/purge'
  on_exit 'ovs-appctl dpif/dump-flows br0'
  
  dnl Should work with the virtual IP address through NAT
@@ -66089,7 +66866,7 @@ index f22d86e466..4808e78de3 100644
      echo Request $i
      NS_CHECK_EXEC([at_ns1], [wget 10.1.1.64 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
  done
-@@ -6743,6 +6945,132 @@ AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE
+@@ -6743,6 +7008,132 @@ AT_CHECK([ovs-ofctl dump-flows br0 | grep table=2, | OFPROTO_CLEAR_DURATION_IDLE
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
  
@@ -66222,7 +66999,7 @@ index f22d86e466..4808e78de3 100644
  AT_BANNER([802.1ad])
  
  AT_SETUP([802.1ad - vlan_limit])
-@@ -7007,12 +7335,12 @@ dnl p1(at_ns1) interface
+@@ -7007,12 +7398,12 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
  
  dnl Check the expected nsh encapsulated packet on the egress interface
@@ -66241,7 +67018,7 @@ index f22d86e466..4808e78de3 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -7039,10 +7367,10 @@ dnl p1(at_ns1) interface
+@@ -7039,10 +7430,10 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 00 64 03 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
  
  dnl Check the expected de-capsulated TCP packet on the egress interface
@@ -66256,7 +67033,7 @@ index f22d86e466..4808e78de3 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -7072,12 +7400,12 @@ dnl p1(at_ns1) interface
+@@ -7072,12 +7463,12 @@ dnl p1(at_ns1) interface
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 01 00 03 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
  
  dnl Check the expected NSH packet with new fields in the header
@@ -66275,7 +67052,7 @@ index f22d86e466..4808e78de3 100644
  
  OVS_TRAFFIC_VSWITCHD_STOP
  AT_CLEANUP
-@@ -7106,23 +7434,23 @@ dnl First send packet from at_ns0 --> OVS with SPI=0x100 and SI=2
+@@ -7106,23 +7497,23 @@ dnl First send packet from at_ns0 --> OVS with SPI=0x100 and SI=2
  NS_CHECK_EXEC([at_ns0], [$PYTHON3 $srcdir/sendpkt.py p0 f2 ff 00 00 00 02 f2 ff 00 00 00 01 89 4f 02 06 01 03 00 01 00 02 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 f2 00 00 00 00 02 f2 00 00 00 00 01 08 00 45 00 00 28 00 01 00 00 40 06 b0 13 c0 a8 00 0a 0a 00 00 0a 04 00 08 00 00 00 00 c8 00 00 00 00 50 02 20 00 b8 5e 00 00 > /dev/null])
  
  dnl Check for the above packet on p1 interface
@@ -67316,9 +68093,77 @@ index fc8ce4a2c0..96c89bd4e6 100644
              && error != WSAECONNRESET
  #endif
 diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
-index 3f58e3e8fd..8c5af459e9 100644
+index 3f58e3e8fd..c96b77cd15 100644
 --- a/tests/tunnel-push-pop-ipv6.at
 +++ b/tests/tunnel-push-pop-ipv6.at
+@@ -63,7 +63,7 @@ AT_CHECK([ovs-ofctl add-flow int-br action=2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ 
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(6),header(size=58,type=109,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x0,proto=0x6558))),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(6),header(size=58,type=109,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x0,proto=0x6558))),out_port(100)),1
+ ])
+ 
+ OVS_VSWITCHD_STOP
+@@ -151,14 +151,14 @@ dnl Check ERSPAN v1 tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(6),header(size=70,type=108,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(6),header(size=70,type=108,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)),1
+ ])
+ 
+ dnl Check ERSPAN v2 tunnel push
+ AT_CHECK([ovs-ofctl mod-flows int-br action=3])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(6),header(size=74,type=108,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=47,tclass=0x0,hlimit=64),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(6),header(size=74,type=108,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=47,tclass=0x0,hlimit=64),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)),1
+ ])
+ 
+ ovs-appctl vlog/set dbg
+@@ -388,28 +388,28 @@ dnl Check VXLAN tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1
+ ])
+ 
+ dnl Check VXLAN tunnel push set tunnel id by flow and checksum
+ AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)),1
+ ])
+ 
+ dnl Check GRE tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=3])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=62,type=109,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=62,type=109,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)),1
+ ])
+ 
+ dnl Check Geneve tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,5"])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(6081),header(size=70,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(6081),header(size=70,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100)),1
+ ])
+ 
+ dnl Check Geneve tunnel push with options
+@@ -417,7 +417,7 @@ AT_CHECK([ovs-ofctl add-tlv-map int-br "{class=0xffff,type=0x80,len=4}->tun_meta
+ AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,set_field:0xa->tun_metadata0,5"])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(6081),header(size=78,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(6081),header(size=78,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100)),1
+ ])
+ 
+ dnl Check decapsulation of GRE packet
 @@ -452,7 +452,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
  
  AT_CHECK([cat ofctl_monitor.log], [0], [dnl
@@ -67328,10 +68173,100 @@ index 3f58e3e8fd..8c5af459e9 100644
  ])
  
  AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  5'], [0], [dnl
+@@ -472,7 +472,7 @@ dnl Check VXLAN tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=36:b1:ee:7c:01:01,dst=36:b1:ee:7c:01:02),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:ca:fe,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:ca:fe,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1
+ ])
+ 
+ AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl
+@@ -490,7 +490,7 @@ dnl Check VXLAN tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=36:b1:ee:7c:01:01,dst=36:b1:ee:7c:01:02),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1
+ ])
+ 
+ AT_CHECK([ovs-appctl tnl/arp/show | tail -n+3 | sort], [0], [dnl
 diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
-index 57589758f4..50f90815a1 100644
+index 57589758f4..65b1469e49 100644
 --- a/tests/tunnel-push-pop.at
 +++ b/tests/tunnel-push-pop.at
+@@ -85,7 +85,7 @@ AT_CHECK([ovs-vsctl -- set Interface br0 options:pcap=br0.pcap])
+ AT_CHECK([ovs-ofctl add-flow int-br action=2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x7b,idx=0x3)),out_port(100)),1
+ ])
+ 
+ dnl Check ERSPAN v2 tunnel push
+@@ -93,7 +93,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br action=3])
+ AT_CHECK([ovs-appctl revalidator/wait])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x237,dir=1,hwid=0x7)),out_port(100)),1
+ ])
+ 
+ dnl Check ERSPAN v2 flow-based tunnel push
+@@ -101,7 +101,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br "action=set_field:1.1.2.94->tun_dst,set_fie
+ AT_CHECK([ovs-appctl revalidator/wait])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x1c8,dir=1,hwid=0x1)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x1c8,dir=1,hwid=0x1)),out_port(100)),1
+ ])
+ 
+ dnl Check ERSPAN v2 flow-based tunnel push, erspan_ver=flow
+@@ -110,7 +110,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br "action=set_field:1.1.2.94->tun_dst,set_fie
+ AT_CHECK([ovs-appctl revalidator/wait])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x38,dir=1,hwid=0x1)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x38,dir=1,hwid=0x1)),out_port(100)),1
+ ])
+ 
+ dnl Dynamically set erspan v1
+@@ -118,7 +118,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br "action=set_field:1.1.2.94->tun_dst,set_fie
+ AT_CHECK([ovs-appctl revalidator/wait])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x38,idx=0x1)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x38,idx=0x1)),out_port(100)),1
+ ])
+ 
+ dnl Check ERSPAN v2 flow-based tunnel push
+@@ -126,7 +126,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br "action=set_field:1.1.2.94->tun_dst,set_fie
+ AT_CHECK([ovs-appctl revalidator/wait])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x1c8,dir=1,hwid=0x1)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x1c8,dir=1,hwid=0x1)),out_port(100)),1
+ ])
+ 
+ dnl Check ERSPAN v2 flow-based tunnel push, erspan_ver=flow
+@@ -135,7 +135,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br "action=set_field:1.1.2.94->tun_dst,set_fie
+ AT_CHECK([ovs-appctl revalidator/wait])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x38,dir=1,hwid=0x1)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=54,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=2,sid=0x38,dir=1,hwid=0x1)),out_port(100)),1
+ ])
+ 
+ dnl Dynamically set erspan v1
+@@ -143,7 +143,7 @@ AT_CHECK([ovs-ofctl mod-flows int-br "action=set_field:1.1.2.94->tun_dst,set_fie
+ AT_CHECK([ovs-appctl revalidator/wait])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x38,idx=0x1)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=50,type=107,eth(dst=f8:bc:12:44:34:b8,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.94,proto=47,tos=0,ttl=64,frag=0x4000),erspan(ver=1,sid=0x38,idx=0x1)),out_port(100)),1
+ ])
+ 
+ dnl Check ERSPAN tunnel pop
 @@ -369,6 +369,26 @@ AT_CHECK([ovs-appctl tnl/neigh/show | grep br | sort], [0], [dnl
  1.1.2.92                                      f8:bc:12:44:34:b6   br0
  ])
@@ -67359,6 +68294,81 @@ index 57589758f4..50f90815a1 100644
  dnl Receive ARP reply without VLAN header
  AT_CHECK([ovs-vsctl set port br0 tag=0])
  AT_CHECK([ovs-appctl tnl/neigh/flush], [0], [OK
+@@ -431,49 +451,49 @@ dnl Check VXLAN tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1
+ ])
+ 
+ dnl Check VXLAN GPE tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=8])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000003,vni=0x159)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0xc000003,vni=0x159)),out_port(100)),1
+ ])
+ 
+ dnl Check VXLAN tunnel push set tunnel id by flow and checksum
+ AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100)),1
+ ])
+ 
+ dnl Check GRE tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=3])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)),1
+ ])
+ 
+ dnl Check L3GRE tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=7])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: pop_eth,clone(tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x2000,proto=0x800),key=0x1c8)),out_port(100)),1)
++  [Datapath actions: pop_eth,tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x2000,proto=0x800),key=0x1c8)),out_port(100)),1
+ ])
+ 
+ dnl Check Geneve tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:1.1.2.92->tun_dst,5"])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100)),1
+ ])
+ 
+ dnl Check Geneve tunnel push with pkt-mark
+ AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:234,6"])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: set(skb_mark(0x4d2)),clone(tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0xea)),out_port(100)),1)
++  [Datapath actions: set(skb_mark(0x4d2)),tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(vni=0xea)),out_port(100)),1
+ ])
+ 
+ dnl Check Geneve tunnel push with options
+@@ -481,7 +501,7 @@ AT_CHECK([ovs-ofctl add-tlv-map int-br "{class=0xffff,type=0x80,len=4}->tun_meta
+ AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:1.1.2.92->tun_dst,set_field:0xa->tun_metadata0,5"])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(6081),header(size=58,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(6081),header(size=58,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=6081,csum=0x0),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100)),1
+ ])
+ 
+ dnl Check GTP-U tunnel push
+@@ -489,7 +509,7 @@ AT_CHECK([ovs-ofctl add-flow int-br "actions=9"])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'],
+ [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: pop_eth,clone(tnl_push(tnl_port(2152),header(size=50,type=110,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=2152,csum=0x0),gtpu(flags=0x30,msgtype=255,teid=0x7b)),out_port(100)),1)
++  [Datapath actions: pop_eth,tnl_push(tnl_port(2152),header(size=50,type=110,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=2152,csum=0x0),gtpu(flags=0x30,msgtype=255,teid=0x7b)),out_port(100)),1
+ ])
+ AT_CHECK([ovs-ofctl del-flows int-br])
+ 
 @@ -546,6 +566,28 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  [[37]]' | sort], [0], [dnl
    port  7: rx pkts=5, bytes=434, drop=?, errs=?, frame=?, over=?, crc=?
  ])
@@ -67406,6 +68416,24 @@ index 57589758f4..50f90815a1 100644
  ])
  
  dnl Receive VXLAN with different MAC and verify that the neigh cache gets updated
+@@ -579,7 +621,7 @@ dnl Check VXLAN tunnel push
+ AT_CHECK([ovs-ofctl add-flow int-br action=2])
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=36:b1:ee:7c:01:01,dst=36:b1:ee:7c:01:02),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:ca:fe,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:ca:fe,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1
+ ])
+ 
+ AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
+@@ -596,7 +638,7 @@ ovs-appctl time/warp 1000
+ dnl Check VXLAN tunnel push
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=36:b1:ee:7c:01:01,dst=36:b1:ee:7c:01:02),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100)),1
+ ])
+ 
+ AT_CHECK([ovs-appctl tnl/neigh/show | tail -n+3 | sort], [0], [dnl
 @@ -718,14 +760,14 @@ dnl Output to tunnel from a int-br internal port.
  dnl Checking that the packet arrived and it was correctly encapsulated.
  AT_CHECK([ovs-ofctl add-flow int-br "in_port=LOCAL,actions=debug_slow,output:2"])
@@ -67424,6 +68452,15 @@ index 57589758f4..50f90815a1 100644
  
  dnl Datapath actions should not have tunnel push action.
  AT_CHECK([ovs-appctl dpctl/dump-flows | grep -q tnl_push], [1])
+@@ -772,7 +814,7 @@ AT_CHECK([ovs-ofctl add-flow int-br action=3])
+ 
+ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=4789)'], [0], [stdout])
+ AT_CHECK([tail -1 stdout], [0],
+-  [Datapath actions: clone(tnl_push(tnl_port(3),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x3000,proto=0x6558),key=0x1c8,seq=0x0)),out_port(100)),1)
++  [Datapath actions: tnl_push(tnl_port(3),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x3000,proto=0x6558),key=0x1c8,seq=0x0)),out_port(100)),1
+ ])
+ 
+ dnl Verify outer L2 and L3 header flow fields can be matched in the underlay bridge
 @@ -842,3 +884,54 @@ Datapath actions: 7
  
  OVS_VSWITCHD_STOP
@@ -67470,11 +68507,11 @@ index 57589758f4..50f90815a1 100644
 +AT_CHECK([tail -2 stdout], [0], [dnl
 +Megaflow: recirc_id=0,eth,in_port=7,dl_src=00:00:00:00:00:00,dnl
 +dl_dst=00:00:00:00:00:00,dl_type=0x0000
-+Datapath actions: push_vlan(vid=200,pcp=0),1,clone(tnl_push(tnl_port(4789),dnl
++Datapath actions: push_vlan(vid=200,pcp=0),1,tnl_push(tnl_port(4789),dnl
 +header(size=50,type=4,eth(dst=aa:55:aa:66:00:00,src=aa:55:aa:55:00:00,dnl
 +dl_type=0x0800),ipv4(src=10.0.0.2,dst=10.0.0.11,proto=17,tos=0,ttl=64,dnl
 +frag=0x4000),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x0)),dnl
-+out_port(100)),8)
++out_port(100)),8
 +])
 +
 +OVS_VSWITCHD_STOP
diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec
index 6d78cf4..9e8720c 100644
--- a/SPECS/openvswitch2.17.spec
+++ b/SPECS/openvswitch2.17.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 2.17.0
-Release: 63%{?dist}
+Release: 65%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -748,6 +748,52 @@ exit 0
 %endif
 
 %changelog
+* Mon Feb 13 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-65
+- Merging upstream branch-2.17 [RH git: 2011158f64]
+    Commit list:
+    6626562c53 sparse: Fix build with DPDK and GCC 12.
+    82dc71f808 ovsdb-server: Fix handling of DNS name for listener configuration.
+    9b341844e7 netdev-offload-tc: If the flow has not been used, report it as such.
+    adac28dcdf netdev-offload-tc: Conntrack ALGs are not supported with tc.
+    a1c2abba78 netdev-offload-tc: Fix tc conntrack force commit support.
+    68a2818b09 ofproto-dpif-upcall: New ukey needs to take the old ukey's dump seq.
+    2eb7a60668 netdev-offload-tc: Preserve tc statistics when flow gets modified.
+    4f51407698 sparse: Fix numa.h for libnuma >= 2.0.13.
+
+
+* Tue Feb 07 2023 Eelco Chaudron <echaudro@redhat.com> - 2.17.0-64
+- ofproto-dpif-xlate: Optimize datapath action set by removing last clone action. [RH git: 684b6e8ad9]
+    Manual backport of the below commit. In addition to the upstream fix,
+    we also had to bring in the nl_msg_reset_size() function. We also had
+    to fix-up nine test cases as they where showing incorrect results.
+    
+    Bugzilla       : https://bugzilla.redhat.com/2110018
+    Upstream commit: 4f5decf4ab3f ("ofproto-dpif-xlate: Optimize datapath action set by removing last clone action.")
+    
+      When OFPROTO non-reversible actions are translated to data plane
+      actions, the only thing looked at is if there are more actions
+      pending. If this is the case, the action is encapsulated in a
+      clone().
+    
+      This could lead to unnecessary clones if no meaningful data
+      plane actions are added. For example, the register pop in the
+      included test case.
+    
+      The best solution would probably be to build the full action
+      path and determine if the clone is needed. However, this would
+      be a huge change in the existing design, so for now, we just try
+      to optimize the generated datapath flow. We can revisit this
+      later, as some of the pending CT issues might need this rework.
+    
+      Fixes: feee58b9587f ("ofproto-dpif-xlate: Keep track of the last action")
+      Fixes: dadd8357f224 ("ofproto-dpif: Fix issue with non-reversible actions on a patch ports.")
+      Acked-by: Ales Musil <amusil@redhat.com>
+      Signed-off-by: Eelco Chaudron <echaudro@redhat.com>
+      Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+    
+    Signed-off-by: Eelco Chaudron <echaudro@redhat.com>
+
+
 * Mon Jan 30 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-63
 - Merging upstream branch-2.17 [RH git: 64bd43b450]
     Commit list: