Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-11 Thread Luyao Huang


On 03/10/2015 06:50 PM, John Ferlan wrote:


On 03/10/2015 06:03 AM, lhuang wrote:

<...snip...>


Interesting idea, but you'd be just throwing things away.  I could
perhaps having some code "periodically" cache addresses... or cache
addresses, subscribe to some event to let you know when a new address is
generated so you can add it to your list (if there is one)...

But, how do you use it?

Sorry, i don't know what these words' ("how do you use it ?") mean.


My point was - how does the existing code decide which of the 'n'
addresses found/returned to use as "the" address?


Oh, got it, i don't want to use it for decide use which address in those 
addresses, i just want to move the check and chose in the function which 
call it (virNetDevGetOneIPAddress()). Also if other people need a 
function to get all the address for one interface in the future, then 
virNetDevGetIfaddrsAddress() will help him (although i can not find a 
place need this until now :-( ).



I guess your mean is ask me how to use the code or function you
mentioned, i think maybe
we can avoid to use it :)

However this should be another patch which add a function to get a list
of ip address.


Sure, but would it be just for display purposes only? Once there is more
than one address per dev_name being queried, code that wants to use "an"
address will need to have some decision point in order to "filter" out
addresses known to be bad. Perhaps this is done by type - multicast,
localnet, etc or perhaps by some other lookup mechanism. I'm thinking of
the netinet/in.h macros (search on MULTICAST, LOCAL, LOOPBACK, etc.).

Whatever "filters" are desired, they could be added as an attribute list
of sorts (eg, filter='multicast,local') that way it's up to the consumer
to decide which filters apply knowing what that filter maps to. In the
example you provided ("2001:db8:ca2:2::1/64") - what about that address
made it unusable? That's what needs to be filtered... Doing a google
search on the address ironically points a bz that Laine owns... I'm not
"up" on all the IPv6 addressing rules, so my view is a more high level...


As you said, if we want to get a right address, we need more information 
from the user (address type...), and still need some (or a lot ) patches 
for this. However, I still think it won't work for every scene even we 
add a lot of filters and check, because we cannot know and control 
everything in the different env :)


So as Jan's advise, hooks can be a good choice in the different scene.


John


Luyao

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-10 Thread John Ferlan


On 03/10/2015 06:03 AM, lhuang wrote:

<...snip...>

>> Interesting idea, but you'd be just throwing things away.  I could
>> perhaps having some code "periodically" cache addresses... or cache
>> addresses, subscribe to some event to let you know when a new address is
>> generated so you can add it to your list (if there is one)...
>>
>> But, how do you use it?
> 
> Sorry, i don't know what these words' ("how do you use it ?") mean.
> 

My point was - how does the existing code decide which of the 'n'
addresses found/returned to use as "the" address?

> I guess your mean is ask me how to use the code or function you
> mentioned, i think maybe
> we can avoid to use it :)
> 
> However this should be another patch which add a function to get a list
> of ip address.
> 

Sure, but would it be just for display purposes only? Once there is more
than one address per dev_name being queried, code that wants to use "an"
address will need to have some decision point in order to "filter" out
addresses known to be bad. Perhaps this is done by type - multicast,
localnet, etc or perhaps by some other lookup mechanism. I'm thinking of
the netinet/in.h macros (search on MULTICAST, LOCAL, LOOPBACK, etc.).

Whatever "filters" are desired, they could be added as an attribute list
of sorts (eg, filter='multicast,local') that way it's up to the consumer
to decide which filters apply knowing what that filter maps to. In the
example you provided ("2001:db8:ca2:2::1/64") - what about that address
made it unusable? That's what needs to be filtered... Doing a google
search on the address ironically points a bz that Laine owns... I'm not
"up" on all the IPv6 addressing rules, so my view is a more high level...


John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-10 Thread lhuang


On 03/10/2015 07:50 AM, John Ferlan wrote:


On 03/09/2015 11:37 AM, Luyao Huang wrote:

On 03/09/2015 07:50 AM, John Ferlan wrote:

On 02/28/2015 04:08 AM, Luyao Huang wrote:

Introduce virNetDevGetIfaddrsAddress to help to get interface IPv6
and IPv4 address.

Introduce virNetDevGetIPAddress to use virNetDevGetIfaddrsAddress
and virNetDevGetIPv4Address to get IP address.

Signed-off-by: Luyao Huang 
---
v2: add a new function virNetDevGetIPAddress to call
virNetDevGetIfaddrsAddress
, and make virNetDevGetIfaddrsAddress can get ipv4 address for a
interface.
Also add a error output in virNetDevGetIfaddrsAddress when get
multiple ip
address for a host interface.

   src/libvirt_private.syms |  1 +
   src/util/virnetdev.c | 98

   src/util/virnetdev.h |  4 ++
   3 files changed, 103 insertions(+)


...

+if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 :
AF_INET)) {
+if (++nIPaddr > 1)
+break;

[1]... hmm not sure about this...


+if (want_ipv6) {
+addr->len = sizeof(addr->data.inet6);
+memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len);
+} else {
+addr->len = sizeof(addr->data.inet4);
+memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len);
+}
+addr->data.stor.ss_family = ifa->ifa_addr->sa_family;
+}
+}
+
+if (nIPaddr == 1)
+ret = 0;
+else if (nIPaddr > 1)
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("Interface '%s' has multiple %s address"),

s/address/addresses


+   ifname, want_ipv6 ? "IPv6" : "IPv4");

[1]
But is this really desired... It seems from the previous review, if
someone wants a specific address they use "
I had an idea but my eyes almost close ;)  so i write here without test
them.

I think it will be better if we make this function to get mutli address
and return the number of address we get, like this:

+static int
+virNetDevGetIfaddrsAddress(const char *ifname,
+   bool want_ipv6,
+   virSocketAddrPtr *addrs)

We'd need to have an naddrs to know how many we can stuff in... or you'd
need to do the *REALLOC on the fly in this module for each address found.


Yes, i forgot this and please ignore the code, it has so many mistake 
(so it is not a good idea to write a patch when you want sleep:-( )



Interesting idea, but you'd be just throwing things away.  I could
perhaps having some code "periodically" cache addresses... or cache
addresses, subscribe to some event to let you know when a new address is
generated so you can add it to your list (if there is one)...

But, how do you use it?


Sorry, i don't know what these words' ("how do you use it ?") mean.

I guess your mean is ask me how to use the code or function you 
mentioned, i think maybe

we can avoid to use it :)

However this should be another patch which add a function to get a list 
of ip address.



John


Luyao

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-09 Thread lhuang


On 03/10/2015 07:44 AM, John Ferlan wrote:


On 03/09/2015 03:35 AM, lhuang wrote:
<...snip...>


I think once you have an address you just return the first one found and
document it that way avoiding this path completely. You could also note
that if you want a specific address use the type='address'


Hmm, yes, I agree it is not a good idea to report error when we get
multiple addresses in this function (In some case, caller just want one
ip address and not care about which one we chose), so remove the check
and error output here is reasonable (maybe we can use a DEBUG or WARNING
here complain about this and set ret to 0).

However this check and error output is a result from last review, i
think maybe we can move them to a right place (should in another patch).
Because we use listen type='network' for migration in the most case, and
if a host interface has multiple address than we always chose the first
one, this will make things worse in some case. An example:

In host A, we have a happy vm which use listen type='network' and use a
spice client to connect to it (listen address is
"fe80::7ae3:b5ff:fec5:189e%enp1s0" and address is get from an interface
via virNetDevGetIfaddrsAddress() ), than we migrate this vm to a another
host B, we found a network have the same name and use a host interface
in host B, we use virNetDevGetIfaddrsAddress() get the first ipv6
address and we get "2001:db8:ca2:2::1/64", unfortunately this address is
not a "good" address (the good one is the second one :-P ) and spice
connection will be broken, and the user will say : "why libvirt chose a
wrong address and broke my connection :-(".

NB: the comment from Laine in this mail:
https://www.redhat.com/archives/libvir-list/2015-February/msg01080.html


Right and as Laine points out:

"... Because it's impossible to do it right, I say we shouldn't even
try; it would be worse for it to work halfway."

Doing it "right" thus requires proper configuration rather than
"premonition" by libvirt.  I think a follow up patch could describe the
migration conundrum where if the plan is to migrate the vm, then the
target node will have to have a "valid" IPv{4|6} address as the first
address; otherwise, the connection will be broken.

Migration is a tricky beast. I recall doing something for a former
project regarding this kind of issue, but I cannot remember the details.
I do remember though our logic filtered out a few address types before
returning what "should" be a usable address. I also recall some sort of
nasty ARP test, but the details were specific to the HP-UX world I used
to live in.


yes, migration part need more patch and more intelligence :)




<...snip...>


+int virNetDevGetIPAddress(const char *ifname,
+  bool want_ipv6,
+  virSocketAddrPtr addr)

same


+{
+int ret;
+
+memset(addr, 0, sizeof(*addr));
+addr->data.stor.ss_family = AF_UNSPEC;
+
+ret = virNetDevGetIfaddrsAddress(ifname, want_ipv6, addr);
+if (ret != -2)
+return ret;
+
+if (!want_ipv6)
+return virNetDevGetIPv4Address(ifname, addr);

Here if we have virNetDevGetIPv4Address() return -2, then we can take
our message above and place it right here while also adjusting the "!
SIOCGIFADDR" to just return -2.


+
+return -1;
+}

NOTE: This does not return -2 in any

should be return -2 (and this only happen when want_ipv6 is true and the
ret is -2)


Hmm... if we return -2, then the caller's caller spits out

"network-based listen not possible, network driver not present"

rather than our message... Which is less than helpful.


right, i forgot this

I still have to process your follow-up email with a patch in it, but my
guess is I'm going to repost the patches I have so that we're on the
same page.


Thanks a lot for your help !


John



Luyao

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-09 Thread John Ferlan


On 03/09/2015 11:37 AM, Luyao Huang wrote:
> 
> On 03/09/2015 07:50 AM, John Ferlan wrote:
>> On 02/28/2015 04:08 AM, Luyao Huang wrote:
>>> Introduce virNetDevGetIfaddrsAddress to help to get interface IPv6
>>> and IPv4 address.
>>>
>>> Introduce virNetDevGetIPAddress to use virNetDevGetIfaddrsAddress
>>> and virNetDevGetIPv4Address to get IP address.
>>>
>>> Signed-off-by: Luyao Huang 
>>> ---
>>> v2: add a new function virNetDevGetIPAddress to call
>>> virNetDevGetIfaddrsAddress
>>> , and make virNetDevGetIfaddrsAddress can get ipv4 address for a
>>> interface.
>>> Also add a error output in virNetDevGetIfaddrsAddress when get
>>> multiple ip
>>> address for a host interface.
>>>
>>>   src/libvirt_private.syms |  1 +
>>>   src/util/virnetdev.c | 98
>>> 
>>>   src/util/virnetdev.h |  4 ++
>>>   3 files changed, 103 insertions(+)
>>>
> ...
>>
>>> +if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 :
>>> AF_INET)) {
>>> +if (++nIPaddr > 1)
>>> +break;
>> [1]... hmm not sure about this...
>>
>>> +if (want_ipv6) {
>>> +addr->len = sizeof(addr->data.inet6);
>>> +memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len);
>>> +} else {
>>> +addr->len = sizeof(addr->data.inet4);
>>> +memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len);
>>> +}
>>> +addr->data.stor.ss_family = ifa->ifa_addr->sa_family;
>>> +}
>>> +}
>>> +
>>> +if (nIPaddr == 1)
>>> +ret = 0;
>>> +else if (nIPaddr > 1)
>>> +virReportError(VIR_ERR_INTERNAL_ERROR,
>>> +   _("Interface '%s' has multiple %s address"),
>> s/address/addresses
>>
>>> +   ifname, want_ipv6 ? "IPv6" : "IPv4");
>> [1]
>> But is this really desired... It seems from the previous review, if
>> someone wants a specific address they use ">
>> Otherwise, they use this function.  Since you'll be returning either an
>> IPv4 or IPv6 address here you'd be causing an error here if the network
>> had more than one IPv4 address defined; whereas, the previous code just
>> returned the "first" from the ioctl(SIOCGIFADDR...).
>>
>> I think once you have an address you just return the first one found and
>> document it that way avoiding this path completely. You could also note
>> that if you want a specific address use the type='address'
>>
>>
> I had an idea but my eyes almost close ;)  so i write here without test
> them.
> 
> I think it will be better if we make this function to get mutli address
> and return the number of address we get, like this:
> 
> +static int
> +virNetDevGetIfaddrsAddress(const char *ifname,
> +   bool want_ipv6,
> +   virSocketAddrPtr *addrs)

We'd need to have an naddrs to know how many we can stuff in... or you'd
need to do the *REALLOC on the fly in this module for each address found.

Interesting idea, but you'd be just throwing things away.  I could
perhaps having some code "periodically" cache addresses... or cache
addresses, subscribe to some event to let you know when a new address is
generated so you can add it to your list (if there is one)...

But, how do you use it?

John

> +{
> +struct ifaddrs *ifap, *ifa;
> +int nIPaddr = 0;
> +
> +if (getifaddrs(&ifap) < 0) {
> +virReportSystemError(errno,
> + _("Could not get interface list for '%s'"),
> + ifname);
> +return -1;
> +}
> +
> +for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
> +virSocketAddrPtr tmpaddr;
> +
> +if (!ifa->ifa_addr ||
> +STRNEQ_NULLABLE(ifa->ifa_name, ifname)) {
> +continue;
> +}
> +
> +if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 :
> AF_INET)) {
> +memset(tmpaddr, 0, sizeof(*tmpaddr));
> +
> +if (!ifa->ifa_addr ||
> +STRNEQ_NULLABLE(ifa->ifa_name, ifname)) {
> +continue;
> +}
> +
> +if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 :
> AF_INET)) {
> +memset(tmpaddr, 0, sizeof(*tmpaddr));
> +
> +if (want_ipv6) {
> +tmpaddr->len = sizeof(tmpaddr->data.inet6);
> +memcpy(&tmpaddr->data.inet6, ifa->ifa_addr, tmpaddr->len);
> +} else {
> +tmpaddr->len = sizeof(tmpaddr->data.inet4);
> +memcpy(&tmpaddr->data.inet4, ifa->ifa_addr, tmpaddr->len);
> +}
> +tmpaddr->data.stor.ss_family = ifa->ifa_addr->sa_family;
> +addrs[nIPaddr++] = tmpaddr;
> +}
> +}
> +if (nIPaddr == 0) {
> +virReportError(VIR_ERR_INTERNAL_ERROR,
> +   _("Interface '%s' not found"),
> +   ifname);
> +return -1;
> +}
> +freeifaddrs(ifap);
> +return nIPaddr;
> +}
> 
>>> +int virN

Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-09 Thread John Ferlan


On 03/09/2015 03:35 AM, lhuang wrote:
> 

<...snip...>

>> I think once you have an address you just return the first one found and
>> document it that way avoiding this path completely. You could also note
>> that if you want a specific address use the type='address'
>>
> 
> Hmm, yes, I agree it is not a good idea to report error when we get
> multiple addresses in this function (In some case, caller just want one
> ip address and not care about which one we chose), so remove the check
> and error output here is reasonable (maybe we can use a DEBUG or WARNING
> here complain about this and set ret to 0).
> 
> However this check and error output is a result from last review, i
> think maybe we can move them to a right place (should in another patch).
> Because we use listen type='network' for migration in the most case, and
> if a host interface has multiple address than we always chose the first
> one, this will make things worse in some case. An example:
> 
> In host A, we have a happy vm which use listen type='network' and use a
> spice client to connect to it (listen address is
> "fe80::7ae3:b5ff:fec5:189e%enp1s0" and address is get from an interface
> via virNetDevGetIfaddrsAddress() ), than we migrate this vm to a another
> host B, we found a network have the same name and use a host interface
> in host B, we use virNetDevGetIfaddrsAddress() get the first ipv6
> address and we get "2001:db8:ca2:2::1/64", unfortunately this address is
> not a "good" address (the good one is the second one :-P ) and spice
> connection will be broken, and the user will say : "why libvirt chose a
> wrong address and broke my connection :-(".
> 
> NB: the comment from Laine in this mail:
> https://www.redhat.com/archives/libvir-list/2015-February/msg01080.html
> 

Right and as Laine points out:

"... Because it's impossible to do it right, I say we shouldn't even
try; it would be worse for it to work halfway."

Doing it "right" thus requires proper configuration rather than
"premonition" by libvirt.  I think a follow up patch could describe the
migration conundrum where if the plan is to migrate the vm, then the
target node will have to have a "valid" IPv{4|6} address as the first
address; otherwise, the connection will be broken.

Migration is a tricky beast. I recall doing something for a former
project regarding this kind of issue, but I cannot remember the details.
I do remember though our logic filtered out a few address types before
returning what "should" be a usable address. I also recall some sort of
nasty ARP test, but the details were specific to the HP-UX world I used
to live in.



<...snip...>

>>> +int virNetDevGetIPAddress(const char *ifname,
>>> +  bool want_ipv6,
>>> +  virSocketAddrPtr addr)
>> same
>>
>>> +{
>>> +int ret;
>>> +
>>> +memset(addr, 0, sizeof(*addr));
>>> +addr->data.stor.ss_family = AF_UNSPEC;
>>> +
>>> +ret = virNetDevGetIfaddrsAddress(ifname, want_ipv6, addr);
>>> +if (ret != -2)
>>> +return ret;
>>> +
>>> +if (!want_ipv6)
>>> +return virNetDevGetIPv4Address(ifname, addr);
>> Here if we have virNetDevGetIPv4Address() return -2, then we can take
>> our message above and place it right here while also adjusting the "!
>> SIOCGIFADDR" to just return -2.
>>
>>> +
>>> +return -1;
>>> +}
>> NOTE: This does not return -2 in any
> 
> should be return -2 (and this only happen when want_ipv6 is true and the
> ret is -2)


Hmm... if we return -2, then the caller's caller spits out

"network-based listen not possible, network driver not present"

rather than our message... Which is less than helpful.

I still have to process your follow-up email with a patch in it, but my
guess is I'm going to repost the patches I have so that we're on the
same page.

John

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list


Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-09 Thread Luyao Huang


On 03/09/2015 07:50 AM, John Ferlan wrote:

On 02/28/2015 04:08 AM, Luyao Huang wrote:

Introduce virNetDevGetIfaddrsAddress to help to get interface IPv6
and IPv4 address.

Introduce virNetDevGetIPAddress to use virNetDevGetIfaddrsAddress
and virNetDevGetIPv4Address to get IP address.

Signed-off-by: Luyao Huang 
---
v2: add a new function virNetDevGetIPAddress to call virNetDevGetIfaddrsAddress
, and make virNetDevGetIfaddrsAddress can get ipv4 address for a interface.
Also add a error output in virNetDevGetIfaddrsAddress when get multiple ip
address for a host interface.

  src/libvirt_private.syms |  1 +
  src/util/virnetdev.c | 98 
  src/util/virnetdev.h |  4 ++
  3 files changed, 103 insertions(+)


...



+if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 : AF_INET)) {
+if (++nIPaddr > 1)
+break;

[1]... hmm not sure about this...


+if (want_ipv6) {
+addr->len = sizeof(addr->data.inet6);
+memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len);
+} else {
+addr->len = sizeof(addr->data.inet4);
+memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len);
+}
+addr->data.stor.ss_family = ifa->ifa_addr->sa_family;
+}
+}
+
+if (nIPaddr == 1)
+ret = 0;
+else if (nIPaddr > 1)
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("Interface '%s' has multiple %s address"),

s/address/addresses


+   ifname, want_ipv6 ? "IPv6" : "IPv4");

[1]
But is this really desired... It seems from the previous review, if
someone wants a specific address they use "I had an idea but my eyes almost close ;)  so i write here without test 
them.


I think it will be better if we make this function to get mutli address 
and return the number of address we get, like this:


+static int
+virNetDevGetIfaddrsAddress(const char *ifname,
+   bool want_ipv6,
+   virSocketAddrPtr *addrs)
+{
+struct ifaddrs *ifap, *ifa;
+int nIPaddr = 0;
+
+if (getifaddrs(&ifap) < 0) {
+virReportSystemError(errno,
+ _("Could not get interface list for '%s'"),
+ ifname);
+return -1;
+}
+
+for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+virSocketAddrPtr tmpaddr;
+
+if (!ifa->ifa_addr ||
+STRNEQ_NULLABLE(ifa->ifa_name, ifname)) {
+continue;
+}
+
+if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 : AF_INET)) {
+memset(tmpaddr, 0, sizeof(*tmpaddr));
+
+if (!ifa->ifa_addr ||
+STRNEQ_NULLABLE(ifa->ifa_name, ifname)) {
+continue;
+}
+
+if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 : AF_INET)) {
+memset(tmpaddr, 0, sizeof(*tmpaddr));
+
+if (want_ipv6) {
+tmpaddr->len = sizeof(tmpaddr->data.inet6);
+memcpy(&tmpaddr->data.inet6, ifa->ifa_addr, tmpaddr->len);
+} else {
+tmpaddr->len = sizeof(tmpaddr->data.inet4);
+memcpy(&tmpaddr->data.inet4, ifa->ifa_addr, tmpaddr->len);
+}
+tmpaddr->data.stor.ss_family = ifa->ifa_addr->sa_family;
+addrs[nIPaddr++] = tmpaddr;
+}
+}
+if (nIPaddr == 0) {
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("Interface '%s' not found"),
+   ifname);
+return -1;
+}
+freeifaddrs(ifap);
+return nIPaddr;
+}


+int virNetDevGetIPAddress(const char *ifname,
+  bool want_ipv6,
+  virSocketAddrPtr addr)

and then rename this function to virNetDevGetOneIPAddress()

and rework the code like this:

+int virNetDevGetOneIPAddress(const char *ifname,
+ bool want_ipv6,
+ virSocketAddrPtr addr)
+{
+int ret;
+virSocketAddrPtr *addrs = NULL;
+
+ret = virNetDevGetIfaddrsAddress(ifname, want_ipv6, addrs);
+if (ret > 0) {
+addr = addrs[0];
+} else if (ret == -2 && !want_ipv6) {
+return virNetDevGetIPv4Address(ifname, addr);
+}
+
+return ret;
+}

...


These changes require modifying src/network/bridge_driver.c (temporarily
until we add the IPv6 aware code later):

diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 2a61991..7d6e173 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -4608,7 +4608,7 @@ networkGetNetworkAddress(const char *netname, char
**netaddr)
  }

  if (dev_name) {
-if (virNetDevGetIPv4Address(dev_name, &addr) < 0)
+if (virNetDevGetIPAddress(dev_name, false, &addr) < 0)
  goto cleanup;
  addrptr = &addr;
  }



At last, a

Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-09 Thread lhuang


On 03/09/2015 07:50 AM, John Ferlan wrote:

On 02/28/2015 04:08 AM, Luyao Huang wrote:

Introduce virNetDevGetIfaddrsAddress to help to get interface IPv6
and IPv4 address.

Introduce virNetDevGetIPAddress to use virNetDevGetIfaddrsAddress
and virNetDevGetIPv4Address to get IP address.

Signed-off-by: Luyao Huang 
---
v2: add a new function virNetDevGetIPAddress to call virNetDevGetIfaddrsAddress
, and make virNetDevGetIfaddrsAddress can get ipv4 address for a interface.
Also add a error output in virNetDevGetIfaddrsAddress when get multiple ip
address for a host interface.

  src/libvirt_private.syms |  1 +
  src/util/virnetdev.c | 98 
  src/util/virnetdev.h |  4 ++
  3 files changed, 103 insertions(+)


Closer...  But still missing a couple of things, which I can add for
you. I'll make my comments and do the changes locally but not commit
until Mon afternoon (Eastern US) so if Laine wants to comment he can and
of course that you agree with my comments...


Thanks in advance for your help

Going to split this commit into two -

The first commit will just make the virNetDevIPAddress shim, moving the
virNetDevIPv4Address to a static function.

The second commit will add the IPv6 option to virNetDevIPAddress



No problem

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ba05cc6..f88626a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1670,6 +1670,7 @@ virNetDevClearIPAddress;
  virNetDevDelMulti;
  virNetDevExists;
  virNetDevGetIndex;
+virNetDevGetIPAddress;
  virNetDevGetIPv4Address;

We can remove the GetIPv4Address and make it static to virtnetdev.c


Yes

  virNetDevGetLinkInfo;
  virNetDevGetMAC;
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index 2a0eb43..318c3b6 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -33,6 +33,10 @@
  #include "virstring.h"
  #include "virutil.h"
  
+#if defined(HAVE_GETIFADDRS)

+# include 
+#endif
+
  #include 
  #include 
  #include 
@@ -1432,6 +1436,100 @@ int virNetDevGetIPv4Address(const char *ifname 
ATTRIBUTE_UNUSED,
  
  #endif /* ! SIOCGIFADDR */
  
+/**

+ * virNetDevGetIfaddrsAddress:
+ * @ifname: name of the interface whose IP address we want
+ * @want_ipv6: get IPv4 or IPv6 address
+ * @addr: filled with the IP address
+ *
+ * This function gets the IP address for the interface @ifname
+ * and stores it in @addr
+ *
+ * Returns 0 on success, -1 on failure, -2 on unsupported.
+ */
+#if defined(HAVE_GETIFADDRS)
+static int virNetDevGetIfaddrsAddress(const char *ifname,
+  bool want_ipv6,
+  virSocketAddrPtr addr)

Although not a rule - we try to make newer API's as:

static int
fname(param1,
   param2)



oh, i should noticed this

+{
+struct ifaddrs *ifap, *ifa;
+int ret = -1;
+int nIPaddr = 0;
+
+if (getifaddrs(&ifap) < 0) {
+virReportSystemError(errno,
+ _("Could not get interface list for '%s'"),
+ ifname);
+return -1;
+}
+
+for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+if (!ifa->ifa_addr ||
+STRNEQ(ifa->ifa_name, ifname)) {
+continue;
+}

STRNEQ_NULLABLE does the trick...


+if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 : AF_INET)) {
+if (++nIPaddr > 1)
+break;

[1]... hmm not sure about this...


+if (want_ipv6) {
+addr->len = sizeof(addr->data.inet6);
+memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len);
+} else {
+addr->len = sizeof(addr->data.inet4);
+memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len);
+}
+addr->data.stor.ss_family = ifa->ifa_addr->sa_family;
+}
+}
+
+if (nIPaddr == 1)
+ret = 0;
+else if (nIPaddr > 1)
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("Interface '%s' has multiple %s address"),

s/address/addresses


+   ifname, want_ipv6 ? "IPv6" : "IPv4");

[1]
But is this really desired... It seems from the previous review, if
someone wants a specific address they use "

Hmm, yes, I agree it is not a good idea to report error when we get 
multiple addresses in this function (In some case, caller just want one 
ip address and not care about which one we chose), so remove the check 
and error output here is reasonable (maybe we can use a DEBUG or WARNING 
here complain about this and set ret to 0).


However this check and error output is a result from last review, i 
think maybe we can move them to a right place (should in another patch). 
Because we use listen type='network' for migration in the most case, and 
if a host interface has multiple address than we always chose the first 
one, this will make things worse in some case. An example:


In host A, we have a happy vm w

Re: [libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-03-08 Thread John Ferlan

On 02/28/2015 04:08 AM, Luyao Huang wrote:
> Introduce virNetDevGetIfaddrsAddress to help to get interface IPv6
> and IPv4 address.
> 
> Introduce virNetDevGetIPAddress to use virNetDevGetIfaddrsAddress
> and virNetDevGetIPv4Address to get IP address.
> 
> Signed-off-by: Luyao Huang 
> ---
> v2: add a new function virNetDevGetIPAddress to call 
> virNetDevGetIfaddrsAddress
> , and make virNetDevGetIfaddrsAddress can get ipv4 address for a interface.
> Also add a error output in virNetDevGetIfaddrsAddress when get multiple ip
> address for a host interface.
> 
>  src/libvirt_private.syms |  1 +
>  src/util/virnetdev.c | 98 
> 
>  src/util/virnetdev.h |  4 ++
>  3 files changed, 103 insertions(+)
> 

Closer...  But still missing a couple of things, which I can add for
you. I'll make my comments and do the changes locally but not commit
until Mon afternoon (Eastern US) so if Laine wants to comment he can and
of course that you agree with my comments...

Going to split this commit into two -

The first commit will just make the virNetDevIPAddress shim, moving the
virNetDevIPv4Address to a static function.

The second commit will add the IPv6 option to virNetDevIPAddress

> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index ba05cc6..f88626a 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1670,6 +1670,7 @@ virNetDevClearIPAddress;
>  virNetDevDelMulti;
>  virNetDevExists;
>  virNetDevGetIndex;
> +virNetDevGetIPAddress;
>  virNetDevGetIPv4Address;

We can remove the GetIPv4Address and make it static to virtnetdev.c

>  virNetDevGetLinkInfo;
>  virNetDevGetMAC;
> diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
> index 2a0eb43..318c3b6 100644
> --- a/src/util/virnetdev.c
> +++ b/src/util/virnetdev.c
> @@ -33,6 +33,10 @@
>  #include "virstring.h"
>  #include "virutil.h"
>  
> +#if defined(HAVE_GETIFADDRS)
> +# include 
> +#endif
> +
>  #include 
>  #include 
>  #include 
> @@ -1432,6 +1436,100 @@ int virNetDevGetIPv4Address(const char *ifname 
> ATTRIBUTE_UNUSED,
>  
>  #endif /* ! SIOCGIFADDR */
>  
> +/**
> + * virNetDevGetIfaddrsAddress:
> + * @ifname: name of the interface whose IP address we want
> + * @want_ipv6: get IPv4 or IPv6 address
> + * @addr: filled with the IP address
> + *
> + * This function gets the IP address for the interface @ifname
> + * and stores it in @addr
> + *
> + * Returns 0 on success, -1 on failure, -2 on unsupported.
> + */
> +#if defined(HAVE_GETIFADDRS)
> +static int virNetDevGetIfaddrsAddress(const char *ifname,
> +  bool want_ipv6,
> +  virSocketAddrPtr addr)

Although not a rule - we try to make newer API's as:

static int
fname(param1,
  param2)


> +{
> +struct ifaddrs *ifap, *ifa;
> +int ret = -1;
> +int nIPaddr = 0;
> +
> +if (getifaddrs(&ifap) < 0) {
> +virReportSystemError(errno,
> + _("Could not get interface list for '%s'"),
> + ifname);
> +return -1;
> +}
> +
> +for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
> +if (!ifa->ifa_addr ||
> +STRNEQ(ifa->ifa_name, ifname)) {
> +continue;
> +}

STRNEQ_NULLABLE does the trick...

> +if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 : AF_INET)) {
> +if (++nIPaddr > 1)
> +break;

[1]... hmm not sure about this...

> +if (want_ipv6) {
> +addr->len = sizeof(addr->data.inet6);
> +memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len);
> +} else {
> +addr->len = sizeof(addr->data.inet4);
> +memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len);
> +}
> +addr->data.stor.ss_family = ifa->ifa_addr->sa_family;
> +}
> +}
> +
> +if (nIPaddr == 1)
> +ret = 0;
> +else if (nIPaddr > 1)
> +virReportError(VIR_ERR_INTERNAL_ERROR,
> +   _("Interface '%s' has multiple %s address"),

s/address/addresses

> +   ifname, want_ipv6 ? "IPv6" : "IPv4");

[1]
But is this really desired... It seems from the previous review, if
someone wants a specific address they use " +else
> +virReportError(VIR_ERR_INTERNAL_ERROR,
> +   _("Interface '%s' not found"),
> +   ifname);
> +
> +freeifaddrs(ifap);
> +return ret;
> +}
> +
> +#else
> +
> +static int virNetDevGetIfaddrsAddress(const char *ifname ATTRIBUTE_UNUSED,
> +  bool want_ipv6,
> +  virSocketAddrPtr addr ATTRIBUTE_UNUSED)

ditto on function definition

> +{
> +virReportSystemError(ENOSYS,
> + _("Unable to get %s address on this platform"),
> + want_ipv6 ? "IPv6" : "IPv4");

While this see

[libvirt] [PATCHv2 1/4] util: introduce 2 new helpers for get interface IPv6 address

2015-02-28 Thread Luyao Huang
Introduce virNetDevGetIfaddrsAddress to help to get interface IPv6
and IPv4 address.

Introduce virNetDevGetIPAddress to use virNetDevGetIfaddrsAddress
and virNetDevGetIPv4Address to get IP address.

Signed-off-by: Luyao Huang 
---
v2: add a new function virNetDevGetIPAddress to call virNetDevGetIfaddrsAddress
, and make virNetDevGetIfaddrsAddress can get ipv4 address for a interface.
Also add a error output in virNetDevGetIfaddrsAddress when get multiple ip
address for a host interface.

 src/libvirt_private.syms |  1 +
 src/util/virnetdev.c | 98 
 src/util/virnetdev.h |  4 ++
 3 files changed, 103 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ba05cc6..f88626a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1670,6 +1670,7 @@ virNetDevClearIPAddress;
 virNetDevDelMulti;
 virNetDevExists;
 virNetDevGetIndex;
+virNetDevGetIPAddress;
 virNetDevGetIPv4Address;
 virNetDevGetLinkInfo;
 virNetDevGetMAC;
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index 2a0eb43..318c3b6 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -33,6 +33,10 @@
 #include "virstring.h"
 #include "virutil.h"
 
+#if defined(HAVE_GETIFADDRS)
+# include 
+#endif
+
 #include 
 #include 
 #include 
@@ -1432,6 +1436,100 @@ int virNetDevGetIPv4Address(const char *ifname 
ATTRIBUTE_UNUSED,
 
 #endif /* ! SIOCGIFADDR */
 
+/**
+ * virNetDevGetIfaddrsAddress:
+ * @ifname: name of the interface whose IP address we want
+ * @want_ipv6: get IPv4 or IPv6 address
+ * @addr: filled with the IP address
+ *
+ * This function gets the IP address for the interface @ifname
+ * and stores it in @addr
+ *
+ * Returns 0 on success, -1 on failure, -2 on unsupported.
+ */
+#if defined(HAVE_GETIFADDRS)
+static int virNetDevGetIfaddrsAddress(const char *ifname,
+  bool want_ipv6,
+  virSocketAddrPtr addr)
+{
+struct ifaddrs *ifap, *ifa;
+int ret = -1;
+int nIPaddr = 0;
+
+if (getifaddrs(&ifap) < 0) {
+virReportSystemError(errno,
+ _("Could not get interface list for '%s'"),
+ ifname);
+return -1;
+}
+
+for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+if (!ifa->ifa_addr ||
+STRNEQ(ifa->ifa_name, ifname)) {
+continue;
+}
+if (ifa->ifa_addr->sa_family == (want_ipv6 ? AF_INET6 : AF_INET)) {
+if (++nIPaddr > 1)
+break;
+if (want_ipv6) {
+addr->len = sizeof(addr->data.inet6);
+memcpy(&addr->data.inet6, ifa->ifa_addr, addr->len);
+} else {
+addr->len = sizeof(addr->data.inet4);
+memcpy(&addr->data.inet4, ifa->ifa_addr, addr->len);
+}
+addr->data.stor.ss_family = ifa->ifa_addr->sa_family;
+}
+}
+
+if (nIPaddr == 1)
+ret = 0;
+else if (nIPaddr > 1)
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("Interface '%s' has multiple %s address"),
+   ifname, want_ipv6 ? "IPv6" : "IPv4");
+else
+virReportError(VIR_ERR_INTERNAL_ERROR,
+   _("Interface '%s' not found"),
+   ifname);
+
+freeifaddrs(ifap);
+return ret;
+}
+
+#else
+
+static int virNetDevGetIfaddrsAddress(const char *ifname ATTRIBUTE_UNUSED,
+  bool want_ipv6,
+  virSocketAddrPtr addr ATTRIBUTE_UNUSED)
+{
+virReportSystemError(ENOSYS,
+ _("Unable to get %s address on this platform"),
+ want_ipv6 ? "IPv6" : "IPv4");
+return -2;
+}
+
+#endif
+
+
+int virNetDevGetIPAddress(const char *ifname,
+  bool want_ipv6,
+  virSocketAddrPtr addr)
+{
+int ret;
+
+memset(addr, 0, sizeof(*addr));
+addr->data.stor.ss_family = AF_UNSPEC;
+
+ret = virNetDevGetIfaddrsAddress(ifname, want_ipv6, addr);
+if (ret != -2)
+return ret;
+
+if (!want_ipv6)
+return virNetDevGetIPv4Address(ifname, addr);
+
+return -1;
+}
 
 /**
  * virNetDevValidateConfig:
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index de8b480..faf3b2f 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -104,6 +104,10 @@ int virNetDevClearIPAddress(const char *ifname,
 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
 int virNetDevGetIPv4Address(const char *ifname, virSocketAddrPtr addr)
 ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevGetIPAddress(const char *ifname,
+  bool want_ipv6,
+  virSocketAddrPtr addr)
+ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK;
 
 
 int virNetDevSetMAC(const char *ifn