>> I would prefer KAME way, no matter, what is it. 8).
>itojun please send information how on KAME SIOCGIFCONF
>ioctl() returns ipv6 adresses (how it's done with struct ifreq ?) etc ...
fine, this is a bit long story...
In summary,
- BSD SIOCGIFCONF has alignment issue already
- KAME SIOCGIFCONF is natural extension to BSD SIOCGIFCONF, which
returns sockaddr_in6
- Solaris8 defined SIOCG*L*IFCONF separately from SIOCGIFCONF.
- KAME and *BSD (well, OpenBSD/NetBSD/BSDI at this moment),
will switch to use getifaddrs(3). getifaddrs uses sysctl internally
to get list of addresses configured. do linux have
sysctl(NET_RT_IFLIST)?
- KAME and *BSD may supply SIOCGLIFCONF as extra interface, if it
gets very popular.
And my recommendation to linux camp is:
- include getifaddrs into libc.
- if you have sysctl(RT_NET_IFLIST):
- use sysctl(RT_NET_IFLIST) as backend of getifaddrs.
- may implement SIOCGLIFCONF as extra interface.
- if you do not have sysctl(RT_NET_IFLIST):
- implement SIOCGLIFCONF. use it as backend of getifaddrs.
getifaddrs implementation is included in BSDI4. It is redistributable
(BSDI folks put normal BSD license on it). If you have trouble
getting the code, I can send one.
itojun
BSD SIOCGIFCONF
===============
structure definition is like this. we pass pointer struct ifconf
to SIOCGIFCONF, pointing a buffer memory region. buffer memory region
will be filled by ifreq (packed structs).
struct ifconf {
int ifc_len; /* size of associated buffer */
union {
caddr_t ifcu_buf;
struct ifreq *ifcu_req;
} ifc_ifcu;
#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
#define ifc_req ifc_ifcu.ifcu_req /* array of structures returned */
};
struct ifreq {
char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
union {
struct sockaddr ifru_addr;
/* other members omitted */
} ifr_ifru;
#define ifr_addr ifr_ifru.ifru_addr /* address */
};
packed ifreq will look like this, regardless from architectures
(since it is packed, there will be no padding)
---
ifr_name 16bytes/"ne0"
ifru_addr 16bytes/sockaddr_in for 10.1.1.1
ifr_name 16bytes/"ne1"
ifru_addr 16bytes/sockaddr_in for 10.1.1.2
ifr_name 16bytes/"lo0"
ifru_addr 16bytes/sockaddr_in for 127.0.0.1
---
Since introduction of AF_LINK (sockaddr_dl - somewhere between 4.3
and 4.4?), we see items larger than sizeof(sockaddr) attached to
ifru_addr. The rule is:
- if item in ifru_addr is smaller than sizeof(sockaddr), we pad them
by sizeof(sockaddr).
- if item in ifru_addr is larger, consult sa_len.
So, it will look like this:
---
ifr_name 16bytes/"ne0"
ifru_addr 16bytes/sockaddr_in for 10.1.1.1
ifr_name 16bytes/"ne1"
ifru_addr 30bytes/sockaddr_dl, sa_len = 30
ifr_name 16bytes/"lo0"
ifru_addr 16bytes/sockaddr_in for 127.0.0.1
---
The API can break alignment constraint on picky architecutures.
For example, in the above "lo0" is from address (start + 78),
which is not multiple of 8. we'll see panic if we point this packed
struct with aligned-to-8 pointer. Luckily, we see very few sockaddr_dl
that violates boundary.
Most of existing userland appliation can cope with ifru_addr larger
than sizeof(sockaddr) - they properly check sa_len. Most of them,
however, are unable to cope with unaligned data access in packed
struct.
KAME SIOCGIFCONF
================
KAME SIOCGIFCONF is natural extension to BSD SIOCGIFCONF. we include
sockaddr_in6 into results whenever necessary. We can skip over
larger sockaddrs by using sa_len, just like AF_LINK.
---
ifr_name 16bytes/"ne0"
ifru_addr 16bytes/sockaddr_in for 10.1.1.1
ifr_name 16bytes/"lo0"
ifru_addr 28bytes/sockaddr_in6, for ::1, sa_len = 28,
ifr_name 16bytes/"lo0"
ifru_addr 16bytes/sockaddr_in for 127.0.0.1
---
This comes with alignment problems, however, this is not us introduced
boundary issues. This was BSD 4.3/4.4 which introduced boundary
issues.
NOTE: we don't promote this. We promote getifaddrs since SIOCGIFCONF
is too hard for normal users to use correctly.
Solaris SIOCGLIFCONF
====================
Solaris has no sa_len, and they are using SIOCGIFCONF without sa_len
(i.e. no AF_LINK). it never return ifru_addr bigger than
sizeof(sockaddr).
To return sockaddr_in6, Solaris8 includes SIOCG*L*IFCONF (stars are
not part of the name, of course). This is defined like this:
struct lifreq {
char lifr_name[LIFNAMSIZ]; /* if name, e.g. "en0" */
union {
int lifru_addrlen; /* for subnet/token etc */
/* other members omitted
} lifr_lifru1;
#define lifr_addrlen lifr_lifru1.lifru_addrlen
int32_t __lifr_pad0; /* pad - sockaddr_storage used */
union {
struct sockaddr_storage lifru_addr;
/* other members omitted */
} lifr_lifru;
#define lifr_addr lifr_lifru.lifru_addr /* address */
};
Since this API uses sockaddr_storage, it will not raise alignment
issues. They define padding constraint differently between 64bit
API and 32bit API, so please consult Solaris 8 headers for complete
definitions.
|