提交 ddd2b025 编写于 作者: S shenhao 提交者: Yang Yingliang

net: hns3: update the device mac address asynchronously

driver inclusion
category: bugfix
bugzilla: NA
CVE: NA

--------------------------------------------

Currently, we change the device address directly in the path
f hns3_set_mac_address(). There is a race with calling
hclge_sync_vport_mac_table(), both them can add/delete mac
address without vport->mac_list_lock protection. This patch
fixes it by only updating mac list, then adding/deleting the
mac address by hclge_sync_vport_mac_table().
Signed-off-by: NJian Shen <shenjian15@huawei.com>
Signed-off-by: Nshenhao <shenhao21@huawei.com>
Reviewed-by: NZhong Zhaohui <zhongzhaohui@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 a9847a07
...@@ -7469,8 +7469,6 @@ int hclge_update_mac_list(struct hclge_vport *vport, ...@@ -7469,8 +7469,6 @@ int hclge_update_mac_list(struct hclge_vport *vport,
list = (mac_type == HCLGE_MAC_ADDR_UC) ? list = (mac_type == HCLGE_MAC_ADDR_UC) ?
&vport->uc_mac_list : &vport->mc_mac_list; &vport->uc_mac_list : &vport->mc_mac_list;
set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state);
spin_lock_bh(&vport->mac_list_lock); spin_lock_bh(&vport->mac_list_lock);
/* if the mac addr is already in the mac list, no need to add a new /* if the mac addr is already in the mac list, no need to add a new
...@@ -7481,6 +7479,7 @@ int hclge_update_mac_list(struct hclge_vport *vport, ...@@ -7481,6 +7479,7 @@ int hclge_update_mac_list(struct hclge_vport *vport,
if (mac_node) { if (mac_node) {
hclge_update_mac_node(mac_node, state); hclge_update_mac_node(mac_node, state);
spin_unlock_bh(&vport->mac_list_lock); spin_unlock_bh(&vport->mac_list_lock);
set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state);
return 0; return 0;
} }
...@@ -7496,6 +7495,8 @@ int hclge_update_mac_list(struct hclge_vport *vport, ...@@ -7496,6 +7495,8 @@ int hclge_update_mac_list(struct hclge_vport *vport,
return -ENOMEM; return -ENOMEM;
} }
set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state);
mac_node->state = state; mac_node->state = state;
ether_addr_copy(mac_node->mac_addr, addr); ether_addr_copy(mac_node->mac_addr, addr);
list_add_tail(&mac_node->node, list); list_add_tail(&mac_node->node, list);
...@@ -8193,45 +8194,47 @@ static void hclge_get_mac_addr(struct hnae3_handle *handle, u8 *p) ...@@ -8193,45 +8194,47 @@ static void hclge_get_mac_addr(struct hnae3_handle *handle, u8 *p)
ether_addr_copy(p, hdev->hw.mac.mac_addr); ether_addr_copy(p, hdev->hw.mac.mac_addr);
} }
/* use new node to replace old node in the list, if old address is still in int hclge_update_mac_node_for_dev_addr(struct hclge_vport *vport,
* mac table, add it to list tail, and try to remove in service task const u8 *old_addr, const u8 *new_addr)
*/
void hclge_replace_mac_node(struct list_head *list, const u8 *old_addr,
const u8 *new_addr, bool keep_old)
{ {
struct hclge_vport_mac_addr_cfg *mac_node, *new_node; struct hclge_vport_mac_addr_cfg *old_node, *new_node;
struct list_head *list = &vport->uc_mac_list;
mac_node = hclge_find_mac_node(list, old_addr); new_node = hclge_find_mac_node(list, new_addr);
if (!mac_node) { if (!new_node) {
new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC);
if (!new_node) if (!new_node)
return; return -ENOMEM;
new_node->state = HCLGE_MAC_ACTIVE; new_node->state = HCLGE_MAC_TO_ADD;
ether_addr_copy(new_node->mac_addr, new_addr); ether_addr_copy(new_node->mac_addr, new_addr);
list_add_tail(&new_node->node, list); list_add(&new_node->node, list);
return; } else {
if (new_node->state == HCLGE_MAC_TO_DEL)
new_node->state = HCLGE_MAC_ACTIVE;
/* make sure the new addr is in the list head, avoid dev
* addr may be not re-added into mac table for the umv space
* limitation after global/imp reset which will clear mac
* table by hardware.
*/
list_move(&new_node->node, list);
} }
mac_node->state = HCLGE_MAC_ACTIVE; if (old_addr && !ether_addr_equal(old_addr, new_addr)) {
ether_addr_copy(mac_node->mac_addr, new_addr); old_node = hclge_find_mac_node(list, old_addr);
if (keep_old) { if (old_node) {
new_node = kzalloc(sizeof(*new_node), GFP_ATOMIC); if (old_node->state == HCLGE_MAC_TO_ADD) {
if (!new_node) list_del(&old_node->node);
return; kfree(old_node);
new_node->state = HCLGE_MAC_TO_DEL; } else {
ether_addr_copy(new_node->mac_addr, old_addr); old_node->state = HCLGE_MAC_TO_DEL;
list_add_tail(&new_node->node, list); }
}
} }
}
void hclge_modify_mac_node_state(struct list_head *list, const u8 *addr, set_bit(HCLGE_VPORT_STATE_MAC_TBL_CHANGE, &vport->state);
enum HCLGE_MAC_NODE_STATE state)
{
struct hclge_vport_mac_addr_cfg *mac_node;
mac_node = hclge_find_mac_node(list, addr); return 0;
if (mac_node)
mac_node->state = state;
} }
static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p, static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p,
...@@ -8240,7 +8243,7 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p, ...@@ -8240,7 +8243,7 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p,
const unsigned char *new_addr = (const unsigned char *)p; const unsigned char *new_addr = (const unsigned char *)p;
struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
bool old_mac_removed = true; unsigned char *old_addr = NULL;
int ret; int ret;
/* mac addr check */ /* mac addr check */
...@@ -8253,63 +8256,33 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p, ...@@ -8253,63 +8256,33 @@ static int hclge_set_mac_addr(struct hnae3_handle *handle, void *p,
return -EINVAL; return -EINVAL;
} }
if ((!is_first || is_kdump_kernel()) && ret = hclge_pause_addr_cfg(hdev, new_addr);
hclge_rm_uc_addr_common(vport, hdev->hw.mac.mac_addr)) {
dev_warn(&hdev->pdev->dev,
"remove old uc mac address fail.\n");
old_mac_removed = false;
}
ret = hclge_add_uc_addr_common(vport, new_addr);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"add uc mac address fail, ret =%d.\n", "Failed to configure mac pause address, ret=%d\n",
ret); ret);
return ret;
if (!is_first) {
ret = hclge_add_uc_addr_common(vport,
hdev->hw.mac.mac_addr);
if (ret) {
old_mac_removed = true;
dev_err(&hdev->pdev->dev,
"restore uc mac address fail.\n");
} else {
old_mac_removed = false;
}
}
/* if old dev addr restore failed, add to the uc mac list,
* and try to restore it in service task
*/
if (old_mac_removed) {
spin_lock_bh(&vport->mac_list_lock);
hclge_modify_mac_node_state(&vport->uc_mac_list,
hdev->hw.mac.mac_addr,
HCLGE_MAC_TO_ADD);
spin_unlock_bh(&vport->mac_list_lock);
}
return -EIO;
} }
/* new dev addr add success, replace the old dev addr in uc mac list. if (!is_first)
* if old dev addr delete fail, keep it in the mac list, and try to del old_addr = hdev->hw.mac.mac_addr;
* it in service task.
*/
spin_lock_bh(&vport->mac_list_lock);
hclge_replace_mac_node(&vport->uc_mac_list, hdev->hw.mac.mac_addr,
new_addr, !old_mac_removed);
spin_unlock_bh(&vport->mac_list_lock);
ret = hclge_pause_addr_cfg(hdev, new_addr); spin_lock_bh(&vport->mac_list_lock);
ret = hclge_update_mac_node_for_dev_addr(vport, old_addr, new_addr);
if (ret) { if (ret) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"configure mac pause address fail, ret =%d.\n", "Failed to change the mac addr:%pM, ret =%d\n",
ret); new_addr, ret);
return -EIO; spin_unlock_bh(&vport->mac_list_lock);
return ret;
} }
/* we must update dev addr with spin lock protect, preventing dev addr
* being removed by set_rx_mode path.
*/
ether_addr_copy(hdev->hw.mac.mac_addr, new_addr); ether_addr_copy(hdev->hw.mac.mac_addr, new_addr);
spin_unlock_bh(&vport->mac_list_lock);
hclge_task_schedule(hdev, 0);
return 0; return 0;
} }
......
...@@ -1018,10 +1018,8 @@ int hclge_update_mac_list(struct hclge_vport *vport, ...@@ -1018,10 +1018,8 @@ int hclge_update_mac_list(struct hclge_vport *vport,
enum HCLGE_MAC_NODE_STATE state, enum HCLGE_MAC_NODE_STATE state,
enum HCLGE_MAC_ADDR_TYPE mac_type, enum HCLGE_MAC_ADDR_TYPE mac_type,
const unsigned char *addr); const unsigned char *addr);
void hclge_replace_mac_node(struct list_head *list, const u8 *old_addr, int hclge_update_mac_node_for_dev_addr(struct hclge_vport *vport,
const u8 *new_addr, bool keep_old); const u8 *old_addr, const u8 *new_addr);
void hclge_modify_mac_node_state(struct list_head *list, const u8 *addr,
enum HCLGE_MAC_NODE_STATE state);
void hclge_rm_vport_all_mac_table(struct hclge_vport *vport, bool is_del_list, void hclge_rm_vport_all_mac_table(struct hclge_vport *vport, bool is_del_list,
enum HCLGE_MAC_ADDR_TYPE mac_type); enum HCLGE_MAC_ADDR_TYPE mac_type);
void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_list); void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_list);
......
...@@ -344,36 +344,6 @@ void hclge_inform_vf_promisc_info(struct hclge_vport *vport) ...@@ -344,36 +344,6 @@ void hclge_inform_vf_promisc_info(struct hclge_vport *vport)
HCLGE_MBX_PUSH_PROMISC_INFO, dest_vfid); HCLGE_MBX_PUSH_PROMISC_INFO, dest_vfid);
} }
static int hclge_modify_vf_mac_addr(struct hclge_vport *vport,
const u8 *old_addr, const u8 *new_addr)
{
bool old_mac_removed = true;
int ret;
ret = hclge_rm_uc_addr_common(vport, old_addr);
if (ret)
old_mac_removed = false;
ret = hclge_add_uc_addr_common(vport, new_addr);
if (ret) {
ret = hclge_add_uc_addr_common(vport, old_addr);
if (ret) {
spin_lock_bh(&vport->mac_list_lock);
hclge_modify_mac_node_state(&vport->uc_mac_list,
old_addr, HCLGE_MAC_TO_ADD);
spin_unlock_bh(&vport->mac_list_lock);
}
return -EIO;
} else {
spin_lock_bh(&vport->mac_list_lock);
hclge_replace_mac_node(&vport->uc_mac_list, old_addr, new_addr,
!old_mac_removed);
spin_unlock_bh(&vport->mac_list_lock);
}
return ret;
}
static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
struct hclge_mbx_vf_to_pf_cmd *mbx_req) struct hclge_mbx_vf_to_pf_cmd *mbx_req)
{ {
...@@ -381,7 +351,7 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, ...@@ -381,7 +351,7 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
const u8 *mac_addr = (const u8 *)(mbx_req->msg.data); const u8 *mac_addr = (const u8 *)(mbx_req->msg.data);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
int status = 0; int status;
if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_MODIFY) { if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_MODIFY) {
const u8 *old_addr = (const u8 *) const u8 *old_addr = (const u8 *)
...@@ -397,25 +367,17 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, ...@@ -397,25 +367,17 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport,
if (!is_valid_ether_addr(mac_addr)) if (!is_valid_ether_addr(mac_addr))
return -EINVAL; return -EINVAL;
if (is_zero_ether_addr(old_addr)) { spin_lock_bh(&vport->mac_list_lock);
status = hclge_add_uc_addr_common(vport, mac_addr); status = hclge_update_mac_node_for_dev_addr(vport, old_addr,
if (!status) mac_addr);
hclge_update_mac_list(vport, HCLGE_MAC_ACTIVE, spin_unlock_bh(&vport->mac_list_lock);
HCLGE_MAC_ADDR_UC, hclge_task_schedule(hdev, 0);
mac_addr);
else
hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD,
HCLGE_MAC_ADDR_UC,
mac_addr);
} else {
hclge_modify_vf_mac_addr(vport, old_addr, mac_addr);
}
} else if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_ADD) { } else if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_ADD) {
hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD, status = hclge_update_mac_list(vport, HCLGE_MAC_TO_ADD,
HCLGE_MAC_ADDR_UC, mac_addr); HCLGE_MAC_ADDR_UC, mac_addr);
} else if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_REMOVE) { } else if (mbx_req->msg.subcode == HCLGE_MBX_MAC_VLAN_UC_REMOVE) {
hclge_update_mac_list(vport, HCLGE_MAC_TO_DEL, status = hclge_update_mac_list(vport, HCLGE_MAC_TO_DEL,
HCLGE_MAC_ADDR_UC, mac_addr); HCLGE_MAC_ADDR_UC, mac_addr);
} else { } else {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"failed to set unicast mac addr, unknown subcode %u\n", "failed to set unicast mac addr, unknown subcode %u\n",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册