Re: [PATCHv2 2/2] util:veth: Create veth device pair by netlink

2020-12-08 Thread Laine Stump

On 12/8/20 4:19 AM, Daniel P. Berrangé wrote:

On Mon, Dec 07, 2020 at 05:54:51PM -0500, Laine Stump wrote:

On 11/22/20 10:28 PM, Shi Lei wrote:

When netlink is supported, use netlink to create veth device pair
rather than 'ip link' command.

Signed-off-by: Shi Lei 
---
   src/util/virnetdevveth.c | 85 ++--
   1 file changed, 56 insertions(+), 29 deletions(-)

diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c
index b3eee1af..b4074371 100644
--- a/src/util/virnetdevveth.c
+++ b/src/util/virnetdevveth.c
@@ -27,6 +27,7 @@
   #include "virfile.h"
   #include "virstring.h"
   #include "virnetdev.h"
+#include "virnetlink.h"
   #define VIR_FROM_THIS VIR_FROM_NONE
@@ -75,6 +76,55 @@ static int virNetDevVethGetFreeNum(int startDev)
   return -1;
   }
+#if defined(WITH_LIBNL)
+static int
+virNetDevVethCreateInternal(const char *veth1, const char *veth2, int *status)
+{
+virNetlinkNewLinkData data = { .veth_peer = veth2 };
+
+return virNetlinkNewLink(veth1, "veth", , status);
+}


The only thing that makes me uncomfortable in this patch is that the two
versions of virNetDevVethCreateInternal() each return something different
for "status". In this first case, it is returning 0 on success, and -errno
on failure...


Just change this to return -1, as we very rarely want to return -errno
in libvirt, as we have formal error reporting.


I guess I should give a bit more detail here - the "-errno" returned by 
virNetlinkNewLink() isn't the value of errno in the libvirt process at 
the time it learns there was an error - it is the value of errno 
returned in the netlink response message, ie what errno was set to in 
the kernel context that is handling and responding to netlink messages. 
errno in the libvirt process will not be set to this value.


And since the libvirt functions that are decoding the response messages 
don't themselves log any errors, they aren't reporting that exact error...


...

Hmmm. this points out that we really need to be logging the exact error 
in virNetDevVethCreateInternal(), since once we return from that 
function we no longer have full info on the reason for the failure. This 
would have been a problem if we had any inclination to retry the 
operation (with a new device name, which the current code must do), but 
once the other series from Shi is applied (the one that changes veth 
name generation to mimic what is done for tap and macvtap), we won't 
need to worry about retrying, and so it will be acceptable to 
immediately log the error.









[...]



+#else
+static int
+virNetDevVethCreateInternal(const char *veth1, const char *veth2, int *status)
+{
+g_autoptr(virCommand) cmd = virCommandNew("ip");
+virCommandAddArgList(cmd, "link", "add", veth1, "type", "veth",
+ "peer", "name", veth2, NULL);
+
+return virCommandRun(cmd, status);
+}



But in this case it is returning the exit code of the "ip link add" command.


Also in this case if status != NULL then virCommandRun() will only log 
an error if it failed to run the "ip" command; if ip runs but fails to 
create the device and returns an error exit code, virCommandRun() will 
silently return the exit code. In this case, we can just call 
"virCommandRun(cmd, NULL)" - when status is NULL, virCommandRun() will 
log an error if the exec fails, and also if the exec is successful but 
the command returns an error.


And since I'm already here typing - when I reviewed the other series 
(the ones that change the device name generation) I did arrive at the 
opinion that we should apply those patches first, and these patches on 
top of that - that way you won't have to worry about the possibility of 
needing to retry virNetDevVethCreateInternal with a new name, and it 
will be okay for its implementations to immediately log errors.





Re: [PATCHv2 2/2] util:veth: Create veth device pair by netlink

2020-12-08 Thread Daniel P . Berrangé
On Mon, Dec 07, 2020 at 05:54:51PM -0500, Laine Stump wrote:
> On 11/22/20 10:28 PM, Shi Lei wrote:
> > When netlink is supported, use netlink to create veth device pair
> > rather than 'ip link' command.
> > 
> > Signed-off-by: Shi Lei 
> > ---
> >   src/util/virnetdevveth.c | 85 ++--
> >   1 file changed, 56 insertions(+), 29 deletions(-)
> > 
> > diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c
> > index b3eee1af..b4074371 100644
> > --- a/src/util/virnetdevveth.c
> > +++ b/src/util/virnetdevveth.c
> > @@ -27,6 +27,7 @@
> >   #include "virfile.h"
> >   #include "virstring.h"
> >   #include "virnetdev.h"
> > +#include "virnetlink.h"
> >   #define VIR_FROM_THIS VIR_FROM_NONE
> > @@ -75,6 +76,55 @@ static int virNetDevVethGetFreeNum(int startDev)
> >   return -1;
> >   }
> > +#if defined(WITH_LIBNL)
> > +static int
> > +virNetDevVethCreateInternal(const char *veth1, const char *veth2, int 
> > *status)
> > +{
> > +virNetlinkNewLinkData data = { .veth_peer = veth2 };
> > +
> > +return virNetlinkNewLink(veth1, "veth", , status);
> > +}
> 
> The only thing that makes me uncomfortable in this patch is that the two
> versions of virNetDevVethCreateInternal() each return something different
> for "status". In this first case, it is returning 0 on success, and -errno
> on failure...

Just change this to return -1, as we very rarely want to return -errno
in libvirt, as we have formal error reporting.

> 
> 
> > [...]
> 
> > +#else
> > +static int
> > +virNetDevVethCreateInternal(const char *veth1, const char *veth2, int 
> > *status)
> > +{
> > +g_autoptr(virCommand) cmd = virCommandNew("ip");
> > +virCommandAddArgList(cmd, "link", "add", veth1, "type", "veth",
> > + "peer", "name", veth2, NULL);
> > +
> > +return virCommandRun(cmd, status);
> > +}
> 
> 
> But in this case it is returning the exit code of the "ip link add" command.
> 
> 
> It turns out that the value of status is only checked for 0 / not-0, so in
> practice it doesn't matter, but it could lead to confusion in the future.
> 
> 
> If we want these patches to be applied before your "netdevveth: Simplify
> virNetDevVethCreate by using virNetDevGenerateName" patch (which I'll get to
> as soon as I send this mail), then we do still need a way to differentiate
> between "The requested device already exists" and "Permanent Failure", and
> in that case I would suggest that "status" be replaced with a variable
> called "retry" which would be set to true if retrying with a different
> device name might lead to success (it would be set based on an
> interpretation of status made by each of the vir*Internal() functions)
> 
> 
> However, if we decide to apply the *other* patchset first, then we will
> never retry anyway (because we've already checked if the device exists
> before we try to create it, and there is therefore no loop) and so we could
> just eliminate the final argument completely, and keep each vir*Internal()
> function's status internal to itself. (As a matter of fact, status in the
> virCommandRun() version could simply be replaced with NULL in the arglist to
> virCommandRun(), and not defined at all; status in the case of
> virNetlinkNewLink() would still need to be defined and passed into the
> function, but its value would just be ignored).
> 
> 
> I think it may be cleaner to do the latter, and it looks like your other
> series was written to be applied without this series anyway; let me look at
> those patches and I'll reply a 2nd time to this based on the results of
> reviewing the other series...
> 
> 
> BTW, I appreciate your patience - I had looked at these patches nearly two
> weeks ago (soon after you sent them), but then a holiday got in the way, and
> I forgot to post my reply after I returned to work :-/
> 
> 
> > [...]
> > -
> > -if (virCommandRun(cmd, ) < 0)
> > +if (virNetDevVethCreateInternal(*veth1 ? *veth1 : veth1auto,
> > +*veth2 ? *veth2 : veth2auto,
> > +) < 0)
> >   goto cleanup;
> >   if (status == 0) {
> 
> 
> This spot here ^ is the only place that status is examined, and I actually
> think it's not going to work as you'd like in the case of netlink - status
> will always be 0 if virNetDevVethCreateInternal() returns 0, and when the
> return is < 0, status may or may not be set to -errno of the attempted
> operation - if status is 0, that means there was a serious error before even
> trying to create the device (e.g. OOM), and if it is non-0, then it might be
> because a device with the desired name already exists, or it might be
> because we don't have enough privilege to create a new device.
> 
> 
> Anyway, let me look at the other patchset...
> 

Regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-

Re: Re: [PATCHv2 2/2] util:veth: Create veth device pair by netlink

2020-12-07 Thread Shi Lei
Okay. According to your comment, I will deal with another series first.
Then I get rid of that 'status' in this patch and post V3 of it.
Thanks!

Shi Lei

On 2020-12-08 at 06:54, Laine Stump wrote:
>On 11/22/20 10:28 PM, Shi Lei wrote:
>> When netlink is supported, use netlink to create veth device pair
>> rather than 'ip link' command.
>>
>> Signed-off-by: Shi Lei 
>> ---
>>   src/util/virnetdevveth.c | 85 ++--
>>   1 file changed, 56 insertions(+), 29 deletions(-)
>>
>> diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c
>> index b3eee1af..b4074371 100644
>> --- a/src/util/virnetdevveth.c
>> +++ b/src/util/virnetdevveth.c
>> @@ -27,6 +27,7 @@
>>   #include "virfile.h"
>>   #include "virstring.h"
>>   #include "virnetdev.h"
>> +#include "virnetlink.h"
>>  
>>   #define VIR_FROM_THIS VIR_FROM_NONE
>>  
>> @@ -75,6 +76,55 @@ static int virNetDevVethGetFreeNum(int startDev)
>>   return -1;
>>   }
>>  
>> +#if defined(WITH_LIBNL)
>> +static int
>> +virNetDevVethCreateInternal(const char *veth1, const char *veth2, int 
>> *status)
>> +{
>> +    virNetlinkNewLinkData data = { .veth_peer = veth2 };
>> +
>> +    return virNetlinkNewLink(veth1, "veth", , status);
>> +}
>
>The only thing that makes me uncomfortable in this patch is that the two
>versions of virNetDevVethCreateInternal() each return something
>different for "status". In this first case, it is returning 0 on
>success, and -errno on failure...
>
>
>> [...]
>
>> +#else
>> +static int
>> +virNetDevVethCreateInternal(const char *veth1, const char *veth2, int 
>> *status)
>> +{
>> +    g_autoptr(virCommand) cmd = virCommandNew("ip");
>> +    virCommandAddArgList(cmd, "link", "add", veth1, "type", "veth",
>> + "peer", "name", veth2, NULL);
>> +
>> +    return virCommandRun(cmd, status);
>> +}
>
>
>But in this case it is returning the exit code of the "ip link add" command.
>
>
>It turns out that the value of status is only checked for 0 / not-0, so
>in practice it doesn't matter, but it could lead to confusion in the future.
>
>
>If we want these patches to be applied before your "netdevveth: Simplify
>virNetDevVethCreate by using virNetDevGenerateName" patch (which I'll
>get to as soon as I send this mail), then we do still need a way to
>differentiate between "The requested device already exists" and
>"Permanent Failure", and in that case I would suggest that "status" be
>replaced with a variable called "retry" which would be set to true if
>retrying with a different device name might lead to success (it would be
>set based on an interpretation of status made by each of the
>vir*Internal() functions)
>
>
>However, if we decide to apply the *other* patchset first, then we will
>never retry anyway (because we've already checked if the device exists
>before we try to create it, and there is therefore no loop) and so we
>could just eliminate the final argument completely, and keep each
>vir*Internal() function's status internal to itself. (As a matter of
>fact, status in the virCommandRun() version could simply be replaced
>with NULL in the arglist to virCommandRun(), and not defined at all;
>status in the case of virNetlinkNewLink() would still need to be defined
>and passed into the function, but its value would just be ignored).
>
>
>I think it may be cleaner to do the latter, and it looks like your other
>series was written to be applied without this series anyway; let me look
>at those patches and I'll reply a 2nd time to this based on the results
>of reviewing the other series...
>
>
>BTW, I appreciate your patience - I had looked at these patches nearly
>two weeks ago (soon after you sent them), but then a holiday got in the
>way, and I forgot to post my reply after I returned to work :-/
>
>
>> [...]
>> -
>> -    if (virCommandRun(cmd, ) < 0)
>> +    if (virNetDevVethCreateInternal(*veth1 ? *veth1 : veth1auto,
>> +    *veth2 ? *veth2 : veth2auto,
>> +    ) < 0)
>>   goto cleanup;
>>  
>>   if (status == 0) {
>
>
>This spot here ^ is the only place that status is examined, and I
>actually think it's not going to work as you'd like in the case of
>netlink - status will always be 0 if virNetDevVethCreateInternal()
>returns 0, and when the return is < 0, status may or may not be set to
>-errno of the attempted operation - if status is 0, that means there was
>a serious error before even trying to create the device (e.g. OOM), and
>if it is non-0, then it might be because a device with the desired name
>already exists, or it might be because we don't have enough privilege to
>create a new device.
>
>
>Anyway, let me look at the other patchset...
>



Re: [PATCHv2 2/2] util:veth: Create veth device pair by netlink

2020-12-07 Thread Laine Stump

On 11/22/20 10:28 PM, Shi Lei wrote:

When netlink is supported, use netlink to create veth device pair
rather than 'ip link' command.

Signed-off-by: Shi Lei 
---
  src/util/virnetdevveth.c | 85 ++--
  1 file changed, 56 insertions(+), 29 deletions(-)

diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c
index b3eee1af..b4074371 100644
--- a/src/util/virnetdevveth.c
+++ b/src/util/virnetdevveth.c
@@ -27,6 +27,7 @@
  #include "virfile.h"
  #include "virstring.h"
  #include "virnetdev.h"
+#include "virnetlink.h"
  
  #define VIR_FROM_THIS VIR_FROM_NONE
  
@@ -75,6 +76,55 @@ static int virNetDevVethGetFreeNum(int startDev)

  return -1;
  }
  
+#if defined(WITH_LIBNL)

+static int
+virNetDevVethCreateInternal(const char *veth1, const char *veth2, int *status)
+{
+virNetlinkNewLinkData data = { .veth_peer = veth2 };
+
+return virNetlinkNewLink(veth1, "veth", , status);
+}


The only thing that makes me uncomfortable in this patch is that the two 
versions of virNetDevVethCreateInternal() each return something 
different for "status". In this first case, it is returning 0 on 
success, and -errno on failure...




[...]



+#else
+static int
+virNetDevVethCreateInternal(const char *veth1, const char *veth2, int *status)
+{
+g_autoptr(virCommand) cmd = virCommandNew("ip");
+virCommandAddArgList(cmd, "link", "add", veth1, "type", "veth",
+ "peer", "name", veth2, NULL);
+
+return virCommandRun(cmd, status);
+}



But in this case it is returning the exit code of the "ip link add" command.


It turns out that the value of status is only checked for 0 / not-0, so 
in practice it doesn't matter, but it could lead to confusion in the future.



If we want these patches to be applied before your "netdevveth: Simplify 
virNetDevVethCreate by using virNetDevGenerateName" patch (which I'll 
get to as soon as I send this mail), then we do still need a way to 
differentiate between "The requested device already exists" and 
"Permanent Failure", and in that case I would suggest that "status" be 
replaced with a variable called "retry" which would be set to true if 
retrying with a different device name might lead to success (it would be 
set based on an interpretation of status made by each of the 
vir*Internal() functions)



However, if we decide to apply the *other* patchset first, then we will 
never retry anyway (because we've already checked if the device exists 
before we try to create it, and there is therefore no loop) and so we 
could just eliminate the final argument completely, and keep each 
vir*Internal() function's status internal to itself. (As a matter of 
fact, status in the virCommandRun() version could simply be replaced 
with NULL in the arglist to virCommandRun(), and not defined at all; 
status in the case of virNetlinkNewLink() would still need to be defined 
and passed into the function, but its value would just be ignored).



I think it may be cleaner to do the latter, and it looks like your other 
series was written to be applied without this series anyway; let me look 
at those patches and I'll reply a 2nd time to this based on the results 
of reviewing the other series...



BTW, I appreciate your patience - I had looked at these patches nearly 
two weeks ago (soon after you sent them), but then a holiday got in the 
way, and I forgot to post my reply after I returned to work :-/




[...]
-
-if (virCommandRun(cmd, ) < 0)
+if (virNetDevVethCreateInternal(*veth1 ? *veth1 : veth1auto,
+*veth2 ? *veth2 : veth2auto,
+) < 0)
  goto cleanup;
  
  if (status == 0) {



This spot here ^ is the only place that status is examined, and I 
actually think it's not going to work as you'd like in the case of 
netlink - status will always be 0 if virNetDevVethCreateInternal() 
returns 0, and when the return is < 0, status may or may not be set to 
-errno of the attempted operation - if status is 0, that means there was 
a serious error before even trying to create the device (e.g. OOM), and 
if it is non-0, then it might be because a device with the desired name 
already exists, or it might be because we don't have enough privilege to 
create a new device.



Anyway, let me look at the other patchset...