[libvirt] [PATCH 3/3] virDomainNetFindIdx: Ignore auto generated MAC addresses

Michal Privoznik mprivozn at redhat.com
Wed Oct 4 14:57:48 UTC 2017


On 10/04/2017 01:19 PM, Erik Skultety wrote:
> On Mon, Oct 02, 2017 at 01:01:20PM +0200, Michal Privoznik wrote:
>> When detaching an <interface/> from domain, it's MAC address is
>> parsed and if not present one is generated. If, however, no
>> corresponding interface is found in the domain, the following
>> error is reported:
>>
>> error: operation failed: no device matching mac address 52:54:00:75:32:5b found
>>
>> where the MAC address is the auto generated one. This might be
>> very confusing. Solution to this is to ignore auto generated MAC
>> address when looking up the device.
>>
>> Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>> ---
> 
> While I think that a better fix would be to not generate the MAC during the
> parsing stage because it's semantically wrong, I also understand that changing
> that properly wouldn't be possible without a large refactor. Also, I'm not
> experienced enough in the networking code to be so sure that moving the burden
> of generating the MAC to individual drivers rather than doing it in the parser
> is a viable solution for all the drivers. Therefore I agree with this approach,
> it gets the job done, but if someone has a stronger opinion backed by solid
> arguments as for why it should be worth to refactor the whole thing, speak up.
> 
>>  src/conf/domain_conf.c | 45 +++++++++++++++++++++++++++++++++++----------
>>  1 file changed, 35 insertions(+), 10 deletions(-)
>>
>> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
>> index 87192eb2d..aab43d307 100644
>> --- a/src/conf/domain_conf.c
>> +++ b/src/conf/domain_conf.c
>> @@ -15634,11 +15634,17 @@ int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net)
>>      return 0;
>>  }
>>
>> -/* virDomainNetFindIdx: search according to mac address and guest side
>> - *                      PCI address (if specified)
>> +/**
>> + * virDomainNetFindIdx:
>> + * @def: domain definition
>> + * @net: interface definition
>>   *
>> - * Return: index of match if unique match found
>> - *         -1 otherwise and an error is logged
>> + * Lookup domain's network interface based on passed @net
>> + * definition. If @net's MAC address was auto generated,
>> + * the MAC comparison is ignored.
>> + *
>> + * Return: index of match if unique match found,
>> + *         -1 otherwise and an error is logged.
>>   */
>>  int
>>  virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
>> @@ -15646,11 +15652,13 @@ virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
>>      size_t i;
>>      int matchidx = -1;
>>      char mac[VIR_MAC_STRING_BUFLEN];
>> +    bool MACAddrSpecified = !net->mac.generated;
>>      bool PCIAddrSpecified = virDomainDeviceAddressIsValid(&net->info,
>>                                                            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI);
>>
>>      for (i = 0; i < def->nnets; i++) {
>> -        if (virMacAddrCmp(&def->nets[i]->mac, &net->mac))
>> +        if (MACAddrSpecified &&
>> +            virMacAddrCmp(&def->nets[i]->mac, &net->mac) != 0)
>>              continue;
> 
> Code-wise, I would probably enhance this loop in the following manner:
> - move the PCI lookup code above ^this hunk because semantically, PCI match has
>   a precedence over MAC (probably because we allow multiple devices with the
>   same MAC, but there might be other historical reasons for that), so you save
>   some CPU cycles
> 
>>
>>          if ((matchidx >= 0) && !PCIAddrSpecified) {
> 
> - you could then drop the second operand ^here, because PCI would be handled
>   first (and it breaks the loop), so we get here only with MAC lookup
> 
>> @@ -15660,9 +15668,15 @@ virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
>>               * specify only vendor and product ID, and there may be
>>               * multiples of those.
>>               */
>> -            virReportError(VIR_ERR_OPERATION_FAILED,
>> -                           _("multiple devices matching mac address %s found"),
>> -                           virMacAddrFormat(&net->mac, mac));
>> +            if (MACAddrSpecified) {
>> +                virReportError(VIR_ERR_OPERATION_FAILED,
>> +                               _("multiple devices matching mac address %s found"),
>> +                               virMacAddrFormat(&net->mac, mac));
>> +            } else {
>> +                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
>> +                               _("multiple matching devices found"));
>> +            }
>> +
>>              return -1;
>>          }
>>          if (PCIAddrSpecified) {
> - ^this block would be moved for the reasons described above
> 
>> @@ -15679,8 +15693,9 @@ virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
>>              matchidx = i;
> 
> - and ^this assignment could be left unguarded by any if-else statement
> 
> Eventually, a patch preceding yours could be similar to the following (I didn't
> bother rebasing and making the changes, I made them on top of this patch, I'm
> sure you'll get the picture):
> 
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index aab43d307..db0451f45 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -15657,11 +15657,23 @@ virDomainNetFindIdx(virDomainDefPtr def, virDomainNetDefPtr net)
>                                                            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI);
> 
>      for (i = 0; i < def->nnets; i++) {
> +        if (PCIAddrSpecified) {
> +            if (!virPCIDeviceAddressEqual(&def->nets[i]->info.addr.pci,
> +                                          &net->info.addr.pci))
> +                continue;
> +
> +            /* exit early if the pci address was specified and
> +             * it matches, as this guarantees no duplicates.
> +             */
> +            matchidx = i;
> +            break;
> +        }

I don't think this is right. Consider the following scenario. There are
two interfaces in a domain with $mac1, $pci1 and $mac2, $pci2. What
happens if user passes $mac1+$pci2 or vice versa? With my code, we error
out. With this suggestion we match device based on PCI address (even
though MAC address doesn't match). But I agree that we can do better
here, so I'm squashing this in:

diff --git i/src/conf/domain_conf.c w/src/conf/domain_conf.c
index a9523df6a..34993de73 100644
--- i/src/conf/domain_conf.c
+++ w/src/conf/domain_conf.c
@@ -15676,7 +15676,12 @@ virDomainNetFindIdx(virDomainDefPtr def,
virDomainNetDefPtr net)
             virMacAddrCmp(&def->nets[i]->mac, &net->mac) != 0)
             continue;

-        if ((matchidx >= 0) && !PCIAddrSpecified) {
+        if (PCIAddrSpecified &&
+            !virPCIDeviceAddressEqual(&def->nets[i]->info.addr.pci,
+                                      &net->info.addr.pci))
+            continue;
+
+        if (matchidx >= 0) {
             /* there were multiple matches on mac address, and no
              * qualifying guest-side PCI address was given, so we must
              * fail (NB: a USB address isn't adequate, since it may
@@ -15694,19 +15699,8 @@ virDomainNetFindIdx(virDomainDefPtr def,
virDomainNetDefPtr net)

             return -1;
         }
-        if (PCIAddrSpecified) {
-            if (virPCIDeviceAddressEqual(&def->nets[i]->info.addr.pci,
-                                         &net->info.addr.pci)) {
-                /* exit early if the pci address was specified and
-                 * it matches, as this guarantees no duplicates.
-                 */
-                matchidx = i;
-                break;
-            }
-        } else {
-            /* no PCI address given, so there may be multiple matches */
-            matchidx = i;
-        }
+
+        matchidx = i;
     }

     if (matchidx < 0) {


> 
> Anyhow, you have my
> Reviewed-by: Erik Skultety <eskultet at redhat.com> to this patch.
> 

Thanks.

Michal




More information about the libvir-list mailing list