8.2 Important structures

8.2.1 The socket structure

ソケットはシステムコールsocketで初期化され,セットアップされる.

include/linux/net.h

/*
 * ソケットの中身.すべてのフィールドがすべての設定で使われるわけではない.
 * 
 *      server          client
 * conn     client connected to server connected to
 * iconn    list of clients     -unused-
 *       awaiting connections
 * wait     sleep for clients,  sleep for connection,
 *      sleep for i/o       sleep for i/o
 */
struct socket {
     short                 type;           /* SOCK_STREAM, ...     */
     socket_state          state;
     long                  flags;
     struct proto_ops      *ops;           /* プロトコルはほとんどをこなす */
     void                  *data;          /* プロトコルのデータ */
     struct socket         *conn;          /* 〜に接続されたサーバソケット */
     struct socket         *iconn;         /* 不完全なソケット */
     struct socket         *next;
     struct wait_queue     **wait;         /* 待ち行列へのポインタ */
     struct inode          *inode;
     struct fasync_struct  *fasync_list;   /* 非同期のウェイクアップリスト */
};
short type; 用途
SOCK_STREAM Transmission Control Protocol (TCP)コネクション
SOCK_DGRAM User Datagram Protcol (UDP)
SOCK_RAW IPパケットの送受信

stateには現在のソケットの状態が格納される.最も重要な状態はSS_CONNECTEDSS_UNCONNECTEDである.

struct proto_ops *opsはソケットを操作する関数へのポインタがメンバである構造体を指す.

include/linux/net.h

struct proto_ops {
    int family;

    int (*create)  (struct socket *sock, int protocol);
    int (*dup)     (struct socket *newsock, struct socket *oldsock);
    int (*release) (struct socket *sock, struct socket *peer);
...略...
};

dataポインタはアドレスファミリと同期するソケットのsubstructureを指す.

conniconnwaitポインタはAF_INETアドレスファミリ内のソケットには使われない.

Linuxでは,各ファイルはinodeによって表される.各BSDソケットにはinodeも存在する.そのため,BSDソケットとそれぞれのinodeは1対1でマッピングされている.inodeには対応するinodeが格納される.

8.2.2 The sk_buff structure -- buffer management in the network

sk_buffは各通信パケットの管理をおこなう(図8.3をみよ).

include/linux/skbuff.h

struct sk_buff {
    struct sk_buff         * volatile next;
    struct sk_buff         * volatile prev;

この構造体の最初の2つのポインタと同じように,link3 ポインタは,循環リストと他のリストとのリンクに必要.

    struct sk_buff         * volatile link3;

sk ポインタはバッファが属しているソケットを指す.

    struct sock            *sk;

変数 when はパケットが最後に転送された時刻を示す.

    volatile unsigned long when;      /* used to compute rtt's    */

1/100 秒単位で時間が記録される.これは,転送時にカーネル変数 jiffies (3.2.4節を見よ)から引き継がれる.しかし,このバッファはパケットの送信時に限らず受信のさいにも用いられる.パケットがネットワークデバイスによってネットワーク実装の高レイヤに転送されると, netif_rx() 関数はタイマ割り込みによって更新されるカーネル変数 xtime を使って, stamp 構造体内の現在時刻を入力する.

    struct timeval         stamp;

ネットワークバッファの管理では,パケットの送信元または受信先のネットワークデバイスの識別情報は極めて重要である. dev ポインタはデバイスの情報を指す.

    struct device          *dev;

mem_addr 構造体は sk_buff によって管理されるバッファの開始位置を指す.

    struct sk_buff         *mem_addr;

この共用体は,パケット内のさまざまなヘッダ構造体へのポインタとしての役割を果たす.IPヘッダへのポインタはソケットに用いられる.

    union {
        struct tcphdr      *th;
        struct ethhdr      *eth;
        struct iphdr       *iph;
        struct udphdr      *uh;
        unsigned char      *raw;
        unsigned long      seq;
    } h;
    struct iphdr           *ip_hdr;   /* IPPROTO_RAW 用 */

mem_lentrusize 変数は予約されたメモリの長さが与えられている. fraglenfraglist は Linux 1.2では使われていない.

    unsigned long          mem_len;
    unsigned long          len;
    unsigned long          fraglen;
    struct sk_buff         *fraglist; /* フラグメントリスト*/
    unsigned long          truesize;

次にパケットが送られるべきアドレスを raddr が保持している間,送信元と送信先のアドレスはそれぞれ saddrdaddr である.

    unsigned long          saddr;
    unsigned long          daddr;
    unsigned long          raddr;     /* 次の hop アドレス */

これらの変数はそれぞれ異なる部分のネットワーク実装によって用いられる.

    volatile char          acked,
                           used,
                           free,
                           arp;
    unsigned char          tries,lock,localroute,pkt_type;
#define PACKET_HOST        0          /* To us */
#define PACKET_BROADCAST   1
#define PACKET_MULTICAST   2
#define PACKET_OTHERHOST   3          /* Unmatched promiscuous */
    unsigned short         users;     /* ユーザカウント - datagram.c を見よ (seqpacket.c/stream.c など...) */
    unsigned short         pkt_class; /* パケットタイプをキャッシュする必要がある場合 (新しいPPP) */
    unsigned long          padding[0];
    unsigned char          data[0];
};

sk_buff 構造体の管理は,通常,双方向連結リストを使うため,リストヘッダの実装はこのような形になる.

struct sk_buff_head {
    struct sk_buff * volatile next;
    struct sk_buff * volatile prev;
};

8.2.3 The INET socket -- a special part of a socket

INET構造体によって,ソケットのネットワーク固有の部分が管理される.

opt ポインタは,このソケットに使われる各IPのオプションを含む構造体を指す.wmem_allocrmem_alloc 変数は,ソケットが書き込みと読み出しを要求したメモリの量を表す.

/*
 * この構造体はマジで整理する必要がある.
 * そのほとんどはTCP用であり,他のプロトコルでは使われていない. 
 */
struct sock {
  struct options           *opt;
  volatile unsigned long   wmem_alloc;
  volatile unsigned long   rmem_alloc;

TCPプロトコルによって要求されるシーケンス番号は,これらの変数に格納される.TCPは接続志向(connection-oriented)であるため,これらのシーケンス番号はソケットごとに管理する必要がある.

  unsigned long            write_seq;
  unsigned long            sent_seq;
  unsigned long            acked_seq;
  unsigned long            copied_seq;
  unsigned long            rcv_ack_seq;
  unsigned long            window_seq;
  unsigned long            fin_seq;
  unsigned long            urg_seq;
  unsigned long            urg_data;

これらの変数はソケットのためにセットされる可能性のある変数とフラグが格納される.

  /*
   * すべてはvolatileというわけではない.
   */
  volatile char            inuse,
                           dead,
                           urginline,
                           intr,
                           blog,
                           done,
                           reuse,
                           keepopen,
                           linger,
                           delay_acks,
                           destroy,
                           ack_timed,
                           no_check,
                           zapped,    /* In ax25 & ipx means not linked */
                           broadcast,
                           nonagle;
  unsigned long            lingertime;

変数 proc は,帯域外のデータの受信時にシグナルを送信するプロセスまたはプロセスグループを格納するために用いられる.

  int                      proc;

next はソケットのハッシュテーブル内の,同じハッシュ値をもつソケットを関連づける.

  struct sock              *next;
  struct sock              *prev; /* Doubly linked chain.. */
  struct sock              *pair;

INETソケットのプロトコルは新しい sock 構造体を設定するために accept() 命令を実行する.

  struct sk_buff           * volatile send_head;
  struct sk_buff           * volatile send_tail;
  struct sk_buff_head      back_log;
  struct sk_buff           *partial;
  struct timer_list        partial_timer;
  long                     retransmits;
  struct sk_buff_head      write_queue,
                           receive_queue;

これらすべてのポインタは,INETソケットに関するバッファの管理に用いられる.循環リストはTCPセグメントの送受信のために,sk_buff_head 構造体を通じて定義される.

  struct proto             *prot;

これには,ソケットが関連付けられているプロトコルの命令の一覧が含まれている.多くの場合,これには tcp_protudp_protraw_protのうちどれかひとつのアドレスだろう.

  struct wait_queue        **sleep;

speepポインタは,このソケット上で動いている間ブロックされているプロセスが含まれている待ち行列を指す.

  unsigned long            daddr;
  unsigned long            saddr;

各IPパケットに入力されていなければならない送信元と送信先のアドレスである.

  unsigned short           max_unacked;
  unsigned short           window;
  unsigned short           bytes_rcv;
/* mss is min(mtu, max_window) */
  unsigned short           mtu;       /* mss negotiated in the syn's */
  volatile unsigned short  mss;       /* current eff. mss - can change */
  volatile unsigned short  user_mss;  /* mss requested by user in ioctl */
  volatile unsigned short  max_window;
  unsigned long            window_clamp;
  unsigned short           num;
  volatile unsigned short  cong_window;
  volatile unsigned short  cong_count;
  volatile unsigned short  ssthresh;
  volatile unsigned short  packets_out;
  volatile unsigned short  shutdown;
  volatile unsigned long   rtt;
  volatile unsigned long   mdev;
  volatile unsigned long   rto;
/* currently backoff isn't used, but I'm maintaining it in case
 * we want to go back to a backoff formula that needs it
 */
  volatile unsigned short  backoff;

構造体内のこれらのフィールドはTCPの利用とほかのプロトコルに関連したデータのためにある.

  volatile short           err;
  unsigned char            protocol;
  volatile unsigned char   state;
  volatile unsigned char   ack_backlog;
  unsigned char            max_ack_backlog;
  unsigned char            priority;
  unsigned char            debug;
  unsigned short           rcvbuf;
  unsigned short           sndbuf;

err変数はC言語のerrnoのようなもの.ソケットの状態はstateで与えられる.rcvbufsndbufは,パケットの送受信時にこのソケットに要求できるメモリの最大量を示す.

  unsigned short           type;
  unsigned char            localroute;    /* Route locally only */

ソケットのタイプの指定typeは,関連するBSDソケット構造体から引き継がれている.パケットをローカルでのみルーティングする必要がある場合はlocalrouteで示す.

/* IP 'private area' or will be eventually */
  int                      ip_ttl;        /* TTL setting */
  int                      ip_tos;        /* TOS */

これらの変数はIPヘッダの生成時に使われ,またヘッダ中の同期しているフィールドに入力される.

  struct tcphdr            dummy_th;

TCP接続がセットアップされたとき一度,TCPヘッダの基本的なフレームワークがここに入力される.

  struct timer_list        keepalive_timer;    /* TCP keepalive hack */
  struct timer_list        retransmit_timer;    /* TCP retransmit timer */
  struct timer_list        ack_timer;        /* TCP delayed ack timer */
  int                      ip_xmit_timeout;    /* Why the timeout is running */

  /* This part is used for the timeout functions (timer.c). */
  int                timeout;    /* What are we waiting for? */
  struct timer_list        timer;        /* This is the TIME_WAIT/receive timer when we are doing IP */
  struct timeval           stamp;

TCPの実装に必要なタイマの管理に使われる.パケットの受信時にstampが更新されるため,最後のパケットが受信された時間を記録できる.

  /* identd */
  struct socket            *socket;

このポインタは関連するBSDソケットを指す.

  /* Callbacks */
  void                     (*state_change)(struct sock *sk);
  void                     (*data_ready)(struct sock *sk,int bytes);
  void                     (*write_space)(struct sock *sk);
  void                     (*error_report)(struct sock *sk);

};

state_change()関数はソケットの状態が変更されると実行される.data_ready()はデータが受信されたときに呼び出され,write_space()は書き込み可能な空きメモリが増加したときに呼び出される.error_report()はエラーが起こったときに呼び出される.

8.2.4 Protocol operations in the proto structure

net/inet/sock.h

struct proto {
  struct sk_buff *    (*wmalloc)(struct sock *sk,
                    unsigned long size, int force,
                    int priority);
  struct sk_buff *    (*rmalloc)(struct sock *sk,
                    unsigned long size, int force,
                    int priority);
  void            (*wfree)(struct sock *sk, struct sk_buff *skb,
                 unsigned long size);
  void            (*rfree)(struct sock *sk, struct sk_buff *skb,
                 unsigned long size);
  unsigned long        (*rspace)(struct sock *sk);
  unsigned long        (*wspace)(struct sock *sk);
  void            (*close)(struct sock *sk, int timeout);
  int            (*read)(struct sock *sk, unsigned char *to,
                int len, int nonblock, unsigned flags);
  int            (*write)(struct sock *sk, unsigned char *to,
                 int len, int nonblock, unsigned flags);
  int            (*sendto)(struct sock *sk,
                  unsigned char *from, int len, int noblock,
                  unsigned flags, struct sockaddr_in *usin,
                  int addr_len);
  int            (*recvfrom)(struct sock *sk,
                    unsigned char *from, int len, int noblock,
                    unsigned flags, struct sockaddr_in *usin,
                    int *addr_len);
  int            (*build_header)(struct sk_buff *skb,
                    unsigned long saddr,
                    unsigned long daddr,
                    struct device **dev, int type,
                    struct options *opt, int len, int tos, int ttl);
  int            (*connect)(struct sock *sk,
                  struct sockaddr_in *usin, int addr_len);
  struct sock *        (*accept) (struct sock *sk, int flags);
  void            (*queue_xmit)(struct sock *sk,
                      struct device *dev, struct sk_buff *skb,
                      int free);
  void            (*retransmit)(struct sock *sk, int all);
  void            (*write_wakeup)(struct sock *sk);
  void            (*read_wakeup)(struct sock *sk);
  int            (*rcv)(struct sk_buff *buff, struct device *dev,
                   struct options *opt, unsigned long daddr,
                   unsigned short len, unsigned long saddr,
                   int redo, struct inet_protocol *protocol);
  int            (*select)(struct sock *sk, int which,
                  select_table *wait);
  int            (*ioctl)(struct sock *sk, int cmd,
                 unsigned long arg);
  int            (*init)(struct sock *sk);
  void            (*shutdown)(struct sock *sk, int how);
  int            (*setsockopt)(struct sock *sk, int level, int optname,
                   char *optval, int optlen);
  int            (*getsockopt)(struct sock *sk, int level, int optname,
                  char *optval, int *option);       
  unsigned short    max_header;
  unsigned long        retransmits;
  struct sock *        sock_array[SOCK_ARRAY_SIZE];
  char            name[80];
  int            inuse, highestinuse;
};

8.2.5 The general structure of a socket address

ソケットは異なるアドレスファミリの異なるアドレス形式をサポートしなければならないため,アドレスファミリ,ポート番号,サイズの違うアドレスのフィールドのような,一般的なアドレス構造がある.IPアドレスの場合,一般的な構造体sockaddrに対応する特別な構造体sockaddr_inが定義されている.

include/linux/socket.h

struct sockaddr {
    unsigned short    sa_family;    /* アドレスファミリ, AF_xxx */
    char              sa_data[14];    /* 14バイトのプロトコルアドレス */
};

include/linux/in.h

/* IPソケットアドレスを記した構造体 */
#define __SOCK_SIZE__    16        /* sizeof(struct sockaddr)    */
struct sockaddr_in {
    short int             sin_family;    /* アドレスファミリ */
    unsigned short int    sin_port;    /* ポート番号 */
    struct in_addr        sin_addr;    /* IPアドレス */

    /* Pad to size of `struct sockaddr'. */
    unsigned char        __pad[__SOCK_SIZE__ - sizeof(short int) -
              sizeof(unsigned short int) - sizeof(struct in_addr)];
};
#define sin_zero    __pad        /* for BSD UNIX comp. -FvK    */