diff --git a/include/net/devlink.h b/include/net/devlink.h
index f466819cc477..6811a614f6fd 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -1294,6 +1294,16 @@ struct devlink_ops {
 				     const struct devlink_trap_group *group,
 				     enum devlink_trap_action action,
 				     struct netlink_ext_ack *extack);
+	/**
+	 * @trap_hard_drop_counter_get: Trap hard drop counter get function.
+	 *
+	 * Should be used by device drivers to report number of packets dropped
+	 * by the underlying device, that have been dropped because device
+	 * failed to pass the trapped packet.
+	 */
+	int (*trap_hard_drop_counter_get)(struct devlink *devlink,
+					  const struct devlink_trap *trap,
+					  u64 *p_drops);
 	/**
 	 * @trap_policer_init: Trap policer initialization function.
 	 *
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index cf89c318f2ac..9247d9c7db03 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -261,12 +261,16 @@ enum {
  * enum devlink_trap_action - Packet trap action.
  * @DEVLINK_TRAP_ACTION_DROP: Packet is dropped by the device and a copy is not
  *                            sent to the CPU.
+ * @DEVLINK_TRAP_ACTION_HARD_DROP: Packet was dropped by the underlying device,
+ *                                 and device cannot report packet to devlink
+ *                                 (or inject it into the kernel RX path).
  * @DEVLINK_TRAP_ACTION_TRAP: The sole copy of the packet is sent to the CPU.
  * @DEVLINK_TRAP_ACTION_MIRROR: Packet is forwarded by the device and a copy is
  *                              sent to the CPU.
  */
 enum devlink_trap_action {
 	DEVLINK_TRAP_ACTION_DROP,
+	DEVLINK_TRAP_ACTION_HARD_DROP,
 	DEVLINK_TRAP_ACTION_TRAP,
 	DEVLINK_TRAP_ACTION_MIRROR,
 };
diff --git a/net/core/devlink.c b/net/core/devlink.c
index ee828e4b1007..5a06e00429e1 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -6732,6 +6732,7 @@ devlink_trap_action_get_from_info(struct genl_info *info,
 	val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
 	switch (val) {
 	case DEVLINK_TRAP_ACTION_DROP:
+	case DEVLINK_TRAP_ACTION_HARD_DROP:
 	case DEVLINK_TRAP_ACTION_TRAP:
 	case DEVLINK_TRAP_ACTION_MIRROR:
 		*p_trap_action = val;
@@ -6820,6 +6821,37 @@ static int devlink_trap_stats_put(struct sk_buff *msg,
 	return -EMSGSIZE;
 }
 
+static int
+devlink_trap_hard_drop_stats_put(struct sk_buff *msg,
+				 struct devlink *devlink,
+				 const struct devlink_trap_item *trap_item)
+{
+	struct nlattr *attr;
+	u64 drops;
+	int err;
+
+	err = devlink->ops->trap_hard_drop_counter_get(devlink, trap_item->trap,
+						       &drops);
+	if (err)
+		return err;
+
+	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
+	if (!attr)
+		return -EMSGSIZE;
+
+	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
+			      DEVLINK_ATTR_PAD))
+		goto nla_put_failure;
+
+	nla_nest_end(msg, attr);
+
+	return 0;
+
+nla_put_failure:
+	nla_nest_cancel(msg, attr);
+	return -EMSGSIZE;
+}
+
 static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
 				const struct devlink_trap_item *trap_item,
 				enum devlink_command cmd, u32 portid, u32 seq,
@@ -6857,7 +6889,10 @@ static int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
 	if (err)
 		goto nla_put_failure;
 
-	err = devlink_trap_stats_put(msg, trap_item->stats);
+	if (trap_item->action == DEVLINK_TRAP_ACTION_HARD_DROP)
+		err = devlink_trap_hard_drop_stats_put(msg, devlink, trap_item);
+	else
+		err = devlink_trap_stats_put(msg, trap_item->stats);
 	if (err)
 		goto nla_put_failure;
 
@@ -9697,6 +9732,10 @@ devlink_trap_register(struct devlink *devlink,
 	if (devlink_trap_item_lookup(devlink, trap->name))
 		return -EEXIST;
 
+	if (trap->init_action == DEVLINK_TRAP_ACTION_HARD_DROP &&
+	    !devlink->ops->trap_hard_drop_counter_get)
+		return -EINVAL;
+
 	trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
 	if (!trap_item)
 		return -ENOMEM;
@@ -9876,6 +9915,9 @@ void devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
 {
 	struct devlink_trap_item *trap_item = trap_ctx;
 
+	if (trap_item->action == DEVLINK_TRAP_ACTION_HARD_DROP)
+		return;
+
 	devlink_trap_stats_update(trap_item->stats, skb->len);
 	devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
 
