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

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

このコミットは、Go言語のsyscallパッケージにおいて、FreeBSDシステムコールに対するソース固有マルチキャスト(Source-Specific Multicast, SSM)ソケットオプションのサポートを追加するものです。これにより、GoアプリケーションがFreeBSD上で特定の送信元からのマルチキャストトラフィックをより細かく制御できるようになります。

コミット

commit 7d8da7dc4d6f7800aababcc054b71a1cda47cc93
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Tue Jun 24 07:03:44 2014 +0900

    syscall: add source-specific multicast socket options for FreeBSD
    
    Update #8266
    
    LGTM=iant
    R=golang-codereviews, iant
    CC=golang-codereviews
    https://golang.org/cl/104290043

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

https://github.com/golang/go/commit/7d8da7dc4d6f7800aababcc054b71a1cda47cc93

元コミット内容

このコミットは、GoのsyscallパッケージにFreeBSD向けのソース固有マルチキャストソケットオプションを追加します。これは、Issue #8266の解決を目的としています。具体的には、GroupReqおよびGroupSourceReq構造体、関連する定数、そしてこれらの構造体を使用するgetsockoptおよびsetsockoptラッパー関数が追加されています。

変更の背景

マルチキャスト通信には、大きく分けて「Any-Source Multicast (ASM)」と「Source-Specific Multicast (SSM)」の2種類があります。従来のASMでは、受信者は特定のマルチキャストグループに参加するだけで、そのグループに送信されるすべてのソースからのトラフィックを受信します。しかし、これにより不要なトラフィックが発生したり、セキュリティ上の懸念が生じたりする可能性がありました。

ソース固有マルチキャスト(SSM)は、この問題を解決するために導入されました。SSMでは、受信者はマルチキャストグループアドレス(G)だけでなく、特定の送信元アドレス(S)も指定してトラフィックを受信します。これにより、受信者は本当に必要なソースからのトラフィックのみを受け取ることができ、ネットワークの効率性、スケーラビリティ、およびセキュリティが向上します。

FreeBSDは、以前からカーネルレベルでSSMをサポートしていました。しかし、Goのsyscallパッケージには、これらのFreeBSD固有のSSMソケットオプションを直接操作するためのAPIが不足していました。このコミットは、GoアプリケーションがFreeBSDのSSM機能を活用できるように、必要なシステムコールラッパーとデータ構造をsyscallパッケージに追加することを目的としています。これにより、Goで記述されたネットワークアプリケーションが、より効率的でセキュアなマルチキャスト通信をFreeBSD上で実現できるようになります。

前提知識の解説

1. マルチキャスト通信

マルチキャストは、ネットワーク上で1対多の通信を実現する技術です。送信元が1つのデータパケットを送信すると、そのパケットは特定のマルチキャストグループに参加している複数の受信者に同時に配信されます。これにより、同じデータを複数の受信者に個別に送信するユニキャストや、ネットワーク内のすべてのデバイスに送信するブロードキャストと比較して、ネットワーク帯域幅を効率的に利用できます。

2. ソース固有マルチキャスト (Source-Specific Multicast, SSM)

SSMは、マルチキャストの一種で、受信者が特定のマルチキャストグループ(G)と、そのグループにデータを送信する特定の送信元(S)の両方を指定して参加するモデルです。これは(S,G)チャネルと呼ばれます。

  • ASM (Any-Source Multicast) との違い:
    • ASM: 受信者はグループGに参加するだけで、そのグループに送信する任意のソースからのトラフィックを受信します。
    • SSM: 受信者はグループGと特定のソースSの両方を指定します。これにより、不要なトラフィックの削減、ルーティングの簡素化(ランデブーポイント不要)、セキュリティの向上が図られます。
  • プロトコル: SSMでは、通常、IPv4ではIGMPv3 (Internet Group Management Protocol version 3)、IPv6ではMLDv2 (Multicast Listener Discovery version 2) が使用されます。これらのプロトコルは、受信者がソース情報をルーターに伝えることを可能にします。
  • IPv4 SSMアドレス範囲: IPv4では、232.0.0.0/8の範囲がSSM専用として予約されています。

3. ソケットオプション

ソケットオプションは、ネットワークソケットの動作を制御するための設定です。getsockopt()関数で現在の設定を取得し、setsockopt()関数で設定を変更します。これらは、ソケットのバッファサイズ、タイムアウト、再利用設定、マルチキャスト関連の動作など、多岐にわたる設定を調整するために使用されます。

4. Go言語の syscall パッケージ

Go言語のsyscallパッケージは、オペレーティングシステム(OS)の低レベルなプリミティブに直接アクセスするためのインターフェースを提供します。これにより、Goプログラムはファイル操作、プロセス管理、ネットワーク通信など、OSカーネルが提供するサービスを直接呼び出すことができます。

  • プラットフォーム依存性: syscallパッケージの関数や定数は、OSによって大きく異なります。このコミットのように、FreeBSD固有の機能を利用する場合、そのOSに特化したコードが必要になります。
  • 現在の推奨: Go 1.4以降、syscallパッケージは「ロックダウン」され、新しい開発ではgolang.org/x/sysパッケージの使用が推奨されています。これは、x/sysがより包括的で移植性の高いシステムコールラッパーを提供するためです。しかし、このコミットはそれ以前のものであるため、syscallパッケージに直接変更が加えられています。
  • mkerrors.sh: syscallパッケージ内にあるシェルスクリプトで、OSのエラー番号やその他のシステム固有の定数を定義するGoソースファイルを生成するために使用されます。Cプリプロセッサを介してOSヘッダーから定義を取得します。

技術的詳細

このコミットは、FreeBSDにおけるソース固有マルチキャストのサポートをGoのsyscallパッケージに統合するために、以下の主要な技術的変更を導入しています。

  1. 新しいデータ構造の追加:

    • RawSockaddrStorage: ソケットアドレスを格納するための汎用的なバッファ。異なる種類のアドレス(IPv4, IPv6など)を統一的に扱えるように設計されています。これは、GroupReqGroupSourceReq内でソケットアドレスを埋め込むために使用されます。
    • GroupReq: マルチキャストグループへの参加/脱退要求に使用される構造体です。インターフェースインデックスとマルチキャストグループアドレス(RawSockaddrStorage形式)を含みます。これは、特定のソースを指定しないグループ操作(例: MCAST_JOIN_GROUP)に用いられます。
    • GroupSourceReq: ソース固有マルチキャストグループへの参加/脱退、またはソースのブロック/アンブロック要求に使用される構造体です。インターフェースインデックス、マルチキャストグループアドレス、および送信元アドレス(両方ともRawSockaddrStorage形式)を含みます。これは、SSMの核心となる構造体です。
  2. 新しいソケットオプション定数の追加: FreeBSDカーネルが提供するSSM関連のソケットオプションに対応する定数が追加されました。これらはMCAST_プレフィックスを持つ定数で、zerrors_freebsd_*.goファイルに定義されています。

    • MCAST_BLOCK_SOURCE: 特定のソースからのマルチキャストトラフィックをブロックします。
    • MCAST_EXCLUDE: 特定のソースを除外してグループに参加します。
    • MCAST_INCLUDE: 特定のソースを含めてグループに参加します。
    • MCAST_JOIN_GROUP: マルチキャストグループに参加します(SSMではない一般的なグループ参加)。
    • MCAST_JOIN_SOURCE_GROUP: 特定のソースからのマルチキャストグループに参加します(SSM)。
    • MCAST_LEAVE_GROUP: マルチキャストグループから脱退します。
    • MCAST_LEAVE_SOURCE_GROUP: 特定のソースからのマルチキャストグループから脱退します(SSM)。
    • MCAST_UNBLOCK_SOURCE: 以前ブロックしたソースのマルチキャストトラフィックのブロックを解除します。
    • MCAST_UNDEFINED: 未定義のマルチキャストオプション。
  3. getsockoptおよびsetsockoptラッパー関数の追加: Goのsyscallパッケージは、C言語のgetsockoptおよびsetsockoptシステムコールをGoから呼び出すためのラッパー関数を提供します。このコミットでは、新しく定義されたGroupReqおよびGroupSourceReq構造体を受け渡しするための専用ラッパー関数が追加されました。

    • GetsockoptGroupReq, SetsockoptGroupReq: GroupReq構造体を使用するソケットオプションの取得/設定用。
    • GetsockoptGroupSourceReq, SetsockoptGroupSourceReq: GroupSourceReq構造体を使用するソケットオプションの取得/設定用。 これらの関数は、Goの型安全性を保ちつつ、C言語のシステムコールに適切なデータ構造を渡す役割を担います。特に、unsafe.Pointerを使用してGoの構造体とCの構造体間でポインタを変換し、_SocklenSizeof*定数を使用して適切なサイズ情報をシステムコールに渡しています。
  4. mkerrors.shの更新: mkerrors.shスクリプトは、Goのsyscallパッケージが使用する定数を自動生成するために使われます。このコミットでは、MCAST_プレフィックスを持つ新しい定数が正しく認識され、生成されるGoファイルに含まれるように、スクリプトの正規表現が更新されました。

これらの変更により、GoアプリケーションはFreeBSD上で、setsockopt関数と新しいMCAST_定数、そしてGroupReqGroupSourceReq構造体を組み合わせて使用することで、ソース固有マルチキャストの参加、脱退、ソースのブロック/アンブロックといった操作を直接行えるようになります。

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

このコミットにおける主要なコード変更は以下のファイルに集中しています。

  1. src/pkg/syscall/mkerrors.sh:

    • MCAST_プレフィックスを持つ定数を認識するための正規表現が追加されました。これにより、FreeBSDのシステムヘッダからSSM関連の定数が正しく抽出され、Goのzerrors_freebsd_*.goファイルに生成されるようになります。
    --- a/src/pkg/syscall/mkerrors.sh
    +++ b/src/pkg/syscall/mkerrors.sh
    @@ -266,7 +266,7 @@ ccflags="$@"
     		$2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ ||
     		$2 ~ /^IN_/ ||
     		$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
    -		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
    +		$2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR|MCAST)_/ ||
     		$2 == "ICMPV6_FILTER" ||
     		$2 == "SOMAXCONN" ||
     		$2 == "NAME_MAX" ||
    
  2. src/pkg/syscall/syscall_freebsd.go:

    • GetsockoptGroupReq, SetsockoptGroupReq, GetsockoptGroupSourceReq, SetsockoptGroupSourceReqという新しい関数が追加されました。これらは、それぞれGroupReqおよびGroupSourceReq構造体を使用して、FreeBSDのgetsockoptおよびsetsockoptシステムコールを呼び出すためのGoラッパーです。
    • 既存のSetsockoptIPMreqn関数の引数型が*IPMreqnからIPMreqnに変更され、unsafe.Sizeof(*mreq)SizeofIPMreqnに修正されました。
    --- a/src/pkg/syscall/syscall_freebsd.go
    +++ b/src/pkg/syscall/syscall_freebsd.go
    @@ -93,14 +93,36 @@ func Pipe(p []int) (err error) {
     }
     
     func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
    -	var value IPMreqn
    -	vallen := _Socklen(SizeofIPMreqn)
    -	errno := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
    -	return &value, errno
    +	var v IPMreqn
    +	l := _Socklen(SizeofIPMreqn)
    +	err := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)
    +	return &v, err
     }
     
    -func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
    -	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
    +func GetsockoptGroupReq(fd, level, opt int) (*GroupReq, error) {
    +	var v GroupReq
    +	l := _Socklen(SizeofGroupReq)
    +	err := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)
    +	return &v, err
    +}
    +
    +func GetsockoptGroupSourceReq(fd, level, opt int) (*GroupSourceReq, error) {
    +	var v GroupSourceReq
    +	l := _Socklen(SizeofGroupSourceReq)
    +	err := getsockopt(fd, level, opt, unsafe.Pointer(&v), &l)
    +	return &v, err
    +}
    +
    +func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) error {
    +	return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreqn)
    +}
    +
    +func SetsockoptGroupReq(fd, level, opt int, greq *GroupReq) error {
    +	return setsockopt(fd, level, opt, unsafe.Pointer(greq), SizeofGroupReq)
    +}
    +
    +func SetsockoptGroupSourceReq(fd, level, opt int, gsreq *GroupSourceReq) error {
    +	return setsockopt(fd, level, opt, unsafe.Pointer(gsreq), SizeofGroupSourceReq)
     }
     
     func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
    
  3. src/pkg/syscall/types_freebsd.go:

    • RawSockaddrStorage, GroupReq, GroupSourceReqという新しいGoの構造体型が追加されました。これらはC言語の対応する構造体(C.struct_sockaddr_storage, C.struct_group_req, C.struct_group_source_req)にマッピングされます。
    • これらの新しい構造体のサイズを定義する定数(SizeofSockaddrStorage, SizeofGroupReq, SizeofGroupSourceReq)も追加されました。
    --- a/src/pkg/syscall/types_freebsd.go
    +++ b/src/pkg/syscall/types_freebsd.go
    @@ -224,6 +224,8 @@ type RawSockaddr C.struct_sockaddr
     
     type RawSockaddrAny C.struct_sockaddr_any
     
    +type RawSockaddrStorage C.struct_sockaddr_storage
    +
     type _Socklen C.socklen_t
     
     type Linger C.struct_linger
    @@ -236,6 +238,10 @@ type IPMreqn C.struct_ip_mreqn
     
     type IPv6Mreq C.struct_ipv6_mreq
     
    +type GroupReq C.struct_group_req
    +
    +type GroupSourceReq C.struct_group_source_req
    +
     type Msghdr C.struct_msghdr
     
     type Cmsghdr C.struct_cmsghdr
    @@ -252,10 +258,13 @@ const (
     	SizeofSockaddrAny      = C.sizeof_struct_sockaddr_any
     	SizeofSockaddrUnix     = C.sizeof_struct_sockaddr_un
     	SizeofSockaddrDatalink = C.sizeof_struct_sockaddr_dl
    +	SizeofSockaddrStorage  = C.sizeof_struct_sockaddr_storage
     	SizeofLinger           = C.sizeof_struct_linger
     	SizeofIPMreq           = C.sizeof_struct_ip_mreq
     	SizeofIPMreqn          = C.sizeof_struct_ip_mreqn
     	SizeofIPv6Mreq         = C.sizeof_struct_ipv6_mreq
    +	SizeofGroupReq         = C.sizeof_struct_group_req
    +	SizeofGroupSourceReq   = C.sizeof_struct_group_source_req
     	SizeofMsghdr           = C.sizeof_struct_msghdr
     	SizeofCmsghdr          = C.sizeof_struct_cmsghdr
     	SizeofInet6Pktinfo     = C.sizeof_struct_in6_pktinfo
    
  4. src/pkg/syscall/zerrors_freebsd_386.go, src/pkg/syscall/zerrors_freebsd_amd64.go, src/pkg/syscall/zerrors_freebsd_arm.go:

    • 各アーキテクチャ(386, amd64, arm)向けの自動生成されたエラー定数ファイルに、MCAST_プレフィックスを持つ新しいソケットオプション定数が追加されました。これらの定数は、FreeBSDカーネルが提供するSSM関連のソケットオプションに対応します。
    --- a/src/pkg/syscall/zerrors_freebsd_386.go
    +++ b/src/pkg/syscall/zerrors_freebsd_386.go
    @@ -1022,6 +1022,15 @@ const (
      	MAP_RESERVED0100                  = 0x100
      	MAP_SHARED                        = 0x1
      	MAP_STACK                         = 0x400
    +	MCAST_BLOCK_SOURCE                = 0x54
    +	MCAST_EXCLUDE                     = 0x2
    +	MCAST_INCLUDE                     = 0x1
    +	MCAST_JOIN_GROUP                  = 0x50
    +	MCAST_JOIN_SOURCE_GROUP           = 0x52
    +	MCAST_LEAVE_GROUP                 = 0x51
    +	MCAST_LEAVE_SOURCE_GROUP          = 0x53
    +	MCAST_UNBLOCK_SOURCE              = 0x55
    +	MCAST_UNDEFINED                   = 0x0
      	MCL_CURRENT                       = 0x1
      	MCL_FUTURE                        = 0x2
      	MSG_CMSG_CLOEXEC                  = 0x40000
    

    (amd64とarmも同様の変更)

  5. src/pkg/syscall/ztypes_freebsd_386.go, src/pkg/syscall/ztypes_freebsd_amd64.go, src/pkg/syscall/ztypes_freebsd_arm.go:

    • 各アーキテクチャ向けの自動生成された型定義ファイルに、RawSockaddrStorage, GroupReq, GroupSourceReq構造体のGo表現が追加されました。また、これらの構造体のサイズを示す定数も更新されました。
    --- a/src/pkg/syscall/ztypes_freebsd_386.go
    +++ b/src/pkg/syscall/ztypes_freebsd_386.go
    @@ -183,6 +183,14 @@ type RawSockaddrAny struct {
      	Pad  [92]int8
      }
      
    +type RawSockaddrStorage struct {
    +	Len         uint8
    +	Family      uint8
    +	X__ss_pad1  [6]int8
    +	X__ss_align int64
    +	X__ss_pad2  [112]int8
    +}
    +
      type _Socklen uint32
      
      type Linger struct {
    @@ -211,6 +219,17 @@ type IPv6Mreq struct {
      	Interface uint32
      }
      
    +type GroupReq struct {
    +	Interface uint32
    +	Group     RawSockaddrStorage
    +}
    +
    +type GroupSourceReq struct {
    +	Interface uint32
    +	Group     RawSockaddrStorage
    +	Source    RawSockaddrStorage
    +}
    +
      type Msghdr struct {
      	Name       *byte
      	Namelen    uint32
    @@ -247,10 +266,13 @@ const (
      	SizeofSockaddrAny      = 0x6c
      	SizeofSockaddrUnix     = 0x6a
      	SizeofSockaddrDatalink = 0x36
    +	SizeofSockaddrStorage  = 0x80
      	SizeofLinger           = 0x8
      	SizeofIPMreq           = 0x8
      	SizeofIPMreqn          = 0xc
      	SizeofIPv6Mreq         = 0x14
    +	SizeofGroupReq         = 0x84
    +	SizeofGroupSourceReq   = 0x104
      	SizeofMsghdr           = 0x1c
      	SizeofCmsghdr          = 0xc
      	SizeofInet6Pktinfo     = 0x14
    

    (amd64とarmも同様の変更。ただし、Pad_cgo_0のようなアライメントのためのパディングバイトが追加されている場合がある。)

コアとなるコードの解説

src/pkg/syscall/syscall_freebsd.go の変更

このファイルでは、FreeBSD固有のシステムコールラッパーが定義されています。追加された関数は以下の通りです。

  • func GetsockoptGroupReq(fd, level, opt int) (*GroupReq, error)

    • ソケットディスクリプタfd、レベルlevel、オプション名optを指定して、GroupReq構造体に関連するソケットオプションの値を取得します。
    • GroupReqは、特定のマルチキャストグループに対する操作(例: MCAST_JOIN_GROUP)に使用される情報(インターフェースとグループアドレス)をカプセル化します。
    • getsockoptシステムコールを呼び出し、結果をGroupReqポインタとして返します。
  • func GetsockoptGroupSourceReq(fd, level, opt int) (*GroupSourceReq, error)

    • ソケットディスクリプタfd、レベルlevel、オプション名optを指定して、GroupSourceReq構造体に関連するソケットオプションの値を取得します。
    • GroupSourceReqは、ソース固有マルチキャスト操作(例: MCAST_JOIN_SOURCE_GROUP)に使用される情報(インターフェース、グループアドレス、ソースアドレス)をカプセル化します。
    • getsockoptシステムコールを呼び出し、結果をGroupSourceReqポインタとして返します。
  • func SetsockoptGroupReq(fd, level, opt int, greq *GroupReq) error

    • ソケットディスクリプタfd、レベルlevel、オプション名opt、そして設定するGroupReq構造体greqを指定して、ソケットオプションを設定します。
    • setsockoptシステムコールを呼び出し、エラーがあれば返します。
  • func SetsockoptGroupSourceReq(fd, level, opt int, gsreq *GroupSourceReq) error

    • ソケットディスクリプタfd、レベルlevel、オプション名opt、そして設定するGroupSourceReq構造体gsreqを指定して、ソケットオプションを設定します。
    • setsockoptシステムコールを呼び出し、エラーがあれば返します。

これらの関数は、GoのアプリケーションがFreeBSDのSSM機能を直接利用するための橋渡しとなります。

src/pkg/syscall/types_freebsd.go の変更

このファイルでは、FreeBSDのC言語の構造体に対応するGoの構造体型が定義されています。

  • type RawSockaddrStorage C.struct_sockaddr_storage

    • sockaddr_storageは、様々な種類のソケットアドレス(IPv4, IPv6など)を格納できる十分な大きさを持つ汎用的なバッファです。これにより、異なるアドレスファミリーのアドレスを統一的に扱うことができます。
  • type GroupReq C.struct_group_req

    • FreeBSDのgroup_req構造体に対応します。これは、特定のマルチキャストグループに対する操作(例: グループへの参加/脱退)に使用されます。
    • 内部には、インターフェースインデックスと、RawSockaddrStorage型のマルチキャストグループアドレスが含まれます。
  • type GroupSourceReq C.struct_group_source_req

    • FreeBSDのgroup_source_req構造体に対応します。これは、ソース固有マルチキャスト操作(例: 特定のソースからのグループ参加、ソースのブロック/アンブロック)に使用されます。
    • 内部には、インターフェースインデックス、RawSockaddrStorage型のマルチキャストグループアドレス、そしてRawSockaddrStorage型の送信元アドレスが含まれます。

これらの構造体は、GoプログラムがFreeBSDカーネルにマルチキャスト関連の情報を渡すためのデータコンテナとして機能します。

src/pkg/syscall/zerrors_freebsd_*.go および src/pkg/syscall/ztypes_freebsd_*.go の変更

これらのファイルは、mkerrors.shスクリプトによって自動生成されるファイルです。

  • zerrors_freebsd_*.go: FreeBSDのシステムヘッダから抽出された、MCAST_プレフィックスを持つ新しいソケットオプション定数(例: MCAST_JOIN_SOURCE_GROUP, MCAST_BLOCK_SOURCEなど)が追加されています。これらの定数は、setsockoptgetsockopt関数で使用され、実行したいマルチキャスト操作の種類を指定します。

  • ztypes_freebsd_*.go: RawSockaddrStorage, GroupReq, GroupSourceReqといった新しい構造体のGo表現と、それらのサイズを示す定数(例: SizeofSockaddrStorage, SizeofGroupReq, SizeofGroupSourceReq)が追加されています。これらのサイズ定数は、システムコールに渡すデータの長さを正確に指定するために重要です。

これらの自動生成ファイルは、GoのsyscallパッケージがFreeBSDの低レベルなネットワーク機能を正しく理解し、操作するために不可欠な要素です。

関連リンク

参考にした情報源リンク