[インデックス 10590] ファイルの概要
このコミットは、Go言語の標準ライブラリnet
パッケージから、UDPConn
およびIPConn
型に存在していたBindToDevice
APIを削除するものです。このAPIは、特定のネットワークインターフェースにソケットをバインドするために使用されていましたが、その基盤となるソケットオプション(SOL_SOCKET
とSO_BINDTODEVICE
)がLinux固有のものであったため、より汎用的なnet
パッケージの公開APIとしては不適切であると判断されました。この変更により、BindToDevice
の機能はsyscall
パッケージのような、より低レベルでプラットフォーム依存の層に降格され、将来的にプラットフォームに依存しない、よりポータブルなAPIの導入が視野に入れられています。
コミット
commit cf4acf80b4abecf5113bbeafb4e6780f5a0b607d
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Fri Dec 2 23:18:16 2011 +0900
net, syscall: remove BindToDevice API from UDPConn, IPConn
For now a pair of socket options SOL_SOCKET and SO_BINDTODEVICE
is supported on Linux only. I'd like to demote BindToDevice API
to syscall level because it's Linux dependent one.
In the near future, probably we may have a bit more portable
API that using IPROTO_IP/IPV6 level socket options to specify,
identify an inbound, outbound IP interface on incoming, outgoing
UDP and raw IP packets.
R=cw, golang-dev
CC=golang-dev
https://golang.org/cl/5447071
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cf4acf80b4abecf5113bbeafb4e6780f5a0b607d
元コミット内容
net, syscall: remove BindToDevice API from UDPConn, IPConn
For now a pair of socket options SOL_SOCKET and SO_BINDTODEVICE
is supported on Linux only. I'd like to demote BindToDevice API
to syscall level because it's Linux dependent one.
In the near future, probably we may have a bit more portable
API that using IPROTO_IP/IPV6 level socket options to specify,
identify an inbound, outbound IP interface on incoming, outgoing
UDP and raw IP packets.
R=cw, golang-dev
CC=golang-dev
https://golang.org/cl/5447071
変更の背景
この変更の主な背景は、Go言語の標準ライブラリnet
パッケージが提供するAPIのポータビリティ(移植性)を向上させることにあります。
BindToDevice
APIは、ソケットを特定のネットワークインターフェース(例: eth0
, wlan0
)にバインドする機能を提供していました。これは、マルチホーム環境(複数のネットワークインターフェースを持つシステム)において、特定のインターフェースからのトラフィックのみを処理したり、特定のインターフェースからトラフィックを送信したりする場合に有用です。
しかし、この機能を実現するために内部で使用されていたソケットオプションSOL_SOCKET
とSO_BINDTODEVICE
は、当時(そして現在も)主にLinuxカーネルによってサポートされている機能でした。Goのnet
パッケージは、様々なオペレーティングシステム(Windows, macOS, BSD系, Linuxなど)で動作するように設計されており、その公開APIは可能な限りプラットフォームに依存しない形で提供されるべきです。
特定のOSにのみ存在する機能を高レベルの公開APIとして提供することは、他のOSでの動作を保証できないため、ライブラリの設計原則に反します。そのため、開発者はBindToDevice
APIをnet
パッケージから削除し、その機能をより低レベルでプラットフォーム固有のsyscall
パッケージに降格させることを決定しました。これにより、net
パッケージはよりクリーンでポータブルなインターフェースを維持しつつ、必要に応じてsyscall
パッケージを通じてプラットフォーム固有の機能にアクセスできる道を残しました。
将来的には、IPROTO_IP
やIPV6
レベルのソケットオプションを使用するなど、よりポータブルな方法でIPインターフェースを指定するAPIが導入される可能性も示唆されています。
前提知識の解説
- ソケット (Socket): ネットワーク通信のエンドポイントを抽象化したものです。アプリケーションはソケットを通じてデータを送受信します。
- ネットワークインターフェース (Network Interface): 物理的または仮想的なネットワーク接続ポイントです。例として、イーサネットカード(
eth0
)、Wi-Fiアダプター(wlan0
)、ループバックインターフェース(lo
)などがあります。 - ソケットオプション (Socket Options): ソケットの動作を制御するための設定です。
setsockopt
システムコールを通じて設定されます。SOL_SOCKET
: ソケットレベルのオプションを指定するためのプロトコルレベルです。SO_BINDTODEVICE
: 特定のネットワークインターフェースにソケットをバインドするためのソケットオプションです。このオプションが設定されたソケットは、指定されたインターフェースからの(または指定されたインターフェースへの)パケットのみを送受信します。これは主にLinuxでサポートされています。
setsockopt
システムコール: ソケットのオプションを設定するために使用されるシステムコールです。setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)
の形式で呼び出され、sockfd
はソケットディスクリプタ、level
はオプションのプロトコルレベル(例:SOL_SOCKET
)、optname
はオプション名(例:SO_BINDTODEVICE
)、optval
はオプションの値へのポインタ、optlen
は値の長さです。UDPConn
(User Datagram Protocol Connection): Goのnet
パッケージにおけるUDPソケットの抽象化です。コネクションレス型の通信に使用されます。IPConn
(IP Connection): Goのnet
パッケージにおけるIPソケット(RAWソケットを含む)の抽象化です。syscall
パッケージ: Go言語において、オペレーティングシステムのシステムコールに直接アクセスするためのパッケージです。このパッケージのAPIは、OSによって異なるため、プラットフォーム固有のコードを記述する際に使用されます。Goの標準ライブラリの他の部分がポータビリティを重視するのに対し、syscall
パッケージは意図的にプラットフォーム依存の機能を提供します。- ポータビリティ (Portability): ソフトウェアが異なる環境(この場合は異なるオペレーティングシステム)で、変更なしに、または最小限の変更で動作する能力を指します。Goの標準ライブラリは高いポータビリティを目指して設計されています。
技術的詳細
このコミットは、Goの標準ライブラリにおけるAPI設計の重要な原則、すなわち「ポータビリティ」と「プラットフォーム固有の機能の扱い」を明確に示しています。
net
パッケージは、ネットワークプログラミングのための高レベルでプラットフォームに依存しないインターフェースを提供することを目的としています。しかし、BindToDevice
のように、その実装が特定のOS(この場合はLinux)のカーネル機能に強く依存している場合、そのAPIをnet
パッケージの公開インターフェースとして維持することは、以下の問題を引き起こします。
- 非Linux環境での動作保証の困難さ:
SO_BINDTODEVICE
がサポートされていないOSでは、BindToDevice
メソッドは常にエラーを返すか、期待通りに動作しません。これは、ユーザーがGoのコードを異なるOSで実行する際に予期せぬ挙動やエラーに直面する原因となります。 - APIの混乱: ユーザーは、
net
パッケージのAPIがどのOSで利用可能で、どのOSで利用できないのかを常に意識する必要があります。これは、ライブラリの使いやすさを損ないます。 - 将来的な拡張性の制約: 特定のOSに特化したAPIを高レベルで維持すると、将来的に他のOSで同様の機能が異なる方法で実装された場合に、統一されたAPIを提供することが難しくなります。
このコミットでは、これらの問題を解決するために、BindToDevice
APIをnet
パッケージから削除し、その機能をsyscall
パッケージに「降格」させました。
net
パッケージからの削除:net.IPConn.BindToDevice
とnet.UDPConn.BindToDevice
メソッドが削除されました。これにより、net
パッケージのユーザーは、これらの高レベルな型を通じて直接インターフェースバインディングを行うことができなくなります。syscall
パッケージへの移動(またはその機能の明示的な非サポート):src/pkg/syscall/syscall_bsd.go
とsrc/pkg/syscall/syscall_windows.go
からBindToDevice
関数が削除されています。これは、これらのOSではSO_BINDTODEVICE
に相当する直接的なシステムコールが存在しないか、Goのsyscall
パッケージで直接サポートされていないことを意味します。Linuxの場合、syscall.BindToDevice
は引き続き存在するか、またはsetsockopt
を直接呼び出す形で利用可能であると推測されます(このコミットのdiffにはLinux固有のsyscall
ファイルの変更は含まれていませんが、コミットメッセージの意図からそう読み取れます)。net/sock.go
の変更:bindToDevice
という内部ヘルパー関数も削除されています。これは、net
パッケージ内でこの機能がもはや使用されないことを反映しています。
この変更は、Goの標準ライブラリが、高レベルの抽象化はポータブルに保ち、プラットフォーム固有の詳細は低レベルのsyscall
パッケージに委ねるという設計哲学を徹底していることを示しています。これにより、Goのコードは異なる環境でより予測可能に動作し、開発者は必要に応じて低レベルのOS機能にアクセスする選択肢を持つことができます。
コミットメッセージで言及されている「将来的に、IPROTO_IP/IPV6
レベルのソケットオプションを使用して、受信および送信UDPおよびRAW IPパケットのインバウンド/アウトバウンドIPインターフェースを指定、識別する、よりポータブルなAPIを持つ可能性がある」という点は、この機能に対するより汎用的なアプローチを模索する意図を示しています。これは、SO_BINDTODEVICE
のようなデバイス名に基づくバインディングではなく、IPアドレスやルーティングテーブルに基づく、より抽象的なインターフェース選択メカニズムを意味する可能性があります。
コアとなるコードの変更箇所
このコミットでは、以下の5つのファイルからBindToDevice
に関連するコードが削除されています。
-
src/pkg/net/iprawsock_posix.go
:IPConn
型からBindToDevice
メソッドが削除されました。- 削除された行数: 10行
-
src/pkg/net/sock.go
:- 内部ヘルパー関数
bindToDevice
が削除されました。 - 削除された行数: 5行
- 内部ヘルパー関数
-
src/pkg/net/udpsock_posix.go
:UDPConn
型からBindToDevice
メソッドが削除されました。- 削除された行数: 10行
-
src/pkg/syscall/syscall_bsd.go
:BindToDevice
関数(BSD系OS向け)が削除されました。この関数は元々ENOSYS
(システムコールが実装されていないことを示すエラー)を返していました。- 削除された行数: 9行
-
src/pkg/syscall/syscall_windows.go
:BindToDevice
関数(Windows向け)が削除されました。この関数も元々EWINDOWS
(Windows固有のエラー)を返していました。- 削除された行数: 1行
合計で35行が削除されており、追加された行はありません。これは、既存の機能の削除と再配置を目的としたコミットであることを明確に示しています。
コアとなるコードの解説
削除された主要なコードブロックは、net
パッケージ内のIPConn
とUDPConn
に定義されていたBindToDevice
メソッドです。
src/pkg/net/iprawsock_posix.go
および src/pkg/net/udpsock_posix.go
から削除されたコード例:
// BindToDevice binds an IPConn to a network interface.
func (c *IPConn) BindToDevice(device string) error {
if !c.ok() {
return os.EINVAL
}
c.fd.incref()
defer c.fd.decref()
return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
}
このコードは、IPConn
(またはUDPConn
)のレシーバーメソッドとして定義されており、device
という文字列引数で指定されたネットワークインターフェースにソケットをバインドしようとします。内部では、syscall.BindToDevice
という関数を呼び出しています。このsyscall.BindToDevice
が、OS固有のsetsockopt
システムコール(SOL_SOCKET
とSO_BINDTODEVICE
を使用)をラップしていました。
このメソッドが削除されたことにより、Goのアプリケーション開発者は、net.IPConn
やnet.UDPConn
のインスタンスに対して直接BindToDevice("eth0")
のような呼び出しを行うことができなくなりました。
src/pkg/net/sock.go
から削除されたコード例:
func bindToDevice(fd *netFD, dev string) error {
// TODO(rsc): call setsockopt with null-terminated string pointer
return os.EINVAL
}
これはnet
パッケージ内部で使用されていたヘルパー関数で、BindToDevice
メソッドの実装の一部として機能していました。この関数も、関連する公開APIの削除に伴い不要となったため削除されました。コメントにあるTODO(rsc)
は、この機能がまだ完全に実装されていなかったか、あるいは将来的な改善の余地があったことを示唆しています。
src/pkg/syscall/syscall_bsd.go
および src/pkg/syscall/syscall_windows.go
から削除されたコード例:
// BindToDevice binds the socket associated with fd to device.
func BindToDevice(fd int, device string) (err error) {
return ENOSYS
}
func BindToDevice(fd Handle, device string) (err error) { return EWINDOWS }
これらのコードは、BSD系OSおよびWindows向けのsyscall
パッケージ内に存在していたBindToDevice
関数の定義です。注目すべきは、これらの関数が常にエラー(ENOSYS
は"Operation not supported"、EWINDOWS
はWindows固有のエラー)を返していた点です。これは、これらのOSではSO_BINDTODEVICE
に相当する機能が直接サポートされていないか、Goのsyscall
パッケージでその機能が実装されていなかったことを意味します。
これらのsyscall
レベルの関数が削除されたのは、高レベルのnet
パッケージからBindToDevice
が削除されたことに伴い、これらのプラットフォームでこの機能がGoの標準ライブラリを通じて利用できないことを明確にするためです。これにより、Goの標準ライブラリは、プラットフォーム固有の機能のサポート状況をより正確に反映するようになりました。
関連リンク
- Go CL 5447071: https://golang.org/cl/5447071
参考にした情報源リンク
- 上記のGo CL (Change List) の内容
- Go言語の
net
パッケージおよびsyscall
パッケージの一般的なドキュメントと設計原則に関する知識 - ソケットプログラミングにおける
setsockopt
、SOL_SOCKET
、SO_BINDTODEVICE
に関する一般的な知識 (例: Linux man pages forsetsockopt(2)
,socket(7)
)