info.fltr_act = ICE_FWD_TO_VSI;
info.vsi_handle = vsi->idx;
info.l_data.vlan.vlan_id = vlan->vid;
+ info.l_data.vlan.tpid = vlan->tpid;
+ info.l_data.vlan.tpid_valid = true;
return ice_fltr_add_entry_to_list(ice_pf_to_dev(vsi->back), &info,
list);
{
struct ice_vlan vlan;
- vlan = ICE_VLAN(0, 0);
+ vlan = ICE_VLAN(0, 0, 0);
return vsi->vlan_ops.add_vlan(vsi, &vlan);
}
/**
* ice_vlan_rx_add_vid - Add a VLAN ID filter to HW offload
* @netdev: network interface to be adjusted
- * @proto: unused protocol
+ * @proto: VLAN TPID
* @vid: VLAN ID to be added
*
* net_device_ops implementation for adding VLAN IDs
*/
static int
-ice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto,
- u16 vid)
+ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
/* Add a switch rule for this VLAN ID so its corresponding VLAN tagged
* packets aren't pruned by the device's internal switch on Rx
*/
- vlan = ICE_VLAN(vid, 0);
+ vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);
ret = vsi->vlan_ops.add_vlan(vsi, &vlan);
if (!ret)
set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state);
/**
* ice_vlan_rx_kill_vid - Remove a VLAN ID filter from HW offload
* @netdev: network interface to be adjusted
- * @proto: unused protocol
+ * @proto: VLAN TPID
* @vid: VLAN ID to be removed
*
* net_device_ops implementation for removing VLAN IDs
*/
static int
-ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto,
- u16 vid)
+ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_vsi *vsi = np->vsi;
/* Make sure VLAN delete is successful before updating VLAN
* information
*/
- vlan = ICE_VLAN(vid, 0);
+ vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);
ret = vsi->vlan_ops.del_vlan(vsi, &vlan);
if (ret)
return ret;
if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
!(netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
- ret = vsi->vlan_ops.ena_stripping(vsi);
+ ret = vsi->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);
if ((features & NETIF_F_HW_VLAN_CTAG_TX) &&
!(netdev->features & NETIF_F_HW_VLAN_CTAG_TX))
- ret = vsi->vlan_ops.ena_insertion(vsi);
+ ret = vsi->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);
int ret = 0;
if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
- ret = vsi->vlan_ops.ena_stripping(vsi);
+ ret = vsi->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);
+ ret = vsi->vlan_ops.ena_insertion(vsi, ETH_P_8021Q);
return ret;
}
struct ice_aqc_sw_rules_elem *s_rule, enum ice_adminq_opc opc)
{
u16 vlan_id = ICE_MAX_VLAN_ID + 1;
+ u16 vlan_tpid = ETH_P_8021Q;
void *daddr = NULL;
u16 eth_hdr_sz;
u8 *eth_hdr;
break;
case ICE_SW_LKUP_VLAN:
vlan_id = f_info->l_data.vlan.vlan_id;
+ if (f_info->l_data.vlan.tpid_valid)
+ vlan_tpid = f_info->l_data.vlan.tpid;
if (f_info->fltr_act == ICE_FWD_TO_VSI ||
f_info->fltr_act == ICE_FWD_TO_VSI_LIST) {
act |= ICE_SINGLE_ACT_PRUNE;
if (!(vlan_id > ICE_MAX_VLAN_ID)) {
off = (__force __be16 *)(eth_hdr + ICE_ETH_VLAN_TCI_OFFSET);
*off = cpu_to_be16(vlan_id);
+ off = (__force __be16 *)(eth_hdr + ICE_ETH_ETHTYPE_OFFSET);
+ *off = cpu_to_be16(vlan_tpid);
}
/* Create the switch rule with the final dummy Ethernet header */
} mac_vlan;
struct {
u16 vlan_id;
+ u16 tpid;
+ u8 tpid_valid;
} vlan;
/* Set lkup_type as ICE_SW_LKUP_ETHERTYPE
* if just using ethertype as filter. Set lkup_type as
mutex_lock(&vf->cfg_lock);
- vf->port_vlan_info = ICE_VLAN(vlan_id, qos);
+ vf->port_vlan_info = ICE_VLAN(ETH_P_8021Q, vlan_id, qos);
if (ice_vf_is_port_vlan_ena(vf))
dev_info(dev, "Setting VLAN %u, QoS %u on VF %d\n",
vlan_id, qos, vf_id);
if (!vid)
continue;
- vlan = ICE_VLAN(vid, 0);
+ vlan = ICE_VLAN(ETH_P_8021Q, vid, 0);
status = vsi->vlan_ops.add_vlan(vsi, &vlan);
if (status) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
if (!vid)
continue;
- vlan = ICE_VLAN(vid, 0);
+ vlan = ICE_VLAN(ETH_P_8021Q, vid, 0);
status = vsi->vlan_ops.del_vlan(vsi, &vlan);
if (status) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
}
vsi = ice_get_vf_vsi(vf);
- if (vsi->vlan_ops.ena_stripping(vsi))
+ if (vsi->vlan_ops.ena_stripping(vsi, ETH_P_8021Q))
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
error_param:
return 0;
if (ice_vf_vlan_offload_ena(vf->driver_caps))
- return vsi->vlan_ops.ena_stripping(vsi);
+ return vsi->vlan_ops.ena_stripping(vsi, ETH_P_8021Q);
else
return vsi->vlan_ops.dis_stripping(vsi);
}
struct ice_time_mac legacy_last_added_umac;
DECLARE_BITMAP(txq_ena, ICE_MAX_RSS_QS_PER_VF);
DECLARE_BITMAP(rxq_ena, ICE_MAX_RSS_QS_PER_VF);
- struct ice_vlan port_vlan_info; /* Port VLAN ID and QoS */
+ struct ice_vlan port_vlan_info; /* Port VLAN ID, QoS, and TPID */
u8 pf_set_mac:1; /* VF MAC address set by VMM admin */
u8 trusted:1;
u8 spoofchk:1;
#include "ice_type.h"
struct ice_vlan {
+ u16 tpid;
u16 vid;
u8 prio;
};
-#define ICE_VLAN(vid, prio) ((struct ice_vlan){ vid, prio })
+#define ICE_VLAN(tpid, vid, prio) ((struct ice_vlan){ tpid, vid, prio })
#endif /* _ICE_VLAN_H_ */
#include "ice_fltr.h"
#include "ice.h"
+static void print_invalid_tpid(struct ice_vsi *vsi, u16 tpid)
+{
+ dev_err(ice_pf_to_dev(vsi->back), "%s %d specified invalid VLAN tpid 0x%04x\n",
+ ice_vsi_type_str(vsi->type), vsi->idx, tpid);
+}
+
+/**
+ * validate_vlan - check if the ice_vlan passed in is valid
+ * @vsi: VSI used for printing error message
+ * @vlan: ice_vlan structure to validate
+ *
+ * Return true if the VLAN TPID is valid or if the VLAN TPID is 0 and the VLAN
+ * VID is 0, which allows for non-zero VLAN filters with the specified VLAN TPID
+ * and untagged VLAN 0 filters to be added to the prune list respectively.
+ */
+static bool validate_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
+{
+ if (vlan->tpid != ETH_P_8021Q && (vlan->tpid || vlan->vid)) {
+ print_invalid_tpid(vsi, vlan->tpid);
+ return false;
+ }
+
+ return true;
+}
+
/**
* ice_vsi_add_vlan - default add VLAN implementation for all VSI types
* @vsi: VSI being configured
{
int err = 0;
+ if (!validate_vlan(vsi, vlan))
+ return -EINVAL;
+
if (!ice_fltr_add_vlan(vsi, vlan)) {
vsi->num_vlan++;
} else {
struct device *dev;
int err;
+ if (!validate_vlan(vsi, vlan))
+ return -EINVAL;
+
dev = ice_pf_to_dev(pf);
err = ice_fltr_remove_vlan(vsi, vlan);
return err;
}
-int ice_vsi_ena_stripping(struct ice_vsi *vsi)
+int ice_vsi_ena_stripping(struct ice_vsi *vsi, const u16 tpid)
{
+ if (tpid != ETH_P_8021Q) {
+ print_invalid_tpid(vsi, tpid);
+ return -EINVAL;
+ }
+
return ice_vsi_manage_vlan_stripping(vsi, true);
}
return ice_vsi_manage_vlan_stripping(vsi, false);
}
-int ice_vsi_ena_insertion(struct ice_vsi *vsi)
+int ice_vsi_ena_insertion(struct ice_vsi *vsi, const u16 tpid)
{
+ if (tpid != ETH_P_8021Q) {
+ print_invalid_tpid(vsi, tpid);
+ return -EINVAL;
+ }
+
return ice_vsi_manage_vlan_insertion(vsi);
}
{
u16 port_vlan_info;
+ if (vlan->tpid != ETH_P_8021Q)
+ return -EINVAL;
+
if (vlan->prio > 7)
return -EINVAL;
int ice_vsi_add_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan);
int ice_vsi_del_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan);
-int ice_vsi_ena_stripping(struct ice_vsi *vsi);
+int ice_vsi_ena_stripping(struct ice_vsi *vsi, u16 tpid);
int ice_vsi_dis_stripping(struct ice_vsi *vsi);
-int ice_vsi_ena_insertion(struct ice_vsi *vsi);
+int ice_vsi_ena_insertion(struct ice_vsi *vsi, u16 tpid);
int ice_vsi_dis_insertion(struct ice_vsi *vsi);
int ice_vsi_set_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan);
struct ice_vsi_vlan_ops {
int (*add_vlan)(struct ice_vsi *vsi, struct ice_vlan *vlan);
int (*del_vlan)(struct ice_vsi *vsi, struct ice_vlan *vlan);
- int (*ena_stripping)(struct ice_vsi *vsi);
+ int (*ena_stripping)(struct ice_vsi *vsi, const u16 tpid);
int (*dis_stripping)(struct ice_vsi *vsi);
- int (*ena_insertion)(struct ice_vsi *vsi);
+ int (*ena_insertion)(struct ice_vsi *vsi, const u16 tpid);
int (*dis_insertion)(struct ice_vsi *vsi);
int (*ena_rx_filtering)(struct ice_vsi *vsi);
int (*dis_rx_filtering)(struct ice_vsi *vsi);