[インデックス 14593] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにstruct tcp_info
の型定義を追加するものです。これにより、Linuxシステムコールを通じてTCP接続の詳細な情報を取得する機能がGoプログラムから利用可能になります。
コミット
commit bef036e3d16695d51dd338f329e1a8afba667bbb
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Mon Dec 10 11:32:07 2012 -0500
syscall: add type for struct tcp_info
R=mikioh.mikioh, rsc
CC=golang-dev
https://golang.org/cl/6900050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/bef036e3d16695d51dd338f329e1a8afba667bbb
元コミット内容
syscall: add type for struct tcp_info
R=mikioh.mikioh, rsc
CC=golang-dev
https://golang.org/cl/6900050
変更の背景
この変更の背景には、GoプログラムがLinuxカーネルが提供するTCP接続に関する詳細な統計情報(tcp_info
構造体)にアクセスできるようにするという目的があります。tcp_info
は、TCPソケットの状態、再送カウンタ、RTT(Round Trip Time)、輻輳ウィンドウサイズなど、ネットワークパフォーマンスの診断や監視に不可欠な情報を含んでいます。
Goのsyscall
パッケージは、OSの低レベルな機能(システムコール)にアクセスするためのインターフェースを提供します。しかし、特定のC言語の構造体(この場合はstruct tcp_info
)がGo側で型として定義されていない場合、その構造体を通じてシステムコールから返されるデータを利用することはできませんでした。
このコミットは、Goプログラムがgetsockopt
などのシステムコールを介してTCP_INFO
オプションを要求した際に、その結果を適切にGoのデータ構造として受け取れるようにするために、struct tcp_info
に対応するGoの型を導入しました。これにより、Goで書かれたネットワークツールや監視アプリケーションが、より詳細なTCPレベルの情報を取得し、分析することが可能になります。
前提知識の解説
1. Go言語のsyscall
パッケージ
Go言語のsyscall
パッケージは、オペレーティングシステムが提供する低レベルなプリミティブ(システムコール)へのインターフェースを提供します。これにより、ファイル操作、プロセス管理、ネットワーク通信など、OSカーネルと直接対話する機能を実現できます。GoプログラムがC言語で書かれたシステムライブラリやカーネルAPIと連携する際に重要な役割を果たします。
2. Linuxのstruct tcp_info
struct tcp_info
は、LinuxカーネルがTCPソケットに関する詳細な統計情報を提供する際に使用するC言語の構造体です。この構造体は、getsockopt
システムコールとTCP_INFO
ソケットオプションを組み合わせて使用することで、アプリケーションから取得できます。含まれる主な情報には以下のようなものがあります。
tcpi_state
: TCP接続の状態(例:TCP_ESTABLISHED
,TCP_LISTEN
など)。tcpi_rto
: 再送タイムアウト(Retransmission Timeout)。tcpi_rtt
: ラウンドトリップタイム(Round Trip Time)。tcpi_snd_cwnd
: 送信輻輳ウィンドウ(Congestion Window)サイズ。tcpi_total_retrans
: 総再送パケット数。
これらの情報は、ネットワークのボトルネック特定、パフォーマンスチューニング、接続の健全性監視などに利用されます。
3. C言語の構造体とGo言語の構造体のマッピング
Go言語はC言語との相互運用性(cgo)を考慮して設計されており、C言語の構造体をGoの構造体として表現し、システムコールを通じてデータをやり取りすることが可能です。この際、Goの構造体のフィールドは、Cの構造体のフィールドとメモリレイアウトが一致するように定義される必要があります。特に、アライメントやパディングに注意が必要です。ztypes_linux_amd64.go
のようなファイルは、特定のアーキテクチャ(この場合はamd64)とOS(Linux)に特化したC構造体のGo表現を自動生成または手動で定義するために使用されます。
技術的詳細
このコミットの技術的詳細は、Goのsyscall
パッケージがLinuxカーネルのstruct tcp_info
をどのようにGoの型として表現し、システムコールを通じてその情報を利用可能にするかにあります。
-
types_linux.go
での型宣言:types_linux.go
は、Linuxシステムコールで使用される一般的な型定義を含むファイルです。このファイルにtype TCPInfo C.struct_tcp_info
というエイリアスが追加されました。これは、Goコード内でTCPInfo
という型名を使用することで、C言語のstruct tcp_info
を参照できるようにするためのものです。C.struct_tcp_info
はcgoがC言語の型をGoに公開する際の記法です。 -
ztypes_linux_amd64.go
での構造体定義:ztypes_linux_amd64.go
は、Linux AMD64アーキテクチャに特化したシステムコール関連の型定義を含むファイルです。このファイルには、struct tcp_info
のGo言語での具体的な構造体定義が追加されました。この定義は、C言語のstruct tcp_info
の各フィールド(tcpi_state
,tcpi_rto
,tcpi_rtt
など)とそのデータ型、そしてメモリ上のオフセットとサイズを正確に反映しています。Pad_cgo_0 [2]byte
のようなフィールドは、C言語の構造体におけるパディング(メモリのアライメント要件を満たすためにコンパイラが挿入する未使用バイト)をGoの構造体でも再現するために追加されます。これにより、GoとCの間で構造体をやり取りする際に、メモリレイアウトの不一致による問題を防ぎます。- 各フィールドの型は、C言語の対応する型(例:
uint8_t
,uint32_t
)に正確にマッピングされています。
-
SizeofTCPInfo
定数の追加:SizeofTCPInfo
定数は、struct tcp_info
のサイズをバイト単位で定義します。これは、システムコールで構造体を渡す際に、カーネルに渡すバッファのサイズを正確に指定するために必要です。C.sizeof_struct_tcp_info
はcgoを通じてC言語のsizeof
演算子を利用し、コンパイル時に実際のサイズを取得します。ztypes_linux_amd64.go
では、具体的な値0x68
(104バイト)が定義されています。
これらの変更により、Goプログラムはsyscall.TCPInfo
型を使用してgetsockopt
システムコールを呼び出し、TCP接続のtcp_info
データを取得し、Goの構造体として直接アクセスできるようになります。これは、Goで高性能なネットワーク診断ツールや監視エージェントを開発する上で非常に重要な基盤となります。
コアとなるコードの変更箇所
src/pkg/syscall/types_linux.go
--- a/src/pkg/syscall/types_linux.go
+++ b/src/pkg/syscall/types_linux.go
@@ -195,6 +195,8 @@ type Inet6Pktinfo C.struct_in6_pktinfo
type Ucred C.struct_ucred
+type TCPInfo C.struct_tcp_info
+
const (
SizeofSockaddrInet4 = C.sizeof_struct_sockaddr_in
SizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
@@ -211,6 +213,7 @@ const (
SizeofInet4Pktinfo = C.sizeof_struct_in_pktinfo
SizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
SizeofUcred = C.sizeof_struct_ucred
+\tSizeofTCPInfo = C.sizeof_struct_tcp_info
)
// Netlink routing and interface messages
src/pkg/syscall/ztypes_linux_amd64.go
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -253,6 +253,40 @@ type Ucred struct {
Gid uint32
}
+type TCPInfo struct {\n\tState uint8\n\tCa_state uint8\n\tRetransmits uint8\n\tProbes uint8\n\tBackoff uint8\n\tOptions uint8\n\tPad_cgo_0 [2]byte\n\tRto uint32\n\tAto uint32\n\tSnd_mss uint32\n\tRcv_mss uint32\n\tUnacked uint32\n\tSacked uint32\n\tLost uint32\n\tRetrans uint32\n\tFackets uint32\n\tLast_data_sent uint32\n\tLast_ack_sent uint32\n\tLast_data_recv uint32\n\tLast_ack_recv uint32\n\tPmtu uint32\n\tRcv_ssthresh uint32\n\tRtt uint32\n\tRttvar uint32\n\tSnd_ssthresh uint32\n\tSnd_cwnd uint32\n\tAdvmss uint32\n\tReordering uint32\n\tRcv_rtt uint32\n\tRcv_space uint32\n\tTotal_retrans uint32\n}\n+\n const (\
SizeofSockaddrInet4 = 0x10
SizeofSockaddrInet6 = 0x1c
@@ -269,6 +303,7 @@ const (
SizeofInet4Pktinfo = 0xc
SizeofInet6Pktinfo = 0x14
SizeofUcred = 0xc
+\tSizeofTCPInfo = 0x68
)
const (
コアとなるコードの解説
src/pkg/syscall/types_linux.go
type TCPInfo C.struct_tcp_info
: この行は、Goのsyscall
パッケージ内でTCPInfo
という新しい型を定義しています。この型は、C言語のstruct tcp_info
に対応するGoのエイリアスとして機能します。これにより、GoプログラムはC言語のtcp_info
構造体をGoの型システムを通じて参照し、操作できるようになります。これは、Goが低レベルのシステムコールインターフェースを提供するための一般的なパターンです。SizeofTCPInfo = C.sizeof_struct_tcp_info
: この定数は、struct tcp_info
のメモリ上でのサイズ(バイト単位)を定義します。C.sizeof_struct_tcp_info
はcgoの機能を利用して、Cコンパイラが計算するstruct tcp_info
の実際のサイズを取得します。このサイズ情報は、システムコール(例:getsockopt
)を呼び出す際に、カーネルに渡すバッファのサイズを正確に指定するために不可欠です。
src/pkg/syscall/ztypes_linux_amd64.go
type TCPInfo struct { ... }
: このブロックは、Linux AMD64アーキテクチャにおけるstruct tcp_info
のGo言語での具体的な構造体定義です。C言語のstruct tcp_info
の各フィールド(State
,Ca_state
,Rto
,Rtt
など)が、対応するGoのデータ型(uint8
,uint32
など)で正確にマッピングされています。Pad_cgo_0 [2]byte
: このフィールドは、C言語の構造体におけるメモリパディングをGoの構造体でも再現するために追加されています。異なるデータ型のフィールドが連続する場合、CPUの効率的なアクセスを保証するためにコンパイラが自動的にパディングを挿入することがあります。このパディングをGo側でも正確に再現することで、GoとCの間で構造体をやり取りする際のメモリレイアウトの不一致を防ぎ、データの破損や予期せぬ動作を回避します。- 各フィールド名は、Linuxカーネルの
tcp_info
構造体のフィールド名(例:tcpi_state
)からtcpi_
プレフィックスを除去し、Goの命名規則(CamelCase)に従って変換されています。
SizeofTCPInfo = 0x68
: この行は、ztypes_linux_amd64.go
ファイル内でSizeofTCPInfo
定数に具体的な値0x68
(10進数で104)を割り当てています。これは、Linux AMD64システムにおけるstruct tcp_info
の実際のサイズを示しています。この値は、types_linux.go
で定義されたC.sizeof_struct_tcp_info
が解決される具体的なサイズであり、Goプログラムがシステムコールでこの構造体を使用する際に、正しいメモリサイズを確保するために利用されます。
これらの変更により、GoプログラムはLinuxのTCPスタックから提供される詳細なtcp_info
データを、Goの型安全な方法で取得し、解析できるようになりました。これは、ネットワーク監視、診断、および最適化ツールをGoで構築する上で重要な機能拡張です。
関連リンク
- Go
syscall
package documentation (このコミット時点のバージョンとは異なる可能性がありますが、syscall
パッケージの一般的な情報源として) - Linux
tcp_info
man page (TCP_INFOソケットオプションとstruct tcp_info
に関する情報)
参考にした情報源リンク
- Go
syscall
package source code - Linux kernel source code (for
struct tcp_info
definition) - Go
getsockopt
example (general usage) (このコミット後に利用可能になったAPIの例) - Go
x/net/internal/socket
package (より高レベルなソケット操作の抽象化) - Go
net
package (Goの標準ネットワークパッケージ) - cgo documentation (GoとCの相互運用性に関する情報)
- Go issue tracker for
tcp_info
related discussions (関連する議論や後続の変更履歴) - Go CL 6900050 (このコミットに対応するGoのコードレビューシステム上の変更リスト)