SOLVED: lo0 not in ioctl( SIOCGIFCONF )
Brooks Davis
brooks at freebsd.org
Tue Jul 22 15:18:09 UTC 2008
On Tue, Jul 22, 2008 at 07:16:24AM +0000, Jens Rehsack wrote:
> Brooks Davis wrote:
>> On Mon, Jul 21, 2008 at 10:36:34PM +0000, Jens Rehsack wrote:
>>> Brooks Davis wrote:
>>>> On Mon, Jul 21, 2008 at 09:30:39PM +0000, Jens Rehsack wrote:
>>>>> Brooks Davis wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> maybe this question is better asked in this list ...
>>>>>>>
>>>>>>> I was searching why ports/net/p5-Net-Interface was not working as
>>>>>>> expected and found some reasons. Most of them I can answer by implementing
>>>>>>> some test code as attached, but now I'm wondering why em0 is shown twice
>>>>>>> and lo0 is not included.
>>>>>>> The same situation on another machine ..
>>>>>> The attachment didn't make it through.
>>>>>>
>>>>>> -- Brooks
>>>>> Copy&Paste starts here ...
>>>>> #include <stdio.h>
>>>>> #include <stdlib.h>
>>>>> #include <sys/socket.h>
>>>>> #include <net/if.h>
>>>>> #include <errno.h>
>>>>> #include <strings.h>
>>>>> #include <sys/ioctl.h>
>>>>> #include <ifaddrs.h>
>>>>>
>>>>> #ifndef _SIZEOF_ADDR_IFREQ
>>>>> #define _SIZEOF_ADDR_IFREQ(ifr) \
>>>>> ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
>>>>> (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
>>>>> (ifr).ifr_addr.sa_len) : sizeof(struct ifreq))
>>>>> #endif
>>>>>
>>>>> int
>>>>> main()
>>>>> {
>>>>> struct ifconf ifc;
>>>>> struct ifreq *ifr, *lifr;
>>>>> int fd;
>>>>> unsigned int n;
>>>>>
>>>>> fd = socket( AF_INET, SOCK_STREAM, 0 );
>>>>> bzero(&ifc, sizeof(ifc));
>>>>> n = 3;
>>>>> ifr = calloc( ifc.ifc_len, sizeof(*ifr) );
>>>>> do
>>>>> {
>>>>> n *= 2;
>>>>> ifr = realloc( ifr, sizeof(*ifr) * n );
>>>>> bzero( ifr, sizeof(*ifr) * n );
>>>>> ifc.ifc_req = ifr;
>>>>> ifc.ifc_len = n * sizeof(*ifr);
>>>>> } while( ( ioctl( fd, SIOCGIFCONF, &ifc ) == -1 ) || (
>>>>> ifc.ifc_len == n * sizeof(*ifr)) );
>>>> There are several problems with this loop. First, icoctl won't return
>>>> an error in the overflow case because that's not how SIOCGIFCONF works.
>>>> SIOCGIFCONF is badly designed in a number of ways, but that's how it
>>>> is. Second, checking that the array is completely full isn't at all
>>>> reliable because what is returned is actually ifreq structures which
>>>> might or might not vary in length as they contain addresses. Thus you
>>>> need <=. Third, you should start by allocating a significant amount of
>>>> space. Yes, your algorithm is O(sqrt(n)), but allocating a larger
>>>> value has effectively no cost so you might as well save some system calls
>>>> on average.
>>> Thanks - that was the information I miss. I'll try tomorrow (it's
>>> slightly late here) and send back the result.
>>> Using <= should produce an endless loop, but maybe checking if
>>> ifc.ifc_len <= (n/2) * sizeof(*ifr) could bring wanted results ...
>>
>> Oops, you're right. Actually, the condition to check is probably
>> (n*sizeof(*ifr) - ifc.ifc_len < sizeof(*ifr)). Actually, since the size
>> of the returned values aren't actually a multiple of sizeof(*ifr), I'd
>> probably switch to allocating a multiple of 4k.
>
> Actually, because there're very different sizes of sockaddr's (sockaddr_in,
> sockaddr_in6, ...), I require at least a page must be left over.
> Because of other OS may support return of errors in overflow, I didn't
> remove the check - finally it must run on AIX, Windows and Linux, too.
>
>>>>> lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
>>>>>
>>>>> while (ifr < lifr) > {
>>>>> printf( "%s\n", ifr->ifr_name );
>>>>> ifr = (struct ifreq *)(((char *)ifr) + _SIZEOF_ADDR_IFREQ(*ifr));
>>>>> }
>>>> This loop has two problems. First, the ifr's are variable length so you
>>>> immediately go off into the weeds.
>>> The _SIZEOF_ADDR_IFREQ macro should handle that correctly, shouldn't it?
>>
>> Right here as well.
>
> Finally - I must enhance this using SA_LEN if available to support systems
> without sa_len member support. I'll try it in office with our linux
> machines there, because I don't have any penguins at home ;)
>
>>>> Second, there is at least one per
>>>> interface and one per address so you to keep track of the last interface
>>>> name and not repeat them.
>>> Good point - if it's sure in this order, this is a good way to handle it.
>>
>> It is in the current implementation and it's hard to imaging that we'd
>> break that.
>
> By the way, because I'm looking for interfaces, I skip everything which is
> no AF_LINK - should work, too (and does for my test-machines ...).
>
> Final question: would it make sense to submit a patch against
> ports/net/p5-Net-Interface using this knowledge to unbreak the port, or
I'd suggest doing both. We want it fixed in CPAN, but having it be useful on
FreeBSD would also be good.
-- Brooks
> /Jens
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/socket.h>
> #include <net/if.h>
> #include <errno.h>
> #include <strings.h>
> #include <sys/ioctl.h>
> #include <ifaddrs.h>
> #include <machine/param.h>
>
> /* FIXME use SA_LEN for systems like Linux */
> #ifndef _SIZEOF_ADDR_IFREQ
> #define _SIZEOF_ADDR_IFREQ(ifr) \
> ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
> (sizeof(struct ifreq) - sizeof(struct sockaddr) + \
> (ifr).ifr_addr.sa_len) : sizeof(struct ifreq))
> #endif
>
> int
> main()
> {
> struct ifconf ifc;
> struct ifreq *ifr, *lifr;
> int fd;
> unsigned int n;
>
> fd = socket( AF_INET, SOCK_STREAM, 0 );
> bzero(&ifc, sizeof(ifc));
> n = 1;
> ifr = calloc( ifc.ifc_len, sizeof(*ifr) );
> do
> {
> n *= 2;
> ifr = realloc( ifr, PAGE_SIZE * n );
> bzero( ifr, PAGE_SIZE * n );
> ifc.ifc_req = ifr;
> ifc.ifc_len = n * PAGE_SIZE;
> } while( ( ioctl( fd, SIOCGIFCONF, &ifc ) == -1 ) || ( ifc.ifc_len >= ( (n-1) * PAGE_SIZE)) );
>
> lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
>
> while (ifr < lifr)
> {
> struct sockaddr *sa = &ifr->ifr_ifru.ifru_addr;
> if( AF_LINK == sa->sa_family )
> {
> printf( "%s\n", ifr->ifr_name );
> }
> ifr = (struct ifreq *)(((char *)ifr) + _SIZEOF_ADDR_IFREQ(*ifr));
> }
>
> return 0;
> }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-net/attachments/20080722/80e0eccf/attachment.pgp
More information about the freebsd-net
mailing list