diff --git a/SOURCES/openvswitch-3.1.0.patch b/SOURCES/openvswitch-3.1.0.patch
index 8f4d15d..3200017 100644
--- a/SOURCES/openvswitch-3.1.0.patch
+++ b/SOURCES/openvswitch-3.1.0.patch
@@ -3984,10 +3984,21 @@ index 0b9dc4278c..9b7e06e0c7 100644
          if (!wc->masks.vlans[i].tci) {
              break;
 diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c
-index 029ca28558..43805ae4d5 100644
+index 029ca28558..98ec67281b 100644
 --- a/lib/mcast-snooping.c
 +++ b/lib/mcast-snooping.c
-@@ -946,8 +946,9 @@ mcast_snooping_wait(struct mcast_snooping *ms)
+@@ -407,7 +407,9 @@ mcast_snooping_add_group(struct mcast_snooping *ms,
+         uint32_t hash = mcast_table_hash(ms, addr, vlan);
+ 
+         if (hmap_count(&ms->table) >= ms->max_entries) {
+-            group_get_lru(ms, &grp);
++            if (!group_get_lru(ms, &grp)) {
++                return false;
++            }
+             mcast_snooping_flush_group(ms, grp);
+         }
+ 
+@@ -946,8 +948,9 @@ mcast_snooping_wait(struct mcast_snooping *ms)
  void
  mcast_snooping_flush_bundle(struct mcast_snooping *ms, void *port)
  {
@@ -3998,7 +4009,7 @@ index 029ca28558..43805ae4d5 100644
  
      if (!mcast_snooping_enabled(ms)) {
          return;
-@@ -971,5 +972,19 @@ mcast_snooping_flush_bundle(struct mcast_snooping *ms, void *port)
+@@ -971,5 +974,19 @@ mcast_snooping_flush_bundle(struct mcast_snooping *ms, void *port)
          }
      }
  
@@ -6326,7 +6337,7 @@ index a75ad36b73..65bbfe8768 100644
      if (inner_error) {
          char *s = ovsdb_error_to_string_free(inner_error);
 diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
-index 634fbb56df..ba720474b6 100644
+index 634fbb56df..d92df28d19 100644
 --- a/lib/ovsdb-idl.c
 +++ b/lib/ovsdb-idl.c
 @@ -177,6 +177,7 @@ static void ovsdb_idl_row_mark_backrefs_for_reparsing(struct ovsdb_idl_row *);
@@ -6371,6 +6382,15 @@ index 634fbb56df..ba720474b6 100644
  }
  
  static struct ovsdb_idl_row *
+@@ -3776,6 +3783,8 @@ ovsdb_idl_txn_delete(const struct ovsdb_idl_row *row_)
+     ovsdb_idl_remove_from_indexes(row_);
+     if (!row->old_datum) {
+         ovsdb_idl_row_unparse(row);
++        ovsdb_idl_destroy_all_map_op_lists(row);
++        ovsdb_idl_destroy_all_set_op_lists(row);
+         ovsdb_idl_row_clear_new(row);
+         ovs_assert(!row->prereqs);
+         hmap_remove(&row->table->rows, &row->hmap_node);
 diff --git a/lib/ovsdb-types.h b/lib/ovsdb-types.h
 index b9eb0928df..d2455fc977 100644
 --- a/lib/ovsdb-types.h
@@ -7032,7 +7052,7 @@ index 96a71550d9..5f0679bb99 100644
      }
  }
 diff --git a/lib/vconn.c b/lib/vconn.c
-index b556762277..e9603432d2 100644
+index b556762277..4b1c262eaa 100644
 --- a/lib/vconn.c
 +++ b/lib/vconn.c
 @@ -682,7 +682,6 @@ do_send(struct vconn *vconn, struct ofpbuf *msg)
@@ -7053,6 +7073,35 @@ index b556762277..e9603432d2 100644
      return retval;
  }
  
+@@ -1015,6 +1017,8 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
+                 VLOG_WARN_RL(&rl, "received bad reply: %s",
+                              ofp_to_string(reply->data, reply->size,
+                                            NULL, NULL, 1));
++                ofpbuf_delete(reply);
++                *replyp = NULL;
+                 return EPROTO;
+             }
+         }
+@@ -1029,9 +1033,9 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
+         case EOF:
+             more = ofpmp_more(reply->header);
+             ofpbuf_delete(reply);
++            *replyp = NULL;
+             reply = NULL;
+             if (!more) {
+-                *replyp = NULL;
+                 return EOF;
+             }
+             break;
+@@ -1039,6 +1043,8 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
+         default:
+             VLOG_WARN_RL(&rl, "parse error in reply (%s)",
+                          ofperr_to_string(retval));
++            ofpbuf_delete(reply);
++            *replyp = NULL;
+             return EPROTO;
+         }
+     }
 diff --git a/lib/vlog.c b/lib/vlog.c
 index 0a615bb664..b6f8bda3e6 100644
 --- a/lib/vlog.c
@@ -7070,7 +7119,7 @@ index 0a615bb664..b6f8bda3e6 100644
  
      /* Install new log file. */
 diff --git a/ofproto/bond.c b/ofproto/bond.c
-index cfdf44f854..c31869a4c7 100644
+index cfdf44f854..0858de3746 100644
 --- a/ofproto/bond.c
 +++ b/ofproto/bond.c
 @@ -186,7 +186,7 @@ static struct bond_member *choose_output_member(const struct bond *,
@@ -7082,6 +7131,15 @@ index cfdf44f854..c31869a4c7 100644
  static bool bond_may_recirc(const struct bond *);
  static void bond_update_post_recirc_rules__(struct bond *, bool force)
      OVS_REQ_WRLOCK(rwlock);
+@@ -246,7 +246,7 @@ bond_create(const struct bond_settings *s, struct ofproto_dpif *ofproto)
+     ovs_refcount_init(&bond->ref_cnt);
+     hmap_init(&bond->pr_rule_ops);
+ 
+-    bond->active_member_mac = eth_addr_zero;
++    bond->active_member_mac = s->active_member_mac;
+     bond->active_member_changed = false;
+     bond->primary = NULL;
+ 
 @@ -299,7 +299,10 @@ bond_unref(struct bond *bond)
      }
      free(bond->hash);
@@ -7603,10 +7661,10 @@ index f579a5ca46..f023b10cdf 100644
  
  /* A node within a next_ct_states list. */
 diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
-index e05ffe3128..9c6a63d7fb 100644
+index e05ffe3128..dccbc8208a 100644
 --- a/ofproto/ofproto-dpif-upcall.c
 +++ b/ofproto/ofproto-dpif-upcall.c
-@@ -47,17 +47,21 @@
+@@ -47,17 +47,22 @@
  
  #define UPCALL_MAX_BATCH 64
  #define REVALIDATE_MAX_BATCH 50
@@ -7620,6 +7678,7 @@ index e05ffe3128..9c6a63d7fb 100644
 -COVERAGE_DEFINE(upcall_ukey_contention);
 -COVERAGE_DEFINE(upcall_ukey_replace);
  COVERAGE_DEFINE(revalidate_missed_dp_flow);
++COVERAGE_DEFINE(revalidate_missing_dp_flow);
 +COVERAGE_DEFINE(ukey_dp_change);
 +COVERAGE_DEFINE(ukey_invalid_stat_reset);
 +COVERAGE_DEFINE(ukey_replace_contention);
@@ -7630,7 +7689,7 @@ index e05ffe3128..9c6a63d7fb 100644
  
  /* A thread that reads upcalls from dpif, forwards each upcall's packet,
   * and possibly sets up a kernel flow as a cache. */
-@@ -287,6 +291,7 @@ struct udpif_key {
+@@ -287,10 +292,12 @@ struct udpif_key {
  
      struct ovs_mutex mutex;                   /* Guards the following. */
      struct dpif_flow_stats stats OVS_GUARDED; /* Last known stats.*/
@@ -7638,7 +7697,12 @@ index e05ffe3128..9c6a63d7fb 100644
      long long int created OVS_GUARDED;        /* Estimate of creation time. */
      uint64_t dump_seq OVS_GUARDED;            /* Tracks udpif->dump_seq. */
      uint64_t reval_seq OVS_GUARDED;           /* Tracks udpif->reval_seq. */
-@@ -780,6 +785,17 @@ udpif_get_n_flows(struct udpif *udpif)
+     enum ukey_state state OVS_GUARDED;        /* Tracks ukey lifetime. */
++    uint32_t missed_dumps OVS_GUARDED;        /* Missed consecutive dumps. */
+ 
+     /* 'state' debug information. */
+     unsigned int state_thread OVS_GUARDED;    /* Thread that transitions. */
+@@ -780,6 +787,17 @@ udpif_get_n_flows(struct udpif *udpif)
          atomic_store_relaxed(&udpif->n_flows_timestamp, now);
          dpif_get_dp_stats(udpif->dpif, &stats);
          flow_count = stats.n_flows;
@@ -7656,7 +7720,7 @@ index e05ffe3128..9c6a63d7fb 100644
          atomic_store_relaxed(&udpif->n_flows, flow_count);
          ovs_mutex_unlock(&udpif->n_flows_mutex);
      } else {
-@@ -972,7 +988,7 @@ udpif_revalidator(void *arg)
+@@ -972,7 +990,7 @@ udpif_revalidator(void *arg)
              udpif->reval_exit = latch_is_set(&udpif->exit_latch);
  
              start_time = time_msec();
@@ -7665,7 +7729,7 @@ index e05ffe3128..9c6a63d7fb 100644
                  bool terse_dump;
  
                  terse_dump = udpif_use_ufid(udpif);
-@@ -981,10 +997,15 @@ udpif_revalidator(void *arg)
+@@ -981,10 +999,15 @@ udpif_revalidator(void *arg)
              }
          }
  
@@ -7682,7 +7746,7 @@ index e05ffe3128..9c6a63d7fb 100644
          }
  
          if (udpif->reval_exit) {
-@@ -1395,8 +1416,6 @@ upcall_cb(const struct dp_packet *packet, const struct flow *flow, ovs_u128 *ufi
+@@ -1395,8 +1418,6 @@ upcall_cb(const struct dp_packet *packet, const struct flow *flow, ovs_u128 *ufi
      }
  
      if (upcall.ukey && !ukey_install(udpif, upcall.ukey)) {
@@ -7691,7 +7755,7 @@ index e05ffe3128..9c6a63d7fb 100644
          error = ENOSPC;
      }
  out:
-@@ -1766,6 +1785,7 @@ ukey_create__(const struct nlattr *key, size_t key_len,
+@@ -1766,6 +1787,7 @@ ukey_create__(const struct nlattr *key, size_t key_len,
      ukey->created = ukey->flow_time = time_msec();
      memset(&ukey->stats, 0, sizeof ukey->stats);
      ukey->stats.used = used;
@@ -7699,7 +7763,7 @@ index e05ffe3128..9c6a63d7fb 100644
      ukey->xcache = NULL;
  
      ukey->offloaded = false;
-@@ -1893,15 +1913,15 @@ try_ukey_replace(struct umap *umap, struct udpif_key *old_ukey,
+@@ -1893,15 +1915,15 @@ try_ukey_replace(struct umap *umap, struct udpif_key *old_ukey,
              transition_ukey(old_ukey, UKEY_DELETED);
              transition_ukey(new_ukey, UKEY_VISIBLE);
              replaced = true;
@@ -7720,7 +7784,7 @@ index e05ffe3128..9c6a63d7fb 100644
      return replaced;
  }
  
-@@ -2095,10 +2115,12 @@ ukey_delete(struct umap *umap, struct udpif_key *ukey)
+@@ -2095,10 +2117,12 @@ ukey_delete(struct umap *umap, struct udpif_key *ukey)
  }
  
  static bool
@@ -7735,7 +7799,7 @@ index e05ffe3128..9c6a63d7fb 100644
  
      if (!used) {
          /* Always revalidate the first time a flow is dumped. */
-@@ -2125,8 +2147,12 @@ should_revalidate(const struct udpif *udpif, uint64_t packets,
+@@ -2125,8 +2149,12 @@ should_revalidate(const struct udpif *udpif, uint64_t packets,
      duration = now - used;
      metric = duration / packets;
  
@@ -7750,7 +7814,7 @@ index e05ffe3128..9c6a63d7fb 100644
          return true;
      }
      return false;
-@@ -2302,6 +2328,27 @@ exit:
+@@ -2302,6 +2330,27 @@ exit:
      return result;
  }
  
@@ -7778,7 +7842,7 @@ index e05ffe3128..9c6a63d7fb 100644
  /* Verifies that the datapath actions of 'ukey' are still correct, and pushes
   * 'stats' for it.
   *
-@@ -2324,7 +2371,7 @@ static enum reval_result
+@@ -2324,7 +2373,7 @@ static enum reval_result
  revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
                  const struct dpif_flow_stats *stats,
                  struct ofpbuf *odp_actions, uint64_t reval_seq,
@@ -7787,7 +7851,7 @@ index e05ffe3128..9c6a63d7fb 100644
      OVS_REQUIRES(ukey->mutex)
  {
      bool need_revalidate = ukey->reval_seq != reval_seq;
-@@ -2335,15 +2382,19 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
+@@ -2335,15 +2384,19 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
  
      push.used = stats->used;
      push.tcp_flags = stats->tcp_flags;
@@ -7814,7 +7878,7 @@ index e05ffe3128..9c6a63d7fb 100644
              if (!ukey->xcache) {
                  ukey->xcache = xlate_cache_new();
              } else {
-@@ -2359,7 +2410,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
+@@ -2359,7 +2412,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
  
      /* Stats for deleted flows will be attributed upon flow deletion. Skip. */
      if (result != UKEY_DELETE) {
@@ -7823,7 +7887,7 @@ index e05ffe3128..9c6a63d7fb 100644
          ukey->stats = *stats;
          ukey->reval_seq = reval_seq;
      }
-@@ -2455,6 +2506,15 @@ push_dp_ops(struct udpif *udpif, struct ukey_op *ops, size_t n_ops)
+@@ -2455,6 +2508,15 @@ push_dp_ops(struct udpif *udpif, struct ukey_op *ops, size_t n_ops)
              push->tcp_flags = stats->tcp_flags | op->ukey->stats.tcp_flags;
              push->n_packets = stats->n_packets - op->ukey->stats.n_packets;
              push->n_bytes = stats->n_bytes - op->ukey->stats.n_bytes;
@@ -7839,7 +7903,7 @@ index e05ffe3128..9c6a63d7fb 100644
              ovs_mutex_unlock(&op->ukey->mutex);
          } else {
              push = stats;
-@@ -2759,6 +2819,22 @@ revalidate(struct revalidator *revalidator)
+@@ -2759,6 +2821,22 @@ revalidate(struct revalidator *revalidator)
                  continue;
              }
  
@@ -7862,7 +7926,7 @@ index e05ffe3128..9c6a63d7fb 100644
              already_dumped = ukey->dump_seq == dump_seq;
              if (already_dumped) {
                  /* The flow has already been handled during this flow dump
-@@ -2790,8 +2866,7 @@ revalidate(struct revalidator *revalidator)
+@@ -2790,8 +2868,7 @@ revalidate(struct revalidator *revalidator)
                  result = UKEY_DELETE;
              } else {
                  result = revalidate_ukey(udpif, ukey, &stats, &odp_actions,
@@ -7872,7 +7936,7 @@ index e05ffe3128..9c6a63d7fb 100644
              }
              ukey->dump_seq = dump_seq;
  
-@@ -2857,6 +2932,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
+@@ -2857,6 +2934,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
              /* Handler threads could be holding a ukey lock while it installs a
               * new flow, so don't hang around waiting for access to it. */
              if (ovs_mutex_trylock(&ukey->mutex)) {
@@ -7880,16 +7944,31 @@ index e05ffe3128..9c6a63d7fb 100644
                  continue;
              }
              ukey_state = ukey->state;
-@@ -2876,7 +2952,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
+@@ -2876,8 +2954,22 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
                      COVERAGE_INC(revalidate_missed_dp_flow);
                      memcpy(&stats, &ukey->stats, sizeof stats);
                      result = revalidate_ukey(udpif, ukey, &stats, &odp_actions,
 -                                             reval_seq, &recircs, false);
 +                                             reval_seq, &recircs);
++                }
++
++                if (ukey->dump_seq != dump_seq) {
++                    ukey->missed_dumps++;
++                    if (ukey->missed_dumps >= 4) {
++                        /* If the flow was not dumped for 4 revalidator rounds,
++                         * we can assume the datapath flow no longer exists
++                         * and the ukey should be deleted. */
++                        COVERAGE_INC(revalidate_missing_dp_flow);
++                        result = UKEY_DELETE;
++                    }
++                } else {
++                    ukey->missed_dumps = 0;
                  }
++
                  if (result != UKEY_KEEP) {
                      /* Clears 'recircs' if filled by revalidate_ukey(). */
-@@ -3111,11 +3187,19 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED,
+                     reval_op_init(&ops[n_ops++], result, udpif, ukey, &recircs,
+@@ -3111,11 +3203,19 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED,
      struct udpif *udpif;
  
      LIST_FOR_EACH (udpif, list_node, &all_udpifs) {
@@ -12081,7 +12160,7 @@ index 14aa554169..6a07e23c64 100644
 +
  AT_CLEANUP
 diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
-index fa6111c1ed..beb33713c7 100644
+index fa6111c1ed..fd87f97ead 100644
 --- a/tests/ofproto-dpif.at
 +++ b/tests/ofproto-dpif.at
 @@ -547,6 +547,23 @@ ovs-appctl time/warp 1000 100
@@ -12108,7 +12187,81 @@ index fa6111c1ed..beb33713c7 100644
  OVS_VSWITCHD_STOP()
  AT_CLEANUP
  
-@@ -849,7 +866,7 @@ table=2 ip actions=set_field:192.168.3.91->ip_src,output(11)
+@@ -740,6 +757,73 @@ Datapath actions: drop
+ OVS_VSWITCHD_STOP()
+ AT_CLEANUP
+ 
++AT_SETUP([ofproto-dpif - active bond member survives restart])
++dnl Create bond0 with members p1, p2 and p3. Initially, set p2 as active.
++dnl Restart ovs-vswitchd. Check that p2 is still active.
++OVS_VSWITCHD_START(
++  [add-bond br0 bond0 p1 p2 p3 bond_mode=active-backup -- \
++   set interface p1 type=dummy ofport_request=1 -- \
++   set interface p2 type=dummy ofport_request=2 -- \
++   set interface p3 type=dummy ofport_request=3 --])
++AT_CHECK([ovs-appctl bond/set-active-member bond0 p2], [0], [ignore])
++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl
++---- bond0 ----
++bond_mode: active-backup
++bond may use recirculation: no, <del>
++bond-hash-basis: 0
++lb_output action: disabled, bond-id: -1
++updelay: 0 ms
++downdelay: 0 ms
++lacp_status: off
++lacp_fallback_ab: false
++active-backup primary: <none>
++<active member mac del>
++
++member p1: enabled
++  may_enable: true
++
++member p2: enabled
++  active member
++  may_enable: true
++
++member p3: enabled
++  may_enable: true
++])
++
++dnl Restart ovs-vswitchd with an empty ovs-vswitchd log file.
++OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
++mv ovs-vswitchd.log ovs-vswitchd_1.log
++AT_CHECK([ovs-vswitchd --enable-dummy --disable-system --disable-system-route --detach \
++         --no-chdir --pidfile --log-file -vfile:rconn:dbg -vvconn -vofproto_dpif -vunixctl],
++         [0], [], [stderr])
++
++OVS_WAIT_UNTIL_EQUAL([ovs-appctl bond/show | STRIP_RECIRC_ID | STRIP_ACTIVE_MEMBER_MAC], [dnl
++---- bond0 ----
++bond_mode: active-backup
++bond may use recirculation: no, <del>
++bond-hash-basis: 0
++lb_output action: disabled, bond-id: -1
++updelay: 0 ms
++downdelay: 0 ms
++lacp_status: off
++lacp_fallback_ab: false
++active-backup primary: <none>
++<active member mac del>
++
++member p1: enabled
++  may_enable: true
++
++member p2: enabled
++  active member
++  may_enable: true
++
++member p3: enabled
++  may_enable: true
++])
++
++OVS_VSWITCHD_STOP
++AT_CLEANUP
++
+ AT_SETUP([bond - allow duplicated frames])
+ dnl Receiving of duplicated multicast frames should be allowed with 'all_members_active'.
+ OVS_VSWITCHD_START([dnl
+@@ -849,7 +933,7 @@ table=2 ip actions=set_field:192.168.3.91->ip_src,output(11)
  AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt])
  AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,nw_frag=no,icmp_type=8,icmp_code=0'], [0], [stdout])
  AT_CHECK([tail -2 stdout], [0],
@@ -12117,7 +12270,7 @@ index fa6111c1ed..beb33713c7 100644
  Datapath actions: 10,set(ipv4(src=192.168.3.91)),11,set(ipv4(src=192.168.3.90)),13
  ])
  OVS_VSWITCHD_STOP
-@@ -912,7 +929,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_ds
+@@ -912,7 +996,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_ds
  # Must match on the source address to be able to restore it's value for
  # the second bucket
  AT_CHECK([tail -2 stdout], [0],
@@ -12126,7 +12279,7 @@ index fa6111c1ed..beb33713c7 100644
  Datapath actions: set(ipv4(src=192.168.3.90)),10,set(ipv4(src=192.168.0.1)),11
  ])
  OVS_VSWITCHD_STOP
-@@ -930,6 +947,28 @@ AT_CHECK([tail -1 stdout], [0],
+@@ -930,6 +1014,28 @@ AT_CHECK([tail -1 stdout], [0],
  OVS_VSWITCHD_STOP
  AT_CLEANUP
  
@@ -12155,7 +12308,7 @@ index fa6111c1ed..beb33713c7 100644
  AT_SETUP([ofproto-dpif - group actions have no effect afterwards])
  OVS_VSWITCHD_START
  add_of_ports br0 1 10
-@@ -944,7 +983,7 @@ done
+@@ -944,7 +1050,7 @@ done
  AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/dp_hash(.*\/0xf)/dp_hash(0xXXXX\/0xf)/' |  sed 's/packets.*actions:/actions:/' | strip_ufid | strip_used | sort], [0], [dnl
  flow-dump from the main thread:
  recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:hash(sym_l4(0)),recirc(0x1)
@@ -12164,7 +12317,7 @@ index fa6111c1ed..beb33713c7 100644
  ])
  
  OVS_VSWITCHD_STOP
-@@ -959,7 +998,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_ds
+@@ -959,7 +1065,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_ds
  # Must match on the source address to be able to restore it's value for
  # the third bucket
  AT_CHECK([tail -2 stdout], [0],
@@ -12173,7 +12326,7 @@ index fa6111c1ed..beb33713c7 100644
  Datapath actions: set(ipv4(src=192.168.3.90)),10,set(ipv4(src=192.168.0.1)),11
  ])
  OVS_VSWITCHD_STOP
-@@ -1536,17 +1575,17 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+@@ -1536,17 +1642,17 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=111,tos=0,ttl=2,frag=no)' -generate], [0], [stdout])
  AT_CHECK([tail -4 stdout], [0], [
  Final flow: ip,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=1,nw_frag=no
@@ -12194,7 +12347,7 @@ index fa6111c1ed..beb33713c7 100644
  Datapath actions: set(ipv6(hlimit=127)),2,set(ipv6(hlimit=126)),3,4
  ])
  
-@@ -1656,7 +1695,7 @@ AT_CHECK([ovs-vsctl -- \
+@@ -1656,7 +1762,7 @@ AT_CHECK([ovs-vsctl -- \
          --id=@q2 create Queue dscp=2], [0], [ignore])
  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(9),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=1.1.1.1,dst=2.2.2.2,proto=1,tos=0xff,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
  AT_CHECK([tail -2 stdout], [0],
@@ -12203,7 +12356,7 @@ index fa6111c1ed..beb33713c7 100644
  Datapath actions: dnl
  100,dnl
  set(ipv4(tos=0x4/0xfc)),set(skb_priority(0x1)),1,dnl
-@@ -5349,7 +5388,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+@@ -5349,7 +5455,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
  flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)"
  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout])
  AT_CHECK_UNQUOTED([tail -1 stdout], [0],
@@ -12212,7 +12365,7 @@ index fa6111c1ed..beb33713c7 100644
  ])
  
  flow="in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)"
-@@ -5388,7 +5427,7 @@ flow="in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x080
+@@ -5388,7 +5494,7 @@ flow="in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x080
  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout])
  actual=`tail -1 stdout | sed 's/Datapath actions: //'`
  
@@ -12221,7 +12374,7 @@ index fa6111c1ed..beb33713c7 100644
  AT_CHECK([ovs-dpctl normalize-actions "$flow" "$expected"], [0], [stdout])
  mv stdout expout
  AT_CHECK([ovs-dpctl normalize-actions "$flow" "$actual"], [0], [expout])
-@@ -5656,7 +5695,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+@@ -5656,7 +5762,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
  flow="in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)"
  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "$flow"], [0], [stdout])
  AT_CHECK_UNQUOTED([tail -1 stdout], [0],
@@ -12230,7 +12383,7 @@ index fa6111c1ed..beb33713c7 100644
  ])
  
  flow="in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)"
-@@ -5854,6 +5893,40 @@ OVS_WAIT_UNTIL([check_flows], [ovs-ofctl dump-flows br0])
+@@ -5854,6 +5960,40 @@ OVS_WAIT_UNTIL([check_flows], [ovs-ofctl dump-flows br0])
  OVS_VSWITCHD_STOP
  AT_CLEANUP
  
@@ -12271,7 +12424,7 @@ index fa6111c1ed..beb33713c7 100644
  AT_SETUP([ofproto-dpif - debug_slow action])
  OVS_VSWITCHD_START
  add_of_ports br0 1 2 3
-@@ -6144,6 +6217,57 @@ AT_CHECK([test 1 = `$PYTHON3 "$top_srcdir/utilities/ovs-pcap.in" p2-tx.pcap | wc
+@@ -6144,6 +6284,57 @@ AT_CHECK([test 1 = `$PYTHON3 "$top_srcdir/utilities/ovs-pcap.in" p2-tx.pcap | wc
  OVS_VSWITCHD_STOP
  AT_CLEANUP
  
@@ -12329,7 +12482,7 @@ index fa6111c1ed..beb33713c7 100644
  AT_SETUP([ofproto-dpif - continuation with patch port])
  AT_KEYWORDS([continuations pause resume])
  OVS_VSWITCHD_START(
-@@ -7619,12 +7743,14 @@ dummy@ovs-dummy: hit:0 missed:0
+@@ -7619,12 +7810,14 @@ dummy@ovs-dummy: hit:0 missed:0
      vm1 5/3: (dummy: ifindex=2011)
  ])
  
@@ -12347,7 +12500,7 @@ index fa6111c1ed..beb33713c7 100644
  
  dnl Prime ARP Cache for 1.1.2.92
  AT_CHECK([ovs-appctl netdev-dummy/receive p0 'recirc_id(0),in_port(1),eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)'])
-@@ -7635,10 +7761,13 @@ ovs-vsctl \
+@@ -7635,10 +7828,13 @@ ovs-vsctl \
     --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" agent=127.0.0.1 \
       header=128 sampling=1 polling=0
  
@@ -12363,7 +12516,7 @@ index fa6111c1ed..beb33713c7 100644
  ])
  
  dnl add rule for int-br to force packet onto tunnel. There is no ifindex
-@@ -11884,7 +12013,7 @@ ovs-ofctl dump-flows br0
+@@ -11884,7 +12080,7 @@ ovs-ofctl dump-flows br0
  
  AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
  AT_CHECK([tail -3 stdout], [0], [dnl
@@ -12372,8 +12525,57 @@ index fa6111c1ed..beb33713c7 100644
  Datapath actions: drop
  Translation failed (Recursion too deep), packet is dropped.
  ])
+@@ -11985,3 +12181,48 @@ AT_CHECK([test 1 = `ovs-ofctl parse-pcap p2-tx.pcap | wc -l`])
+ 
+ OVS_VSWITCHD_STOP
+ AT_CLEANUP
++
++AT_SETUP([ofproto-dpif - Cleanup missing datapath flows])
++
++OVS_VSWITCHD_START
++add_of_ports br0 1 2
++
++m4_define([ICMP_PKT], [m4_join([,],
++    [eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800)],
++    [ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no)],
++    [icmp(type=8,code=0)])])
++
++AT_CHECK([ovs-ofctl del-flows br0])
++AT_CHECK([ovs-ofctl add-flow br0 'actions=normal' ])
++
++AT_CHECK([ovs-appctl netdev-dummy/receive p1 'ICMP_PKT'])
++
++AT_CHECK([ovs-appctl dpctl/dump-flows --names | strip_used | strip_stats | dnl
++          strip_duration | strip_dp_hash | sort], [0], [dnl
++flow-dump from the main thread:
++recirc_id(0),in_port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:br0,p2
++])
++
++dnl Make sure the ukey exists.
++AT_CHECK([ovs-appctl upcall/show | grep '(keys' | awk '{print $3}' | \
++            grep -q '1)'], [0])
++
++dnl Delete all datapath flows, and make sure they are gone.
++AT_CHECK([ovs-appctl dpctl/del-flows])
++AT_CHECK([ovs-appctl dpctl/dump-flows --names ], [0], [])
++
++dnl Move forward in time and make sure we have at least 4 * 500ms.
++AT_CHECK([ovs-appctl time/warp 3000 300], [0], [ignore])
++
++dnl Make sure no more ukeys exists.
++AT_CHECK([ovs-appctl upcall/show | grep '(keys' | awk '{print $3}' | \
++            grep -qv '0)'], [1])
++
++dnl Verify coverage counter was hit.
++AT_CHECK([ovs-appctl coverage/read-counter revalidate_missing_dp_flow], [0],
++         [dnl
++1
++])
++
++OVS_VSWITCHD_STOP(["/failed to flow_del (No such file or directory)/d"])
++AT_CLEANUP
 diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at
-index 676d55aa95..fcffe21075 100644
+index 676d55aa95..c6dcb00792 100644
 --- a/tests/ofproto-macros.at
 +++ b/tests/ofproto-macros.at
 @@ -141,6 +141,21 @@ strip_stats () {
@@ -12398,6 +12600,18 @@ index 676d55aa95..fcffe21075 100644
  # Changes all 'recirc(...)' and 'recirc=...' to say 'recirc(<recirc_id>)' and
  # 'recirc=<recirc_id>' respectively.  This should make output easier to
  # compare.
+@@ -149,6 +164,11 @@ strip_recirc() {
+         s/recirc_id=[[x0-9]]*/recirc_id=<recirc>/
+         s/recirc([[x0-9]]*)/recirc(<recirc>)/'
+ }
++
++# Strips dp_hash from output.
++strip_dp_hash() {
++    sed 's/dp_hash([[0-9a-fx/]]*),//'
++}
+ m4_divert_pop([PREPARE_TESTS])
+ 
+ m4_define([TESTABLE_LOG], [-vPATTERN:ANY:'%c|%p|%m'])
 diff --git a/tests/ofproto.at b/tests/ofproto.at
 index a666bebcac..2889f81fb1 100644
 --- a/tests/ofproto.at
@@ -12871,7 +13085,7 @@ index e72bf06069..fd1c7a2395 100644
  [{"count":1},{"details":"cannot delete b row <0> because of 2 remaining reference(s)","error":"referential integrity violation"}]
  [{"count":1}]
 diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
-index 5a7e76eaa9..3ed3ec86f8 100644
+index 5a7e76eaa9..15553e4be0 100644
 --- a/tests/ovsdb-idl.at
 +++ b/tests/ovsdb-idl.at
 @@ -1,17 +1,6 @@
@@ -13245,7 +13459,19 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     m4_if([$2], [], [],
       [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
     AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-partial-update-map-column unix:socket $3],
-@@ -1777,7 +1895,7 @@ OVSDB_CHECK_IDL_PY([partial-map update set refmap idl],
+@@ -1741,7 +1859,10 @@ OVSDB_CHECK_IDL_PARTIAL_UPDATE_MAP_COLUMN([map, simple2 idl-partial-update-map-c
+ 007: name=String2 smap=[[key2 : value2]] imap=[[3 : myids2]]
+ 008: After trying to delete a deleted element
+ 009: name=String2 smap=[[key2 : value2]] imap=[[3 : myids2]]
+-010: End test
++010: After Create element, update smap and Delete element
++011: name=String2 smap=[[key2 : value2]] imap=[[3 : myids2]]
++012: After update smap and Delete element
++014: End test
+ ]])
+ 
+ OVSDB_CHECK_IDL_PY([partial-map idl],
+@@ -1777,7 +1898,7 @@ OVSDB_CHECK_IDL_PY([partial-map update set refmap idl],
  m4_define([OVSDB_CHECK_IDL_PARTIAL_UPDATE_SET_COLUMN],
    [AT_SETUP([$1 - C])
     AT_KEYWORDS([ovsdb server idl partial update set column positive $5])
@@ -13254,7 +13480,18 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     m4_if([$2], [], [],
       [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
     AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-partial-update-set-column unix:socket $3],
-@@ -1957,6 +2075,36 @@ OVSDB_CHECK_IDL_NOTIFY([simple idl verify notify],
+@@ -1804,7 +1925,9 @@ OVSDB_CHECK_IDL_PARTIAL_UPDATE_SET_COLUMN([set, simple3 idl-partial-update-set-c
+ 009: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[] uuid=<2>
+ 010: After add to other table + set of strong ref
+ 011: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[<5>] uuid=<2>
+-012: End test
++012: After Create element, update set and Delete element
++013: table simple3: name=String2 uset=[<0>,<1>,<4>] uref=[<5>] uuid=<2>
++014: End test
+ ]])
+ 
+ OVSDB_CHECK_IDL_PY([partial-set idl],
+@@ -1957,6 +2080,36 @@ OVSDB_CHECK_IDL_NOTIFY([simple idl verify notify],
  015: done
  ]])
  
@@ -13291,7 +13528,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
  # Tests to verify the functionality of the one column compound index.
  # It tests index for one column string and integer indexes.
  # The run of test-ovsdb generates the output of the display of data using the different indexes defined in
-@@ -1966,7 +2114,7 @@ OVSDB_CHECK_IDL_NOTIFY([simple idl verify notify],
+@@ -1966,7 +2119,7 @@ OVSDB_CHECK_IDL_NOTIFY([simple idl verify notify],
  m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C],
    [AT_SETUP([$1 - C])
     AT_KEYWORDS([ovsdb server idl compound_index_single_column compound_index positive $5])
@@ -13300,7 +13537,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     m4_if([$2], [], [],
       [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
  # Generate the data to be tested.
-@@ -2113,7 +2261,7 @@ OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C([Compound_index, single column te
+@@ -2113,7 +2266,7 @@ OVSDB_CHECK_IDL_COMPOUND_INDEX_SINGLE_COLUMN_C([Compound_index, single column te
  m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C],
    [AT_SETUP([$1 - C])
     AT_KEYWORDS([ovsdb server idl compound_index_double_column compound_index positive $5])
@@ -13309,7 +13546,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     m4_if([$2], [], [],
       [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
  # Generate the data to be tested.
-@@ -2252,7 +2400,7 @@ OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C([Compound_index, double column te
+@@ -2252,7 +2405,7 @@ OVSDB_CHECK_IDL_COMPOUND_INDEX_DOUBLE_COLUMN_C([Compound_index, double column te
  m4_define([OVSDB_CHECK_IDL_COMPOUND_INDEX_WITH_REF],
    [AT_SETUP([$1 - C])
     AT_KEYWORDS([ovsdb server idl compound_index compound_index_with_ref positive $5])
@@ -13318,7 +13555,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     m4_if([$2], [], [],
       [AT_CHECK([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore])])
     AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 -c idl-compound-index-with-ref unix:socket $3],
-@@ -2280,7 +2428,7 @@ m4_define([CHECK_STREAM_OPEN_BLOCK],
+@@ -2280,7 +2433,7 @@ m4_define([CHECK_STREAM_OPEN_BLOCK],
     AT_SKIP_IF([test "$3" = "tcp6" && test "$IS_WIN32" = "yes"])
     AT_SKIP_IF([test "$3" = "tcp6" && test "$HAVE_IPV6" = "no"])
     AT_KEYWORDS([ovsdb server stream open_block $3])
@@ -13327,7 +13564,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT])
     WRONG_PORT=$(($TCP_PORT + 101))
     AT_CHECK([$2 tcp:$4:$TCP_PORT], [0], [ignore])
-@@ -2296,6 +2444,23 @@ CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py],
+@@ -2296,6 +2449,23 @@ CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py],
  CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py],
                          [tcp6], [[[::1]]])
  
@@ -13351,7 +13588,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
  # same as OVSDB_CHECK_IDL but uses Python IDL implementation with tcp
  # with multiple remotes to assert the idl connects to the leader of the Raft cluster
  m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY],
-@@ -2311,10 +2476,11 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY],
+@@ -2311,10 +2481,11 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY],
     pids=$(cat s2.pid s3.pid s1.pid | tr '\n' ',')
     echo $pids
     AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t30 idl-cluster $srcdir/idltest.ovsschema $remotes $pids $3],
@@ -13364,7 +13601,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     AT_CLEANUP])
  
  OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL connects to leader], 3, ['remote'])
-@@ -2357,6 +2523,7 @@ m4_define([OVSDB_CHECK_CLUSTER_IDL_C],
+@@ -2357,6 +2528,7 @@ m4_define([OVSDB_CHECK_CLUSTER_IDL_C],
     AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]),
              [0], [$5])
     m4_ifval([$8], [AT_CHECK([grep '$8' stderr], [1])], [], [])
@@ -13372,7 +13609,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     AT_CLEANUP])
  
  # Same as OVSDB_CHECK_CLUSTER_IDL_C but uses the Python IDL implementation.
-@@ -2377,6 +2544,7 @@ m4_define([OVSDB_CHECK_CLUSTER_IDL_PY],
+@@ -2377,6 +2549,7 @@ m4_define([OVSDB_CHECK_CLUSTER_IDL_PY],
     AT_CHECK([sort stdout | uuidfilt]m4_if([$7],,, [[| $7]]),
              [0], [$5])
     m4_if([$8], [AT_CHECK([grep '$8' stderr], [1])], [], [])
@@ -13380,7 +13617,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     AT_CLEANUP])
  
  m4_define([OVSDB_CHECK_CLUSTER_IDL],
-@@ -2468,7 +2636,7 @@ reconnect.*waiting .* seconds before reconnect)
+@@ -2468,7 +2641,7 @@ reconnect.*waiting .* seconds before reconnect)
  
  AT_SETUP([idl table and column presence check])
  AT_KEYWORDS([ovsdb server idl table column check])
@@ -13389,7 +13626,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
  
  AT_CHECK(ovsdb-tool create db2 $abs_srcdir/idltest.ovsschema)
  AT_CHECK(ovsdb-server -vconsole:warn --log-file=ovsdb-server2.log --detach dnl
-@@ -2596,7 +2764,7 @@ OVSDB_CHECK_IDL_TRACK([track, insert and delete, refs to link2],
+@@ -2596,7 +2769,7 @@ OVSDB_CHECK_IDL_TRACK([track, insert and delete, refs to link2],
  m4_define([OVSDB_CHECK_IDL_PERS_UUID_INSERT_C],
    [AT_SETUP([$1 - C])
     AT_KEYWORDS([idl persistent uuid insert])
@@ -13398,7 +13635,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket $2],
              [0], [stdout], [stderr])
     AT_CHECK([sort stdout],
-@@ -2608,7 +2776,7 @@ m4_define([OVSDB_CHECK_IDL_PERS_UUID_INSERT_C],
+@@ -2608,7 +2781,7 @@ m4_define([OVSDB_CHECK_IDL_PERS_UUID_INSERT_C],
  m4_define([OVSDB_CHECK_IDL_PERS_UUID_INSERT_PY],
    [AT_SETUP([$1 - Python3])
     AT_KEYWORDS([idl persistent uuid insert])
@@ -13407,7 +13644,7 @@ index 5a7e76eaa9..3ed3ec86f8 100644
     AT_CHECK([$PYTHON3 $srcdir/test-ovsdb.py  -t10 idl $srcdir/idltest.ovsschema unix:socket $2],
              [0], [stdout], [stderr])
     AT_CHECK([sort stdout],
-@@ -2650,3 +2818,93 @@ OVSDB_CHECK_IDL_PERS_UUID_INSERT([simple idl, persistent uuid insert],
+@@ -2650,3 +2823,93 @@ OVSDB_CHECK_IDL_PERS_UUID_INSERT([simple idl, persistent uuid insert],
  011: done
  ]],
    [['This UUID would duplicate a UUID already present within the table or deleted within the same transaction']])
@@ -17094,7 +17331,7 @@ index a38bf9e6df..86a223caff 100644
      for (i = 0; i < n_threads; i++) {
          printf(" %6" PRIu64, thread_working_ms[i]);
 diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
-index 1bc5ac17a0..e6d83e12da 100644
+index 1bc5ac17a0..371dc7314b 100644
 --- a/tests/test-ovsdb.c
 +++ b/tests/test-ovsdb.c
 @@ -870,7 +870,8 @@ do_parse_rows(struct ovs_cmdl_context *ctx)
@@ -17251,6 +17488,58 @@ index 1bc5ac17a0..e6d83e12da 100644
          }
          seqno = ovsdb_idl_get_seqno(idl);
  
+@@ -2969,6 +3020,29 @@ do_idl_partial_update_map_column(struct ovs_cmdl_context *ctx)
+     printf("%03d: After trying to delete a deleted element\n", step++);
+     dump_simple2(idl, myRow, step++);
+ 
++    myTxn = ovsdb_idl_txn_create(idl);
++    myRow = idltest_simple2_insert(myTxn);
++    idltest_simple2_update_smap_setkey(myRow, "key3", "myList3");
++    idltest_simple2_set_name(myRow, "String2");
++    idltest_simple2_delete(myRow);
++    ovsdb_idl_txn_commit_block(myTxn);
++    ovsdb_idl_txn_destroy(myTxn);
++    ovsdb_idl_get_initial_snapshot(idl);
++    printf("%03d: After Create element, update smap and Delete element\n",
++           step++);
++    dump_simple2(idl, myRow, step++);
++
++    myTxn = ovsdb_idl_txn_create(idl);
++    myRow = idltest_simple2_first(idl);
++    idltest_simple2_update_smap_setkey(myRow, "key4", "myList4");
++    idltest_simple2_set_name(myRow, "String3");
++    idltest_simple2_delete(myRow);
++    ovsdb_idl_txn_commit_block(myTxn);
++    ovsdb_idl_txn_destroy(myTxn);
++    ovsdb_idl_get_initial_snapshot(idl);
++    printf("%03d: After update smap and Delete element\n", step++);
++    dump_simple2(idl, myRow, step++);
++
+     ovsdb_idl_destroy(idl);
+     printf("%03d: End test\n", step);
+ }
+@@ -3067,6 +3141,21 @@ do_idl_partial_update_set_column(struct ovs_cmdl_context *ctx)
+     ovsdb_idl_get_initial_snapshot(idl);
+     printf("%03d: After add to other table + set of strong ref\n", step++);
+     dump_simple3(idl, myRow, step++);
++
++    /* create row, insert key, delete row */
++    myTxn = ovsdb_idl_txn_create(idl);
++    myRow = idltest_simple3_insert(myTxn);
++    uuid_from_string(&uuid_to_add, "12345678-dd3f-4616-ab6a-83a490bb0991");
++    idltest_simple3_update_uset_addvalue(myRow, uuid_to_add);
++    idltest_simple3_set_name(myRow, "String2");
++    idltest_simple3_delete(myRow);
++    ovsdb_idl_txn_commit_block(myTxn);
++    ovsdb_idl_txn_destroy(myTxn);
++    ovsdb_idl_get_initial_snapshot(idl);
++    printf("%03d: After Create element, update set and Delete element\n",
++           step++);
++    dump_simple3(idl, myRow, step++);
++
+     ovsdb_idl_destroy(idl);
+     printf("%03d: End test\n", step);
+ }
 diff --git a/tests/test-ovsdb.py b/tests/test-ovsdb.py
 index a841adba4e..67a45f044b 100644
 --- a/tests/test-ovsdb.py
diff --git a/SPECS/openvswitch3.1.spec b/SPECS/openvswitch3.1.spec
index 8277e77..59ef2f6 100644
--- a/SPECS/openvswitch3.1.spec
+++ b/SPECS/openvswitch3.1.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 3.1.0
-Release: 129%{?dist}
+Release: 130%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -756,6 +756,16 @@ exit 0
 %endif
 
 %changelog
+* Mon Sep 16 2024 Open vSwitch CI <ovs-ci@redhat.com> - 3.1.0-130
+- Merging upstream branch-3.1 [RH git: 1036ded5d1]
+    Commit list:
+    99e7cf9cce vconn: Always properly free flow stats reply.
+    72f2f60dd7 mcast-snooping: Properly check group_get_lru return code.
+    f59f19bf69 ovsdb-idl: Fix IDL memory leak.
+    8b2e703a48 ofproto/bond: Preserve active bond member over restarts.
+    88b50b4cda ofproto-dpif-upcall: Avoid stale ukeys leaks.
+
+
 * Wed Aug 14 2024 Open vSwitch CI <ovs-ci@redhat.com> - 3.1.0-129
 - Merging upstream branch-3.1 [RH git: c2c244d6c4]
     Commit list: