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

[インデックス 18380] ファイルの概要

このコミットは、Go言語のネットワークパッケージにおけるPlan 9オペレーティングシステム上でのIPv4スタックの検出方法を改善するものです。具体的には、IPv4スタックの存在を確認するためのプローブ処理が、より堅牢な方法に変更されています。

コミット

commit 1e89eb2c317b20dbe1bb8650b9c5eeae37b26e72
Author: Jeff Sickel <jas@corpus-callosum.com>
Date:   Thu Jan 30 09:49:32 2014 +0900

    net: net: better IPv4 stack probe on Plan 9
    
    LGTM=mischief, mikioh.mikioh
    R=golang-codereviews, 0intro, mischief, mikioh.mikioh
    CC=golang-codereviews
    https://golang.org/cl/53960044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/1e89eb2c317b20dbe1bb8650b9c5eeae37b26e72

元コミット内容

このコミットは、Go言語のnetパッケージ内のsrc/pkg/net/ipsock_plan9.goファイルに対して行われた変更です。主な変更点は以下の通りです。

  1. probe関数のシグネチャからbufSize引数が削除されました。
    • 変更前: func probe(filename, query string, bufSize int) bool
    • 変更後: func probe(filename, query string) bool
  2. probeIPv4Stack関数内のIPv4スタック検出ロジックが変更されました。
    • 変更前は、netdir+"/ipselftab"に対して"127.0.0.1"をクエリとして使用していました。
    • 変更後は、netdir+"/iproute"に対して"4i"をクエリとして使用するようになりました。
  3. probeIPv6Stack関数内のIPv6スタック検出およびIPv4-mapping検出ロジックが変更されました。
    • IPv6スタック検出のprobe呼び出しからbufSize引数が削除されました。
    • IPv4-mapping検出のクエリが"4b"から"4i"に変更されました。

変更の背景

この変更の背景には、Plan 9オペレーティングシステムにおけるIPv4スタックの検出の信頼性向上が挙げられます。以前の検出方法では、ipselftabファイルに127.0.0.1が存在するかどうかを確認していましたが、これは必ずしもIPv4スタックが完全に機能していることを保証するものではありませんでした。

Plan 9のネットワークスタックは、ファイルシステムを通じてネットワークデバイスや設定を操作するという独特の設計思想を持っています。ipselftabは自己アドレスを管理するファイルですが、より広範なルーティング情報を提供するiprouteファイルの方が、システムがIPv4通信を適切に処理できるかどうかを判断する上で、より正確な指標となります。

特に、"4i"というクエリは、IPv4インターフェースの存在を確認するためのものであり、単にループバックアドレスが存在するかどうかをチェックするよりも、システムがIPv4ネットワークに接続可能であるか、またはIPv4パケットをルーティングできるかという、より実用的な意味でのIPv4スタックの健全性を判断するのに適しています。

この改善により、GoプログラムがPlan 9上でネットワーク機能を初期化する際に、IPv4スタックの有無をより正確に判断できるようになり、結果としてネットワーク関連の挙動が安定することが期待されます。

前提知識の解説

このコミットを理解するためには、以下のPlan 9オペレーティングシステムのネットワークに関する概念と、Go言語のネットワークパッケージの基本的な構造について理解しておく必要があります。

Plan 9のファイルシステムベースのネットワーク

Plan 9は、"Everything is a file"(すべてはファイルである)という哲学を徹底しており、ネットワークインターフェースやプロトコルスタックもファイルシステムを通じてアクセス・制御されます。

  • /netディレクトリ: Plan 9におけるネットワーク関連のファイルシステムツリーのルートです。このディレクトリ以下に、ネットワークインターフェース、プロトコルスタック、ルーティングテーブルなどがファイルとして表現されます。
  • ipselftab: /net/ipselftabは、システムの自己アドレス(ローカルに設定されたIPアドレス)をリストするファイルです。これにはループバックアドレス(127.0.0.1::1)などが含まれます。
  • iproute: /net/iprouteは、IPルーティングテーブルを管理するファイルです。このファイルにクエリを書き込むことで、特定のルーティング情報を取得したり、ルーティングエントリを追加・削除したりできます。
  • ctlファイル: 多くのネットワークデバイスやプロトコルスタックのディレクトリにはctl(control)ファイルが存在します。このファイルにコマンドを書き込むことで、そのデバイスやスタックの動作を制御できます。
  • dataファイル: ネットワークデバイスのdataファイルは、パケットの送受信に使用されます。

iprouteファイルへのクエリ

iprouteファイルは、特定の情報を取得するために特殊なクエリ文字列を受け付けます。

  • 4i: IPv4インターフェースに関する情報を要求するクエリです。システムにIPv4インターフェースが設定され、アクティブである場合に、関連情報が返されます。これは、システムがIPv4通信を行う能力があるかどうかの強力な指標となります。
  • 6i: IPv6インターフェースに関する情報を要求するクエリです。
  • 4b: IPv4ブロードキャストアドレスに関する情報を要求するクエリです。このクエリは、IPv4スタックの存在を間接的に示すものですが、4iほど直接的ではありません。

Go言語のnetパッケージ

Go言語のnetパッケージは、ネットワークI/Oプリミティブを提供します。これにはTCP/IP、UDP、ドメインネーム解決、Unixドメインソケットなどが含まれます。オペレーティングシステム固有のネットワーク機能へのアクセスは、内部的にOS固有のコード(例: ipsock_plan9.go)を通じて抽象化されています。

  • probe関数: このコミットで変更されているprobe関数は、特定のファイル(例: /net/ipselftab/net/iproute)に対してクエリを実行し、その結果に基づいてネットワークスタックの機能(例: IPv4やIPv6が利用可能か)を検出するためのユーティリティ関数です。

技術的詳細

このコミットの技術的な核心は、Plan 9におけるIPv4スタックの「プローブ(検出)」方法の変更にあります。

probe関数の変更

probe関数は、指定されたfilename(例: /net/ipselftab/net/iproute)を開き、query文字列を書き込み、その結果を読み取ることで、特定のネットワーク機能の有無を判断します。

変更前は、probe関数はbufSizeという引数を持っていました。これは、クエリの結果を読み取るためのバッファサイズを指定するものと考えられます。しかし、このコミットではbufSizeが削除されています。これは、以下のいずれかの理由によるものと推測されます。

  1. 不要な引数: bufSizeが常に固定値(例: 128)で呼び出されており、関数のシグネチャから削除しても問題ない、あるいは内部で適切なバッファサイズが自動的に決定されるようになった。
  2. APIの簡素化: probe関数の利用側がバッファサイズを意識する必要がなくなり、APIがよりシンプルになった。
  3. Plan 9のファイルI/Oの特性: Plan 9のファイルシステムI/Oは、読み取り時に指定されたバッファサイズよりも少ないデータしか利用できない場合でも、利用可能なデータを返すため、厳密なバッファサイズ指定が不要になった可能性。

IPv4スタック検出の改善

最も重要な変更は、probeIPv4Stack関数におけるIPv4スタックの検出方法です。

  • 変更前: probe(netdir+"/ipselftab", "127.0.0.1", 128)
    • これは/net/ipselftabファイルに"127.0.0.1"を書き込み、その結果を読み取ることで、ループバックアドレスが自己アドレスとして設定されているかを確認していました。しかし、ループバックアドレスの存在は、必ずしもシステムが外部のIPv4ネットワークと通信できることを意味しません。例えば、IPv4ルーティングが設定されていない場合でも、ループバックアドレスは存在する可能性があります。
  • 変更後: probe(netdir+"/iproute", "4i")
    • これは/net/iprouteファイルに"4i"(IPv4インターフェース)を書き込み、その結果を読み取ります。/net/iproute"4i"をクエリすると、システムにアクティブなIPv4インターフェースが存在する場合に、その情報が返されます。これは、システムがIPv4パケットを送受信できる能力があることを直接的に示唆するため、より堅牢なIPv4スタックの検出方法と言えます。

IPv6スタック検出におけるIPv4-mappingの変更

probeIPv6Stack関数では、IPv6スタックの存在と、IPv6スタックがIPv4-mapped IPv6アドレスをサポートしているかどうかの両方を検出します。

  • IPv6スタック検出: r := probe(netdir+"/iproute", "6i")
    • これはIPv6インターフェースの存在を確認するもので、変更はありませんが、probe関数のシグネチャ変更に伴いbufSize引数が削除されています。
  • IPv4-mapping検出: v = probe(netdir+"/iproute", "4i")
    • 変更前は"4b"(IPv4ブロードキャストアドレス)をクエリしていましたが、変更後は"4i"(IPv4インターフェース)をクエリするようになりました。これは、IPv4-mappedアドレスのサポートを判断する上で、ブロードキャストアドレスの存在よりもIPv4インターフェースの存在の方がより適切な指標であるという判断に基づいていると考えられます。IPv4-mappedアドレスは、IPv6ソケット上でIPv4通信を行うためのメカニズムであり、その機能が利用可能であるかを判断するには、基盤となるIPv4インターフェースの健全性を確認するのが自然です。

これらの変更により、GoのnetパッケージはPlan 9環境において、より正確かつ信頼性の高い方法でネットワークスタックの機能を判断できるようになりました。

コアとなるコードの変更箇所

変更はsrc/pkg/net/ipsock_plan9.goファイルに集中しています。

--- a/src/pkg/net/ipsock_plan9.go
+++ b/src/pkg/net/ipsock_plan9.go
@@ -12,7 +12,7 @@ import (
 	"syscall"
 )
 
-func probe(filename, query string, bufSize int) bool {
+func probe(filename, query string) bool {
 	var file *file
 	var err error
 	if file, err = open(filename); err != nil {
@@ -37,7 +37,7 @@ func probe(filename, query string, bufSize int) bool {
 }
 
 func probeIPv4Stack() bool {
-	return probe(netdir+"/ipselftab", "127.0.0.1", 128)
+	return probe(netdir+"/iproute", "4i")
 }
 
 // probeIPv6Stack returns two boolean values.  If the first boolean
@@ -45,10 +45,10 @@ func probeIPv4Stack() bool {
 // second boolean value is true, kernel supports IPv6 IPv4-mapping.
 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	// Plan 9 uses IPv6 natively, see ip(3).
-	r := probe(netdir+"/iproute", "6i", 128)
+	r := probe(netdir+"/iproute", "6i")
 	v := false
 	if r {
-		v = probe(netdir+"/iproute", "4b", 128)
+		v = probe(netdir+"/iproute", "4i")
 	}
 	return r, v
 }

コアとなるコードの解説

probe関数のシグネチャ変更

-func probe(filename, query string, bufSize int) bool {
+func probe(filename, query string) bool {

probe関数からbufSize引数が削除されました。これにより、この関数を呼び出す側は、結果を読み取るためのバッファサイズを意識する必要がなくなりました。これは、関数の内部実装がバッファサイズを適切に管理するか、あるいはPlan 9のファイルI/Oの特性上、この引数が不要になったことを示唆しています。

probeIPv4Stack関数の変更

-	return probe(netdir+"/ipselftab", "127.0.0.1", 128)
+	return probe(netdir+"/iproute", "4i")

probeIPv4Stack関数は、システムがIPv4スタックをサポートしているかどうかを検出します。 変更前は、/net/ipselftabファイルにループバックアドレス"127.0.0.1"をクエリしていました。これは、システムにIPv4の自己アドレスが設定されているかを確認するものでした。 変更後は、/net/iprouteファイルに"4i"(IPv4インターフェース)をクエリするようになりました。これは、システムにアクティブなIPv4インターフェースが存在するかどうかを直接的に確認するもので、より正確なIPv4スタックの検出を可能にします。

probeIPv6Stack関数の変更

-	r := probe(netdir+"/iproute", "6i", 128)
+	r := probe(netdir+"/iproute", "6i")

IPv6スタックの検出部分では、probe関数のシグネチャ変更に伴い、bufSize引数(128)が削除されました。クエリ自体は"6i"(IPv6インターフェース)のままで、IPv6スタックの存在を確認します。

-		v = probe(netdir+"/iproute", "4b", 128)
+		v = probe(netdir+"/iproute", "4i")

IPv4-mappingのサポートを検出する部分では、クエリが"4b"(IPv4ブロードキャストアドレス)から"4i"(IPv4インターフェース)に変更されました。これにより、IPv4-mappedアドレスのサポートを判断する際に、より関連性の高いIPv4インターフェースの存在がチェックされるようになりました。

これらの変更は、Plan 9環境におけるGoのネットワーク機能の堅牢性と正確性を向上させるための重要な改善です。

関連リンク

  • Go言語のnetパッケージに関する公式ドキュメント: https://pkg.go.dev/net
  • Plan 9 from Bell Labs: https://9p.io/plan9/
  • Plan 9のネットワークに関するドキュメント(ip(3)など): Plan 9のインストールに含まれるマニュアルページを参照するか、オンラインのPlan 9マニュアルを参照してください。例: http://man.cat-v.org/plan_9/3/ip

参考にした情報源リンク

  • Go言語のコミット履歴とコードレビューシステム (Gerrit): https://go.googlesource.com/go および https://go-review.googlesource.com/
  • Plan 9のネットワークに関する一般的な情報源(Stack Overflow, フォーラムなど)
  • Plan 9のソースコードやマニュアルページ(特に/netディレクトリの構造やipコマンド、iprouteファイルに関する記述)
  • このコミットのGerritレビューページ: https://golang.org/cl/53960044 (コミットメッセージに記載)
  • Plan 9のiprouteファイルに関する情報: https://9p.io/magic/man2html/3/ip (Plan 9のip(3)マニュアルページ)
  • Plan 9のipselftabに関する情報: https://9p.io/magic/man2html/3/ipselftab (Plan 9のipselftab(3)マニュアルページ)
  • Plan 9のネットワークスタックの設計思想に関する一般的な記事や論文。