#include <linux/mlx5/fs.h>
 #include "mlx5_core.h"
 #include "eswitch.h"
+#include "fs_core.h"
 
 #define UPLINK_VPORT 0xFFFF
 
 static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
                                    struct mlx5_vport *vport)
 {
+       struct mlx5_fc *counter = vport->ingress.drop_counter;
+       struct mlx5_flow_destination drop_ctr_dst = {0};
+       struct mlx5_flow_destination *dst = NULL;
        struct mlx5_flow_act flow_act = {0};
        struct mlx5_flow_spec *spec;
+       int dest_num = 0;
        int err = 0;
        u8 *smac_v;
 
 
        memset(spec, 0, sizeof(*spec));
        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
+
+       /* Attach drop flow counter */
+       if (counter) {
+               flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
+               drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+               drop_ctr_dst.counter = counter;
+               dst = &drop_ctr_dst;
+               dest_num++;
+       }
        vport->ingress.drop_rule =
                mlx5_add_flow_rules(vport->ingress.acl, spec,
-                                   &flow_act, NULL, 0);
+                                   &flow_act, dst, dest_num);
        if (IS_ERR(vport->ingress.drop_rule)) {
                err = PTR_ERR(vport->ingress.drop_rule);
                esw_warn(esw->dev,
 static int esw_vport_egress_config(struct mlx5_eswitch *esw,
                                   struct mlx5_vport *vport)
 {
+       struct mlx5_fc *counter = vport->egress.drop_counter;
+       struct mlx5_flow_destination drop_ctr_dst = {0};
+       struct mlx5_flow_destination *dst = NULL;
        struct mlx5_flow_act flow_act = {0};
        struct mlx5_flow_spec *spec;
+       int dest_num = 0;
        int err = 0;
 
        esw_vport_cleanup_egress_rules(esw, vport);
        /* Drop others rule (star rule) */
        memset(spec, 0, sizeof(*spec));
        flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
+
+       /* Attach egress drop flow counter */
+       if (counter) {
+               flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
+               drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
+               drop_ctr_dst.counter = counter;
+               dst = &drop_ctr_dst;
+               dest_num++;
+       }
        vport->egress.drop_rule =
                mlx5_add_flow_rules(vport->egress.acl, spec,
-                                   &flow_act, NULL, 0);
+                                   &flow_act, dst, dest_num);
        if (IS_ERR(vport->egress.drop_rule)) {
                err = PTR_ERR(vport->egress.drop_rule);
                esw_warn(esw->dev,
        }
 }
 
+static void esw_vport_create_drop_counters(struct mlx5_vport *vport)
+{
+       struct mlx5_core_dev *dev = vport->dev;
+
+       if (MLX5_CAP_ESW_INGRESS_ACL(dev, flow_counter)) {
+               vport->ingress.drop_counter = mlx5_fc_create(dev, false);
+               if (IS_ERR(vport->ingress.drop_counter)) {
+                       esw_warn(dev,
+                                "vport[%d] configure ingress drop rule counter failed\n",
+                                vport->vport);
+                       vport->ingress.drop_counter = NULL;
+               }
+       }
+
+       if (MLX5_CAP_ESW_EGRESS_ACL(dev, flow_counter)) {
+               vport->egress.drop_counter = mlx5_fc_create(dev, false);
+               if (IS_ERR(vport->egress.drop_counter)) {
+                       esw_warn(dev,
+                                "vport[%d] configure egress drop rule counter failed\n",
+                                vport->vport);
+                       vport->egress.drop_counter = NULL;
+               }
+       }
+}
+
+static void esw_vport_destroy_drop_counters(struct mlx5_vport *vport)
+{
+       struct mlx5_core_dev *dev = vport->dev;
+
+       if (vport->ingress.drop_counter)
+               mlx5_fc_destroy(dev, vport->ingress.drop_counter);
+       if (vport->egress.drop_counter)
+               mlx5_fc_destroy(dev, vport->egress.drop_counter);
+}
+
 static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
                             int enable_events)
 {
        if (!vport_num)
                vport->info.trusted = true;
 
+       /* create steering drop counters for ingress and egress ACLs */
+       if (vport_num && esw->mode == SRIOV_LEGACY)
+               esw_vport_create_drop_counters(vport);
+
        esw_vport_change_handle_locked(vport);
 
        esw->enabled_vports++;
                                              MLX5_ESW_VPORT_ADMIN_STATE_DOWN);
                esw_vport_disable_egress_acl(esw, vport);
                esw_vport_disable_ingress_acl(esw, vport);
+               esw_vport_destroy_drop_counters(vport);
        }
        esw->enabled_vports--;
        mutex_unlock(&esw->state_lock);
        return err;
 }
 
+static void mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev *dev,
+                                               int vport_idx,
+                                               struct mlx5_vport_drop_stats *stats)
+{
+       struct mlx5_eswitch *esw = dev->priv.eswitch;
+       struct mlx5_vport *vport = &esw->vports[vport_idx];
+       u64 bytes = 0;
+       u16 idx = 0;
+
+       if (!vport->enabled || esw->mode != SRIOV_LEGACY)
+               return;
+
+       if (vport->egress.drop_counter) {
+               idx = vport->egress.drop_counter->id;
+               mlx5_fc_query(dev, idx, &stats->rx_dropped, &bytes);
+       }
+
+       if (vport->ingress.drop_counter) {
+               idx = vport->ingress.drop_counter->id;
+               mlx5_fc_query(dev, idx, &stats->tx_dropped, &bytes);
+       }
+}
+
 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
                                 int vport,
                                 struct ifla_vf_stats *vf_stats)
 {
        int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
        u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {0};
+       struct mlx5_vport_drop_stats stats = {0};
        int err = 0;
        u32 *out;
 
        vf_stats->broadcast =
                MLX5_GET_CTR(out, received_eth_broadcast.packets);
 
+       mlx5_eswitch_query_vport_drop_stats(esw->dev, vport, &stats);
+       vf_stats->rx_dropped = stats.rx_dropped;
+       vf_stats->tx_dropped = stats.tx_dropped;
+
 free_out:
        kvfree(out);
        return err;