netdev
[Top] [All Lists]

Re: SIOCGIFCONF and IPv6 addresses

To: Arkadiusz Miskiewicz <misiek@xxxxxxxxxx>
Subject: Re: SIOCGIFCONF and IPv6 addresses
From: itojun@xxxxxxxxxx
Date: Sat, 26 Feb 2000 14:06:13 +0900
Cc: netdev@xxxxxxxxxxx, core@xxxxxxxx
In-reply-to: misiek's message of Wed, 23 Feb 2000 18:10:35 +0100. <20000223181035.A637@xxxxxxxxxxxxxxxxxxx>
Sender: owner-netdev@xxxxxxxxxxx
>> 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.

<Prev in Thread] Current Thread [Next in Thread>