struct skbuff
は Linux Kernel networking code で最も利用される構造体の1つで、include/linux/skbuff.h
に定義されています。
「最も利用される」ため、コピー時のオーバーヘッド削減など様々な改良が継続的に加えられているため、メンバー変数の型や名前も大いに変遷しています。
そのうちの各レイヤのヘッダの場所を示す変数の変遷を調べたのでメモ。
v2.6.0 ~ v2.6.21
union {
struct tcphdr *th;
struct udphdr *uh;
struct icmphdr *icmph;
struct igmphdr *igmph;
struct iphdr *ipiph;
struct ipv6hdr *ipv6h;
unsigned char *raw;
} h;
union {
struct iphdr *iph;
struct ipv6hdr *ipv6h;
struct arphdr *arph;
unsigned char *raw;
} nh;
union {
unsigned char *raw;
} mac;
この時代は各レイヤ事にヘッダへのポインタが union されていました。
実は v2.6.21 ~ v2.6.22 の間はいきなり変更されたのではなく、いくつもの commit により少しずつunion内のメンバーが減っていき、最終的に *raw
だけになり、v2.6.22 以降の sk_buff_data_t
になるという変遷をたどっています。
全てを列挙するのはあきらめましたので一部だけご紹介します。
- [SK_BUFF]: Introduce ip_hdr(), remove skb->nh.iph
- [SK_BUFF]: Introduce arp_hdr(), remove skb->nh.arph
- [SK_BUFF]: Introduce ipv6_hdr(), remove skb->nh.ipv6h
ここまでで union { ... } hn;
のメンバーは *raw
1つになります。
union {
- struct ipv6hdr *ipv6h;
unsigned char *raw;
} nh;
- [SK_BUFF]: unions of just one member don't get anything done, kill them
- b0e380b1d8a8e0aca215df97702f99815f05c094
- Renaming skb->h to skb->transport_header, skb->nh to skb->network_header and
skb->mac to skb->mac_header, to match the names of the associated helpers
(skb[[re]set]{transport,network,mac}_header)
ここで union
から unsigned char
となり、名前も変更されます。
- union {
- unsigned char *raw;
- } h;
-
- union {
- unsigned char *raw;
- } nh;
-
- union {
- unsigned char *raw;
- } mac;
-
+ unsigned char *transport_header;
+ unsigned char *network_header;
+ unsigned char *mac_header;
v2.6.22 ~ v2.6.39 (last v2.6.x), v3.0 ~ v3.10
#ifdef NET_SKBUFF_DATA_USES_OFFSET
typedef unsigned int sk_buff_data_t;
#else
typedef unsigned char *sk_buff_data_t;
#endif
sk_buff_data_t transport_header;
sk_buff_data_t network_header;
sk_buff_data_t mac_header;
このバージョンではポインタではなくオフセットを使うようになります。
(NET_SKBUFF_DATA_USES_OFFSET
が定義されていない場合は従来通り char
ポインタになります。)
- [SK_BUFF]: Use offsets for skb->{mac,network,transport}_header on 64bit architectures
- unsigned char *transport_header;
- unsigned char *network_header;
- unsigned char *mac_header;
+ sk_buff_data_t transport_header;
+ sk_buff_data_t network_header;
+ sk_buff_data_t mac_header;
v3.11 ~ v3.19, v4.0 ~ v4.5 (last v4.x as of 2016/04/22)
__u16 transport_header;
__u16 network_header;
__u16 mac_header;
現在は sk_buff構造体のサイズを小さくするために、sk_buff_data_t ではなく、__u16
を使用しています。
- net: Use 16bits for *_headers fields of struct skbuff
- 1a37e412a0225fcba5587f24c0dfc7636efc8b69
- In order to mitigate ongoing incresase in the size of struct skbuff use 16 bit integer offsets rather than pointers for inner_*_headers.
- sk_buff_data_t inner_transport_header;
- sk_buff_data_t inner_network_header;
- sk_buff_data_t inner_mac_header;
- sk_buff_data_t transport_header;
- sk_buff_data_t network_header;
- sk_buff_data_t mac_header;
+ __u16 inner_transport_header;
+ __u16 inner_network_header;
+ __u16 inner_mac_header;
+ __u16 transport_header;
+ __u16 network_header;
+ __u16 mac_header;
参考リンク
変更が行われたコミットを発見するために以下手順で進めました。
-
git log <tag> | head -1
でtag(ex: v2.6.11)のコミット番号見つけてhttp://github.com/torvalds/linux/blame/<commit>/<file>
で変更箇所の表示 - tag間で複数の commit で行われた変更の場合blameでは見つからないので、tag間の
git log
を表示させ検索- 例:v2.6.21 と v2.6.22間の変更を調査
$ git log v2.6.21 | head -1
commit de46c33745f5e2ad594c72f2cf5f490861b16ce1
$ git log v2.6.22 | head -1
commit 7dcca30a32aadb0520417521b0c44f42d09fe05c
$ git log 94a05509a9e11806acd797153d03019706e466f1 7dcca30a32aadb0520417521b0c44f42d09fe05c > ../tools/git-log-v2.6.21-22.log
2016/04/22 追記
コミット番号だけでなく、以下例のようにv2.6.11, v3.14等のTag名でもファイルを確認する事が可能です。
https://github.com/torvalds/linux/blame/<tag>/include/linux/skbuff.h
https://github.com/torvalds/linux/blame/v3.14/include/linux/skbuff.h
また、Twitter: @hiroysato さんにご紹介頂いた以下リンクを参考にしました。ありがとうございました。