Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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の型として表現し、システムコールを通じてその情報を利用可能にするかにあります。

  1. 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に公開する際の記法です。

  2. 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)に正確にマッピングされています。
  3. 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に関する情報)

参考にした情報源リンク