Commit c31af68a authored by Brett Creeley's avatar Brett Creeley Committed by Tony Nguyen

ice: Add outer_vlan_ops and VSI specific VLAN ops implementations

Add a new outer_vlan_ops member to the ice_vsi structure as outer VLAN
ops are only available when the device is in Double VLAN Mode (DVM).
Depending on the VSI type, the requirements for what operations to
use/allow differ.

By default all VSI's have unsupported inner and outer VSI VLAN ops. This
implementation was chosen to prevent unexpected crashes due to null
pointer dereferences. Instead, if a VSI calls an unsupported op, it will
just return -EOPNOTSUPP.

Add implementations to support modifying outer VLAN fields for VSI
context. This includes the ability to modify VLAN stripping, insertion,
and the port VLAN based on the outer VLAN handling fields of the VSI
context.

These functions should only ever be used if DVM is enabled because that
means the firmware supports the outer VLAN fields in the VSI context. If
the device is in DVM, then always use the outer_vlan_ops, else use the
vlan_ops since the device is in Single VLAN Mode (SVM).

Also, move adding the untagged VLAN 0 filter from ice_vsi_setup() to
ice_vsi_vlan_setup() as the latter function is specific to the PF and
all other VSI types that need an untagged VLAN 0 filter already do this
in their specific flows. Without this change, Flow Director is failing
to initialize because it does not implement any VSI VLAN ops.
Signed-off-by: default avatarBrett Creeley <brett.creeley@intel.com>
Tested-by: default avatarGurucharan G <gurucharanx.g@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 7bd527aa
......@@ -18,6 +18,7 @@ ice-y := ice_main.o \
ice_txrx_lib.o \
ice_txrx.o \
ice_fltr.o \
ice_pf_vsi_vlan_ops.o \
ice_vsi_vlan_ops.o \
ice_vsi_vlan_lib.o \
ice_fdir.o \
......@@ -31,8 +32,12 @@ ice-y := ice_main.o \
ice_ethtool.o \
ice_repr.o \
ice_tc_lib.o
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_allowlist.o
ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o ice_virtchnl_fdir.o
ice-$(CONFIG_PCI_IOV) += \
ice_virtchnl_allowlist.o \
ice_virtchnl_fdir.o \
ice_sriov.o \
ice_vf_vsi_vlan_ops.o \
ice_virtchnl_pf.o
ice-$(CONFIG_PTP_1588_CLOCK) += ice_ptp.o ice_ptp_hw.o
ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o
ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
......
......@@ -369,7 +369,8 @@ struct ice_vsi {
u8 irqs_ready:1;
u8 current_isup:1; /* Sync 'link up' logging */
u8 stat_offsets_loaded:1;
struct ice_vsi_vlan_ops vlan_ops;
struct ice_vsi_vlan_ops inner_vlan_ops;
struct ice_vsi_vlan_ops outer_vlan_ops;
u16 num_vlan;
/* queue information */
......
......@@ -115,9 +115,12 @@ static int ice_eswitch_setup_env(struct ice_pf *pf)
struct ice_vsi *uplink_vsi = pf->switchdev.uplink_vsi;
struct net_device *uplink_netdev = uplink_vsi->netdev;
struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
struct ice_vsi_vlan_ops *vlan_ops;
bool rule_added = false;
ctrl_vsi->vlan_ops.dis_stripping(ctrl_vsi);
vlan_ops = ice_get_compat_vsi_vlan_ops(ctrl_vsi);
if (vlan_ops->dis_stripping(ctrl_vsi))
return -ENODEV;
ice_remove_vsi_fltr(&pf->hw, uplink_vsi->idx);
......
......@@ -8,6 +8,7 @@
#include "ice_fltr.h"
#include "ice_dcb_lib.h"
#include "ice_devlink.h"
#include "ice_vsi_vlan_ops.h"
/**
* ice_vsi_type_str - maps VSI type enum to string equivalents
......@@ -2458,17 +2459,6 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
if (ret)
goto unroll_vector_base;
/* Always add VLAN ID 0 switch rule by default. This is needed
* in order to allow all untagged and 0 tagged priority traffic
* if Rx VLAN pruning is enabled. Also there are cases where we
* don't get the call to add VLAN 0 via ice_vlan_rx_add_vid()
* so this handles those cases (i.e. adding the PF to a bridge
* without the 8021q module loaded).
*/
ret = ice_vsi_add_vlan_zero(vsi);
if (ret)
goto unroll_clear_rings;
ice_vsi_map_rings_to_vectors(vsi);
/* ICE_VSI_CTRL does not need RSS so skip RSS processing */
......@@ -3918,13 +3908,110 @@ int ice_set_link(struct ice_vsi *vsi, bool ena)
/**
* ice_vsi_add_vlan_zero - add VLAN 0 filter(s) for this VSI
* @vsi: VSI used to add VLAN filters
*
* In Single VLAN Mode (SVM), single VLAN filters via ICE_SW_LKUP_VLAN are based
* on the inner VLAN ID, so the VLAN TPID (i.e. 0x8100 or 0x888a8) doesn't
* matter. In Double VLAN Mode (DVM), outer/single VLAN filters via
* ICE_SW_LKUP_VLAN are based on the outer/single VLAN ID + VLAN TPID.
*
* For both modes add a VLAN 0 + no VLAN TPID filter to handle untagged traffic
* when VLAN pruning is enabled. Also, this handles VLAN 0 priority tagged
* traffic in SVM, since the VLAN TPID isn't part of filtering.
*
* If DVM is enabled then an explicit VLAN 0 + VLAN TPID filter needs to be
* added to allow VLAN 0 priority tagged traffic in DVM, since the VLAN TPID is
* part of filtering.
*/
int ice_vsi_add_vlan_zero(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
struct ice_vlan vlan;
int err;
vlan = ICE_VLAN(0, 0, 0);
err = vlan_ops->add_vlan(vsi, &vlan);
if (err && err != -EEXIST)
return err;
/* in SVM both VLAN 0 filters are identical */
if (!ice_is_dvm_ena(&vsi->back->hw))
return 0;
vlan = ICE_VLAN(ETH_P_8021Q, 0, 0);
err = vlan_ops->add_vlan(vsi, &vlan);
if (err && err != -EEXIST)
return err;
return 0;
}
/**
* ice_vsi_del_vlan_zero - delete VLAN 0 filter(s) for this VSI
* @vsi: VSI used to add VLAN filters
*
* Delete the VLAN 0 filters in the same manner that they were added in
* ice_vsi_add_vlan_zero.
*/
int ice_vsi_del_vlan_zero(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
struct ice_vlan vlan;
int err;
vlan = ICE_VLAN(0, 0, 0);
return vsi->vlan_ops.add_vlan(vsi, &vlan);
err = vlan_ops->del_vlan(vsi, &vlan);
if (err && err != -EEXIST)
return err;
/* in SVM both VLAN 0 filters are identical */
if (!ice_is_dvm_ena(&vsi->back->hw))
return 0;
vlan = ICE_VLAN(ETH_P_8021Q, 0, 0);
err = vlan_ops->del_vlan(vsi, &vlan);
if (err && err != -EEXIST)
return err;
return 0;
}
/**
* ice_vsi_num_zero_vlans - get number of VLAN 0 filters based on VLAN mode
* @vsi: VSI used to get the VLAN mode
*
* If DVM is enabled then 2 VLAN 0 filters are added, else if SVM is enabled
* then 1 VLAN 0 filter is added. See ice_vsi_add_vlan_zero for more details.
*/
static u16 ice_vsi_num_zero_vlans(struct ice_vsi *vsi)
{
#define ICE_DVM_NUM_ZERO_VLAN_FLTRS 2
#define ICE_SVM_NUM_ZERO_VLAN_FLTRS 1
/* no VLAN 0 filter is created when a port VLAN is active */
if (vsi->type == ICE_VSI_VF &&
ice_vf_is_port_vlan_ena(&vsi->back->vf[vsi->vf_id]))
return 0;
if (ice_is_dvm_ena(&vsi->back->hw))
return ICE_DVM_NUM_ZERO_VLAN_FLTRS;
else
return ICE_SVM_NUM_ZERO_VLAN_FLTRS;
}
/**
* ice_vsi_has_non_zero_vlans - check if VSI has any non-zero VLANs
* @vsi: VSI used to determine if any non-zero VLANs have been added
*/
bool ice_vsi_has_non_zero_vlans(struct ice_vsi *vsi)
{
return (vsi->num_vlan > ice_vsi_num_zero_vlans(vsi));
}
/**
* ice_vsi_num_non_zero_vlans - get the number of non-zero VLANs for this VSI
* @vsi: VSI used to get the number of non-zero VLANs added
*/
u16 ice_vsi_num_non_zero_vlans(struct ice_vsi *vsi)
{
return (vsi->num_vlan - ice_vsi_num_zero_vlans(vsi));
}
/**
......
......@@ -123,6 +123,9 @@ void ice_vsi_ctx_set_allow_override(struct ice_vsi_ctx *ctx);
void ice_vsi_ctx_clear_allow_override(struct ice_vsi_ctx *ctx);
int ice_vsi_add_vlan_zero(struct ice_vsi *vsi);
int ice_vsi_del_vlan_zero(struct ice_vsi *vsi);
bool ice_vsi_has_non_zero_vlans(struct ice_vsi *vsi);
u16 ice_vsi_num_non_zero_vlans(struct ice_vsi *vsi);
bool ice_is_feature_supported(struct ice_pf *pf, enum ice_feature f);
void ice_clear_feature_support(struct ice_pf *pf, enum ice_feature f);
void ice_init_feature_support(struct ice_pf *pf);
......
......@@ -21,6 +21,7 @@
#include "ice_trace.h"
#include "ice_eswitch.h"
#include "ice_tc_lib.h"
#include "ice_vsi_vlan_ops.h"
#define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver"
static const char ice_driver_string[] = DRV_SUMMARY;
......@@ -244,7 +245,7 @@ static int ice_set_promisc(struct ice_vsi *vsi, u8 promisc_m)
if (vsi->type != ICE_VSI_PF)
return 0;
if (vsi->num_vlan > 1)
if (ice_vsi_has_non_zero_vlans(vsi))
status = ice_fltr_set_vlan_vsi_promisc(&vsi->back->hw, vsi, promisc_m);
else
status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 0);
......@@ -264,7 +265,7 @@ static int ice_clear_promisc(struct ice_vsi *vsi, u8 promisc_m)
if (vsi->type != ICE_VSI_PF)
return 0;
if (vsi->num_vlan > 1)
if (ice_vsi_has_non_zero_vlans(vsi))
status = ice_fltr_clear_vlan_vsi_promisc(&vsi->back->hw, vsi, promisc_m);
else
status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 0);
......@@ -279,6 +280,7 @@ static int ice_clear_promisc(struct ice_vsi *vsi, u8 promisc_m)
*/
static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
struct device *dev = ice_pf_to_dev(vsi->back);
struct net_device *netdev = vsi->netdev;
bool promisc_forced_on = false;
......@@ -352,7 +354,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
/* check for changes in promiscuous modes */
if (changed_flags & IFF_ALLMULTI) {
if (vsi->current_netdev_flags & IFF_ALLMULTI) {
if (vsi->num_vlan > 1)
if (ice_vsi_has_non_zero_vlans(vsi))
promisc_m = ICE_MCAST_VLAN_PROMISC_BITS;
else
promisc_m = ICE_MCAST_PROMISC_BITS;
......@@ -366,7 +368,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
}
} else {
/* !(vsi->current_netdev_flags & IFF_ALLMULTI) */
if (vsi->num_vlan > 1)
if (ice_vsi_has_non_zero_vlans(vsi))
promisc_m = ICE_MCAST_VLAN_PROMISC_BITS;
else
promisc_m = ICE_MCAST_PROMISC_BITS;
......@@ -396,7 +398,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
goto out_promisc;
}
err = 0;
vsi->vlan_ops.dis_rx_filtering(vsi);
vlan_ops->dis_rx_filtering(vsi);
}
} else {
/* Clear Rx filter to remove traffic from wire */
......@@ -410,7 +412,7 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)
goto out_promisc;
}
if (vsi->num_vlan > 1)
vsi->vlan_ops.ena_rx_filtering(vsi);
vlan_ops->ena_rx_filtering(vsi);
}
}
}
......@@ -3411,6 +3413,7 @@ static int
ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi_vlan_ops *vlan_ops;
struct ice_vsi *vsi = np->vsi;
struct ice_vlan vlan;
int ret;
......@@ -3419,9 +3422,11 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
if (!vid)
return 0;
vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
/* Enable VLAN pruning when a VLAN other than 0 is added */
if (!ice_vsi_is_vlan_pruning_ena(vsi)) {
ret = vsi->vlan_ops.ena_rx_filtering(vsi);
ret = vlan_ops->ena_rx_filtering(vsi);
if (ret)
return ret;
}
......@@ -3430,7 +3435,7 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
* packets aren't pruned by the device's internal switch on Rx
*/
vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);
ret = vsi->vlan_ops.add_vlan(vsi, &vlan);
ret = vlan_ops->add_vlan(vsi, &vlan);
if (!ret)
set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state);
......@@ -3449,6 +3454,7 @@ static int
ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi_vlan_ops *vlan_ops;
struct ice_vsi *vsi = np->vsi;
struct ice_vlan vlan;
int ret;
......@@ -3457,17 +3463,19 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
if (!vid)
return 0;
vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
/* Make sure VLAN delete is successful before updating VLAN
* information
*/
vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);
ret = vsi->vlan_ops.del_vlan(vsi, &vlan);
ret = vlan_ops->del_vlan(vsi, &vlan);
if (ret)
return ret;
/* Disable pruning when VLAN 0 is the only VLAN rule */
if (vsi->num_vlan == 1 && ice_vsi_is_vlan_pruning_ena(vsi))
vsi->vlan_ops.dis_rx_filtering(vsi);
vlan_ops->dis_rx_filtering(vsi);
set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state);
return ret;
......@@ -5579,6 +5587,7 @@ static int
ice_set_features(struct net_device *netdev, netdev_features_t features)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi_vlan_ops *vlan_ops;
struct ice_vsi *vsi = np->vsi;
struct ice_pf *pf = vsi->back;
int ret = 0;
......@@ -5595,6 +5604,8 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
return -EBUSY;
}
vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
/* Multiple features can be changed in one call so keep features in
* separate if/else statements to guarantee each feature is checked
*/
......@@ -5606,24 +5617,24 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
!(netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
ret = vsi->vlan_ops.ena_stripping(vsi, ETH_P_8021Q);
ret = vlan_ops->ena_stripping(vsi, ETH_P_8021Q);
else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) &&
(netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
ret = vsi->vlan_ops.dis_stripping(vsi);
ret = vlan_ops->dis_stripping(vsi);
if ((features & NETIF_F_HW_VLAN_CTAG_TX) &&
!(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
ret = vsi->vlan_ops.ena_insertion(vsi, ETH_P_8021Q);
ret = vlan_ops->ena_insertion(vsi, ETH_P_8021Q);
else if (!(features & NETIF_F_HW_VLAN_CTAG_TX) &&
(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
ret = vsi->vlan_ops.dis_insertion(vsi);
ret = vlan_ops->dis_insertion(vsi);
if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
!(netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
ret = vsi->vlan_ops.ena_rx_filtering(vsi);
ret = vlan_ops->ena_rx_filtering(vsi);
else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) &&
(netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
ret = vsi->vlan_ops.dis_rx_filtering(vsi);
ret = vlan_ops->dis_rx_filtering(vsi);
if ((features & NETIF_F_NTUPLE) &&
!(netdev->features & NETIF_F_NTUPLE)) {
......@@ -5651,19 +5662,21 @@ ice_set_features(struct net_device *netdev, netdev_features_t features)
}
/**
* ice_vsi_vlan_setup - Setup VLAN offload properties on a VSI
* ice_vsi_vlan_setup - Setup VLAN offload properties on a PF VSI
* @vsi: VSI to setup VLAN properties for
*/
static int ice_vsi_vlan_setup(struct ice_vsi *vsi)
{
int ret = 0;
struct ice_vsi_vlan_ops *vlan_ops;
vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
ret = vsi->vlan_ops.ena_stripping(vsi, ETH_P_8021Q);
vlan_ops->ena_stripping(vsi, ETH_P_8021Q);
if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)
ret = vsi->vlan_ops.ena_insertion(vsi, ETH_P_8021Q);
vlan_ops->ena_insertion(vsi, ETH_P_8021Q);
return ret;
return ice_vsi_add_vlan_zero(vsi);
}
/**
......@@ -6264,11 +6277,12 @@ static void ice_napi_disable_all(struct ice_vsi *vsi)
*/
int ice_down(struct ice_vsi *vsi)
{
int i, tx_err, rx_err, link_err = 0;
int i, tx_err, rx_err, link_err = 0, vlan_err = 0;
WARN_ON(!test_bit(ICE_VSI_DOWN, vsi->state));
if (vsi->netdev && vsi->type == ICE_VSI_PF) {
vlan_err = ice_vsi_del_vlan_zero(vsi);
if (!ice_is_e810(&vsi->back->hw))
ice_ptp_link_change(vsi->back, vsi->back->hw.pf_id, false);
netif_carrier_off(vsi->netdev);
......@@ -6310,7 +6324,7 @@ int ice_down(struct ice_vsi *vsi)
ice_for_each_rxq(vsi, i)
ice_clean_rx_ring(vsi->rx_rings[i]);
if (tx_err || rx_err || link_err) {
if (tx_err || rx_err || link_err || vlan_err) {
netdev_err(vsi->netdev, "Failed to close VSI 0x%04X on switch 0x%04X\n",
vsi->vsi_num, vsi->vsw->sw_id);
return -EIO;
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019-2021, Intel Corporation. */
#include "ice_vsi_vlan_ops.h"
#include "ice_vsi_vlan_lib.h"
#include "ice.h"
#include "ice_pf_vsi_vlan_ops.h"
void ice_pf_vsi_init_vlan_ops(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops;
if (ice_is_dvm_ena(&vsi->back->hw)) {
vlan_ops = &vsi->outer_vlan_ops;
vlan_ops->add_vlan = ice_vsi_add_vlan;
vlan_ops->del_vlan = ice_vsi_del_vlan;
vlan_ops->ena_stripping = ice_vsi_ena_outer_stripping;
vlan_ops->dis_stripping = ice_vsi_dis_outer_stripping;
vlan_ops->ena_insertion = ice_vsi_ena_outer_insertion;
vlan_ops->dis_insertion = ice_vsi_dis_outer_insertion;
vlan_ops->ena_rx_filtering = ice_vsi_ena_rx_vlan_filtering;
vlan_ops->dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering;
} else {
vlan_ops = &vsi->inner_vlan_ops;
vlan_ops->add_vlan = ice_vsi_add_vlan;
vlan_ops->del_vlan = ice_vsi_del_vlan;
vlan_ops->ena_stripping = ice_vsi_ena_inner_stripping;
vlan_ops->dis_stripping = ice_vsi_dis_inner_stripping;
vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
vlan_ops->ena_rx_filtering = ice_vsi_ena_rx_vlan_filtering;
vlan_ops->dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering;
}
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2019-2021, Intel Corporation. */
#ifndef _ICE_PF_VSI_VLAN_OPS_H_
#define _ICE_PF_VSI_VLAN_OPS_H_
#include "ice_vsi_vlan_ops.h"
struct ice_vsi;
void ice_pf_vsi_init_vlan_ops(struct ice_vsi *vsi);
#endif /* _ICE_PF_VSI_VLAN_OPS_H_ */
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019-2021, Intel Corporation. */
#include "ice_vsi_vlan_ops.h"
#include "ice_vsi_vlan_lib.h"
#include "ice.h"
#include "ice_vf_vsi_vlan_ops.h"
#include "ice_virtchnl_pf.h"
static int
noop_vlan_arg(struct ice_vsi __always_unused *vsi,
struct ice_vlan __always_unused *vlan)
{
return 0;
}
/**
* ice_vf_vsi_init_vlan_ops - Initialize default VSI VLAN ops for VF VSI
* @vsi: VF's VSI being configured
*/
void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops;
struct ice_pf *pf = vsi->back;
struct ice_vf *vf;
vf = &pf->vf[vsi->vf_id];
if (ice_is_dvm_ena(&pf->hw)) {
vlan_ops = &vsi->outer_vlan_ops;
/* outer VLAN ops regardless of port VLAN config */
vlan_ops->add_vlan = ice_vsi_add_vlan;
vlan_ops->ena_rx_filtering = ice_vsi_ena_rx_vlan_filtering;
vlan_ops->dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering;
vlan_ops->ena_tx_filtering = ice_vsi_ena_tx_vlan_filtering;
vlan_ops->dis_tx_filtering = ice_vsi_dis_tx_vlan_filtering;
if (ice_vf_is_port_vlan_ena(vf)) {
/* setup outer VLAN ops */
vlan_ops->set_port_vlan = ice_vsi_set_outer_port_vlan;
/* setup inner VLAN ops */
vlan_ops = &vsi->inner_vlan_ops;
vlan_ops->add_vlan = noop_vlan_arg;
vlan_ops->del_vlan = noop_vlan_arg;
vlan_ops->ena_stripping = ice_vsi_ena_inner_stripping;
vlan_ops->dis_stripping = ice_vsi_dis_inner_stripping;
vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
}
} else {
vlan_ops = &vsi->inner_vlan_ops;
/* inner VLAN ops regardless of port VLAN config */
vlan_ops->add_vlan = ice_vsi_add_vlan;
vlan_ops->ena_rx_filtering = ice_vsi_ena_rx_vlan_filtering;
vlan_ops->dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering;
vlan_ops->ena_tx_filtering = ice_vsi_ena_tx_vlan_filtering;
vlan_ops->dis_tx_filtering = ice_vsi_dis_tx_vlan_filtering;
if (ice_vf_is_port_vlan_ena(vf)) {
vlan_ops->set_port_vlan = ice_vsi_set_inner_port_vlan;
} else {
vlan_ops->del_vlan = ice_vsi_del_vlan;
vlan_ops->ena_stripping = ice_vsi_ena_inner_stripping;
vlan_ops->dis_stripping = ice_vsi_dis_inner_stripping;
vlan_ops->ena_insertion = ice_vsi_ena_inner_insertion;
vlan_ops->dis_insertion = ice_vsi_dis_inner_insertion;
}
}
}
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2019-2021, Intel Corporation. */
#ifndef _ICE_VF_VSI_VLAN_OPS_H_
#define _ICE_VF_VSI_VLAN_OPS_H_
#include "ice_vsi_vlan_ops.h"
struct ice_vsi;
#ifdef CONFIG_PCI_IOV
void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi);
#else
static inline void ice_vf_vsi_init_vlan_ops(struct ice_vsi *vsi) { }
#endif /* CONFIG_PCI_IOV */
#endif /* _ICE_PF_VSI_VLAN_OPS_H_ */
......@@ -10,6 +10,7 @@
#include "ice_eswitch.h"
#include "ice_virtchnl_allowlist.h"
#include "ice_flex_pipe.h"
#include "ice_vf_vsi_vlan_ops.h"
#define FIELD_SELECTOR(proto_hdr_field) \
BIT((proto_hdr_field) & PROTO_HDR_FIELD_MASK)
......@@ -761,7 +762,7 @@ static u8 ice_vf_get_port_vlan_prio(struct ice_vf *vf)
return vf->port_vlan_info.prio;
}
static bool ice_vf_is_port_vlan_ena(struct ice_vf *vf)
bool ice_vf_is_port_vlan_ena(struct ice_vf *vf)
{
return (ice_vf_get_port_vlan_id(vf) || ice_vf_get_port_vlan_prio(vf));
}
......@@ -769,26 +770,30 @@ static bool ice_vf_is_port_vlan_ena(struct ice_vf *vf)
/**
* ice_vf_rebuild_host_vlan_cfg - add VLAN 0 filter or rebuild the Port VLAN
* @vf: VF to add MAC filters for
* @vsi: Pointer to VSI
*
* Called after a VF VSI has been re-added/rebuilt during reset. The PF driver
* always re-adds either a VLAN 0 or port VLAN based filter after reset.
*/
static int ice_vf_rebuild_host_vlan_cfg(struct ice_vf *vf)
static int ice_vf_rebuild_host_vlan_cfg(struct ice_vf *vf, struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
struct device *dev = ice_pf_to_dev(vf->pf);
struct ice_vsi *vsi = ice_get_vf_vsi(vf);
int err;
if (ice_vf_is_port_vlan_ena(vf)) {
err = vsi->vlan_ops.set_port_vlan(vsi, &vf->port_vlan_info);
err = vlan_ops->set_port_vlan(vsi, &vf->port_vlan_info);
if (err) {
dev_err(dev, "failed to configure port VLAN via VSI parameters for VF %u, error %d\n",
vf->vf_id, err);
return err;
}
err = vlan_ops->add_vlan(vsi, &vf->port_vlan_info);
} else {
err = ice_vsi_add_vlan_zero(vsi);
}
err = vsi->vlan_ops.add_vlan(vsi, &vf->port_vlan_info);
if (err) {
dev_err(dev, "failed to add VLAN %u filter for VF %u during VF rebuild, error %d\n",
ice_vf_is_port_vlan_ena(vf) ?
......@@ -834,9 +839,12 @@ static int ice_cfg_mac_antispoof(struct ice_vsi *vsi, bool enable)
*/
static int ice_vsi_ena_spoofchk(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops;
int err;
err = vsi->vlan_ops.ena_tx_filtering(vsi);
vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
err = vlan_ops->ena_tx_filtering(vsi);
if (err)
return err;
......@@ -849,9 +857,12 @@ static int ice_vsi_ena_spoofchk(struct ice_vsi *vsi)
*/
static int ice_vsi_dis_spoofchk(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops;
int err;
err = vsi->vlan_ops.dis_tx_filtering(vsi);
vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
err = vlan_ops->dis_tx_filtering(vsi);
if (err)
return err;
......@@ -1269,7 +1280,7 @@ ice_vf_set_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m)
if (ice_vf_is_port_vlan_ena(vf))
status = ice_fltr_set_vsi_promisc(hw, vsi->idx, promisc_m,
ice_vf_get_port_vlan_id(vf));
else if (vsi->num_vlan > 1)
else if (ice_vsi_has_non_zero_vlans(vsi))
status = ice_fltr_set_vlan_vsi_promisc(hw, vsi, promisc_m);
else
status = ice_fltr_set_vsi_promisc(hw, vsi->idx, promisc_m, 0);
......@@ -1292,7 +1303,7 @@ ice_vf_clear_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m)
if (ice_vf_is_port_vlan_ena(vf))
status = ice_fltr_clear_vsi_promisc(hw, vsi->idx, promisc_m,
ice_vf_get_port_vlan_id(vf));
else if (vsi->num_vlan > 1)
else if (ice_vsi_has_non_zero_vlans(vsi))
status = ice_fltr_clear_vlan_vsi_promisc(hw, vsi, promisc_m);
else
status = ice_fltr_clear_vsi_promisc(hw, vsi->idx, promisc_m, 0);
......@@ -1377,7 +1388,7 @@ static void ice_vf_rebuild_host_cfg(struct ice_vf *vf)
dev_err(dev, "failed to rebuild default MAC configuration for VF %d\n",
vf->vf_id);
if (ice_vf_rebuild_host_vlan_cfg(vf))
if (ice_vf_rebuild_host_vlan_cfg(vf, vsi))
dev_err(dev, "failed to rebuild VLAN configuration for VF %u\n",
vf->vf_id);
......@@ -3023,6 +3034,7 @@ static int ice_vc_cfg_promiscuous_mode_msg(struct ice_vf *vf, u8 *msg)
bool rm_promisc, alluni = false, allmulti = false;
struct virtchnl_promisc_info *info =
(struct virtchnl_promisc_info *)msg;
struct ice_vsi_vlan_ops *vlan_ops;
int mcast_err = 0, ucast_err = 0;
struct ice_pf *pf = vf->pf;
struct ice_vsi *vsi;
......@@ -3061,16 +3073,15 @@ static int ice_vc_cfg_promiscuous_mode_msg(struct ice_vf *vf, u8 *msg)
rm_promisc = !allmulti && !alluni;
if (vsi->num_vlan || ice_vf_is_port_vlan_ena(vf)) {
if (rm_promisc)
ret = vsi->vlan_ops.ena_rx_filtering(vsi);
else
ret = vsi->vlan_ops.dis_rx_filtering(vsi);
if (ret) {
dev_err(dev, "Failed to configure VLAN pruning in promiscuous mode\n");
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
if (rm_promisc)
ret = vlan_ops->ena_rx_filtering(vsi);
else
ret = vlan_ops->dis_rx_filtering(vsi);
if (ret) {
dev_err(dev, "Failed to configure VLAN pruning in promiscuous mode\n");
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (!test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags)) {
......@@ -3097,7 +3108,8 @@ static int ice_vc_cfg_promiscuous_mode_msg(struct ice_vf *vf, u8 *msg)
} else {
u8 mcast_m, ucast_m;
if (ice_vf_is_port_vlan_ena(vf) || vsi->num_vlan > 1) {
if (ice_vf_is_port_vlan_ena(vf) ||
ice_vsi_has_non_zero_vlans(vsi)) {
mcast_m = ICE_MCAST_VLAN_PROMISC_BITS;
ucast_m = ICE_UCAST_VLAN_PROMISC_BITS;
} else {
......@@ -4164,6 +4176,27 @@ static bool ice_vf_vlan_offload_ena(u32 caps)
return !!(caps & VIRTCHNL_VF_OFFLOAD_VLAN);
}
/**
* ice_vf_has_max_vlans - check if VF already has the max allowed VLAN filters
* @vf: VF to check against
* @vsi: VF's VSI
*
* If the VF is trusted then the VF is allowed to add as many VLANs as it
* wants to, so return false.
*
* When the VF is untrusted compare the number of non-zero VLANs + 1 to the max
* allowed VLANs for an untrusted VF. Return the result of this comparison.
*/
static bool ice_vf_has_max_vlans(struct ice_vf *vf, struct ice_vsi *vsi)
{
if (ice_is_vf_trusted(vf))
return false;
#define ICE_VF_ADDED_VLAN_ZERO_FLTRS 1
return ((ice_vsi_num_non_zero_vlans(vsi) +
ICE_VF_ADDED_VLAN_ZERO_FLTRS) >= ICE_MAX_VLAN_PER_VF);
}
/**
* ice_vc_process_vlan_msg
* @vf: pointer to the VF info
......@@ -4177,6 +4210,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
struct virtchnl_vlan_filter_list *vfl =
(struct virtchnl_vlan_filter_list *)msg;
struct ice_vsi_vlan_ops *vlan_ops;
struct ice_pf *pf = vf->pf;
bool vlan_promisc = false;
struct ice_vsi *vsi;
......@@ -4218,8 +4252,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
goto error_param;
}
if (add_v && !ice_is_vf_trusted(vf) &&
vsi->num_vlan >= ICE_MAX_VLAN_PER_VF) {
if (add_v && ice_vf_has_max_vlans(vf, vsi)) {
dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n",
vf->vf_id);
/* There is no need to let VF know about being not trusted,
......@@ -4238,13 +4271,13 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
test_bit(ICE_FLAG_VF_TRUE_PROMISC_ENA, pf->flags))
vlan_promisc = true;
vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
if (add_v) {
for (i = 0; i < vfl->num_elements; i++) {
u16 vid = vfl->vlan_id[i];
struct ice_vlan vlan;
if (!ice_is_vf_trusted(vf) &&
vsi->num_vlan >= ICE_MAX_VLAN_PER_VF) {
if (ice_vf_has_max_vlans(vf, vsi)) {
dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n",
vf->vf_id);
/* There is no need to let VF know about being
......@@ -4262,7 +4295,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
continue;
vlan = ICE_VLAN(ETH_P_8021Q, vid, 0);
status = vsi->vlan_ops.add_vlan(vsi, &vlan);
status = vsi->inner_vlan_ops.add_vlan(vsi, &vlan);
if (status) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
......@@ -4271,7 +4304,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
/* Enable VLAN pruning when non-zero VLAN is added */
if (!vlan_promisc && vid &&
!ice_vsi_is_vlan_pruning_ena(vsi)) {
status = vsi->vlan_ops.ena_rx_filtering(vsi);
status = vlan_ops->ena_rx_filtering(vsi);
if (status) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
dev_err(dev, "Enable VLAN pruning on VLAN ID: %d failed error-%d\n",
......@@ -4315,16 +4348,16 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v)
continue;
vlan = ICE_VLAN(ETH_P_8021Q, vid, 0);
status = vsi->vlan_ops.del_vlan(vsi, &vlan);
status = vsi->inner_vlan_ops.del_vlan(vsi, &vlan);
if (status) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
/* Disable VLAN pruning when only VLAN 0 is left */
if (vsi->num_vlan == 1 &&
if (!ice_vsi_has_non_zero_vlans(vsi) &&
ice_vsi_is_vlan_pruning_ena(vsi))
status = vsi->vlan_ops.dis_rx_filtering(vsi);
status = vlan_ops->dis_rx_filtering(vsi);
/* Disable Unicast/Multicast VLAN promiscuous mode */
if (vlan_promisc) {
......@@ -4393,7 +4426,7 @@ static int ice_vc_ena_vlan_stripping(struct ice_vf *vf)
}
vsi = ice_get_vf_vsi(vf);
if (vsi->vlan_ops.ena_stripping(vsi, ETH_P_8021Q))
if (vsi->inner_vlan_ops.ena_stripping(vsi, ETH_P_8021Q))
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
error_param:
......@@ -4428,7 +4461,7 @@ static int ice_vc_dis_vlan_stripping(struct ice_vf *vf)
goto error_param;
}
if (vsi->vlan_ops.dis_stripping(vsi))
if (vsi->inner_vlan_ops.dis_stripping(vsi))
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
error_param:
......@@ -4458,9 +4491,9 @@ static int ice_vf_init_vlan_stripping(struct ice_vf *vf)
return 0;
if (ice_vf_vlan_offload_ena(vf->driver_caps))
return vsi->vlan_ops.ena_stripping(vsi, ETH_P_8021Q);
return vsi->inner_vlan_ops.ena_stripping(vsi, ETH_P_8021Q);
else
return vsi->vlan_ops.dis_stripping(vsi);
return vsi->inner_vlan_ops.dis_stripping(vsi);
}
static struct ice_vc_vf_ops ice_vc_vf_dflt_ops = {
......
......@@ -211,6 +211,7 @@ 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_vf_is_port_vlan_ena(struct ice_vf *vf);
#else /* CONFIG_PCI_IOV */
static inline void ice_process_vflr_event(struct ice_pf *pf) { }
static inline void ice_free_vfs(struct ice_pf *pf) { }
......@@ -343,5 +344,10 @@ static inline bool ice_is_any_vf_in_promisc(struct ice_pf __always_unused *pf)
{
return false;
}
static inline bool ice_vf_is_port_vlan_ena(struct ice_vf __always_unused *vf)
{
return false;
}
#endif /* CONFIG_PCI_IOV */
#endif /* _ICE_VIRTCHNL_PF_H_ */
......@@ -23,4 +23,10 @@ int ice_vsi_dis_rx_vlan_filtering(struct ice_vsi *vsi);
int ice_vsi_ena_tx_vlan_filtering(struct ice_vsi *vsi);
int ice_vsi_dis_tx_vlan_filtering(struct ice_vsi *vsi);
int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid);
int ice_vsi_dis_outer_stripping(struct ice_vsi *vsi);
int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid);
int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi);
int ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan);
#endif /* _ICE_VSI_VLAN_LIB_H_ */
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2019-2021, Intel Corporation. */
#include "ice_vsi_vlan_ops.h"
#include "ice_pf_vsi_vlan_ops.h"
#include "ice_vf_vsi_vlan_ops.h"
#include "ice_lib.h"
#include "ice.h"
static int
op_unsupported_vlan_arg(struct ice_vsi * __always_unused vsi,
struct ice_vlan * __always_unused vlan)
{
return -EOPNOTSUPP;
}
static int
op_unsupported_tpid_arg(struct ice_vsi *__always_unused vsi,
u16 __always_unused tpid)
{
return -EOPNOTSUPP;
}
static int op_unsupported(struct ice_vsi *__always_unused vsi)
{
return -EOPNOTSUPP;
}
/* If any new ops are added to the VSI VLAN ops interface then an unsupported
* implementation should be set here.
*/
static struct ice_vsi_vlan_ops ops_unsupported = {
.add_vlan = op_unsupported_vlan_arg,
.del_vlan = op_unsupported_vlan_arg,
.ena_stripping = op_unsupported_tpid_arg,
.dis_stripping = op_unsupported,
.ena_insertion = op_unsupported_tpid_arg,
.dis_insertion = op_unsupported,
.ena_rx_filtering = op_unsupported,
.dis_rx_filtering = op_unsupported,
.ena_tx_filtering = op_unsupported,
.dis_tx_filtering = op_unsupported,
.set_port_vlan = op_unsupported_vlan_arg,
};
/**
* ice_vsi_init_unsupported_vlan_ops - init all VSI VLAN ops to unsupported
* @vsi: VSI to initialize VSI VLAN ops to unsupported for
*
* By default all inner and outer VSI VLAN ops return -EOPNOTSUPP. This was done
* as oppsed to leaving the ops null to prevent unexpected crashes. Instead if
* an unsupported VSI VLAN op is called it will just return -EOPNOTSUPP.
*
*/
static void ice_vsi_init_unsupported_vlan_ops(struct ice_vsi *vsi)
{
vsi->outer_vlan_ops = ops_unsupported;
vsi->inner_vlan_ops = ops_unsupported;
}
/**
* ice_vsi_init_vlan_ops - initialize type specific VSI VLAN ops
* @vsi: VSI to initialize ops for
*
* If any VSI types are added and/or require different ops than the PF or VF VSI
* then they will have to add a case here to handle that. Also, VSI type
* specific files should be added in the same manner that was done for PF VSI.
*/
void ice_vsi_init_vlan_ops(struct ice_vsi *vsi)
{
vsi->vlan_ops.add_vlan = ice_vsi_add_vlan;
vsi->vlan_ops.del_vlan = ice_vsi_del_vlan;
vsi->vlan_ops.ena_stripping = ice_vsi_ena_inner_stripping;
vsi->vlan_ops.dis_stripping = ice_vsi_dis_inner_stripping;
vsi->vlan_ops.ena_insertion = ice_vsi_ena_inner_insertion;
vsi->vlan_ops.dis_insertion = ice_vsi_dis_inner_insertion;
vsi->vlan_ops.ena_rx_filtering = ice_vsi_ena_rx_vlan_filtering;
vsi->vlan_ops.dis_rx_filtering = ice_vsi_dis_rx_vlan_filtering;
vsi->vlan_ops.ena_tx_filtering = ice_vsi_ena_tx_vlan_filtering;
vsi->vlan_ops.dis_tx_filtering = ice_vsi_dis_tx_vlan_filtering;
vsi->vlan_ops.set_port_vlan = ice_vsi_set_inner_port_vlan;
/* Initialize all VSI types to have unsupported VSI VLAN ops */
ice_vsi_init_unsupported_vlan_ops(vsi);
switch (vsi->type) {
case ICE_VSI_PF:
case ICE_VSI_SWITCHDEV_CTRL:
ice_pf_vsi_init_vlan_ops(vsi);
break;
case ICE_VSI_VF:
ice_vf_vsi_init_vlan_ops(vsi);
break;
default:
dev_dbg(ice_pf_to_dev(vsi->back), "%s does not support VLAN operations\n",
ice_vsi_type_str(vsi->type));
break;
}
}
/**
* ice_get_compat_vsi_vlan_ops - Get VSI VLAN ops based on VLAN mode
* @vsi: VSI used to get the VSI VLAN ops
*
* This function is meant to be used when the caller doesn't know which VLAN ops
* to use (i.e. inner or outer). This allows backward compatibility for VLANs
* since most of the Outer VSI VLAN functins are not supported when
* the device is configured in Single VLAN Mode (SVM).
*/
struct ice_vsi_vlan_ops *ice_get_compat_vsi_vlan_ops(struct ice_vsi *vsi)
{
if (ice_is_dvm_ena(&vsi->back->hw))
return &vsi->outer_vlan_ops;
else
return &vsi->inner_vlan_ops;
}
......@@ -23,6 +23,12 @@ struct ice_vsi_vlan_ops {
int (*set_port_vlan)(struct ice_vsi *vsi, struct ice_vlan *vlan);
};
static inline bool ice_is_dvm_ena(struct ice_hw __always_unused *hw)
{
return false;
}
void ice_vsi_init_vlan_ops(struct ice_vsi *vsi);
struct ice_vsi_vlan_ops *ice_get_compat_vsi_vlan_ops(struct ice_vsi *vsi);
#endif /* _ICE_VSI_VLAN_OPS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment