Blob Blame History Raw
diff --git a/.ci/linux-prepare.sh b/.ci/linux-prepare.sh
index 2a191b57fb..5f8a1db6af 100755
--- a/.ci/linux-prepare.sh
+++ b/.ci/linux-prepare.sh
@@ -23,7 +23,7 @@ cd ..
 #     https://github.com/pypa/pip/issues/10655
 pip3 install --disable-pip-version-check --user wheel
 pip3 install --disable-pip-version-check --user \
-    flake8 netaddr pyparsing sarif-tools sphinx setuptools
+    flake8 netaddr pyparsing sarif-tools==2.0.0 sphinx setuptools
 
 # Install python test dependencies
 pip3 install -r python/test_requirements.txt
diff --git a/Documentation/ref/ovs-appctl.8.rst b/Documentation/ref/ovs-appctl.8.rst
index 7054cf559e..e7c8b96d49 100644
--- a/Documentation/ref/ovs-appctl.8.rst
+++ b/Documentation/ref/ovs-appctl.8.rst
@@ -6,11 +6,11 @@ Synopsis
 ========
 
 ``ovs-appctl``
-[``--target=``<target> | ``-t`` <target>]
-[``--timeout=``<secs> | ``-T`` <secs>]
-[``--format=``<format> | ``-f`` <format>]
+[``--target=``\ *target* | ``-t`` *target*]
+[``--timeout=``\ *secs* | ``-T`` *secs*]
+[``--format=``\ *format* | ``-f`` *format*]
 [``--pretty``]
-<command> [<arg>...]
+*command* [*arg* ``...``]
 
 ``ovs-appctl --help``
 
@@ -33,11 +33,11 @@ command and prints the daemon's response on standard output.
 
 In normal use only a single option is accepted:
 
-* ``-t`` <target> or ``--target`` <target>
+* ``-t`` *target* or ``--target=``\ *target*
 
   Tells ``ovs-appctl`` which daemon to contact.
 
-  If <target> begins with ``/`` it must name a Unix domain socket on
+  If *target* begins with ``/`` it must name a Unix domain socket on
   which an Open vSwitch daemon is listening for control channel
   connections.  By default, each daemon listens on a Unix domain socket
   in the rundir (e.g. ``/run``) named ``<program>.<pid>.ctl``, where
@@ -47,33 +47,33 @@ In normal use only a single option is accepted:
 
   Otherwise, ``ovs-appctl`` looks in the rundir for a pidfile, that is,
   a file whose contents are the process ID of a running process as a
-  decimal number, named ``<target>.pid``.  (The ``--pidfile`` option
+  decimal number, named *target*\ ``.pid``.  (The ``--pidfile`` option
   makes an Open vSwitch daemon create a pidfile.)  ``ovs-appctl`` reads
   the pidfile, then looks in the rundir for a Unix socket named
-  ``<target>.<pid>.ctl``, where <pid> is replaced by the process ID read
+  *target*\ ``.<pid>.ctl``, where <pid> is replaced by the process ID read
   from the pidfile, and uses that file as if it had been specified
   directly as the target.
 
-  On Windows, <target> can be an absolute path to a file that contains a
+  On Windows, *target* can be an absolute path to a file that contains a
   localhost TCP port on which an Open vSwitch daemon is listening for
   control channel connections. By default, each daemon writes the TCP
   port on which it is listening for control connection into the file
-  ``<program>.ctl`` located inside the rundir. If <target> is not an
+  ``<program>.ctl`` located inside the rundir. If *target* is not an
   absolute path, ``ovs-appctl`` looks in the rundir for a file named
-  ``<target>.ctl``.  The default target is ``ovs-vswitchd``.
+  *target*\ ``.ctl``.  The default *target* is ``ovs-vswitchd``.
 
-* ``-T <secs>`` or ``--timeout=<secs>``
+* ``-T`` *secs* or ``--timeout=``\ *secs*
 
-  By default, or with a <secs> of ``0``, ``ovs-appctl`` waits forever to
+  By default, or with a *secs* of ``0``, ``ovs-appctl`` waits forever to
   connect to the daemon and receive a response.  This option limits
-  runtime to approximately <secs> seconds.  If the timeout expires,
+  runtime to approximately *secs* seconds.  If the timeout expires,
   ``ovs-appctl`` exits with a ``SIGALRM`` signal.
 
-* ``-f <format>`` or ``--format=<format>``
+* ``-f`` *format* or ``--format=``\ *format*
 
   Tells ``ovs-appctl`` which output format to use.  By default, or with a
-  <format> of ``text``, ``ovs-appctl`` will print plain-text for humans.
-  When <format> is ``json``, ``ovs-appctl`` will return a JSON document.
+  *format* of ``text``, ``ovs-appctl`` will print plain-text for humans.
+  When *format* is ``json``, ``ovs-appctl`` will return a JSON document.
   When ``json`` is requested, but a command has not implemented JSON
   output, the plain-text output will be wrapped in a provisional JSON
   document with the following structure::
@@ -158,10 +158,10 @@ and adjusting log levels:
 
   Lists logging pattern used for each destination.
 
-* ``vlog/set`` [<spec>]
+* ``vlog/set`` [*spec*]
 
-  Sets logging levels.  Without any <spec>, sets the log level for
-  every module and destination to ``dbg``.  Otherwise, <spec> is a
+  Sets logging levels.  Without any *spec*, sets the log level for
+  every module and destination to ``dbg``.  Otherwise, *spec* is a
   list of words separated by spaces or commas or colons, up to one from
   each category below:
 
@@ -173,7 +173,7 @@ and adjusting log levels:
     change to only to the system log, to the console, or to a file,
     respectively.
 
-    On Windows platform, ``syslog`` is only useful if <target> was
+    On Windows platform, ``syslog`` is only useful if *target* was
     started with the ``--syslog-target`` option (it has no effect
     otherwise).
 
@@ -182,20 +182,20 @@ and adjusting log levels:
     will be logged, and messages of lower severity will be filtered out.
     ``off`` filters out all messages.
 
-  Case is not significant within <spec>.
+  Case is not significant within *spec*.
 
   Regardless of the log levels set for ``file``, logging to a file
   will not take place unless the target application was invoked with the
   ``--log-file`` option.
 
   For compatibility with older versions of OVS, ``any`` is accepted
-  within <spec> but it has no effect.
+  within *spec* but it has no effect.
 
-* ``vlog/set PATTERN:<destination>:<pattern>``
+* ``vlog/set PATTERN:``\ *destination*:*pattern*
 
-  Sets the log pattern for <destination> to <pattern>.  Each time a
-  message is logged to <destination>, <pattern> determines the
-  message's formatting.  Most characters in <pattern> are copied
+  Sets the log pattern for *destination* to *pattern*.  Each time a
+  message is logged to *destination*, *pattern* determines the
+  message's formatting.  Most characters in *pattern* are copied
   literally to the log, but special escapes beginning with ``%`` are
   expanded as follows:
 
@@ -214,13 +214,13 @@ and adjusting log levels:
 
   * ``%d``
 
-    The current date and time in ISO 8601 format (YYYY-MM-DD HH:MM:SS).
+    The current date and time in ISO 8601 format (``YYYY-MM-DD HH:MM:SS``).
 
-  * ``%d{<format>}``
+  * ``%d{``\ *format*\ ``}``
 
-    The current date and time in the specified <format>, which takes
-    the same format as the <template> argument to ``strftime(3)``.  As
-    an extension, any ``#`` characters in <format> will be replaced by
+    The current date and time in the specified *format*, which takes
+    the same format as the ``template`` argument to ``strftime(3)``.  As
+    an extension, any ``#`` characters in *format* will be replaced by
     fractional seconds, e.g. use ``%H:%M:%S.###`` for the time to the
     nearest millisecond.  Sub-second times are only approximate and
     currently decimal places after the third will always be reported
@@ -228,14 +228,14 @@ and adjusting log levels:
 
   * ``%D``
 
-    The current UTC date and time in ISO 8601 format (YYYY-MM-DD
-    HH:MM:SS).
+    The current UTC date and time in ISO 8601 format
+    (``YYYY-MM-DD HH:MM:SS``).
 
-  * ``%D{<format>}``
+  * ``%D{``\ *format*\ ``}``
 
-    The current UTC date and time in the specified <format>, which
-    takes the same format as the <template> argument to
-    ``strftime``(3).  Supports the same extension for sub-second
+    The current UTC date and time in the specified *format*, which
+    takes the same format as the ``template`` argument to
+    ``strftime(3)``.  Supports the same extension for sub-second
     resolution as ``%d{...}``.
 
   * ``%E``
@@ -299,22 +299,23 @@ and adjusting log levels:
     Pad the field to the field width with ``0`` characters.  Padding
     with spaces is the default.
 
-  * <width>
+  * *width*
 
     A number specifies the minimum field width.  If the escape expands
-    to fewer characters than <width> then it is padded to fill the
-    field width.  (A field wider than <width> is not truncated to
+    to fewer characters than *width* then it is padded to fill the
+    field width.  (A field wider than *width* is not truncated to
     fit.)
 
-  The default pattern for console and file output is ``%D{%Y-%m-%dT
-  %H:%M:%SZ}|%05N|%c|%p|%m``; for syslog output, ``%05N|%c|%p|%m``.
+  The default pattern for console and file output is
+  ``%D{%Y-%m-%dT %H:%M:%SZ}|%05N|%c|%p|%m``; for syslog output,
+  ``%05N|%c|%p|%m``.
 
   Daemons written in Python (e.g. ``ovs-monitor-ipsec``) do not allow
   control over the log pattern.
 
-* ``vlog/set FACILITY:<facility>``
+* ``vlog/set FACILITY:``\ *facility*
 
-  Sets the RFC5424 facility of the log message. <facility> can be one
+  Sets the RFC5424 facility of the log message. *facility* can be one
   of ``kern``, ``user``, ``mail``, ``daemon``, ``auth``, ``syslog``,
   ``lpr``, ``news``, ``uucp``, ``clock``, ``ftp``, ``ntp``, ``audit``,
   ``alert``, ``clock2``, ``local0``, ``local1``, ``local2``,
diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c
index dc5164b41c..bf25e6f20a 100644
--- a/lib/mcast-snooping.c
+++ b/lib/mcast-snooping.c
@@ -432,7 +432,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);
         }
 
diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index 16c56608d8..529d64fe1d 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -254,7 +254,7 @@ dp_packet_tnl_ol_process(struct dp_packet *packet,
 
             if (IP_VER(ip->ip_ihl_ver) == 4) {
                 dp_packet_hwol_set_tx_ipv4(packet);
-                dp_packet_hwol_tx_ip_csum(packet);
+                dp_packet_hwol_set_tx_ip_csum(packet);
             } else if (IP_VER(ip->ip_ihl_ver) == 6) {
                 dp_packet_hwol_set_tx_ipv6(packet);
             }
diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index ba720474b6..d92df28d19 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -3783,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/vconn.c b/lib/vconn.c
index e9603432d2..4b1c262eaa 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -1017,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;
             }
         }
@@ -1031,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;
@@ -1041,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/ofproto/bond.c b/ofproto/bond.c
index c31869a4c7..0858de3746 100644
--- a/ofproto/bond.c
+++ b/ofproto/bond.c
@@ -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;
 
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 4d39bc5a71..e7d4c2b2c3 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -57,6 +57,7 @@ COVERAGE_DEFINE(dumped_inconsistent_flow);
 COVERAGE_DEFINE(dumped_new_flow);
 COVERAGE_DEFINE(handler_duplicate_upcall);
 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);
@@ -284,6 +285,7 @@ enum flow_del_reason {
     FDR_TOO_EXPENSIVE,      /* Too expensive to revalidate. */
     FDR_UPDATE_FAIL,        /* Datapath update failed. */
     FDR_XLATION_ERROR,      /* Flow translation error. */
+    FDR_FLOW_MISSING_DP,    /* Flow is missing from the datapath. */
 };
 
 /* 'udpif_key's are responsible for tracking the little bit of state udpif
@@ -318,6 +320,7 @@ struct udpif_key {
     uint64_t dump_seq OVS_GUARDED;            /* Tracks udpif->dump_seq. */
     uint64_t reval_seq OVS_GUARDED;           /* Tracks udpif->reval_seq. */
     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. */
@@ -3040,6 +3043,21 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
                     result = revalidate_ukey(udpif, ukey, &stats, &odp_actions,
                                              reval_seq, &recircs, &del_reason);
                 }
+
+                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);
+                        del_reason = FDR_FLOW_MISSING_DP;
+                        result = UKEY_DELETE;
+                    }
+                } else {
+                    ukey->missed_dumps = 0;
+                }
+
                 if (result != UKEY_KEEP) {
                     /* Clears 'recircs' if filled by revalidate_ukey(). */
                     reval_op_init(&ops[n_ops++], result, udpif, ukey, &recircs,
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 42fb66de68..12cb7f7a6a 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -757,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([ofproto-dpif - bond - allow duplicated frames])
 dnl Receiving of duplicated multicast frames should be allowed with 'all_members_active'.
 OVS_VSWITCHD_START([dnl
@@ -12661,3 +12728,48 @@ AT_CHECK([ovs-appctl revalidator/resume])
 
 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/ovsdb-idl.at b/tests/ovsdb-idl.at
index 9070ea051a..74ccaccdd2 100644
--- a/tests/ovsdb-idl.at
+++ b/tests/ovsdb-idl.at
@@ -1881,7 +1881,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],
@@ -1944,7 +1947,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],
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index 41c1525f45..710341b655 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -3020,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);
 }
@@ -3118,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/utilities/usdt-scripts/flow_reval_monitor.py b/utilities/usdt-scripts/flow_reval_monitor.py
index 28479a5650..80c9c98bdb 100755
--- a/utilities/usdt-scripts/flow_reval_monitor.py
+++ b/utilities/usdt-scripts/flow_reval_monitor.py
@@ -255,6 +255,7 @@ FdrReasons = IntEnum(
         "FDR_TOO_EXPENSIVE",
         "FDR_UPDATE_FAIL",
         "FDR_XLATION_ERROR",
+        "FDR_FLOW_MISSING_DP"
     ],
     start=0,
 )
@@ -270,7 +271,8 @@ FdrReasonStrings = {
     FdrReasons.FDR_PURGE: "User requested flow deletion",
     FdrReasons.FDR_TOO_EXPENSIVE: "Too expensive to revalidate",
     FdrReasons.FDR_UPDATE_FAIL: "Datapath update failed",
-    FdrReasons.FDR_XLATION_ERROR: "Flow translation error"
+    FdrReasons.FDR_XLATION_ERROR: "Flow translation error",
+    FdrReasons.FDR_FLOW_MISSING_DP: "Flow is missing from the datapath"
 }