diff --git a/NEWS b/NEWS
index 224a7b83e..6c4573b50 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,7 @@
 Post v22.09.0
 -------------
+  - ovn-northd: Add configuration knobs to enable drop sampling using OVS's
+    per-flow IPFIX sampling.
 
 OVN v22.09.0 - 16 Sep 2022
 --------------------------
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 7dd83e7f4..0752a71ad 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -3172,6 +3172,8 @@ lflow_output_sb_meter_handler(struct engine_node *node, void *data)
 struct ed_type_pflow_output {
     /* Desired physical flows. */
     struct ovn_desired_flow_table flow_table;
+    /* Drop debugging options. */
+    struct physical_debug debug;
 };
 
 static void init_physical_ctx(struct engine_node *node,
@@ -3216,6 +3218,11 @@ static void init_physical_ctx(struct engine_node *node,
         chassis = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
     }
 
+    const struct sbrec_sb_global_table *sb_global_table =
+        EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
+    const struct sbrec_sb_global *sb_global =
+        sbrec_sb_global_table_first(sb_global_table);
+
     ovs_assert(br_int && chassis);
 
     struct ed_type_ct_zones *ct_zones_data =
@@ -3237,6 +3244,13 @@ static void init_physical_ctx(struct engine_node *node,
     p_ctx->local_bindings = &rt_data->lbinding_data.bindings;
     p_ctx->patch_ofports = &non_vif_data->patch_ofports;
     p_ctx->chassis_tunnels = &non_vif_data->chassis_tunnels;
+    p_ctx->debug.collector_set_id = smap_get_uint(&sb_global->options,
+                                                  "debug_drop_collector_set",
+                                                  0);
+
+    p_ctx->debug.obs_domain_id = smap_get_uint(&sb_global->options,
+                                               "debug_drop_domain_id",
+                                               0);
 }
 
 static void *
@@ -3439,6 +3453,32 @@ pflow_output_activated_ports_handler(struct engine_node *node, void *data)
     return true;
 }
 
+static bool
+pflow_output_sb_sb_global_handler(struct engine_node *node, void *data)
+{
+    const struct sbrec_sb_global_table *sb_global_table =
+        EN_OVSDB_GET(engine_get_input("SB_sb_global", node));
+    const struct sbrec_sb_global *sb_global =
+        sbrec_sb_global_table_first(sb_global_table);
+
+    struct ed_type_pflow_output *pfo = data;
+
+    uint32_t collector_set_id = smap_get_uint(&sb_global->options,
+                                              "debug_drop_collector_set",
+                                              0);
+    uint32_t obs_domain_id = smap_get_uint(&sb_global->options,
+                                           "debug_drop_domain_id",
+                                           0);
+
+    if (pfo->debug.collector_set_id != collector_set_id ||
+        pfo->debug.obs_domain_id != obs_domain_id) {
+        engine_set_node_state(node, EN_UPDATED);
+        pfo->debug.collector_set_id = collector_set_id;
+        pfo->debug.obs_domain_id = obs_domain_id;
+    }
+    return true;
+}
+
 static void *
 en_flow_output_init(struct engine_node *node OVS_UNUSED,
                     struct engine_arg *arg OVS_UNUSED)
@@ -3781,6 +3821,8 @@ main(int argc, char *argv[])
     engine_add_input(&en_pflow_output, &en_mff_ovn_geneve, NULL);
     engine_add_input(&en_pflow_output, &en_ovs_open_vswitch, NULL);
     engine_add_input(&en_pflow_output, &en_ovs_bridge, NULL);
+    engine_add_input(&en_pflow_output, &en_sb_sb_global,
+                     pflow_output_sb_sb_global_handler);
 
     engine_add_input(&en_northd_options, &en_sb_sb_global,
                      en_northd_options_sb_sb_global_handler);
diff --git a/controller/physical.c b/controller/physical.c
index 58c4e1f05..bda64741e 100644
--- a/controller/physical.c
+++ b/controller/physical.c
@@ -834,14 +834,32 @@ put_zones_ofpacts(const struct zone_ids *zone_ids, struct ofpbuf *ofpacts_p)
 }
 
 static void
-add_default_drop_flow(uint8_t table_id,
+put_drop(const struct physical_debug *debug, uint8_t table_id,
+         struct ofpbuf *ofpacts)
+{
+    if (debug->collector_set_id) {
+        struct ofpact_sample *os = ofpact_put_SAMPLE(ofpacts);
+        os->probability = UINT16_MAX;
+        os->collector_set_id = debug->collector_set_id;
+        os->obs_domain_id = (debug->obs_domain_id << 24);
+        os->obs_point_id = table_id;
+    }
+}
+
+static void
+add_default_drop_flow(const struct physical_ctx *p_ctx,
+                      uint8_t table_id,
                       struct ovn_desired_flow_table *flow_table)
 {
     struct match match = MATCH_CATCHALL_INITIALIZER;
     struct ofpbuf ofpacts;
     ofpbuf_init(&ofpacts, 0);
+
+    put_drop(&p_ctx->debug, table_id, &ofpacts);
     ofctrl_add_flow(flow_table, table_id, 0, 0, &match,
                     &ofpacts, hc_uuid);
+
+    ofpbuf_uninit(&ofpacts);
 }
 
 static void
@@ -849,6 +867,7 @@ put_local_common_flows(uint32_t dp_key,
                        const struct sbrec_port_binding *pb,
                        const struct sbrec_port_binding *parent_pb,
                        const struct zone_ids *zone_ids,
+                       const struct physical_debug *debug,
                        struct ofpbuf *ofpacts_p,
                        struct ovn_desired_flow_table *flow_table)
 {
@@ -884,6 +903,7 @@ put_local_common_flows(uint32_t dp_key,
      * and the MLF_ALLOW_LOOPBACK flag is not set. */
     match_init_catchall(&match);
     ofpbuf_clear(ofpacts_p);
+    put_drop(debug, OFTABLE_CHECK_LOOPBACK, ofpacts_p);
     match_set_metadata(&match, htonll(dp_key));
     match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
                          0, MLF_ALLOW_LOOPBACK);
@@ -1155,6 +1175,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
                       const struct hmap *chassis_tunnels,
                       const struct sbrec_port_binding *binding,
                       const struct sbrec_chassis *chassis,
+                      const struct physical_debug *debug,
                       struct ovn_desired_flow_table *flow_table,
                       struct ofpbuf *ofpacts_p)
 {
@@ -1178,7 +1199,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
 
         struct zone_ids binding_zones = get_zone_ids(binding, ct_zones);
         put_local_common_flows(dp_key, binding, NULL, &binding_zones,
-                               ofpacts_p, flow_table);
+                               debug, ofpacts_p, flow_table);
 
         ofpbuf_clear(ofpacts_p);
         match_outport_dp_and_port_keys(&match, dp_key, port_key);
@@ -1354,7 +1375,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
         /* Pass the parent port binding if the port is a nested
          * container. */
         put_local_common_flows(dp_key, binding, parent_port, &zone_ids,
-                               ofpacts_p, flow_table);
+                               debug, ofpacts_p, flow_table);
 
         /* Table 0, Priority 150 and 100.
          * ==============================
@@ -1486,6 +1507,7 @@ consider_port_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
 
             /* Drop LOCAL_ONLY traffic leaking through localnet ports. */
             ofpbuf_clear(ofpacts_p);
+            put_drop(debug, OFTABLE_CHECK_LOOPBACK, ofpacts_p);
             match_outport_dp_and_port_keys(&match, dp_key, port_key);
             match_set_reg_masked(&match, MFF_LOG_FLAGS - MFF_REG0,
                                  MLF_LOCAL_ONLY, MLF_LOCAL_ONLY);
@@ -1883,7 +1905,8 @@ physical_eval_port_binding(struct physical_ctx *p_ctx,
                           p_ctx->local_bindings,
                           p_ctx->patch_ofports,
                           p_ctx->chassis_tunnels,
-                          pb, p_ctx->chassis, flow_table, &ofpacts);
+                          pb, p_ctx->chassis, &p_ctx->debug,
+                          flow_table, &ofpacts);
     ofpbuf_uninit(&ofpacts);
 }
 
@@ -2006,7 +2029,8 @@ physical_run(struct physical_ctx *p_ctx,
                               p_ctx->local_bindings,
                               p_ctx->patch_ofports,
                               p_ctx->chassis_tunnels, binding,
-                              p_ctx->chassis, flow_table, &ofpacts);
+                              p_ctx->chassis, &p_ctx->debug,
+                              flow_table, &ofpacts);
     }
 
     /* Handle output to multicast groups, in tables 37 and 38. */
@@ -2130,7 +2154,7 @@ physical_run(struct physical_ctx *p_ctx,
      *
      * Drop packets tha do not match any tunnel in_port.
      */
-    add_default_drop_flow(OFTABLE_PHY_TO_LOG, flow_table);
+    add_default_drop_flow(p_ctx, OFTABLE_PHY_TO_LOG, flow_table);
 
     /* Table 37, priority 150.
      * =======================
@@ -2182,7 +2206,7 @@ physical_run(struct physical_ctx *p_ctx,
      *
      * Drop packets that do not match previous flows.
      */
-    add_default_drop_flow(OFTABLE_LOCAL_OUTPUT, flow_table);
+    add_default_drop_flow(p_ctx, OFTABLE_LOCAL_OUTPUT, flow_table);
 
     /* Table 39, Priority 0.
      * =======================
@@ -2215,7 +2239,7 @@ physical_run(struct physical_ctx *p_ctx,
      *
      * Drop packets that do not match previous flows.
      */
-    add_default_drop_flow(OFTABLE_LOG_TO_PHY, flow_table);
+    add_default_drop_flow(p_ctx, OFTABLE_LOG_TO_PHY, flow_table);
 
     ofpbuf_uninit(&ofpacts);
 }
diff --git a/controller/physical.h b/controller/physical.h
index 1b8f1ea55..f450dca94 100644
--- a/controller/physical.h
+++ b/controller/physical.h
@@ -43,6 +43,11 @@ struct local_nonvif_data;
 #define OVN_GENEVE_TYPE 0x80     /* Critical option. */
 #define OVN_GENEVE_LEN 4
 
+struct physical_debug {
+    uint32_t collector_set_id;
+    uint32_t obs_domain_id;
+};
+
 struct physical_ctx {
     struct ovsdb_idl_index *sbrec_port_binding_by_name;
     struct ovsdb_idl_index *sbrec_port_binding_by_datapath;
@@ -59,6 +64,7 @@ struct physical_ctx {
     struct shash *local_bindings;
     struct simap *patch_ofports;
     struct hmap *chassis_tunnels;
+    struct physical_debug debug;
 };
 
 void physical_register_ovs_idl(struct ovsdb_idl *);
diff --git a/northd/automake.mk b/northd/automake.mk
index 81582867d..14cf525d8 100644
--- a/northd/automake.mk
+++ b/northd/automake.mk
@@ -1,6 +1,8 @@
 # ovn-northd
 bin_PROGRAMS += northd/ovn-northd
 northd_ovn_northd_SOURCES = \
+	northd/debug.c \
+	northd/debug.h \
 	northd/mac-binding-aging.c \
 	northd/mac-binding-aging.h \
 	northd/northd.c \
diff --git a/northd/debug.c b/northd/debug.c
new file mode 100644
index 000000000..59da5d4f6
--- /dev/null
+++ b/northd/debug.c
@@ -0,0 +1,98 @@
+#include <config.h>
+
+#include <string.h>
+
+#include "debug.h"
+
+#include "openvswitch/dynamic-string.h"
+#include "openvswitch/vlog.h"
+#include "smap.h"
+
+VLOG_DEFINE_THIS_MODULE(debug)
+
+struct debug_config {
+    bool enabled;
+    uint32_t collector_set_id;
+    uint32_t observation_domain_id;
+    struct ds drop_action;
+};
+
+static struct debug_config config;
+
+static bool
+debug_enabled(void)
+{
+    return config.collector_set_id != 0;
+}
+
+void
+init_debug_config(const struct nbrec_nb_global *nb)
+{
+
+    const struct smap *options = &nb->options;
+    uint32_t collector_set_id = smap_get_uint(options,
+                                              "debug_drop_collector_set",
+                                              0);
+    uint32_t observation_domain_id = smap_get_uint(options,
+                                                   "debug_drop_domain_id",
+                                                   0);
+
+    if (collector_set_id != config.collector_set_id ||
+        observation_domain_id != config.observation_domain_id ||
+        !config.drop_action.length) {
+
+        if (observation_domain_id >= UINT8_MAX) {
+            VLOG_ERR("Observation domain id must be an 8-bit number");
+            return;
+        }
+
+        config.collector_set_id = collector_set_id;
+        config.observation_domain_id = observation_domain_id;
+
+        ds_clear(&config.drop_action);
+
+        if (debug_enabled()) {
+            ds_put_format(&config.drop_action,
+                          "sample(probability=65535,"
+                          "collector_set=%d,"
+                          "obs_domain=%d,"
+                          "obs_point=$cookie); ",
+                          config.collector_set_id,
+                          config.observation_domain_id);
+
+            ds_put_cstr(&config.drop_action, "/* drop */");
+            VLOG_DBG("Debug drop sampling: enabled");
+        } else {
+            ds_put_cstr(&config.drop_action, "drop;");
+            VLOG_DBG("Debug drop sampling: disabled");
+        }
+    }
+}
+
+void
+destroy_debug_config(void)
+{
+    if (config.drop_action.string) {
+        ds_destroy(&config.drop_action);
+        ds_init(&config.drop_action);
+    }
+}
+
+const char *
+debug_drop_action(void) {
+    if (OVS_UNLIKELY(debug_enabled())) {
+        return ds_cstr_ro(&config.drop_action);
+    } else {
+        return "drop;";
+    }
+}
+
+const char *
+debug_implicit_drop_action(void)
+{
+    if (OVS_UNLIKELY(debug_enabled())) {
+        return ds_cstr_ro(&config.drop_action);
+    } else {
+        return "/* drop */";
+    }
+}
diff --git a/northd/debug.h b/northd/debug.h
new file mode 100644
index 000000000..c1a5e5aad
--- /dev/null
+++ b/northd/debug.h
@@ -0,0 +1,30 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NORTHD_DEBUG_H
+#define NORTHD_DEBUG_H 1
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "lib/ovn-nb-idl.h"
+#include "openvswitch/dynamic-string.h"
+
+void init_debug_config(const struct nbrec_nb_global *nb);
+void destroy_debug_config(void);
+
+const char *debug_drop_action(void);
+const char *debug_implicit_drop_action(void);
+
+#endif /* NORTHD_DEBUG_H */
diff --git a/northd/northd.c b/northd/northd.c
index 1cccc33df..1911746b8 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+#include "debug.h"
 #include "bitmap.h"
 #include "dirs.h"
 #include "ipam.h"
@@ -3827,7 +3828,7 @@ build_lb_vip_actions(struct ovn_lb_vip *lb_vip,
         if (!n_active_backends) {
             if (!lb_vip->empty_backend_rej) {
                 ds_clear(action);
-                ds_put_cstr(action, "drop;");
+                ds_put_cstr(action, debug_drop_action());
                 skip_hash_fields = true;
             } else {
                 reject = true;
@@ -5161,7 +5162,7 @@ __ovn_lflow_add_default_drop(struct hmap *lflow_map,
                              enum ovn_stage stage,
                              const char *where)
 {
-    ovn_lflow_add_at(lflow_map, od, stage, 0, "1", "drop;",
+        ovn_lflow_add_at(lflow_map, od, stage, 0, "1", debug_drop_action(),
                          NULL, NULL, NULL, where );
 }
 
@@ -6392,7 +6393,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
             } else {
                 ds_put_format(match, " && (%s)", acl->match);
                 build_acl_log(actions, acl, meter_groups);
-                ds_put_cstr(actions, "/* drop */");
+                ds_put_cstr(actions, debug_implicit_drop_action());
                 ovn_lflow_add_with_hint(lflows, od, stage,
                                         acl->priority + OVN_ACL_PRI_OFFSET,
                                         ds_cstr(match), ds_cstr(actions),
@@ -6420,7 +6421,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
             } else {
                 ds_put_format(match, " && (%s)", acl->match);
                 build_acl_log(actions, acl, meter_groups);
-                ds_put_cstr(actions, "/* drop */");
+                ds_put_cstr(actions, debug_implicit_drop_action());
                 ovn_lflow_add_with_hint(lflows, od, stage,
                                         acl->priority + OVN_ACL_PRI_OFFSET,
                                         ds_cstr(match), ds_cstr(actions),
@@ -6437,7 +6438,7 @@ consider_acl(struct hmap *lflows, struct ovn_datapath *od,
                                        actions, &acl->header_, meter_groups);
             } else {
                 build_acl_log(actions, acl, meter_groups);
-                ds_put_cstr(actions, "/* drop */");
+                ds_put_cstr(actions, debug_implicit_drop_action());
                 ovn_lflow_add_with_hint(lflows, od, stage,
                                         acl->priority + OVN_ACL_PRI_OFFSET,
                                         acl->match, ds_cstr(actions),
@@ -6673,9 +6674,9 @@ build_acls(struct ovn_datapath *od, const struct chassis_features *features,
                       use_ct_inv_match ? "ct.inv || " : "",
                       ct_blocked_match);
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
-                      ds_cstr(&match), "drop;");
+                      ds_cstr(&match), debug_drop_action());
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
-                      ds_cstr(&match), "drop;");
+                      ds_cstr(&match),  debug_drop_action());
 
         /* Ingress and Egress ACL Table (Priority 65535 - 3).
          *
@@ -7775,7 +7776,7 @@ build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
                         rp->lsp_addrs[k].ipv4_addrs[l].addr_s);
                     ovn_lflow_add_with_lport_and_hint(
                         lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100,
-                        ds_cstr(&match), "drop;", port->key,
+                        ds_cstr(&match),  debug_drop_action(), port->key,
                         &op->nbsp->header_);
                 }
                 for (size_t l = 0; l < rp->lsp_addrs[k].n_ipv6_addrs; l++) {
@@ -7791,7 +7792,7 @@ build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
                         rp->lsp_addrs[k].ipv6_addrs[l].addr_s);
                     ovn_lflow_add_with_lport_and_hint(
                         lflows, op->od, S_SWITCH_IN_EXTERNAL_PORT, 100,
-                        ds_cstr(&match), "drop;", port->key,
+                        ds_cstr(&match), debug_drop_action(), port->key,
                         &op->nbsp->header_);
                 }
 
@@ -7806,7 +7807,8 @@ build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op,
                 ovn_lflow_add_with_lport_and_hint(lflows, op->od,
                                                   S_SWITCH_IN_EXTERNAL_PORT,
                                                   100, ds_cstr(&match),
-                                                  "drop;", port->key,
+                                                  debug_drop_action(),
+                                                  port->key,
                                                   &op->nbsp->header_);
             }
         }
@@ -7844,7 +7846,7 @@ build_lswitch_flows(const struct hmap *datapaths,
                           "outport = \""MC_UNKNOWN "\"; output;");
         } else {
             ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 50,
-                          "outport == \"none\"", "drop;");
+                          "outport == \"none\"",  debug_drop_action());
         }
         ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_UNKNOWN, 0, "1",
                       "output;");
@@ -7887,18 +7889,18 @@ build_lswitch_lflows_admission_control(struct ovn_datapath *od,
         if (!is_vlan_transparent(od)) {
             /* Block logical VLANs. */
             ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100,
-                          "vlan.present", "drop;");
+                          "vlan.present", debug_drop_action());
         }
 
         /* Broadcast/multicast source address is invalid. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 100,
-                      "eth.src[40]", "drop;");
+                      "eth.src[40]", debug_drop_action());
 
         ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 50, "1",
                       REGBIT_PORT_SEC_DROP" = check_in_port_sec(); next;");
 
         ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 50,
-                      REGBIT_PORT_SEC_DROP" == 1", "drop;");
+                      REGBIT_PORT_SEC_DROP" == 1", debug_drop_action());
 
         ovn_lflow_add(lflows, od, S_SWITCH_IN_APPLY_PORT_SEC, 0, "1", "next;");
     }
@@ -8427,7 +8429,7 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
                  */
                 if (!mcast_sw_info->flood_relay &&
                         !mcast_sw_info->flood_static) {
-                    ds_put_cstr(actions, "drop;");
+                    ds_put_cstr(actions, debug_drop_action());
                 }
 
                 ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 80,
@@ -8952,7 +8954,7 @@ build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od,
                       out_port->json_key);
 
     } else if (!strcmp(rule->action, "drop")) {
-        ds_put_cstr(&actions, "drop;");
+        ds_put_cstr(&actions, debug_drop_action());
     } else if (!strcmp(rule->action, "allow")) {
         uint32_t pkt_mark = ovn_smap_get_uint(&rule->options, "pkt_mark", 0);
         if (pkt_mark) {
@@ -9802,7 +9804,7 @@ add_route(struct hmap *lflows, struct ovn_datapath *od,
     struct ds common_actions = DS_EMPTY_INITIALIZER;
     struct ds actions = DS_EMPTY_INITIALIZER;
     if (is_discard_route) {
-        ds_put_format(&actions, "drop;");
+        ds_put_cstr(&actions, debug_drop_action());
     } else {
         ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s = ",
                       is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6);
@@ -10585,7 +10587,7 @@ build_lrouter_arp_flow(struct ovn_datapath *od, struct ovn_port *op,
         ds_put_format(&match, " && %s", ds_cstr(extra_match));
     }
     if (drop) {
-        ds_put_format(&actions, "drop;");
+        ds_put_cstr(&actions, debug_drop_action());
     } else {
         ds_put_format(&actions,
                       "eth.dst = eth.src; "
@@ -10641,7 +10643,7 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op,
     }
 
     if (drop) {
-        ds_put_format(&actions, "drop;");
+        ds_put_cstr(&actions, debug_drop_action());
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority,
                                 ds_cstr(&match), ds_cstr(&actions), hint);
     } else {
@@ -10791,7 +10793,7 @@ build_lrouter_drop_own_dest(struct ovn_port *op, enum ovn_stage stage,
 
             char *match = xasprintf("ip4.dst == {%s}", ds_cstr(&match_ips));
             ovn_lflow_add_with_hint(lflows, op->od, stage, priority,
-                                    match, "drop;",
+                                    match, debug_drop_action(),
                                     &op->nbrp->header_);
             free(match);
         }
@@ -10820,7 +10822,7 @@ build_lrouter_drop_own_dest(struct ovn_port *op, enum ovn_stage stage,
 
             char *match = xasprintf("ip6.dst == {%s}", ds_cstr(&match_ips));
             ovn_lflow_add_with_hint(lflows, op->od, stage, priority,
-                                    match, "drop;",
+                                    match, debug_drop_action(),
                                     &op->nbrp->header_);
             free(match);
         }
@@ -10988,7 +10990,7 @@ build_adm_ctrl_flows_for_lrouter(
         /* Logical VLANs not supported.
          * Broadcast/multicast source address is invalid. */
         ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100,
-                      "vlan.present || eth.src[40]", "drop;");
+                      "vlan.present || eth.src[40]", debug_drop_action());
 
         /* Default action for L2 security is to drop. */
         ovn_lflow_add_default_drop(lflows, od, S_ROUTER_IN_ADMISSION);
@@ -11581,7 +11583,7 @@ build_mcast_lookup_flows_for_lrouter(
          * i.e., router solicitation and router advertisement.
          */
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
-                      "nd_rs || nd_ra", "drop;");
+                      "nd_rs || nd_ra", debug_drop_action());
         if (!od->mcast_info.rtr.relay) {
             return;
         }
@@ -11628,13 +11630,13 @@ build_mcast_lookup_flows_for_lrouter(
                 ds_put_format(match, "eth.src == %s && igmp",
                               op->lrp_networks.ea_s);
                 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
-                              ds_cstr(match), "drop;");
+                              ds_cstr(match), debug_drop_action());
 
                 ds_clear(match);
                 ds_put_format(match, "eth.src == %s && (mldv1 || mldv2)",
                               op->lrp_networks.ea_s);
                 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10550,
-                              ds_cstr(match), "drop;");
+                              ds_cstr(match), debug_drop_action());
             }
 
             ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10460,
@@ -11658,7 +11660,7 @@ build_mcast_lookup_flows_for_lrouter(
                           "};");
         } else {
             ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, 10450,
-                          "ip4.mcast || ip6.mcast", "drop;");
+                          "ip4.mcast || ip6.mcast", debug_drop_action());
         }
     }
 }
@@ -12484,7 +12486,7 @@ build_misc_local_traffic_drop_flows_for_lrouter(
                       "ip4.dst == 127.0.0.0/8 || "
                       "ip4.src == 0.0.0.0/8 || "
                       "ip4.dst == 0.0.0.0/8",
-                      "drop;");
+                      debug_drop_action());
 
         /* Drop ARP packets (priority 85). ARP request packets for router's own
          * IPs are handled with priority-90 flows.
@@ -12492,7 +12494,7 @@ build_misc_local_traffic_drop_flows_for_lrouter(
          * IPs are handled with priority-90 flows.
          */
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 85,
-                      "arp || nd", "drop;");
+                      "arp || nd", debug_drop_action());
 
         /* Allow IPv6 multicast traffic that's supposed to reach the
          * router pipeline (e.g., router solicitations).
@@ -12502,21 +12504,22 @@ build_misc_local_traffic_drop_flows_for_lrouter(
 
         /* Drop other reserved multicast. */
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 83,
-                      "ip6.mcast_rsvd", "drop;");
+                      "ip6.mcast_rsvd", debug_drop_action());
 
         /* Allow other multicast if relay enabled (priority 82). */
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 82,
                       "ip4.mcast || ip6.mcast",
-                      od->mcast_info.rtr.relay ? "next;" : "drop;");
+                      (od->mcast_info.rtr.relay ? "next;" :
+                                                  debug_drop_action()));
 
         /* Drop Ethernet local broadcast.  By definition this traffic should
          * not be forwarded.*/
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
-                      "eth.bcast", "drop;");
+                      "eth.bcast", debug_drop_action());
 
         /* TTL discard */
         ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30,
-                      "ip4 && ip.ttl == {0, 1}", "drop;");
+                      "ip4 && ip.ttl == {0, 1}", debug_drop_action());
 
         /* Pass other traffic not already handled to the next table for
          * routing. */
@@ -12778,7 +12781,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
             op_put_v4_networks(match, op, true);
             ds_put_cstr(match, " && "REGBIT_EGRESS_LOOPBACK" == 0");
             ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
-                                    ds_cstr(match), "drop;",
+                                    ds_cstr(match), debug_drop_action(),
                                     &op->nbrp->header_);
 
             /* ICMP echo reply.  These flows reply to ICMP echo requests
@@ -13835,8 +13838,8 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows,
             struct ovn_port *op = ovn_port_find(ports, nat->logical_port);
             if (op && op->nbsp && !strcmp(op->nbsp->type, "virtual")) {
                 ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT,
-                                        80, ds_cstr(match), "drop;",
-                                        &nat->header_);
+                                        80, ds_cstr(match),
+                                        debug_drop_action(), &nat->header_);
             }
             ds_put_format(match, " && is_chassis_resident(\"%s\")",
                           nat->logical_port);
@@ -15566,6 +15569,7 @@ northd_destroy(struct northd_data *data)
 
     destroy_datapaths_and_ports(&data->datapaths, &data->ports,
                                 &data->lr_list);
+    destroy_debug_config();
 }
 
 static void
@@ -15649,6 +15653,9 @@ ovnnb_db_run(struct northd_input *input_data,
                                               false);
 
     build_chassis_features(input_data, &data->features);
+
+    init_debug_config(nb);
+
     build_datapaths(input_data, ovnsb_txn, &data->datapaths, &data->lr_list);
     build_lbs(input_data, &data->datapaths, &data->lbs, &data->lb_groups);
     build_ports(input_data, ovnsb_txn, sbrec_chassis_by_name,
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index ab01add2f..eb38b51f7 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -4847,4 +4847,30 @@ clone {
       </ul>
     </p>
 
+    <h1>Drop sampling</h1>
+
+    <p>
+      As described in the previous section, there are several places where
+      ovn-northd might decided to drop a packet by explicitly creating a
+      <code>Logical_Flow</code> with the <code>drop;</code> action.
+    </p>
+
+    <p>
+      When debug drop-sampling has been cofigured in the OVN Northbound
+      database, the ovn-northd will replace all the <code>drop;</code>
+      actions with a <code>sample(priority=65535, collector_set=<var>id</var>,
+      obs_domain=<var>obs_id</var>, obs_point=@cookie)</code> action, where:
+      <ul>
+        <li>
+        <var>id</var> is the value the <code>debug_drop_collector_set</code>
+        option configured in the OVN Northbound.
+        </li>
+        <li>
+        <var>obs_id</var> has it's 8 most significant bits equal to the value
+        of the <code>debug_drop_domain_id</code> option in the OVN Northbound
+        and it's 24 least significant bits equal to the datapath's tunnel key.
+        </li>
+      </ul>
+    </p>
+
 </manpage>
diff --git a/ovn-nb.xml b/ovn-nb.xml
index f41e9d7c0..548e2ddb0 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -264,6 +264,34 @@
         </p>
       </column>
 
+      <column name="options" key="debug_drop_domain_id">
+        <p>
+          If set to a 8-bit number and if
+          <code>debug_drop_collector_set</code> is also configured,
+          <code>ovn-northd</code> will add a <code>sample</code> action to
+          every logical flow that contains a 'drop' action.
+          The 8 most significant bits of the observation_domain_id field will
+          be those specified in the
+          <code> debug_drop_domain_id</code>.
+          The 24 least significant bits of the observation_domain_id field will
+          be the datapath's key.
+        </p>
+        <p>
+          The observation_point_id will be set to the first 32 bits of the
+          logical flow's UUID.
+        </p>
+      </column>
+
+      <column name="options" key="debug_drop_collector_set">
+        <p>
+          If set to a 32-bit number <code>ovn-northd</code> will add a
+          <code>sample</code> action to every logical flow that contains a
+          'drop' action. The sample action will have the specified
+          collector_set_id. The value must match that of the local OVS
+          configuration as described in <code>ovs-actions</code>(7).
+        </p>
+      </column>
+
       <group title="Options for configuring interconnection route advertisement">
         <p>
           These options control how routes are advertised between OVN
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 75ead78fa..2893c45f9 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -198,6 +198,35 @@
           BFD option <code>mult</code> value to use when configuring BFD on
           tunnel interfaces.
         </column>
+
+        <column name="options" key="debug_drop_domain_id">
+          <p>
+            If set to a 8-bit number and if
+            <code>debug_drop_collector_set</code> is also configured,
+            <code>ovn-controller</code> will add a <code>sample</code> action
+            to every flow that does not come from a logical flow that contains
+            a 'drop' action.
+            The 8 most significant bits of the observation_domain_id field will
+            be those specified in the
+            <code> debug_drop_domain_id</code>.
+            The 24 least significant bits of the observation_domain_id field
+            will be zero.
+          </p>
+          <p>
+            The observation_point_id will be set to the OpenFlow table number.
+          </p>
+        </column>
+
+        <column name="options" key="debug_drop_collector_set">
+          <p>
+            If set to a 32-bit number <code>ovn-controller</code> will add a
+            <code>sample</code> action to every flow that does not come from
+            a logical flow that contains a 'drop' action.
+            The sample action will have the specified collector_set_id.
+            The value must match that of the local OVS configuration as
+            described in <code>ovs-actions</code>(7).
+          </p>
+        </column>
       </group>
 
       <group title="Options for configuring Load Balancers">
diff --git a/tests/ovn.at b/tests/ovn.at
index 792655f99..b65c31078 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -33102,6 +33102,43 @@ check_default_flows() {
     done
 }
 
+# Check that every drop flow gets sampled.
+check_sample_drops() {
+
+    check ovn-nbctl -- remove NB_Global . options debug_drop_collector_set \
+                    -- remove NB_Global . options debug_drop_domain_id
+    check ovn-nbctl --wait=hv sync
+
+    ovs-ofctl dump-flows --no-stats br-int > oflows_nosample
+    AT_CAPTURE_FILE([oflows_nosample])
+    # Take match part of flows that contain "drop".
+    drop_matches="$(grep 'drop' oflows_nosample | grep -oP 'table=\d*, priority=.* ')"
+
+    check ovn-nbctl -- set NB_Global . options:debug_drop_collector_set="123" \
+                    -- set NB_Global . options:debug_drop_domain_id="1"
+    check ovn-nbctl --wait=hv sync
+
+    ovs-ofctl dump-flows --no-stats br-int > oflows_sample
+    AT_CAPTURE_FILE([oflows_sample])
+
+    # Check that every drop has now contains a "sample" action.
+    for flow in "$drop_matches"; do
+        AT_CHECK([grep -q "$flow actions=.*sample.*" oflows_sample], [0], [ignore], [ignore], [echo "Flow $flow has a drop and did not get sampled"])
+    done
+}
+
+check_drops() {
+    as hv1
+    check_default_flows
+    as hv2
+    check_default_flows
+
+    as hv1
+    check_sample_drops
+    as hv2
+    check_sample_drops
+}
+
 # Logical network:
 # Two LRs - R1 and R2 that are connected to each other as peers in 20.0.0.0/24
 # network. R1 has a switchs ls1 (191.168.1.0/24) connected to it.
@@ -33167,10 +33204,7 @@ ovs-vsctl -- add-port br-int hv2-vif1 -- \
 wait_for_ports_up
 check ovn-nbctl --wait=hv sync
 
-as hv1
-check_default_flows
-as hv2
-check_default_flows
+check_debug
 
 # Add stateless ACL
 check ovn-nbctl --wait=sb \
@@ -33178,10 +33212,7 @@ check ovn-nbctl --wait=sb \
 check ovn-nbctl --wait=sb \
                 -- acl-add ls2 from-lport 100 'ip4' allow-stateless
 
-as hv1
-check_default_flows
-as hv2
-check_default_flows
+check_debug
 
 check ovn-nbctl --wait=sb acl-del ls1
 check ovn-nbctl --wait=sb acl-del ls2
@@ -33192,10 +33223,7 @@ check ovn-nbctl --wait=sb \
 check ovn-nbctl --wait=sb \
                 -- acl-add ls2 from-lport 100 "udp" allow-related
 
-as hv1
-check_default_flows
-as hv2
-check_default_flows
+check_debug
 
 check ovn-nbctl --wait=sb acl-del ls1
 check ovn-nbctl --wait=sb acl-del ls2
@@ -33209,10 +33237,7 @@ check ovn-nbctl --wait=sb \
     -- lb-add lb2 "10.0.1.1" "10.0.1.2" \
     -- ls-lb-add ls2 lb2
 
-as hv1
-check_default_flows
-as hv2
-check_default_flows
+check_drops
 
 # LB + stateless ACL
 check ovn-nbctl --wait=sb \
@@ -33220,10 +33245,7 @@ check ovn-nbctl --wait=sb \
 check ovn-nbctl --wait=sb \
                 -- acl-add ls2 from-lport 100 'ip4' allow-stateless
 
-as hv1
-check_default_flows
-as hv2
-check_default_flows
+check_drops
 
 check ovn-nbctl --wait=sb acl-del ls1
 check ovn-nbctl --wait=sb acl-del ls2
@@ -33234,10 +33256,7 @@ check ovn-nbctl --wait=sb \
 check ovn-nbctl --wait=sb \
                 -- acl-add ls2 from-lport 100 "udp" allow-related
 
-as hv1
-check_default_flows
-as hv2
-check_default_flows
+check_drops
 
 OVN_CLEANUP([hv1],[hv2])
 AT_CLEANUP
