From c414463ab1bb098e67f4c1a4ef64f3e97780f087 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Feb 2023 09:09:19 -0800 Subject: ice: move ice_is_malicious_vf() to ice_virtchnl.c The ice_is_malicious_vf() function is currently implemented in ice_sriov.c This function is not Single Root specific, and a future change is going to refactor the ice_vc_process_vf_msg() function to call this instead of calling it before ice_vc_process_vf_msg() in the main loop of __ice_clean_ctrlq. To make that change easier to review, first move this function into ice_virtchnl.c but leave the call in __ice_clean_ctrlq() alone. Signed-off-by: Jacob Keller Reviewed-by: Michal Swiatkowski Tested-by: Marek Szlosek Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_virtchnl.c | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers/net/ethernet/intel/ice/ice_virtchnl.c') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index e24e3f5017ca..e0c573d9d1b9 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -3833,6 +3833,51 @@ void ice_virtchnl_set_repr_ops(struct ice_vf *vf) vf->virtchnl_ops = &ice_virtchnl_repr_ops; } +/** + * ice_is_malicious_vf - helper function to detect a malicious VF + * @pf: ptr to struct ice_pf + * @event: pointer to the AQ event + * @mbxdata: data about the state of the mailbox + */ +bool +ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info *event, + struct ice_mbx_data *mbxdata) +{ + s16 vf_id = le16_to_cpu(event->desc.retval); + struct device *dev = ice_pf_to_dev(pf); + bool report_malvf = false; + struct ice_vf *vf; + int status; + + vf = ice_get_vf_by_id(pf, vf_id); + if (!vf) + return false; + + if (test_bit(ICE_VF_STATE_DIS, vf->vf_states)) + goto out_put_vf; + + /* check to see if we have a newly malicious VF */ + status = ice_mbx_vf_state_handler(&pf->hw, mbxdata, &vf->mbx_info, + &report_malvf); + if (status) + dev_warn_ratelimited(dev, "Unable to check status of mailbox overflow for VF %u MAC %pM, status %d\n", + vf->vf_id, vf->dev_lan_addr, status); + + if (report_malvf) { + struct ice_vsi *pf_vsi = ice_get_main_vsi(pf); + u8 zero_addr[ETH_ALEN] = {}; + + dev_warn(dev, "VF MAC %pM on PF MAC %pM is generating asynchronous messages and may be overflowing the PF message queue. Please see the Adapter User Guide for more information\n", + vf->dev_lan_addr, + pf_vsi ? pf_vsi->netdev->dev_addr : zero_addr); + } + +out_put_vf: + ice_put_vf(vf); + + return vf->mbx_info.malicious; +} + /** * ice_vc_process_vf_msg - Process request from VF * @pf: pointer to the PF structure -- cgit v1.2.3 From be96815c616822d3800405b8fbebe3e069d6eed2 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Feb 2023 09:09:20 -0800 Subject: ice: call ice_is_malicious_vf() from ice_vc_process_vf_msg() The main loop in __ice_clean_ctrlq first checks if a VF might be malicious before calling ice_vc_process_vf_msg(). This results in duplicate code in both functions to obtain a reference to the VF, and exports the ice_is_malicious_vf() from ice_virtchnl.c unnecessarily. Refactor ice_is_malicious_vf() to be a static function that takes a pointer to the VF. Call this in ice_vc_process_vf_msg() just after we obtain a reference to the VF by calling ice_get_vf_by_id. Pass the mailbox data from the __ice_clean_ctrlq function into ice_vc_process_vf_msg() instead of calling ice_is_malicious_vf(). This reduces the number of exported functions and avoids the need to obtain the VF reference twice for every mailbox message. Note that the state check for ICE_VF_STATE_DIS is kept in ice_is_malicious_vf() and we call this before checking that state in ice_vc_process_vf_msg. This is intentional, as we stop responding to VF messages from a VF once we detect that it may be overflowing the mailbox. This ensures that we continue to silently ignore the message as before without responding via ice_vc_send_msg_to_vf(). Signed-off-by: Jacob Keller Reviewed-by: Michal Swiatkowski Tested-by: Marek Szlosek Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 3 +-- drivers/net/ethernet/intel/ice/ice_virtchnl.c | 36 ++++++++++++++------------- drivers/net/ethernet/intel/ice/ice_virtchnl.h | 17 +++---------- 3 files changed, 24 insertions(+), 32 deletions(-) (limited to 'drivers/net/ethernet/intel/ice/ice_virtchnl.c') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index a7e7a186009e..20b3f3e6eda1 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1517,8 +1517,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) data.max_num_msgs_mbx = hw->mailboxq.num_rq_entries; data.async_watermark_val = ICE_MBX_OVERFLOW_WATERMARK; - if (!ice_is_malicious_vf(pf, &event, &data)) - ice_vc_process_vf_msg(pf, &event); + ice_vc_process_vf_msg(pf, &event, &data); break; case ice_aqc_opc_fw_logging: ice_output_fw_log(hw, &event.desc, event.msg_buf); diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index e0c573d9d1b9..97243c616d5d 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -3834,27 +3834,26 @@ void ice_virtchnl_set_repr_ops(struct ice_vf *vf) } /** - * ice_is_malicious_vf - helper function to detect a malicious VF - * @pf: ptr to struct ice_pf - * @event: pointer to the AQ event + * ice_is_malicious_vf - check if this vf might be overflowing mailbox + * @vf: the VF to check * @mbxdata: data about the state of the mailbox + * + * Detect if a given VF might be malicious and attempting to overflow the PF + * mailbox. If so, log a warning message and ignore this event. */ -bool -ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info *event, - struct ice_mbx_data *mbxdata) +static bool +ice_is_malicious_vf(struct ice_vf *vf, struct ice_mbx_data *mbxdata) { - s16 vf_id = le16_to_cpu(event->desc.retval); - struct device *dev = ice_pf_to_dev(pf); bool report_malvf = false; - struct ice_vf *vf; + struct device *dev; + struct ice_pf *pf; int status; - vf = ice_get_vf_by_id(pf, vf_id); - if (!vf) - return false; + pf = vf->pf; + dev = ice_pf_to_dev(pf); if (test_bit(ICE_VF_STATE_DIS, vf->vf_states)) - goto out_put_vf; + return vf->mbx_info.malicious; /* check to see if we have a newly malicious VF */ status = ice_mbx_vf_state_handler(&pf->hw, mbxdata, &vf->mbx_info, @@ -3872,9 +3871,6 @@ ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info *event, pf_vsi ? pf_vsi->netdev->dev_addr : zero_addr); } -out_put_vf: - ice_put_vf(vf); - return vf->mbx_info.malicious; } @@ -3882,11 +3878,13 @@ out_put_vf: * ice_vc_process_vf_msg - Process request from VF * @pf: pointer to the PF structure * @event: pointer to the AQ event + * @mbxdata: information used to detect VF attempting mailbox overflow * * called from the common asq/arq handler to * process request from VF */ -void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event) +void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event, + struct ice_mbx_data *mbxdata) { u32 v_opcode = le32_to_cpu(event->desc.cookie_high); s16 vf_id = le16_to_cpu(event->desc.retval); @@ -3908,6 +3906,10 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event) mutex_lock(&vf->cfg_lock); + /* Check if the VF is trying to overflow the mailbox */ + if (ice_is_malicious_vf(vf, mbxdata)) + goto finish; + /* Check if VF is disabled. */ if (test_bit(ICE_VF_STATE_DIS, vf->vf_states)) { err = -EPERM; diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.h b/drivers/net/ethernet/intel/ice/ice_virtchnl.h index 648a383fad85..cd747718de73 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.h @@ -63,10 +63,8 @@ int ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, enum virtchnl_status_code v_retval, u8 *msg, u16 msglen); bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id); -bool -ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info *event, - struct ice_mbx_data *mbxdata); -void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event); +void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event, + struct ice_mbx_data *mbxdata); #else /* CONFIG_PCI_IOV */ static inline void ice_virtchnl_set_dflt_ops(struct ice_vf *vf) { } static inline void ice_virtchnl_set_repr_ops(struct ice_vf *vf) { } @@ -86,16 +84,9 @@ static inline bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16 vsi_id) return false; } -static inline bool -ice_is_malicious_vf(struct ice_pf __always_unused *pf, - struct ice_rq_event_info __always_unused *event, - struct ice_mbx_data *mbxdata) -{ - return false; -} - static inline void -ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event) +ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event, + struct ice_mbx_data *mbxdata) { } #endif /* !CONFIG_PCI_IOV */ -- cgit v1.2.3 From 7255355a0636b4eff08d5e8139c77d98f151c4fc Mon Sep 17 00:00:00 2001 From: Dawid Wesierski Date: Tue, 18 Apr 2023 11:52:55 +0200 Subject: ice: Fix ice VF reset during iavf initialization Fix the current implementation that causes ice_trigger_vf_reset() to start resetting the VF even when the VF-NIC is still initializing. When we reset NIC with ice driver it can interfere with iavf-vf initialization e.g. during consecutive resets induced by ice iavf ice | | |<-----------------| | ice resets vf iavf | reset | start | |<-----------------| | ice resets vf | causing iavf | initialization | error | | iavf reset end This leads to a series of -53 errors (failed to init adminq) from the IAVF. Change the state of the vf_state field to be not active when the IAVF is still initializing. Make sure to wait until receiving the message on the message box to ensure that the vf is ready and initializded. In simple terms we use the ACTIVE flag to make sure that the ice driver knows if the iavf is ready for another reset iavf ice | | | | |<------------- ice resets vf iavf vf_state != ACTIVE reset | start | | | | | iavf | reset-------> vf_state == ACTIVE end ice resets vf | | | | Fixes: c54d209c78b8 ("ice: Wait for VF to be reset/ready before configuration") Signed-off-by: Dawid Wesierski Signed-off-by: Kamil Maziarz Acked-by: Jacob Keller Tested-by: Rafal Romanowski Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_sriov.c | 8 ++++---- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 19 +++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_vf_lib.h | 1 + drivers/net/ethernet/intel/ice/ice_virtchnl.c | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers/net/ethernet/intel/ice/ice_virtchnl.c') diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index f1dca59bd844..588ad8696756 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -1171,7 +1171,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) if (!vf) return -EINVAL; - ret = ice_check_vf_ready_for_cfg(vf); + ret = ice_check_vf_ready_for_reset(vf); if (ret) goto out_put_vf; @@ -1286,7 +1286,7 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) goto out_put_vf; } - ret = ice_check_vf_ready_for_cfg(vf); + ret = ice_check_vf_ready_for_reset(vf); if (ret) goto out_put_vf; @@ -1340,7 +1340,7 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) return -EOPNOTSUPP; } - ret = ice_check_vf_ready_for_cfg(vf); + ret = ice_check_vf_ready_for_reset(vf); if (ret) goto out_put_vf; @@ -1653,7 +1653,7 @@ ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, if (!vf) return -EINVAL; - ret = ice_check_vf_ready_for_cfg(vf); + ret = ice_check_vf_ready_for_reset(vf); if (ret) goto out_put_vf; diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index 89fd6982df09..bf74a2f3a4f8 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -185,6 +185,25 @@ int ice_check_vf_ready_for_cfg(struct ice_vf *vf) return 0; } +/** + * ice_check_vf_ready_for_reset - check if VF is ready to be reset + * @vf: VF to check if it's ready to be reset + * + * The purpose of this function is to ensure that the VF is not in reset, + * disabled, and is both initialized and active, thus enabling us to safely + * initialize another reset. + */ +int ice_check_vf_ready_for_reset(struct ice_vf *vf) +{ + int ret; + + ret = ice_check_vf_ready_for_cfg(vf); + if (!ret && !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) + ret = -EAGAIN; + + return ret; +} + /** * ice_trigger_vf_reset - Reset a VF on HW * @vf: pointer to the VF structure diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h index e3cda6fb71ab..a38ef00a3679 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h @@ -215,6 +215,7 @@ u16 ice_get_num_vfs(struct ice_pf *pf); struct ice_vsi *ice_get_vf_vsi(struct ice_vf *vf); bool ice_is_vf_disabled(struct ice_vf *vf); int ice_check_vf_ready_for_cfg(struct ice_vf *vf); +int ice_check_vf_ready_for_reset(struct ice_vf *vf); void ice_set_vf_state_dis(struct ice_vf *vf); bool ice_is_any_vf_in_unicast_promisc(struct ice_pf *pf); void diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c index 97243c616d5d..f4a524f80b11 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c @@ -3955,6 +3955,7 @@ error_handler: ice_vc_notify_vf_link_state(vf); break; case VIRTCHNL_OP_RESET_VF: + clear_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); ops->reset_vf(vf); break; case VIRTCHNL_OP_ADD_ETH_ADDR: -- cgit v1.2.3