return 0;
 }
 
+static bool ice_is_fltr_lldp(struct ice_tc_flower_fltr *fltr)
+{
+       return fltr->outer_headers.l2_key.n_proto == htons(ETH_P_LLDP);
+}
+
+static bool ice_is_fltr_pf_tx_lldp(struct ice_tc_flower_fltr *fltr)
+{
+       struct ice_vsi *vsi = fltr->src_vsi, *uplink;
+
+       if (!ice_is_switchdev_running(vsi->back))
+               return false;
+
+       uplink = vsi->back->eswitch.uplink_vsi;
+       return vsi == uplink && fltr->action.fltr_act == ICE_DROP_PACKET &&
+              ice_is_fltr_lldp(fltr) &&
+              fltr->direction == ICE_ESWITCH_FLTR_EGRESS &&
+              fltr->flags == ICE_TC_FLWR_FIELD_ETH_TYPE_ID;
+}
+
+static bool ice_is_fltr_vf_tx_lldp(struct ice_tc_flower_fltr *fltr)
+{
+       struct ice_vsi *vsi = fltr->src_vsi, *uplink;
+
+       uplink = vsi->back->eswitch.uplink_vsi;
+       return fltr->src_vsi->type == ICE_VSI_VF && ice_is_fltr_lldp(fltr) &&
+              fltr->direction == ICE_ESWITCH_FLTR_EGRESS &&
+              fltr->dest_vsi == uplink;
+}
+
+static struct ice_tc_flower_fltr *
+ice_find_pf_tx_lldp_fltr(struct ice_pf *pf)
+{
+       struct ice_tc_flower_fltr *fltr;
+
+       hlist_for_each_entry(fltr, &pf->tc_flower_fltr_list, tc_flower_node)
+               if (ice_is_fltr_pf_tx_lldp(fltr))
+                       return fltr;
+
+       return NULL;
+}
+
+static bool ice_any_vf_lldp_tx_ena(struct ice_pf *pf)
+{
+       struct ice_vf *vf;
+       unsigned int bkt;
+
+       ice_for_each_vf(pf, bkt, vf)
+               if (vf->lldp_tx_ena)
+                       return true;
+
+       return false;
+}
+
+int ice_pass_vf_tx_lldp(struct ice_vsi *vsi, bool deinit)
+{
+       struct ice_rule_query_data remove_entry = {
+               .rid = vsi->vf->lldp_recipe_id,
+               .rule_id = vsi->vf->lldp_rule_id,
+               .vsi_handle = vsi->idx,
+       };
+       struct ice_pf *pf = vsi->back;
+       int err;
+
+       if (vsi->vf->lldp_tx_ena)
+               return 0;
+
+       if (!deinit && !ice_find_pf_tx_lldp_fltr(vsi->back))
+               return -EINVAL;
+
+       if (!deinit && ice_any_vf_lldp_tx_ena(pf))
+               return -EINVAL;
+
+       err = ice_rem_adv_rule_by_id(&pf->hw, &remove_entry);
+       if (!err)
+               vsi->vf->lldp_tx_ena = true;
+
+       return err;
+}
+
+int ice_drop_vf_tx_lldp(struct ice_vsi *vsi, bool init)
+{
+       struct ice_rule_query_data rule_added;
+       struct ice_adv_rule_info rinfo = {
+               .priority = 7,
+               .src_vsi = vsi->idx,
+               .sw_act = {
+                       .src = vsi->idx,
+                       .flag = ICE_FLTR_TX,
+                       .fltr_act = ICE_DROP_PACKET,
+                       .vsi_handle = vsi->idx,
+               },
+               .flags_info.act_valid = true,
+       };
+       struct ice_adv_lkup_elem list[3];
+       struct ice_pf *pf = vsi->back;
+       int err;
+
+       if (!init && !vsi->vf->lldp_tx_ena)
+               return 0;
+
+       memset(list, 0, sizeof(list));
+       ice_rule_add_direction_metadata(&list[0]);
+       ice_rule_add_src_vsi_metadata(&list[1]);
+       list[2].type = ICE_ETYPE_OL;
+       list[2].h_u.ethertype.ethtype_id = htons(ETH_P_LLDP);
+       list[2].m_u.ethertype.ethtype_id = htons(0xFFFF);
+
+       err = ice_add_adv_rule(&pf->hw, list, ARRAY_SIZE(list), &rinfo,
+                              &rule_added);
+       if (err) {
+               dev_err(&pf->pdev->dev,
+                       "Failed to add an LLDP rule to VSI 0x%X: %d\n",
+                       vsi->idx, err);
+       } else {
+               vsi->vf->lldp_recipe_id = rule_added.rid;
+               vsi->vf->lldp_rule_id = rule_added.rule_id;
+               vsi->vf->lldp_tx_ena = false;
+       }
+
+       return err;
+}
+
+static void ice_handle_add_pf_lldp_drop_rule(struct ice_vsi *vsi)
+{
+       struct ice_tc_flower_fltr *fltr;
+       struct ice_pf *pf = vsi->back;
+
+       hlist_for_each_entry(fltr, &pf->tc_flower_fltr_list, tc_flower_node) {
+               if (!ice_is_fltr_vf_tx_lldp(fltr))
+                       continue;
+               ice_pass_vf_tx_lldp(fltr->src_vsi, true);
+               break;
+       }
+}
+
+static void ice_handle_del_pf_lldp_drop_rule(struct ice_pf *pf)
+{
+       int i;
+
+       /* Make the VF LLDP fwd to uplink rule dormant */
+       ice_for_each_vsi(pf, i) {
+               struct ice_vsi *vf_vsi = pf->vsi[i];
+
+               if (vf_vsi && vf_vsi->type == ICE_VSI_VF)
+                       ice_drop_vf_tx_lldp(vf_vsi, false);
+       }
+}
+
 static int
 ice_eswitch_add_tc_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr)
 {
                return -EOPNOTSUPP;
        }
 
+       if (ice_is_fltr_vf_tx_lldp(fltr))
+               return ice_pass_vf_tx_lldp(vsi, false);
+
        lkups_cnt = ice_tc_count_lkups(flags, fltr);
        list = kcalloc(lkups_cnt, sizeof(*list), GFP_ATOMIC);
        if (!list)
                goto exit;
        }
 
+       if (ice_is_fltr_pf_tx_lldp(fltr))
+               ice_handle_add_pf_lldp_drop_rule(vsi);
+
        /* store the output params, which are needed later for removing
         * advanced switch filter
         */
        struct ice_pf *pf = vsi->back;
        int err;
 
+       if (ice_is_fltr_pf_tx_lldp(fltr))
+               ice_handle_del_pf_lldp_drop_rule(pf);
+
+       if (ice_is_fltr_vf_tx_lldp(fltr))
+               return ice_drop_vf_tx_lldp(vsi, false);
+
        rule_rem.rid = fltr->rid;
        rule_rem.rule_id = fltr->rule_id;
        rule_rem.vsi_handle = fltr->dest_vsi_handle;