提交 fea4e7dc 编写于 作者: S shenjian 提交者: Xie XiuQi

net: hns3: add support for spoof check setting

driver inclusion
category: bugfix
bugzilla: NA
CVE: NA

This patch adds support for spoof check configuration for VFs.
When it is enabled, "spoof checking" is done for both mac address
and VLAN. For each VF, the HW ensures that the source MAC address
(or VLAN) of every outgoing packet exists in the MAC-list (or
VLAN-list) configured for RX filtering for that VF. If not,
the packet is dropped.

Feature or Bugfix:Bugfix
Signed-off-by: Nshenjian (K) <shenjian15@huawei.com>
Reviewed-by: Nlipeng <lipeng321@huawei.com>
Reviewed-by: NYunsheng Lin <linyunsheng@huawei.com>
Reviewed-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 65246909
......@@ -358,6 +358,8 @@ struct hnae3_ae_dev {
* Enable/disable HW GRO
* add_arfs_entry
* Check the 5-tuples of flow, and create flow director rule
* set_vf_spoofchk
* Enable/disable spoof check for specified vf
*/
struct hnae3_ae_ops {
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
......@@ -526,6 +528,8 @@ struct hnae3_ae_ops {
bool (*reset_done)(struct hnae3_handle *handle, bool done);
void (*restore_vlan_table)(struct hnae3_handle *handle);
void (*handle_imp_error)(struct hnae3_handle *handle);
int (*set_vf_spoofchk)(struct hnae3_handle *handle, int vf,
bool enable);
#ifdef CONFIG_HNS3_TEST
int (*send_cmdq)(struct hnae3_handle *handle, void *data, int num);
int (*test_cmdq)(struct hnae3_handle *handle, void *data, int *len);
......
......@@ -1715,6 +1715,19 @@ static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
return ret;
}
static int hns3_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable)
{
struct hnae3_handle *handle = hns3_get_handle(netdev);
if (hns3_nic_resetting(netdev))
return -EBUSY;
if (!handle->ae_algo->ops->set_vf_spoofchk)
return -EOPNOTSUPP;
return handle->ae_algo->ops->set_vf_spoofchk(handle, vf, enable);
}
static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
......@@ -1920,6 +1933,7 @@ struct net_device_ops hns3_nic_netdev_ops = {
.ndo_vlan_rx_add_vid = hns3_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid,
.ndo_set_vf_vlan = hns3_ndo_set_vf_vlan,
.ndo_set_vf_spoofchk = hns3_set_vf_spoofchk,
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = hns3_rx_flow_steer,
#endif
......
......@@ -2849,9 +2849,11 @@ static int hclge_get_vf_config(struct hnae3_handle *handle, int vf,
/* vf start from 1 in vport */
vf += HCLGE_VF_VPORT_START_NUM;
vport = &hdev->vport[vf];
ivf->vf = vf;
ivf->linkstate = hdev->vport[vf].link_state;
ether_addr_copy(ivf->mac, hdev->vport[vf].mac);
ivf->linkstate = vport->link_state;
ivf->spoofchk = vport->spoofchk;
ether_addr_copy(ivf->mac, vport->mac);
return 0;
}
......@@ -7646,6 +7648,7 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid,
bool is_kill, u16 vlan,
__be16 proto)
{
struct hclge_vport *vport = &hdev->vport[vfid];
struct hclge_vlan_filter_vf_cfg_cmd *req0;
struct hclge_vlan_filter_vf_cfg_cmd *req1;
struct hclge_desc desc[2];
......@@ -7654,10 +7657,18 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid,
int ret;
/* if vf vlan table is full, firmware will close vf vlan filter, it
* is unable and unnecessary to add new vlan id to vf vlan filter
* is unable and unnecessary to add new vlan id to vf vlan filter.
* If spoof check is enable, and vf vlan is full, it shouldn't add
* new vlan, because tx packets with these vlan id will be dropped.
*/
if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill)
if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill) {
if (vport->spoofchk) {
dev_err(&hdev->pdev->dev,
"Can't add vlan due to spoof check is on and vf vlan table is full\n");
return -EPERM;
}
return 0;
}
hclge_cmd_setup_basic_desc(&desc[0],
HCLGE_OPC_VLAN_FILTER_VF_CFG, false);
......@@ -9400,6 +9411,95 @@ static void hclge_stats_clear(struct hclge_dev *hdev)
memset(&hdev->hw_stats, 0, sizeof(hdev->hw_stats));
}
static int hclge_set_mac_spoofchk(struct hclge_dev *hdev, int vf, bool enable)
{
return hclge_config_switch_param(hdev, vf, enable,
HCLGE_SWITCH_ANTI_SPOOF_MASK);
}
static int hclge_set_vlan_spoofchk(struct hclge_dev *hdev, int vf, bool enable)
{
return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF,
HCLGE_FILTER_FE_NIC_INGRESS_B,
enable, vf);
}
static int hclge_set_vf_spoofchk_hw(struct hclge_dev *hdev, int vf, bool enable)
{
int ret;
ret = hclge_set_mac_spoofchk(hdev, vf, enable);
if (ret) {
dev_err(&hdev->pdev->dev,
"Set vf %d mac spoof check %s failed, ret=%d\n",
vf, enable ? "on" : "off", ret);
return ret;
}
ret = hclge_set_vlan_spoofchk(hdev, vf, enable);
if (ret)
dev_err(&hdev->pdev->dev,
"Set vf %d vlan spoof check %s failed, ret=%d\n",
vf, enable ? "on" : "off", ret);
return ret;
}
static int hclge_set_vf_spoofchk(struct hnae3_handle *handle, int vf,
bool enable)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
int ret;
if (hdev->pdev->revision == 0x20)
return -EOPNOTSUPP;
if (vf < 0 || vf >= hdev->num_alloc_vfs)
return -EINVAL;
vport = &hdev->vport[vf];
if (vport->spoofchk == enable)
return 0;
if (enable && test_bit(vf, hdev->vf_vlan_full))
dev_warn(&hdev->pdev->dev,
"vf %d vlan table is full, enable spoof check may cause its packet send fail\n",
vf);
else if (enable && hclge_is_umv_space_full(vport))
dev_warn(&hdev->pdev->dev,
"vf %d mac table is full, enable spoof check may cause its packet send fail\n",
vf);
ret = hclge_set_vf_spoofchk_hw(hdev, vf, enable);
if (ret)
return ret;
vport->spoofchk = enable;
return 0;
}
static int hclge_reset_vport_spoofchk(struct hclge_dev *hdev)
{
struct hclge_vport *vport = hdev->vport;
int ret;
int i;
if (hdev->pdev->revision == 0x20)
return 0;
/* resume the vf spoof check state after reset */
for (i = 0; i < hdev->num_alloc_vport; i++) {
ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id,
vport->spoofchk);
if (ret)
return ret;
vport++;
}
return 0;
}
static void hclge_reset_vport_state(struct hclge_dev *hdev)
{
struct hclge_vport *vport = hdev->vport;
......@@ -9509,6 +9609,9 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
}
hclge_reset_vport_state(hdev);
ret = hclge_reset_vport_spoofchk(hdev);
if (ret)
return ret;
dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n",
HCLGE_DRIVER_NAME);
......@@ -10245,6 +10348,7 @@ struct hnae3_ae_ops hclge_ops = {
.handle_imp_error = hclge_handle_imp_error,
.get_vf_config = hclge_get_vf_config,
.set_vf_link_state = hclge_set_vf_link_state,
.set_vf_spoofchk = hclge_set_vf_spoofchk,
};
struct hnae3_ae_algo ae_algo = {
......
......@@ -975,6 +975,8 @@ struct hclge_vport {
u8 mac[ETH_ALEN];
int mps; /* Max packet size */
u32 spoofchk;
struct list_head uc_mac_list; /* Store VF unicast table */
struct list_head mc_mac_list; /* Store VF multicast table */
};
......
......@@ -356,6 +356,9 @@ static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport,
proto = msg_cmd->proto;
status = hclge_set_vlan_filter(handle, cpu_to_be16(proto),
vlan, is_kill);
if (mbx_req->mbx_need_resp)
return hclge_gen_resp_to_vf(vport, mbx_req, status,
NULL, 0);
} else if (msg_cmd->subcode == HCLGE_MBX_VLAN_RX_OFF_CFG) {
struct hnae3_handle *handle = &vport->nic;
bool en = msg_cmd->is_kill ? true : false;
......
......@@ -1239,7 +1239,7 @@ static int hclgevf_set_vlan_filter(struct hnae3_handle *handle,
memcpy(&msg_data[3], &proto, sizeof(proto));
ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN,
HCLGE_MBX_VLAN_FILTER, msg_data,
HCLGEVF_VLAN_MBX_MSG_LEN, false, NULL, 0);
HCLGEVF_VLAN_MBX_MSG_LEN, true, NULL, 0);
/* when remove hw vlan filter failed, record the vlan id,
* and try to remove it from hw later, to be consistence
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册