On Tue, Apr 4, 2017 at 10:16 AM, Duyck, Alexander H
<alexander.h.du...@intel.com> wrote:
>> -----Original Message-----
>> From: Intel-wired-lan [mailto:intel-wired-lan-boun...@lists.osuosl.org] On
>> Behalf Of Corinna Vinschen
>> Sent: Tuesday, April 4, 2017 8:11 AM
>> To: intel-wired-...@lists.osuosl.org
>> Cc: netdev@vger.kernel.org
>> Subject: [Intel-wired-lan] [PATCH] igb: Allow to remove administratively set 
>> MAC
>> on VFs
>>
>>   Before libvirt modifies the MAC address and vlan tag for an SRIOV VF
>>   for use by a virtual machine (either using vfio device assignment or
>>   macvtap passthru mode), it saves the current MAC address and vlan tag
>>   so that it can reset them to their original value when the guest is
>>   done.  Libvirt can't leave the VF MAC set to the value used by the
>>   now-defunct guest since it may be started again later using a
>>   different VF, but it certainly shouldn't just pick any random value,
>>   either. So it saves the state of everything prior to using the VF, and
>>   resets it to that.
>>
>>   The igb driver initializes the MAC addresses of all VFs to
>>   00:00:00:00:00:00, and reports that when asked (via an RTM_GETLINK
>>   netlink message, also visible in the list of VFs in the output of "ip
>>   link show"). But when libvirt attempts to restore the MAC address back
>>   to 00:00:00:00:00:00 (using an RTM_SETLINK netlink message) the kernel
>>   responds with "Invalid argument".
>>
>>   Forbidding a reset back to the original value leaves the VF MAC at the
>>   value set for the now-defunct virtual machine. Especially on a system
>>   with NetworkManager enabled, this has very bad consequences, since
>>   NetworkManager forces all interfacess to be IFF_UP all the time - if
>>   the same virtual machine is restarted using a different VF (or even on
>>   a different host), there will be multiple interfaces watching for
>>   traffic with the same MAC address.
>>
>>   To allow libvirt to revert to the original state, we need a way to
>>   remove the administrative set MAC on a VF, to allow normal host
>>   operation again, and to reset/overwrite the VF MAC via VF netdev.
>>
>>   This patch implements the outlined scenario by allowing to set the
>>   VF MAC to 00:00:00:00:00:00 via RTM_SETLINK on the PF.
>>   igb_ndo_set_vf_mac resets the IGB_VF_FLAG_PF_SET_MAC flag to 0,
>>   so it's possible to reset the VF MAC back to the original value via
>>   the VF netdev.
>>
>>   Note: Recent patches to libvirt allow for a workaround if the NIC
>>   isn't capable of resetting the administrative MAC back to all 0, but
>>   in theory the NIC should allow resetting the MAC in the fisr place.
>
> Minor typo here. I assume you mean "first place".
>
>> Signed-off-by: Corinna Vinschen <vinsc...@redhat.com>
>> ---
>>  drivers/net/ethernet/intel/igb/igb_main.c | 25 ++++++++++++++++++++-----
>>  1 file changed, 20 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/intel/igb/igb_main.c
>> b/drivers/net/ethernet/intel/igb/igb_main.c
>> index 26a821f..e7a61b1 100644
>> --- a/drivers/net/ethernet/intel/igb/igb_main.c
>> +++ b/drivers/net/ethernet/intel/igb/igb_main.c
>> @@ -8125,12 +8125,27 @@ static int igb_set_vf_mac(struct igb_adapter
>> *adapter,  static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, 
>> u8
>> *mac)  {
>>       struct igb_adapter *adapter = netdev_priv(netdev);
>> -     if (!is_valid_ether_addr(mac) || (vf >= adapter->vfs_allocated_count))
>> +
>> +     if (vf >= adapter->vfs_allocated_count)
>> +             return -EINVAL;
>
> I would add an blank line here just for readability.
>
>> +     /* Setting the VF MAC to 0 reverts the IGB_VF_FLAG_PF_SET_MAC
>> +        flag and allows to overwrite the MAC via VF netdev.  This
>> +        is necessary to allow libvirt a way to restore the original
>> +        MAC after unbinding vfio-pci and reloading igbvf after shutting
>> +        down a VM. */
>
> Minor coding style issue here. The "*/" should be on a separate line.
>
>> +     if (is_zero_ether_addr(mac)) {
>> +             adapter->vf_data[vf].flags &= ~IGB_VF_FLAG_PF_SET_MAC;
>> +             dev_info(&adapter->pdev->dev,
>> +                      "remove administratively set MAC on VF %d\n",
>> +                      vf);
>> +     } else if (is_valid_ether_addr (mac)) {
>> +             adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC;
>> +             dev_info(&adapter->pdev->dev, "setting MAC %pM on VF
>> %d\n",
>> +                      mac, vf);
>> +             dev_info(&adapter->pdev->dev,
>> +                      "Reload the VF driver to make this change 
>> effective.");
>> +     } else
>>               return -EINVAL;
>
> Minor coding style issue here. The else should also have "{}" wrapping the 
> statement. Generally if any one of the statements in an if/else series needs 
> the braces they should all have the braces.
>
>> -     adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC;
>> -     dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac,
>> vf);
>> -     dev_info(&adapter->pdev->dev,
>> -              "Reload the VF driver to make this change effective.");
>>       if (test_bit(__IGB_DOWN, &adapter->state)) {
>
> You might need to change this to allow us to clear the VF MAC address while 
> the PF is down without the message. It doesn't add much in this case and 
> allowing us to clear it would make sense.
>
>>               dev_warn(&adapter->pdev->dev,
>>                        "The VF MAC address has been set, but the PF device is
>> not up.\n");

So I just realized there is one other minor issue I just found. In
igb_rar_set_qsel you should probably add a check for
"is_valid_ether_addr(addr)" before you set the E1000_RAH_AV bit. For
the zeroed MAC address it should be cleared so that we aren't
filtering on a MAC address of all 0's for the VF.

- Alex

Reply via email to