Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 22 Jul 2008 10:18:47 -0500
From:      Brooks Davis <brooks@freebsd.org>
To:        Jens Rehsack <rehsack@web.de>
Cc:        FreeBSD Net <freebsd-net@freebsd.org>
Subject:   Re: SOLVED: lo0 not in ioctl( SIOCGIFCONF )
Message-ID:  <20080722151847.GI1699@lor.one-eyed-alien.net>
In-Reply-To: <48858948.9020403@web.de>
References:  <4884F401.4050103@web.de> <20080721204820.GE1699@lor.one-eyed-alien.net> <4884FFFF.9090908@web.de> <20080721222416.GG1699@lor.one-eyed-alien.net> <48850F72.90204@web.de> <20080721224618.GH1699@lor.one-eyed-alien.net> <48858948.9020403@web.de>

next in thread | previous in thread | raw e-mail | index | archive | help

--FUFe+yI/t+r3nyH4
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

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,
>>>>>>>=20
>>>>>>> maybe this question is better asked in this list ...
>>>>>>>=20
>>>>>>> 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 imple=
menting
>>>>>>> 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.
>>>>>>=20
>>>>>> -- 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>
>>>>>=20
>>>>> #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
>>>>>=20
>>>>> int
>>>>> main()
>>>>> {
>>>>>     struct ifconf ifc;
>>>>>     struct ifreq *ifr, *lifr;
>>>>>     int fd;
>>>>>     unsigned int n;
>>>>>=20
>>>>>     fd =3D socket( AF_INET, SOCK_STREAM, 0 );
>>>>>     bzero(&ifc, sizeof(ifc));
>>>>>         n =3D 3;
>>>>>         ifr =3D calloc( ifc.ifc_len, sizeof(*ifr) );
>>>>>         do
>>>>>         {
>>>>>             n *=3D 2;
>>>>>             ifr =3D realloc( ifr, sizeof(*ifr) * n );
>>>>>             bzero( ifr, sizeof(*ifr) * n );
>>>>>             ifc.ifc_req =3D ifr;
>>>>>             ifc.ifc_len =3D n * sizeof(*ifr);
>>>>>         } while( ( ioctl( fd, SIOCGIFCONF, &ifc ) =3D=3D -1 ) || (=20
>>>>> ifc.ifc_len =3D=3D 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 <=3D.  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 ca=
lls
>>>> on average.
>>> Thanks - that was the information I miss. I'll try tomorrow (it's=20
>>> slightly late here) and send back the result.
>>> Using <=3D should produce an endless loop, but maybe checking if=20
>>> ifc.ifc_len <=3D (n/2) * sizeof(*ifr) could bring wanted results ...
>>=20
>> 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.
>=20
> Actually, because there're very different sizes of sockaddr's (sockaddr_i=
n,=20
> 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=20
> remove the check - finally it must run on AIX, Windows and Linux, too.
>=20
>>>>>     lifr =3D (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
>>>>>=20
>>>>>     while (ifr < lifr) >     {
>>>>>         printf( "%s\n", ifr->ifr_name );
>>>>>         ifr =3D (struct ifreq *)(((char *)ifr) + _SIZEOF_ADDR_IFREQ(*=
ifr));
>>>>>     }
>>>> This loop has two problems.  First, the ifr's are variable length so y=
ou
>>>> immediately go off into the weeds.
>>> The _SIZEOF_ADDR_IFREQ macro should handle that correctly, shouldn't it?
>>=20
>> Right here as well.
>=20
> Finally - I must enhance this using SA_LEN if available to support system=
s=20
> without sa_len member support. I'll try it in office with our linux=20
> machines there, because I don't have any penguins at home ;)
>=20
>>>>  Second, there is at least one per
>>>> interface and one per address so you to keep track of the last interfa=
ce
>>>> name and not repeat them.
>>> Good point - if it's sure in this order, this is a good way to handle i=
t.
>>=20
>> It is in the current implementation and it's hard to imaging that we'd
>> break that.
>=20
> By the way, because I'm looking for interfaces, I skip everything which i=
s=20
> no AF_LINK - should work, too (and does for my test-machines ...).
>=20
> Final question: would it make sense to submit a patch against=20
> ports/net/p5-Net-Interface using this knowledge to unbreak the port, or=
=20

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>
>=20
> /* 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
>=20
> int
> main()
> {
>     struct ifconf ifc;
>     struct ifreq *ifr, *lifr;
>     int fd;
>     unsigned int n;
>=20
>     fd =3D socket( AF_INET, SOCK_STREAM, 0 );
>     bzero(&ifc, sizeof(ifc));
>         n =3D 1;
>         ifr =3D calloc( ifc.ifc_len, sizeof(*ifr) );
>         do
>         {
>             n *=3D 2;
>             ifr =3D realloc( ifr, PAGE_SIZE * n );
>             bzero( ifr, PAGE_SIZE * n );
>             ifc.ifc_req =3D ifr;
>             ifc.ifc_len =3D n * PAGE_SIZE;
>         } while( ( ioctl( fd, SIOCGIFCONF, &ifc ) =3D=3D -1 ) || ( ifc.if=
c_len >=3D ( (n-1) * PAGE_SIZE)) );
>=20
>     lifr =3D (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
>=20
>     while (ifr < lifr)
>     {
>         struct sockaddr *sa =3D &ifr->ifr_ifru.ifru_addr;
>         if( AF_LINK =3D=3D sa->sa_family )
>         {
>             printf( "%s\n", ifr->ifr_name );
>         }
>         ifr =3D (struct ifreq *)(((char *)ifr) + _SIZEOF_ADDR_IFREQ(*ifr)=
);
>     }
>=20
>     return 0;
> }


--FUFe+yI/t+r3nyH4
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (FreeBSD)

iD8DBQFIhfpXXY6L6fI4GtQRAtBRAKDhEpvRIkATfsa4HChBrxA20NSqZwCfUAyz
09yOhimYruPEua5tDSjX4IU=
=omn2
-----END PGP SIGNATURE-----

--FUFe+yI/t+r3nyH4--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080722151847.GI1699>