diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index a02f34d8f0fe..b7974f451e62 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -2125,6 +2125,74 @@ static void teardown_steering(struct mlx5_vdpa_net *ndev) mlx5_destroy_flow_table(ndev->rxft); } +static int mlx5_vdpa_change_mac(struct mlx5_vdpa_net *ndev, + struct mlx5_core_dev *pfmdev, + const u8 *new_mac) +{ + struct mlx5_vdpa_dev *mvdev = &ndev->mvdev; + u8 old_mac[ETH_ALEN]; + + if (is_zero_ether_addr(new_mac)) + return -EINVAL; + + if (!is_zero_ether_addr(ndev->config.mac)) { + if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { + mlx5_vdpa_warn(mvdev, "failed to delete old MAC %pM from MPFS table\n", + ndev->config.mac); + return -EIO; + } + } + + if (mlx5_mpfs_add_mac(pfmdev, (u8 *)new_mac)) { + mlx5_vdpa_warn(mvdev, "failed to insert new MAC %pM into MPFS table\n", + new_mac); + return -EIO; + } + + /* backup the original mac address so that if failed to add the forward rules + * we could restore it + */ + ether_addr_copy(old_mac, ndev->config.mac); + + ether_addr_copy(ndev->config.mac, new_mac); + + /* Need recreate the flow table entry, so that the packet could forward back + */ + mac_vlan_del(ndev, old_mac, 0, false); + + if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) { + mlx5_vdpa_warn(mvdev, "failed to insert forward rules, try to restore\n"); + + /* Although it hardly run here, we still need double check */ + if (is_zero_ether_addr(old_mac)) { + mlx5_vdpa_warn(mvdev, "restore mac failed: Original MAC is zero\n"); + return -EIO; + } + + /* Try to restore original mac address to MFPS table, and try to restore + * the forward rule entry. + */ + if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { + mlx5_vdpa_warn(mvdev, "restore mac failed: delete MAC %pM from MPFS table failed\n", + ndev->config.mac); + } + + if (mlx5_mpfs_add_mac(pfmdev, old_mac)) { + mlx5_vdpa_warn(mvdev, "restore mac failed: insert old MAC %pM into MPFS table failed\n", + old_mac); + } + + ether_addr_copy(ndev->config.mac, old_mac); + + if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) + mlx5_vdpa_warn(mvdev, "restore forward rules failed: insert forward rules failed\n"); + + return -EIO; + } + + return 0; +} + static virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd) { struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); @@ -2132,12 +2200,13 @@ static virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd) virtio_net_ctrl_ack status = VIRTIO_NET_ERR; struct mlx5_core_dev *pfmdev; size_t read; - u8 mac[ETH_ALEN], mac_back[ETH_ALEN]; + u8 mac[ETH_ALEN]; pfmdev = pci_get_drvdata(pci_physfn(mvdev->mdev->pdev)); switch (cmd) { case VIRTIO_NET_CTRL_MAC_ADDR_SET: - read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)mac, ETH_ALEN); + read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, + (void *)mac, ETH_ALEN); if (read != ETH_ALEN) break; @@ -2145,66 +2214,8 @@ static virtio_net_ctrl_ack handle_ctrl_mac(struct mlx5_vdpa_dev *mvdev, u8 cmd) status = VIRTIO_NET_OK; break; } - - if (is_zero_ether_addr(mac)) - break; - - if (!is_zero_ether_addr(ndev->config.mac)) { - if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { - mlx5_vdpa_warn(mvdev, "failed to delete old MAC %pM from MPFS table\n", - ndev->config.mac); - break; - } - } - - if (mlx5_mpfs_add_mac(pfmdev, mac)) { - mlx5_vdpa_warn(mvdev, "failed to insert new MAC %pM into MPFS table\n", - mac); - break; - } - - /* backup the original mac address so that if failed to add the forward rules - * we could restore it - */ - memcpy(mac_back, ndev->config.mac, ETH_ALEN); - - memcpy(ndev->config.mac, mac, ETH_ALEN); - - /* Need recreate the flow table entry, so that the packet could forward back - */ - mac_vlan_del(ndev, mac_back, 0, false); - - if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) { - mlx5_vdpa_warn(mvdev, "failed to insert forward rules, try to restore\n"); - - /* Although it hardly run here, we still need double check */ - if (is_zero_ether_addr(mac_back)) { - mlx5_vdpa_warn(mvdev, "restore mac failed: Original MAC is zero\n"); - break; - } - - /* Try to restore original mac address to MFPS table, and try to restore - * the forward rule entry. - */ - if (mlx5_mpfs_del_mac(pfmdev, ndev->config.mac)) { - mlx5_vdpa_warn(mvdev, "restore mac failed: delete MAC %pM from MPFS table failed\n", - ndev->config.mac); - } - - if (mlx5_mpfs_add_mac(pfmdev, mac_back)) { - mlx5_vdpa_warn(mvdev, "restore mac failed: insert old MAC %pM into MPFS table failed\n", - mac_back); - } - - memcpy(ndev->config.mac, mac_back, ETH_ALEN); - - if (mac_vlan_add(ndev, ndev->config.mac, 0, false)) - mlx5_vdpa_warn(mvdev, "restore forward rules failed: insert forward rules failed\n"); - - break; - } - - status = VIRTIO_NET_OK; + status = mlx5_vdpa_change_mac(ndev, pfmdev, mac) ? VIRTIO_NET_ERR : + VIRTIO_NET_OK; break; default: