i40e: Fix VF driver MAC address configuration
authorGreg Rose <gregory.v.rose@intel.com>
Thu, 28 Nov 2013 06:39:42 +0000 (06:39 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Mon, 6 Jan 2014 10:57:05 +0000 (02:57 -0800)
Fix a problem where the 'ip link show' command would display stale
link address information after the link address was set via the 'ip
link set' command.  In addition, fix problem with the user being
allowed to overwrite the administratively set VF MAC address.

Change-Id: I669ed14e55f2b633ef7b456b713632b08468671c
Signed-off-by: Greg Rose <gregory.v.rose@intel.com>
Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Tested-by: Sibai Li <sibai.li@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h

index a983858c45ce501008e82b4ba5785e78fbca3384..55ec2db71fa1a21f9587772b57cbf9a8582bf26b 100644 (file)
@@ -1330,6 +1330,37 @@ error_param:
                                      (u8 *)&stats, sizeof(stats));
 }
 
+/**
+ * i40e_check_vf_permission
+ * @vf: pointer to the vf info
+ * @macaddr: pointer to the MAC Address being checked
+ *
+ * Check if the VF has permission to add or delete unicast MAC address
+ * filters and return error code -EPERM if not.  Then check if the
+ * address filter requested is broadcast or zero and if so return
+ * an invalid MAC address error code.
+ **/
+static inline int i40e_check_vf_permission(struct i40e_vf *vf, u8 *macaddr)
+{
+       struct i40e_pf *pf = vf->pf;
+       int ret = 0;
+
+       if (is_broadcast_ether_addr(macaddr) ||
+                  is_zero_ether_addr(macaddr)) {
+               dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n", macaddr);
+               ret = I40E_ERR_INVALID_MAC_ADDR;
+       } else if (vf->pf_set_mac && !is_multicast_ether_addr(macaddr)) {
+               /* If the host VMM administrator has set the VF MAC address
+                * administratively via the ndo_set_vf_mac command then deny
+                * permission to the VF to add or delete unicast MAC addresses.
+                */
+               dev_err(&pf->pdev->dev,
+                       "VF attempting to override administratively set MAC address\nPlease reload the VF driver to resume normal operation\n");
+               ret = -EPERM;
+       }
+       return ret;
+}
+
 /**
  * i40e_vc_add_mac_addr_msg
  * @vf: pointer to the vf info
@@ -1345,24 +1376,20 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
        struct i40e_pf *pf = vf->pf;
        struct i40e_vsi *vsi = NULL;
        u16 vsi_id = al->vsi_id;
-       i40e_status aq_ret = 0;
+       i40e_status ret = 0;
        int i;
 
        if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
            !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) ||
            !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-               aq_ret = I40E_ERR_PARAM;
+               ret = I40E_ERR_PARAM;
                goto error_param;
        }
 
        for (i = 0; i < al->num_elements; i++) {
-               if (is_broadcast_ether_addr(al->list[i].addr) ||
-                   is_zero_ether_addr(al->list[i].addr)) {
-                       dev_err(&pf->pdev->dev, "invalid VF MAC addr %pMAC\n",
-                               al->list[i].addr);
-                       aq_ret = I40E_ERR_INVALID_MAC_ADDR;
+               ret = i40e_check_vf_permission(vf, al->list[i].addr);
+               if (ret)
                        goto error_param;
-               }
        }
        vsi = pf->vsi[vsi_id];
 
@@ -1383,7 +1410,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
                if (!f) {
                        dev_err(&pf->pdev->dev,
                                "Unable to add VF MAC filter\n");
-                       aq_ret = I40E_ERR_PARAM;
+                       ret = I40E_ERR_PARAM;
                        goto error_param;
                }
        }
@@ -1395,7 +1422,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 error_param:
        /* send the response to the vf */
        return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
-                                      aq_ret);
+                                      ret);
 }
 
 /**
@@ -1413,15 +1440,21 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
        struct i40e_pf *pf = vf->pf;
        struct i40e_vsi *vsi = NULL;
        u16 vsi_id = al->vsi_id;
-       i40e_status aq_ret = 0;
+       i40e_status ret = 0;
        int i;
 
        if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
            !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) ||
            !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-               aq_ret = I40E_ERR_PARAM;
+               ret = I40E_ERR_PARAM;
                goto error_param;
        }
+
+       for (i = 0; i < al->num_elements; i++) {
+               ret = i40e_check_vf_permission(vf, al->list[i].addr);
+               if (ret)
+                       goto error_param;
+       }
        vsi = pf->vsi[vsi_id];
 
        /* delete addresses from the list */
@@ -1436,7 +1469,7 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
 error_param:
        /* send the response to the vf */
        return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS,
-                                      aq_ret);
+                                      ret);
 }
 
 /**
@@ -1918,6 +1951,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
                goto error_param;
        }
        memcpy(vf->default_lan_addr.addr, mac, ETH_ALEN);
+       vf->pf_set_mac = true;
        dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n");
        ret = 0;
 
index bf3384f0abcb2a64511385cb078ed721e0374c77..8d0f4dd2a25274d64a235348b6783e55ed620180 100644 (file)
@@ -83,6 +83,7 @@ struct i40e_vf {
        struct i40e_virtchnl_ether_addr default_lan_addr;
        struct i40e_virtchnl_ether_addr default_fcoe_addr;
        u16 port_vlan_id;
+       bool pf_set_mac;        /* The VMM admin set the VF MAC address */
 
        /* VSI indices - actual VSI pointers are maintained in the PF structure
         * When assigned, these will be non-zero, because VSI 0 is always