]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ice: receive LLDP on trusted VFs
authorMateusz Pacuszka <mateuszx.pacuszka@intel.com>
Fri, 14 Feb 2025 08:50:37 +0000 (09:50 +0100)
committerTony Nguyen <anthony.l.nguyen@intel.com>
Fri, 11 Apr 2025 16:45:30 +0000 (09:45 -0700)
When a trusted VF tries to configure an LLDP multicast address, configure a
rule that would mirror the traffic to this VF, untrusted VFs are not
allowed to receive LLDP at all, so the request to add LLDP MAC address will
always fail for them.

Add a forwarding LLDP filter to a trusted VF when it tries to add an LLDP
multicast MAC address. The MAC address has to be added after enabling
trust (through restarting the LLDP service).

Signed-off-by: Mateusz Pacuszka <mateuszx.pacuszka@intel.com>
Co-developed-by: Larysa Zaremba <larysa.zaremba@intel.com>
Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com>
Reviewed-by: Michal Swiatkowski <michal.swiatkowski@linux.intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
drivers/net/ethernet/intel/ice/ice_dcb_lib.c
drivers/net/ethernet/intel/ice/ice_ethtool.c
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_lib.h
drivers/net/ethernet/intel/ice/ice_sriov.c
drivers/net/ethernet/intel/ice/ice_vf_lib.c
drivers/net/ethernet/intel/ice/ice_vf_lib.h
drivers/net/ethernet/intel/ice/ice_virtchnl.c

index a7c5108328240095aac4afe923c0b9d813eac1d2..67988c7ab08e6f40a653a21b5bb91056d1b421ac 100644 (file)
@@ -846,7 +846,7 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked)
                        goto dcb_init_err;
                }
 
-               ice_cfg_sw_lldp(pf_vsi, false, true);
+               ice_cfg_sw_rx_lldp(pf, true);
 
                pf->dcbx_cap = ice_dcb_get_mode(port_info, true);
                return 0;
index 7c2dc347e4e57c2f4cd551a138a88d539e5309e9..648815170477c8db524260376c5785e44943996d 100644 (file)
@@ -1818,7 +1818,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags)
                        /* Remove rule to direct LLDP packets to default VSI.
                         * The FW LLDP engine will now be consuming them.
                         */
-                       ice_cfg_sw_lldp(vsi, false, false);
+                       ice_cfg_sw_rx_lldp(vsi->back, false);
 
                        /* AQ command to start FW LLDP agent will return an
                         * error if the agent is already started
index 542b76b5707a079e346d405f9f8e62382628ef6c..03bb16191237e85e492855593695e963f3231558 100644 (file)
@@ -2065,12 +2065,15 @@ static void ice_vsi_set_tc_cfg(struct ice_vsi *vsi)
 }
 
 /**
- * ice_cfg_sw_lldp - Config switch rules for LLDP packet handling
+ * ice_vsi_cfg_sw_lldp - Config switch rules for LLDP packet handling
  * @vsi: the VSI being configured
  * @tx: bool to determine Tx or Rx rule
  * @create: bool to determine create or remove Rule
+ *
+ * Adding an ethtype Tx rule to the uplink VSI results in it being applied
+ * to the whole port, so LLDP transmission for VFs will be blocked too.
  */
-void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create)
+void ice_vsi_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create)
 {
        int (*eth_fltr)(struct ice_vsi *v, u16 type, u16 flag,
                        enum ice_sw_fwd_act_type act);
@@ -2109,6 +2112,37 @@ report:
                         vsi->vsi_num, status);
 }
 
+/**
+ * ice_cfg_sw_rx_lldp - Enable/disable software handling of LLDP
+ * @pf: the PF being configured
+ * @enable: enable or disable
+ *
+ * Configure switch rules to enable/disable LLDP handling by software
+ * across PF.
+ */
+void ice_cfg_sw_rx_lldp(struct ice_pf *pf, bool enable)
+{
+       struct ice_vsi *vsi;
+       struct ice_vf *vf;
+       unsigned int bkt;
+
+       vsi = ice_get_main_vsi(pf);
+       ice_vsi_cfg_sw_lldp(vsi, false, enable);
+
+       if (!test_bit(ICE_FLAG_SRIOV_ENA, pf->flags))
+               return;
+
+       ice_for_each_vf(pf, bkt, vf) {
+               vsi = ice_get_vf_vsi(vf);
+
+               if (WARN_ON(!vsi))
+                       continue;
+
+               if (ice_vf_is_lldp_ena(vf))
+                       ice_vsi_cfg_sw_lldp(vsi, false, enable);
+       }
+}
+
 /**
  * ice_set_agg_vsi - sets up scheduler aggregator node and move VSI into it
  * @vsi: pointer to the VSI
@@ -2537,7 +2571,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_vsi_cfg_params *params)
        if (!ice_is_safe_mode(pf) && vsi->type == ICE_VSI_PF) {
                ice_fltr_add_eth(vsi, ETH_P_PAUSE, ICE_FLTR_TX,
                                 ICE_DROP_PACKET);
-               ice_cfg_sw_lldp(vsi, true, true);
+               ice_vsi_cfg_sw_lldp(vsi, true, true);
        }
 
        if (!vsi->agg_node)
@@ -2834,9 +2868,11 @@ int ice_vsi_release(struct ice_vsi *vsi)
        /* The Rx rule will only exist to remove if the LLDP FW
         * engine is currently stopped
         */
-       if (!ice_is_safe_mode(pf) && vsi->type == ICE_VSI_PF &&
-           !test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags))
-               ice_cfg_sw_lldp(vsi, false, false);
+       if (!ice_is_safe_mode(pf) &&
+           !test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags) &&
+           (vsi->type == ICE_VSI_PF || (vsi->type == ICE_VSI_VF &&
+            ice_vf_is_lldp_ena(vsi->vf))))
+               ice_vsi_cfg_sw_lldp(vsi, false, false);
 
        ice_vsi_decfg(vsi);
 
index b4c9cb28a016ec0444c3b51436c55bdfa712f1b4..654516c5fc3ededf99d3aa9574a546177295a716 100644 (file)
@@ -29,7 +29,8 @@ ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
 
 int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi);
 
-void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create);
+void ice_vsi_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create);
+void ice_cfg_sw_rx_lldp(struct ice_pf *pf, bool enable);
 
 int ice_set_link(struct ice_vsi *vsi, bool ena);
 
index f1648cf103b74205bf7a16b677d3b8f71491a87a..0e4dc1a5cff0f3f690d78b146a7ddb8de9aab31a 100644 (file)
@@ -63,6 +63,7 @@ static void ice_free_vf_res(struct ice_vf *vf)
        if (vf->lan_vsi_idx != ICE_NO_VSI) {
                ice_vf_vsi_release(vf);
                vf->num_mac = 0;
+               vf->num_mac_lldp = 0;
        }
 
        last_vector_idx = vf->first_vector_idx + vf->num_msix - 1;
@@ -1402,6 +1403,9 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted)
 
        mutex_lock(&vf->cfg_lock);
 
+       while (!trusted && vf->num_mac_lldp)
+               ice_vf_update_mac_lldp_num(vf, ice_get_vf_vsi(vf), false);
+
        vf->trusted = trusted;
        ice_reset_vf(vf, ICE_VF_RESET_NOTIFY);
        dev_info(ice_pf_to_dev(pf), "VF %u is now %strusted\n",
index 815ad0bfe8326bd2c5b9ac8942de8053bc7190e5..48cd533e93b74356cabdfa4d79cb9db439b33e1f 100644 (file)
@@ -226,6 +226,7 @@ static void ice_vf_clear_counters(struct ice_vf *vf)
                vsi->num_vlan = 0;
 
        vf->num_mac = 0;
+       vf->num_mac_lldp = 0;
        memset(&vf->mdd_tx_events, 0, sizeof(vf->mdd_tx_events));
        memset(&vf->mdd_rx_events, 0, sizeof(vf->mdd_rx_events));
 }
@@ -1401,3 +1402,28 @@ struct ice_vsi *ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi)
        rcu_read_unlock();
        return ctrl_vsi;
 }
+
+/**
+ * ice_vf_update_mac_lldp_num - update the VF's number of LLDP addresses
+ * @vf: a VF to add the address to
+ * @vsi: the corresponding VSI
+ * @incr: is the rule added or removed
+ */
+void ice_vf_update_mac_lldp_num(struct ice_vf *vf, struct ice_vsi *vsi,
+                               bool incr)
+{
+       bool lldp_by_fw = test_bit(ICE_FLAG_FW_LLDP_AGENT, vsi->back->flags);
+       bool was_ena = ice_vf_is_lldp_ena(vf) && !lldp_by_fw;
+       bool is_ena;
+
+       if (WARN_ON(!vsi)) {
+               vf->num_mac_lldp = 0;
+               return;
+       }
+
+       vf->num_mac_lldp += incr ? 1 : -1;
+       is_ena = ice_vf_is_lldp_ena(vf) && !lldp_by_fw;
+
+       if (was_ena != is_ena)
+               ice_vsi_cfg_sw_lldp(vsi, false, is_ena);
+}
index 799b2c1f118447236d4dfd3453c65fc0210107c1..f4c9ca1f51ce23bbaac58ebe11995f8269ec1b34 100644 (file)
@@ -134,6 +134,7 @@ struct ice_vf {
        unsigned long vf_caps;          /* VF's adv. capabilities */
        u8 num_req_qs;                  /* num of queue pairs requested by VF */
        u16 num_mac;
+       u16 num_mac_lldp;
        u16 num_vf_qs;                  /* num of queue configured per VF */
        u8 vlan_strip_ena;              /* Outer and Inner VLAN strip enable */
 #define ICE_INNER_VLAN_STRIP_ENA       BIT(0)
@@ -180,6 +181,11 @@ static inline u16 ice_vf_get_port_vlan_tpid(struct ice_vf *vf)
        return vf->port_vlan_info.tpid;
 }
 
+static inline bool ice_vf_is_lldp_ena(struct ice_vf *vf)
+{
+       return vf->num_mac_lldp && vf->trusted;
+}
+
 /* VF Hash Table access functions
  *
  * These functions provide abstraction for interacting with the VF hash table.
@@ -245,6 +251,8 @@ ice_vf_clear_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m);
 int ice_reset_vf(struct ice_vf *vf, u32 flags);
 void ice_reset_all_vfs(struct ice_pf *pf);
 struct ice_vsi *ice_get_vf_ctrl_vsi(struct ice_pf *pf, struct ice_vsi *vsi);
+void ice_vf_update_mac_lldp_num(struct ice_vf *vf, struct ice_vsi *vsi,
+                               bool incr);
 #else /* CONFIG_PCI_IOV */
 static inline struct ice_vf *ice_get_vf_by_id(struct ice_pf *pf, u16 vf_id)
 {
index 7c3006eb68dd071ab76e62d8715dc2729610586a..b147f6cf26151ec6e56eaf391ae85804e86d7725 100644 (file)
@@ -2265,6 +2265,51 @@ ice_vfhw_mac_add(struct ice_vf *vf, struct virtchnl_ether_addr *vc_ether_addr)
        }
 }
 
+/**
+ * ice_is_mc_lldp_eth_addr - check if the given MAC is a multicast LLDP address
+ * @mac: address to check
+ *
+ * Return: true if the address is one of the three possible LLDP multicast
+ *        addresses, false otherwise.
+ */
+static bool ice_is_mc_lldp_eth_addr(const u8 *mac)
+{
+       const u8 lldp_mac_base[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
+
+       if (memcmp(mac, lldp_mac_base, sizeof(lldp_mac_base)))
+               return false;
+
+       return (mac[5] == 0x0e || mac[5] == 0x03 || mac[5] == 0x00);
+}
+
+/**
+ * ice_vc_can_add_mac - check if the VF is allowed to add a given MAC
+ * @vf: a VF to add the address to
+ * @mac: address to check
+ *
+ * Return: true if the VF is allowed to add such MAC address, false otherwise.
+ */
+static bool ice_vc_can_add_mac(const struct ice_vf *vf, const u8 *mac)
+{
+       struct device *dev = ice_pf_to_dev(vf->pf);
+
+       if (is_unicast_ether_addr(mac) &&
+           !ice_can_vf_change_mac((struct ice_vf *)vf)) {
+               dev_err(dev,
+                       "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
+               return false;
+       }
+
+       if (!vf->trusted && ice_is_mc_lldp_eth_addr(mac)) {
+               dev_warn(dev,
+                        "An untrusted VF %u is attempting to configure an LLDP multicast address\n",
+                        vf->vf_id);
+               return false;
+       }
+
+       return true;
+}
+
 /**
  * ice_vc_add_mac_addr - attempt to add the MAC address passed in
  * @vf: pointer to the VF info
@@ -2283,10 +2328,8 @@ ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
        if (ether_addr_equal(mac_addr, vf->dev_lan_addr))
                return 0;
 
-       if (is_unicast_ether_addr(mac_addr) && !ice_can_vf_change_mac(vf)) {
-               dev_err(dev, "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
+       if (!ice_vc_can_add_mac(vf, mac_addr))
                return -EPERM;
-       }
 
        ret = ice_fltr_add_mac(vsi, mac_addr, ICE_FWD_TO_VSI);
        if (ret == -EEXIST) {
@@ -2301,6 +2344,8 @@ ice_vc_add_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
                return ret;
        } else {
                vf->num_mac++;
+               if (ice_is_mc_lldp_eth_addr(mac_addr))
+                       ice_vf_update_mac_lldp_num(vf, vsi, true);
        }
 
        ice_vfhw_mac_add(vf, vc_ether_addr);
@@ -2395,6 +2440,8 @@ ice_vc_del_mac_addr(struct ice_vf *vf, struct ice_vsi *vsi,
        ice_vfhw_mac_del(vf, vc_ether_addr);
 
        vf->num_mac--;
+       if (ice_is_mc_lldp_eth_addr(mac_addr))
+               ice_vf_update_mac_lldp_num(vf, vsi, false);
 
        return 0;
 }