[Intel-wired-lan] [PATCH S55 01/14] ice: warn about potentially malicious VFs
Jankowski, Konrad0
konrad0.jankowski at intel.com
Wed Apr 21 18:49:18 UTC 2021
> -----Original Message-----
> From: Intel-wired-lan <intel-wired-lan-bounces at osuosl.org> On Behalf Of
> Tony Nguyen
> Sent: wtorek, 2 marca 2021 19:12
> To: intel-wired-lan at lists.osuosl.org
> Subject: [Intel-wired-lan] [PATCH S55 01/14] ice: warn about potentially
> malicious VFs
>
> From: Vignesh Sridhar <vignesh.sridhar at intel.com>
>
> Attempt to detect malicious VFs and, if suspected, log the information but
> keep going to allow the user to take any desired actions.
>
> Potentially malicious VFs are identified by checking if the VFs are transmitting
> too many messages via the PF-VF mailbox which could cause an overflow of
> this channel resulting in denial of service. This is done by creating a snapshot
> or static capture of the mailbox buffer which can be traversed and in which
> the messages sent by VFs are tracked.
>
> Co-developed-by: Yashaswini Raghuram Prathivadi Bhayankaram
> <yashaswini.raghuram.prathivadi.bhayankaram at intel.com>
> Signed-off-by: Yashaswini Raghuram Prathivadi Bhayankaram
> <yashaswini.raghuram.prathivadi.bhayankaram at intel.com>
> Co-developed-by: Paul M Stillwell Jr <paul.m.stillwell.jr at intel.com>
> Signed-off-by: Paul M Stillwell Jr <paul.m.stillwell.jr at intel.com>
> Co-developed-by: Brett Creeley <brett.creeley at intel.com>
> Signed-off-by: Brett Creeley <brett.creeley at intel.com>
> Signed-off-by: Vignesh Sridhar <vignesh.sridhar at intel.com>
> Signed-off-by: Tony Nguyen <anthony.l.nguyen at intel.com>
> ---
> drivers/net/ethernet/intel/ice/ice.h | 1 +
> drivers/net/ethernet/intel/ice/ice_main.c | 7 +-
> drivers/net/ethernet/intel/ice/ice_sriov.c | 400 +++++++++++++++++-
> drivers/net/ethernet/intel/ice/ice_sriov.h | 20 +-
> drivers/net/ethernet/intel/ice/ice_type.h | 75 ++++
> .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 92 +++-
> .../net/ethernet/intel/ice/ice_virtchnl_pf.h | 12 +
> 7 files changed, 603 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice.h
> b/drivers/net/ethernet/intel/ice/ice.h
> index 07d4715e1bcd..ca94b01626d2 100644
> --- a/drivers/net/ethernet/intel/ice/ice.h
> +++ b/drivers/net/ethernet/intel/ice/ice.h
> @@ -414,6 +414,7 @@ struct ice_pf {
> u16 num_msix_per_vf;
> /* used to ratelimit the MDD event logging */
> unsigned long last_printed_mdd_jiffies;
> + DECLARE_BITMAP(malvfs, ICE_MAX_VF_COUNT);
> DECLARE_BITMAP(state, __ICE_STATE_NBITS);
> DECLARE_BITMAP(flags, ICE_PF_FLAGS_NBITS);
> unsigned long *avail_txqs; /* bitmap to track PF Tx queue usage
> */
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c
> b/drivers/net/ethernet/intel/ice/ice_main.c
> index 5b66b27a98aa..9cf876e420c9 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -1210,6 +1210,10 @@ static int __ice_clean_ctrlq(struct ice_pf *pf,
> enum ice_ctl_q q_type)
> case ICE_CTL_Q_MAILBOX:
> cq = &hw->mailboxq;
> qtype = "Mailbox";
> + /* we are going to try to detect a malicious VF, so set the
> + * state to begin detection
> + */
> + hw->mbx_snapshot.mbx_buf.state =
> +ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
> break;
> default:
> dev_warn(dev, "Unknown control queue type 0x%x\n",
> q_type); @@ -1291,7 +1295,8 @@ static int __ice_clean_ctrlq(struct ice_pf
> *pf, enum ice_ctl_q q_type)
> ice_vf_lan_overflow_event(pf, &event);
> break;
> case ice_mbx_opc_send_msg_to_pf:
> - ice_vc_process_vf_msg(pf, &event);
> + if (!ice_is_malicious_vf(pf, &event, i, pending))
> + ice_vc_process_vf_msg(pf, &event);
> 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_sriov.c
> b/drivers/net/ethernet/intel/ice/ice_sriov.c
> index 554f567476f3..aa11d07793d4 100644
> --- a/drivers/net/ethernet/intel/ice/ice_sriov.c
> +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
> @@ -2,7 +2,6 @@
> /* Copyright (c) 2018, Intel Corporation. */
>
> #include "ice_common.h"
> -#include "ice_adminq_cmd.h"
> #include "ice_sriov.h"
>
> /**
> @@ -132,3 +131,402 @@ u32 ice_conv_link_speed_to_virtchnl(bool
> adv_link_support, u16 link_speed)
>
> return speed;
> }
> +
> +/* The mailbox overflow detection algorithm helps to check if there
> + * is a possibility of a malicious VF transmitting too many MBX
> +messages to the
> + * PF.
> + * 1. The mailbox snapshot structure, ice_mbx_snapshot, is initialized
> +during
> + * driver initialization in ice_init_hw() using ice_mbx_init_snapshot().
> + * The struct ice_mbx_snapshot helps to track and traverse a static
> +window of
> + * messages within the mailbox queue while looking for a malicious VF.
> + *
> + * 2. When the caller starts processing its mailbox queue in response
> +to an
> + * interrupt, the structure ice_mbx_snapshot is expected to be cleared
> +before
> + * the algorithm can be run for the first time for that interrupt. This
> +can be
> + * done via ice_mbx_reset_snapshot().
> + *
> + * 3. For every message read by the caller from the MBX Queue, the
> +caller must
> + * call the detection algorithm's entry function ice_mbx_vf_state_handler().
> + * Before every call to ice_mbx_vf_state_handler() the struct
> +ice_mbx_data is
> + * filled as it is required to be passed to the algorithm.
> + *
> + * 4. Every time a message is read from the MBX queue, a VFId is
> +received which
> + * is passed to the state handler. The boolean output is_malvf of the
> +state
> + * handler ice_mbx_vf_state_handler() serves as an indicator to the
> +caller
> + * whether this VF is malicious or not.
> + *
> + * 5. When a VF is identified to be malicious, the caller can send a
> +message
> + * to the system administrator. The caller can invoke
> +ice_mbx_report_malvf()
> + * to help determine if a malicious VF is to be reported or not. This
> +function
> + * requires the caller to maintain a global bitmap to track all
> +malicious VFs
> + * and pass that to ice_mbx_report_malvf() along with the VFID which
> +was identified
> + * to be malicious by ice_mbx_vf_state_handler().
> + *
> + * 6. The global bitmap maintained by PF can be cleared completely if
> +PF is in
> + * reset or the bit corresponding to a VF can be cleared if that VF is in reset.
> + * When a VF is shut down and brought back up, we assume that the new
> +VF
> + * brought up is not malicious and hence report it if found malicious.
> + *
> + * 7. The function ice_mbx_reset_snapshot() is called to reset the
> +information
> + * in ice_mbx_snapshot for every new mailbox interrupt handled.
> + *
> + * 8. The memory allocated for variables in ice_mbx_snapshot is
> +de-allocated
> + * when driver is unloaded.
> + */
> +#define ICE_RQ_DATA_MASK(rq_data) ((rq_data) &
> PF_MBX_ARQH_ARQH_M)
> +/* Using the highest value for an unsigned 16-bit value 0xFFFF to
> +indicate that
> + * the max messages check must be ignored in the algorithm */
> +#define ICE_IGNORE_MAX_MSG_CNT 0xFFFF
> +
> +/**
> + * ice_mbx_traverse - Pass through mailbox snapshot
> + * @hw: pointer to the HW struct
> + * @new_state: new algorithm state
> + *
> + * Traversing the mailbox static snapshot without checking
> + * for malicious VFs.
> + */
> +static void
> +ice_mbx_traverse(struct ice_hw *hw,
> + enum ice_mbx_snapshot_state *new_state) {
> + struct ice_mbx_snap_buffer_data *snap_buf;
> + u32 num_iterations;
> +
> + snap_buf = &hw->mbx_snapshot.mbx_buf;
> +
> + /* As mailbox buffer is circular, applying a mask
> + * on the incremented iteration count.
> + */
> + num_iterations = ICE_RQ_DATA_MASK(++snap_buf-
> >num_iterations);
> +
> + /* Checking either of the below conditions to exit snapshot traversal:
> + * Condition-1: If the number of iterations in the mailbox is equal to
> + * the mailbox head which would indicate that we have reached the
> end
> + * of the static snapshot.
> + * Condition-2: If the maximum messages serviced in the mailbox for
> a
> + * given interrupt is the highest possible value then there is no need
> + * to check if the number of messages processed is equal to it. If not
> + * check if the number of messages processed is greater than or
> equal
> + * to the maximum number of mailbox entries serviced in current
> work item.
> + */
> + if (num_iterations == snap_buf->head ||
> + (snap_buf->max_num_msgs_mbx <
> ICE_IGNORE_MAX_MSG_CNT &&
> + ++snap_buf->num_msg_proc >= snap_buf-
> >max_num_msgs_mbx))
> + *new_state =
> ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
> +}
> +
> +/**
> + * ice_mbx_detect_malvf - Detect malicious VF in snapshot
> + * @hw: pointer to the HW struct
> + * @vf_id: relative virtual function ID
> + * @new_state: new algorithm state
> + * @is_malvf: boolean output to indicate if VF is malicious
> + *
> + * This function tracks the number of asynchronous messages
> + * sent per VF and marks the VF as malicious if it exceeds
> + * the permissible number of messages to send.
> + */
> +static enum ice_status
> +ice_mbx_detect_malvf(struct ice_hw *hw, u16 vf_id,
> + enum ice_mbx_snapshot_state *new_state,
> + bool *is_malvf)
> +{
> + struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
> +
> + if (vf_id >= snap->mbx_vf.vfcntr_len)
> + return ICE_ERR_OUT_OF_RANGE;
> +
> + /* increment the message count in the VF array */
> + snap->mbx_vf.vf_cntr[vf_id]++;
> +
> + if (snap->mbx_vf.vf_cntr[vf_id] >=
> ICE_ASYNC_VF_MSG_THRESHOLD)
> + *is_malvf = true;
> +
> + /* continue to iterate through the mailbox snapshot */
> + ice_mbx_traverse(hw, new_state);
> +
> + return 0;
> +}
> +
> +/**
> + * ice_mbx_reset_snapshot - Reset mailbox snapshot structure
> + * @snap: pointer to mailbox snapshot structure in the ice_hw struct
> + *
> + * Reset the mailbox snapshot structure and clear VF counter array.
> + */
> +static void ice_mbx_reset_snapshot(struct ice_mbx_snapshot *snap) {
> + u32 vfcntr_len;
> +
> + if (!snap || !snap->mbx_vf.vf_cntr)
> + return;
> +
> + /* Clear VF counters. */
> + vfcntr_len = snap->mbx_vf.vfcntr_len;
> + if (vfcntr_len)
> + memset(snap->mbx_vf.vf_cntr, 0,
> + (vfcntr_len * sizeof(*snap->mbx_vf.vf_cntr)));
> +
> + /* Reset mailbox snapshot for a new capture. */
> + memset(&snap->mbx_buf, 0, sizeof(snap->mbx_buf));
> + snap->mbx_buf.state =
> ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
> +}
> +
> +/**
> + * ice_mbx_vf_state_handler - Handle states of the overflow algorithm
> + * @hw: pointer to the HW struct
> + * @mbx_data: pointer to structure containing mailbox data
> + * @vf_id: relative virtual function (VF) ID
> + * @is_malvf: boolean output to indicate if VF is malicious
> + *
> + * The function serves as an entry point for the malicious VF
> + * detection algorithm by handling the different states and state
> + * transitions of the algorithm:
> + * New snapshot: This state is entered when creating a new static
> + * snapshot. The data from any previous mailbox snapshot is
> + * cleared and a new capture of the mailbox head and tail is
> + * logged. This will be the new static snapshot to detect
> + * asynchronous messages sent by VFs. On capturing the snapshot
> + * and depending on whether the number of pending messages in that
> + * snapshot exceed the watermark value, the state machine enters
> + * traverse or detect states.
> + * Traverse: If pending message count is below watermark then iterate
> + * through the snapshot without any action on VF.
> + * Detect: If pending message count exceeds watermark traverse
> + * the static snapshot and look for a malicious VF.
> + */
> +enum ice_status
> +ice_mbx_vf_state_handler(struct ice_hw *hw,
> + struct ice_mbx_data *mbx_data, u16 vf_id,
> + bool *is_malvf)
> +{
> + struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
> + struct ice_mbx_snap_buffer_data *snap_buf;
> + struct ice_ctl_q_info *cq = &hw->mailboxq;
> + enum ice_mbx_snapshot_state new_state;
> + enum ice_status status = 0;
> +
> + if (!is_malvf || !mbx_data)
> + return ICE_ERR_BAD_PTR;
> +
> + /* When entering the mailbox state machine assume that the VF
> + * is not malicious until detected.
> + */
> + *is_malvf = false;
> +
> + /* Checking if max messages allowed to be processed while servicing
> current
> + * interrupt is not less than the defined AVF message threshold.
> + */
> + if (mbx_data->max_num_msgs_mbx <=
> ICE_ASYNC_VF_MSG_THRESHOLD)
> + return ICE_ERR_INVAL_SIZE;
> +
> + /* The watermark value should not be lesser than the threshold limit
> + * set for the number of asynchronous messages a VF can send to
> mailbox
> + * nor should it be greater than the maximum number of messages in
> the
> + * mailbox serviced in current interrupt.
> + */
> + if (mbx_data->async_watermark_val <
> ICE_ASYNC_VF_MSG_THRESHOLD ||
> + mbx_data->async_watermark_val > mbx_data-
> >max_num_msgs_mbx)
> + return ICE_ERR_PARAM;
> +
> + new_state = ICE_MAL_VF_DETECT_STATE_INVALID;
> + snap_buf = &snap->mbx_buf;
> +
> + switch (snap_buf->state) {
> + case ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT:
> + /* Clear any previously held data in mailbox snapshot
> structure. */
> + ice_mbx_reset_snapshot(snap);
> +
> + /* Collect the pending ARQ count, number of messages
> processed and
> + * the maximum number of messages allowed to be
> processed from the
> + * Mailbox for current interrupt.
> + */
> + snap_buf->num_pending_arq = mbx_data-
> >num_pending_arq;
> + snap_buf->num_msg_proc = mbx_data->num_msg_proc;
> + snap_buf->max_num_msgs_mbx = mbx_data-
> >max_num_msgs_mbx;
> +
> + /* Capture a new static snapshot of the mailbox by logging
> the
> + * head and tail of snapshot and set num_iterations to the tail
> + * value to mark the start of the iteration through the
> snapshot.
> + */
> + snap_buf->head = ICE_RQ_DATA_MASK(cq-
> >rq.next_to_clean +
> + mbx_data-
> >num_pending_arq);
> + snap_buf->tail = ICE_RQ_DATA_MASK(cq->rq.next_to_clean
> - 1);
> + snap_buf->num_iterations = snap_buf->tail;
> +
> + /* Pending ARQ messages returned by ice_clean_rq_elem
> + * is the difference between the head and tail of the
> + * mailbox queue. Comparing this value against the
> watermark
> + * helps to check if we potentially have malicious VFs.
> + */
> + if (snap_buf->num_pending_arq >=
> + mbx_data->async_watermark_val) {
> + new_state = ICE_MAL_VF_DETECT_STATE_DETECT;
> + status = ice_mbx_detect_malvf(hw, vf_id,
> &new_state, is_malvf);
> + } else {
> + new_state =
> ICE_MAL_VF_DETECT_STATE_TRAVERSE;
> + ice_mbx_traverse(hw, &new_state);
> + }
> + break;
> +
> + case ICE_MAL_VF_DETECT_STATE_TRAVERSE:
> + new_state = ICE_MAL_VF_DETECT_STATE_TRAVERSE;
> + ice_mbx_traverse(hw, &new_state);
> + break;
> +
> + case ICE_MAL_VF_DETECT_STATE_DETECT:
> + new_state = ICE_MAL_VF_DETECT_STATE_DETECT;
> + status = ice_mbx_detect_malvf(hw, vf_id, &new_state,
> is_malvf);
> + break;
> +
> + default:
> + new_state = ICE_MAL_VF_DETECT_STATE_INVALID;
> + status = ICE_ERR_CFG;
> + }
> +
> + snap_buf->state = new_state;
> +
> + return status;
> +}
> +
> +/**
> + * ice_mbx_report_malvf - Track and note malicious VF
> + * @hw: pointer to the HW struct
> + * @all_malvfs: all malicious VFs tracked by PF
> + * @bitmap_len: length of bitmap in bits
> + * @vf_id: relative virtual function ID of the malicious VF
> + * @report_malvf: boolean to indicate if malicious VF must be reported
> + *
> + * This function will update a bitmap that keeps track of the malicious
> + * VFs attached to the PF. A malicious VF must be reported only once if
> + * discovered between VF resets or loading so the function checks
> + * the input vf_id against the bitmap to verify if the VF has been
> + * detected in any previous mailbox iterations.
> + */
> +enum ice_status
> +ice_mbx_report_malvf(struct ice_hw *hw, unsigned long *all_malvfs,
> + u16 bitmap_len, u16 vf_id, bool *report_malvf) {
> + if (!all_malvfs || !report_malvf)
> + return ICE_ERR_PARAM;
> +
> + *report_malvf = false;
> +
> + if (bitmap_len < hw->mbx_snapshot.mbx_vf.vfcntr_len)
> + return ICE_ERR_INVAL_SIZE;
> +
> + if (vf_id >= bitmap_len)
> + return ICE_ERR_OUT_OF_RANGE;
> +
> + /* If the vf_id is found in the bitmap set bit and boolean to true */
> + if (!test_and_set_bit(vf_id, all_malvfs))
> + *report_malvf = true;
> +
> + return 0;
> +}
> +
> +/**
> + * ice_mbx_clear_malvf - Clear VF bitmap and counter for VF ID
> + * @snap: pointer to the mailbox snapshot structure
> + * @all_malvfs: all malicious VFs tracked by PF
> + * @bitmap_len: length of bitmap in bits
> + * @vf_id: relative virtual function ID of the malicious VF
> + *
> + * In case of a VF reset, this function can be called to clear
> + * the bit corresponding to the VF ID in the bitmap tracking all
> + * malicious VFs attached to the PF. The function also clears the
> + * VF counter array at the index of the VF ID. This is to ensure
> + * that the new VF loaded is not considered malicious before going
> + * through the overflow detection algorithm.
> + */
> +enum ice_status
> +ice_mbx_clear_malvf(struct ice_mbx_snapshot *snap, unsigned long
> *all_malvfs,
> + u16 bitmap_len, u16 vf_id)
> +{
> + if (!snap || !all_malvfs)
> + return ICE_ERR_PARAM;
> +
> + if (bitmap_len < snap->mbx_vf.vfcntr_len)
> + return ICE_ERR_INVAL_SIZE;
> +
> + /* Ensure VF ID value is not larger than bitmap or VF counter length
> */
> + if (vf_id >= bitmap_len || vf_id >= snap->mbx_vf.vfcntr_len)
> + return ICE_ERR_OUT_OF_RANGE;
> +
> + /* Clear VF ID bit in the bitmap tracking malicious VFs attached to PF
> */
> + clear_bit(vf_id, all_malvfs);
> +
> + /* Clear the VF counter in the mailbox snapshot structure for that VF
> ID.
> + * This is to ensure that if a VF is unloaded and a new one brought
> back
> + * up with the same VF ID for a snapshot currently in traversal or
> detect
> + * state the counter for that VF ID does not increment on top of
> existing
> + * values in the mailbox overflow detection algorithm.
> + */
> + snap->mbx_vf.vf_cntr[vf_id] = 0;
> +
> + return 0;
> +}
> +
> +/**
> + * ice_mbx_init_snapshot - Initialize mailbox snapshot structure
> + * @hw: pointer to the hardware structure
> + * @vf_count: number of VFs allocated on a PF
> + *
> + * Clear the mailbox snapshot structure and allocate memory
> + * for the VF counter array based on the number of VFs allocated
> + * on that PF.
> + *
> + * Assumption: This function will assume ice_get_caps() has already
> +been
> + * called to ensure that the vf_count can be compared against the
> +number
> + * of VFs supported as defined in the functional capabilities of the device.
> + */
> +enum ice_status ice_mbx_init_snapshot(struct ice_hw *hw, u16 vf_count)
> +{
> + struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
> +
> + /* Ensure that the number of VFs allocated is non-zero and
> + * is not greater than the number of supported VFs defined in
> + * the functional capabilities of the PF.
> + */
> + if (!vf_count || vf_count > hw->func_caps.num_allocd_vfs)
> + return ICE_ERR_INVAL_SIZE;
> +
> + snap->mbx_vf.vf_cntr = devm_kcalloc(ice_hw_to_dev(hw),
> vf_count,
> + sizeof(*snap->mbx_vf.vf_cntr),
> + GFP_KERNEL);
> + if (!snap->mbx_vf.vf_cntr)
> + return ICE_ERR_NO_MEMORY;
> +
> + /* Setting the VF counter length to the number of allocated
> + * VFs for given PF's functional capabilities.
> + */
> + snap->mbx_vf.vfcntr_len = vf_count;
> +
> + /* Clear mbx_buf in the mailbox snaphot structure and setting the
> + * mailbox snapshot state to a new capture.
> + */
> + memset(&snap->mbx_buf, 0, sizeof(snap->mbx_buf));
> + snap->mbx_buf.state =
> ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
> +
> + return 0;
> +}
> +
> +/**
> + * ice_mbx_deinit_snapshot - Free mailbox snapshot structure
> + * @hw: pointer to the hardware structure
> + *
> + * Clear the mailbox snapshot structure and free the VF counter array.
> + */
> +void ice_mbx_deinit_snapshot(struct ice_hw *hw) {
> + struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
> +
> + /* Free VF counter array and reset VF counter length */
> + devm_kfree(ice_hw_to_dev(hw), snap->mbx_vf.vf_cntr);
> + snap->mbx_vf.vfcntr_len = 0;
> +
> + /* Clear mbx_buf in the mailbox snaphot structure */
> + memset(&snap->mbx_buf, 0, sizeof(snap->mbx_buf)); }
> diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.h
> b/drivers/net/ethernet/intel/ice/ice_sriov.h
> index 3d78a0795138..161dc55d9e9c 100644
> --- a/drivers/net/ethernet/intel/ice/ice_sriov.h
> +++ b/drivers/net/ethernet/intel/ice/ice_sriov.h
> @@ -4,7 +4,14 @@
> #ifndef _ICE_SRIOV_H_
> #define _ICE_SRIOV_H_
>
> -#include "ice_common.h"
> +#include "ice_type.h"
> +#include "ice_controlq.h"
> +
> +/* Defining the mailbox message threshold as 63 asynchronous
> + * pending messages. Normal VF functionality does not require
> + * sending more than 63 asynchronous pending message.
> + */
> +#define ICE_ASYNC_VF_MSG_THRESHOLD 63
>
> #ifdef CONFIG_PCI_IOV
> enum ice_status
> @@ -12,6 +19,17 @@ ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid,
> u32 v_opcode, u32 v_retval,
> u8 *msg, u16 msglen, struct ice_sq_cd *cd);
>
> u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16
> link_speed);
> +enum ice_status
> +ice_mbx_vf_state_handler(struct ice_hw *hw, struct ice_mbx_data
> *mbx_data,
> + u16 vf_id, bool *is_mal_vf);
> +enum ice_status
> +ice_mbx_clear_malvf(struct ice_mbx_snapshot *snap, unsigned long
> *all_malvfs,
> + u16 bitmap_len, u16 vf_id);
> +enum ice_status ice_mbx_init_snapshot(struct ice_hw *hw, u16 vf_count);
> +void ice_mbx_deinit_snapshot(struct ice_hw *hw); enum ice_status
> +ice_mbx_report_malvf(struct ice_hw *hw, unsigned long *all_malvfs,
> + u16 bitmap_len, u16 vf_id, bool *report_malvf);
> #else /* CONFIG_PCI_IOV */
> static inline enum ice_status
> ice_aq_send_msg_to_vf(struct ice_hw __always_unused *hw, diff --git
> a/drivers/net/ethernet/intel/ice/ice_type.h
> b/drivers/net/ethernet/intel/ice/ice_type.h
> index eae7ba73731e..420fd487fd57 100644
> --- a/drivers/net/ethernet/intel/ice/ice_type.h
> +++ b/drivers/net/ethernet/intel/ice/ice_type.h
> @@ -643,6 +643,80 @@ struct ice_fw_log_cfg {
> struct ice_fw_log_evnt evnts[ICE_AQC_FW_LOG_ID_MAX]; };
>
> +/* Enum defining the different states of the mailbox snapshot in the
> + * PF-VF mailbox overflow detection algorithm. The snapshot can be in
> + * states:
> + * 1. ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT - generate a new static
> +snapshot
> + * within the mailbox buffer.
> + * 2. ICE_MAL_VF_DETECT_STATE_TRAVERSE - iterate through the mailbox
> +snaphot
> + * 3. ICE_MAL_VF_DETECT_STATE_DETECT - track the messages sent per VF
> +via the
> + * mailbox and mark any VFs sending more messages than the threshold
> limit set.
> + * 4. ICE_MAL_VF_DETECT_STATE_INVALID - Invalid mailbox state set to
> 0xFFFFFFFF.
> + */
> +enum ice_mbx_snapshot_state {
> + ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT = 0,
> + ICE_MAL_VF_DETECT_STATE_TRAVERSE,
> + ICE_MAL_VF_DETECT_STATE_DETECT,
> + ICE_MAL_VF_DETECT_STATE_INVALID = 0xFFFFFFFF, };
> +
> +/* Structure to hold information of the static snapshot and the mailbox
> + * buffer data used to generate and track the snapshot.
> + * 1. state: the state of the mailbox snapshot in the malicious VF
> + * detection state handler ice_mbx_vf_state_handler()
> + * 2. head: head of the mailbox snapshot in a circular mailbox buffer
> + * 3. tail: tail of the mailbox snapshot in a circular mailbox buffer
> + * 4. num_iterations: number of messages traversed in circular mailbox
> +buffer
> + * 5. num_msg_proc: number of messages processed in mailbox
> + * 6. num_pending_arq: number of pending asynchronous messages
> + * 7. max_num_msgs_mbx: maximum messages in mailbox for currently
> + * serviced work item or interrupt.
> + */
> +struct ice_mbx_snap_buffer_data {
> + enum ice_mbx_snapshot_state state;
> + u32 head;
> + u32 tail;
> + u32 num_iterations;
> + u16 num_msg_proc;
> + u16 num_pending_arq;
> + u16 max_num_msgs_mbx;
> +};
> +
> +/* Structure to track messages sent by VFs on mailbox:
> + * 1. vf_cntr: a counter array of VFs to track the number of
> + * asynchronous messages sent by each VF
> + * 2. vfcntr_len: number of entries in VF counter array */ struct
> +ice_mbx_vf_counter {
> + u32 *vf_cntr;
> + u32 vfcntr_len;
> +};
> +
> +/* Structure to hold data relevant to the captured static snapshot
> + * of the PF-VF mailbox.
> + */
> +struct ice_mbx_snapshot {
> + struct ice_mbx_snap_buffer_data mbx_buf;
> + struct ice_mbx_vf_counter mbx_vf;
> +};
> +
> +/* Structure to hold data to be used for capturing or updating a
> + * static snapshot.
> + * 1. num_msg_proc: number of messages processed in mailbox
> + * 2. num_pending_arq: number of pending asynchronous messages
> + * 3. max_num_msgs_mbx: maximum messages in mailbox for currently
> + * serviced work item or interrupt.
> + * 4. async_watermark_val: An upper threshold set by caller to
> +determine
> + * if the pending arq count is large enough to assume that there is
> + * the possibility of a mailicious VF.
> + */
> +struct ice_mbx_data {
> + u16 num_msg_proc;
> + u16 num_pending_arq;
> + u16 max_num_msgs_mbx;
> + u16 async_watermark_val;
> +};
> +
> /* Port hardware description */
> struct ice_hw {
> u8 __iomem *hw_addr;
> @@ -774,6 +848,7 @@ struct ice_hw {
> DECLARE_BITMAP(fdir_perfect_fltr, ICE_FLTR_PTYPE_MAX);
> struct mutex rss_locks; /* protect RSS configuration */
> struct list_head rss_list_head;
> + struct ice_mbx_snapshot mbx_snapshot;
> };
>
> /* Statistics collected by each port, VSI, VEB, and S-channel */ diff --git
> a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
> b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
> index 6be6a54eb29c..0da9c84ed30f 100644
> --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
> +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c
> @@ -424,6 +424,12 @@ void ice_free_vfs(struct ice_pf *pf)
> wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
> }
> }
> +
> + /* clear malicious info if the VFs are getting released */
> + for (i = 0; i < tmp; i++)
> + if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs,
> ICE_MAX_VF_COUNT, i))
> + dev_dbg(dev, "failed to clear malicious VF state for
> VF %u\n", i);
> +
> clear_bit(__ICE_VF_DIS, pf->state);
> clear_bit(ICE_FLAG_SRIOV_ENA, pf->flags); } @@ -1262,6 +1268,11
> @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr)
> if (!pf->num_alloc_vfs)
> return false;
>
> + /* clear all malicious info if the VFs are getting reset */
> + ice_for_each_vf(pf, i)
> + if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs,
> ICE_MAX_VF_COUNT, i))
> + dev_dbg(dev, "failed to clear malicious VF state for
> VF %u\n", i);
> +
> /* If VFs have been disabled, there is no need to reset */
> if (test_and_set_bit(__ICE_VF_DIS, pf->state))
> return false;
> @@ -1447,6 +1458,10 @@ bool ice_reset_vf(struct ice_vf *vf, bool is_vflr)
>
> ice_vf_post_vsi_rebuild(vf);
>
> + /* if the VF has been reset allow it to come up again */
> + if (ice_mbx_clear_malvf(&hw->mbx_snapshot, pf->malvfs,
> ICE_MAX_VF_COUNT, vf->vf_id))
> + dev_dbg(dev, "failed to clear malicious VF state for VF
> %u\n", i);
> +
> return true;
> }
>
> @@ -1779,6 +1794,7 @@ int ice_sriov_configure(struct pci_dev *pdev, int
> num_vfs) {
> struct ice_pf *pf = pci_get_drvdata(pdev);
> struct device *dev = ice_pf_to_dev(pf);
> + enum ice_status status;
> int err;
>
> err = ice_check_sriov_allowed(pf);
> @@ -1787,6 +1803,7 @@ int ice_sriov_configure(struct pci_dev *pdev, int
> num_vfs)
>
> if (!num_vfs) {
> if (!pci_vfs_assigned(pdev)) {
> + ice_mbx_deinit_snapshot(&pf->hw);
> ice_free_vfs(pf);
> if (pf->lag)
> ice_enable_lag(pf->lag);
> @@ -1797,9 +1814,15 @@ int ice_sriov_configure(struct pci_dev *pdev, int
> num_vfs)
> return -EBUSY;
> }
>
> + status = ice_mbx_init_snapshot(&pf->hw, num_vfs);
> + if (status)
> + return ice_status_to_errno(status);
> +
> err = ice_pci_sriov_ena(pf, num_vfs);
> - if (err)
> + if (err) {
> + ice_mbx_deinit_snapshot(&pf->hw);
> return err;
> + }
>
> if (pf->lag)
> ice_disable_lag(pf->lag);
> @@ -4382,3 +4405,70 @@ void ice_restore_all_vfs_msi_state(struct pci_dev
> *pdev)
> }
> }
> }
> +
> +/**
> + * ice_is_malicious_vf - helper function to detect a malicious VF
> + * @pf: ptr to struct ice_pf
> + * @event: pointer to the AQ event
> + * @num_msg_proc: the number of messages processed so far
> + * @num_msg_pending: the number of messages peinding in admin queue
> */
> +bool ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info
> +*event,
> + u16 num_msg_proc, u16 num_msg_pending) {
> + s16 vf_id = le16_to_cpu(event->desc.retval);
> + struct device *dev = ice_pf_to_dev(pf);
> + struct ice_mbx_data mbxdata;
> + enum ice_status status;
> + bool malvf = false;
> + struct ice_vf *vf;
> +
> + if (ice_validate_vf_id(pf, vf_id))
> + return false;
> +
> + vf = &pf->vf[vf_id];
> + /* Check if VF is disabled. */
> + if (test_bit(ICE_VF_STATE_DIS, vf->vf_states))
> + return false;
> +
> + mbxdata.num_msg_proc = num_msg_proc;
> + mbxdata.num_pending_arq = num_msg_pending;
> + mbxdata.max_num_msgs_mbx = pf->hw.mailboxq.num_rq_entries;
> #define
> +ICE_MBX_OVERFLOW_WATERMARK 64
> + mbxdata.async_watermark_val =
> ICE_MBX_OVERFLOW_WATERMARK;
> +
> + /* check to see if we have a malicious VF */
> + status = ice_mbx_vf_state_handler(&pf->hw, &mbxdata, vf_id,
> &malvf);
> + if (status)
> + return false;
> +
> + if (malvf) {
> + bool report_vf = false;
> +
> + /* if the VF is malicious and we haven't let the user
> + * know about it, then let them know now
> + */
> + status = ice_mbx_report_malvf(&pf->hw, pf->malvfs,
> + ICE_MAX_VF_COUNT, vf_id,
> + &report_vf);
> + if (status)
> + dev_dbg(dev, "Error reporting malicious VF\n");
> +
> + if (report_vf) {
> + struct ice_vsi *pf_vsi = ice_get_main_vsi(pf);
> +
> + if (pf_vsi)
> + 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.addr[0],
> + pf_vsi->netdev->dev_addr);
> + }
> +
> + return true;
> + }
> +
> + /* if there was an error in detection or the VF is not malicious then
> + * return false
> + */
> + return false;
> +}
> diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
> b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
> index afd5c22015e1..53391ac1f068 100644
> --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
> +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h
> @@ -126,6 +126,9 @@ void ice_vc_notify_reset(struct ice_pf *pf); bool
> ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr); bool ice_reset_vf(struct
> ice_vf *vf, bool is_vflr); void ice_restore_all_vfs_msi_state(struct pci_dev
> *pdev);
> +bool
> +ice_is_malicious_vf(struct ice_pf *pf, struct ice_rq_event_info *event,
> + u16 num_msg_proc, u16 num_msg_pending);
>
> int
> ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8
> qos, @@ -165,6 +168,15 @@ bool ice_vc_isvalid_vsi_id(struct ice_vf *vf, u16
> vsi_id); #define ice_print_vf_rx_mdd_event(vf) do {} while (0) #define
> ice_restore_all_vfs_msi_state(pdev) do {} while (0)
>
> +static inline bool
> +ice_is_malicious_vf(struct ice_pf __always_unused *pf,
> + struct ice_rq_event_info __always_unused *event,
> + u16 __always_unused num_msg_proc,
> + u16 __always_unused num_msg_pending) {
> + return false;
> +}
> +
> static inline bool
> ice_reset_all_vfs(struct ice_pf __always_unused *pf,
> bool __always_unused is_vflr)
Tested-by: Konrad Jankowski <konrad0.jankowski at intel.com>
More information about the Intel-wired-lan
mailing list