読者です 読者をやめる 読者になる 読者になる

ifreq を調べる

ネットワーク Linux

ifreqについて、簡単にではありますが調べました。

ifreq とは

"/usr/include/net/if.h"に定義されています。

"man netdevice"によると、

Linux supports some standard ioctls to configure network devices.They can be used on any socket's file descriptor regardless of the family or type. They pass an ifreq structure:

ということで、ネットワークデバイスを設定する際にioctl(2)に渡して、設定や情報取得を行うための構造体のようです。

ifreqの中身

struct ifreq {
    char ifr_name[IFNAMSIZ]; /* Interface name */
    union {
        struct sockaddr ifr_addr;
        struct sockaddr ifr_dstaddr;
        struct sockaddr ifr_broadaddr;
        struct sockaddr ifr_netmask;
        struct sockaddr ifr_hwaddr;
        short           ifr_flags;
        int             ifr_ifindex;
        int             ifr_metric;
        int             ifr_mtu;
        struct ifmap    ifr_map;
        char            ifr_slave[IFNAMSIZ];
        char            ifr_newname[IFNAMSIZ];
        char           *ifr_data;
    };
};

こちらも"man netdevice"から引用しました。

  • ifr_name
    • インターフェース名
    • IF_NAMESIZEは16

"ifr_name"以外のメンバはその都度違うようです。ioctlの第二引数に渡す値によって変わります。今回は"sockaddr", "ifmap"について調べてみます。

sockaddr

sockaddr構造体なのですが、調べてみると"sys/socket.h"に定義されているということだったので、"/usr/include/sys"にあるのかなぁと思って探してみると、"/usr/include/i386-linux-gnu/bits/socket.h"にそれらしきものが定義されていました。

/* Structure describing a generic socket address.  */
struct sockaddr
  {
        __SOCKADDR_COMMON (sa_);    /* Common data: address family and length.  */
        char sa_data[14];           /* Address data.  */
  };

この"__SOCKADDR_COMMON"はどこで定義されているかというと、"/usr/include/i386-linux-gnu/bits/sockaddr.h"に、

/* This macro is used to declare the initial common members
   of the data types used for socket addresses, `struct sockaddr',
      `struct sockaddr_in', `struct sockaddr_un', etc.  */

#define __SOCKADDR_COMMON(sa_prefix) \
  sa_family_t sa_prefix##family

このように定義されていました。

ここで、プリプロセッサによって、上が以下のように展開されるようです。

/* Structure describing a generic socket address.  */
struct sockaddr
  {
        sa_family_t sa_family;    /* Common data: address family and length.  */
        char sa_data[14];           /* Address data.  */
  };

sa_familyについては、"/usr/include/i386-linux-gnu/bits/socket.h"にプロトコルごとの値が定義されていました。

/* Address families.  */
#define AF_UNSPEC       PF_UNSPEC
#define AF_LOCAL        PF_LOCAL
#define AF_UNIX         PF_UNIX
#define AF_FILE         PF_FILE
#define AF_INET         PF_INET
#define AF_AX25         PF_AX25
#define AF_IPX          PF_IPX
...以下略...
/* Protocol families.  */
#define PF_UNSPEC       0       /* Unspecified.  */
#define PF_LOCAL        1       /* Local to host (pipes and file-domain).  */
#define PF_UNIX         PF_LOCAL /* POSIX name for PF_LOCAL.  */
#define PF_FILE         PF_LOCAL /* Another non-standard name for PF_LOCAL.  */
#define PF_INET         2       /* IP protocol family.  */
#define PF_AX25         3       /* Amateur Radio AX.25.  */
#define PF_IPX          4       /* Novell Internet Protocol.  */
...以下略...

最近、socketを使ったプログラミングをしていく中で、"AF_INET"と"PF_INET"、何が違うんだろうと疑問だったのですが、アドレスファミリかプロトコルファミリの違いだったんですね。

ifmap

次にifmapです。

"/usr/include/net/if.h"に定義されている箇所がありました。

/* Device mapping structure. I'd just gone off and designed a
   beautiful scheme using only loadable modules with arguments for
   driver options and along come the PCMCIA people 8)

   Ah well. The get() side of this is good for WDSETUP, and it'll be
   handy for debugging things. The set side is fine for now and being
   very small might be worth keeping for clean configuration.  */

struct ifmap
{
    unsigned long int mem_start;
    unsigned long int mem_end;
    unsigned short int base_addr;
    unsigned char irq;
    unsigned char dma;
    unsigned char port;
    /* 3 bytes spare */
};

"ifmap"によってインターフェースのハードウェアパラメータを設定することが出来ます。値が何を表すかはデバイスドライバなどによって変わってくるみたいです。