This the multi-page printable view of this section. Click here to print.
Blog
5GのOSSってどこまで使えるの?
はじめに
5Gあるいは5Gサービスと聞くとモバイルキャリアにより提供されるネットワークサービスで、大手ベンダ製品を使ってモバイルネットワークが構築されているイメージを持たれる方も多いのではないでしょうか。
最近では、5Gネットワークをオープンソースソフトウェア(以下、OSS)で実現する動きが出始めており、個人でも手軽に5G環境を構築することが可能となっています。
本記事では、5GのOSSについて紹介したいと思います。
そもそも、モバイルネットワークとは?
「端末 (User Equipment)」、「無線アクセスネットワーク (Radio Access Network) 」、「コアネットワーク (Core Network)」の3要素から構成される無線通信設備を指しています。
端末=スマホ、無線アクセスネットワーク=基地局、コアネットワーク=認証サーバやルータ等をイメージするとわかりやすいかと思います。
5GのOSSについて
5GのOSSについて、構成要素(UE/RAN/CN)ごとにそれぞれコミュニティがあり、開発が行われています。
RAN
代表的な、OpenAirInterfaceCとUERANSIMについて記載します。それ以外にも、srsRANやSD-RANe等のOSSがあります。
- OpenAirInterface Software Alliance(OSA)が提供する3GPPプロトコルに準拠した無線アクセスネットワーク系(eNB/gNB/UE)のソフトウェア
- 3GPP仕様に則り開発されているため、リファレンスコードとしても利用される
- オープンソースの5G端末(UE)や無線アクセスネットワーク(RAN)を実装
- 主にコアネットワークと接続するための上位レイヤーのプロトコル(NGAP,NASなど)が実装されている
CN
代表的な、free5GCとOpen5GSについて記載します。それ以外にも、magmaやSD-Core等、様々なOSSがあります。
- 3GPP Realse15に準拠したオープンソースソフトウェアの5Gコアであり、StandAlone(SA)構成に対応
- 様々なネットワークファンクションを実装(NRF/AMF/AUSF/SMF/PCF/UDM/UDR/NSSF/UPF/N3IWF)
- コミュニティの動きも活発で、「free5GC forum」も存在
- C言語で実装された、オープンソースソフトウェアの5Gコア及びEPC
- 3GPP Realse16に準拠し、StandAlone(SA)構成に対応
- OpenAirInterface Software Alliance(OSA)が提供する3GPPプロトコルに準拠したコアネットワーク系(EPC and 5G)のソフトウェア
- 3GPP仕様に則り開発されているため、リファレンスコードとしても利用される
- 新興国にコネクティビティを届けることを目的に開発が始まったOSS。EPCの機能(A-GW)だけではなく集中管理機能(Orchestrator)やMNOとの連携機能(F-GW)を有する。
- 5Gコアについては、Telecom Infra Projectと連携して最小構成版Minimum Viable Core(MVC版)を開発中。
5GのOSSってどこまで使えるの?
5GのOSSも様々なコミュニティで開発が進んでいる状況で、群雄割拠の状態です。 OSS実装の完成度や、特徴について、free5GCを例に記載します。
- 小規模に実証実験を行うレベルまでは、5GコアのOSSも成長してきており、5G特有の機能・実装も進んでいます。
- 構築も簡単で導入しやすいのですが、商用を見据えると、性能面や運用面でまだまだ課題が残る状況です。
5GのOSS関連で困ったことがあったら
モバイルネットワークに関連するOSSの開発者・ユーザ同士で情報交換や新たな繋がりを形成する場として、Open Mobile Network Infra Communityを活用してみてはいかがでしょうか。
過去のMeetupやHands-onについてもYouTubeにて公開しております。 イベントの様子がわかると思いますので、ぜひご覧ください。
https://www.youtube.com/channel/UCnZp6DJTQQfoT6rLt8CBz5g
また、情報交換の場としてOpen Mobile Network Infra CommunityのSlackワークスペースも用意しています。
https://join.slack.com/t/omni-jp/shared_invite/zt-nrwl8rw3-gZIS1FckzeQ2efagTrWUpA
これまでの活動成果は以下のgithubにまとめております。ぜひご覧ください。
最後に
5GのOSSにより、モバイルネットワークを自営でかつ簡単に構築可能になりつつあります。 この機会にお手元のPCで5G環境を構築してみてはいかがでしょうか?
UEのIPアドレスの割り当て -- free5GC編 --
はじめに
5GではUEのIPアドレスは、どのような仕組みで割り当てられるのでしょうか? 5GCがDHCPサーバーの機能を保有しているのでしょうか? はたまた、5GCとは別にRADIUSサーバーが存在しており、5GCとRADIUSサーバーが連携することでIPアドレスが割り当てられるのでしょうか?
UEのIPアドレスの割り当てについて、free5GCではどのように実現しているのか解説したいと思います。
5Gの規格ではどうなっているのか?
TS 23.501の5.8.2.2 UE IP Address Managementで詳細な仕様が述べられていますが、ざっくりまとめると以下の仕様になっています。
- NGAP/NASを通してUEとSMFの間でPDU Session Typeがやりとりされる。
- PDU Session TypeによってIPv4かIPv6か決まる。
- IPアドレスの割り当ては大きくわけて2種類ある。
- PDU Session確立後にDHCPもしくはDN-AAAを利用してIPアドレスの割り当てを行う。
- PDU Sessionの確立中にSMFがSM NAS Signalingを介してUEのIPアドレスを送信する。
DHCPやDN-AAA以外にもSMFが割り当てるという仕様も存在することがわかりました。 では実際にfree5GCではどのような実装になっているのか追ってみたいと思います。
パケットキャプチャで確認
UERANSIMとfree5GCで簡単な構成を組んでパケットをキャプチャして確認してみます。
DHCPやDN-AAAであれば、N3のU-Plane側でそれぞれのプロトコルのやりとりがあるはずです。 一方で、SMFが割り当てる方式であればSM NAS Signalingの中にUEのIPアドレスが入っていることが確認できるはずです。
N3のU-Plane側のキャプチャを見てみましょう。
UEのIPアドレスが確定した状態のパケットしかありません。
今度はN1/N2のC-Plane側のキャプチャを見てみましょう。
UEからのPDU Session Establish requestに対する応答で、NASの中にPDU Addressフィールドがあり、そこにUEのIPアドレスが入っていることが確認できます。
free5GCではDHCP/DN-AAAではなくSMFがUEのIPアドレスを割り当てる実装になっていることがわかりました。
SMFの実装を追ってみる
SMFのディレクトリを探索してみましょう。
※ 執筆時点ではSMF v1.0.0をベースにしています。
github.com/free5gc/smf/
+- context/
+- ip_allocator.go
contextディレクトリ配下にip_allocator.goという、そのものズバリなソースコードがありますね。まずは構造体を見てみましょう。
type IPAllocator struct {
ipNetwork *net.IPNet
g *_IDPool
}
いかにもIPアドレスを割り当てそうな名前の構造体です。 メンバーとしてipNetworkという名前のネットワークアドレスとgという名前のIPアドレスのプールらしきものを保有しています。 この構造体を使って割り当てを行っていると考えて間違いないでしょう。
ネットワークアドレスはわかるとして、この_IDPoolとは具体的になにものなのか見てみましょう。
type _IDPool struct {
minValue int64
maxValue int64
isUsed map[int64]bool
}
ふむふむ。最大値と最小値らしきものを保有してますね。 他にもisUsedというboolean型のマップも持っています。これはIPアドレスが実際に使用されているかどうかを判定するためのものでしょうか。 それにしても不思議です。IPアドレスを表現する型であれば4byteか16byteのbyte列となるはずです。しかし、なぜかint64になっています。
int64の謎は後で詳しく調べることにして、この_IDPoolのメソッドを見てみましょう。
func (i *_IDPool) allocate() (id int64, err error) {
for id := i.minValue; id <= i.maxValue; id++ {
if _, exist := i.isUsed[id]; !exist {
i.isUsed[id] = true
return id, nil
}
}
return 0, errors.New("No available value range to allocate id")
}
func (i *_IDPool) release(id int64) {
delete(i.isUsed, id)
}
このメソッドからわかることは、allocate()を呼び出すとint64の型の値が返ってくる。そしてallocate()で割り当てられたidをrelease()に渡して呼び出すときっとプールに戻してくれる(はず)。
そして、構造体のメンバーから察すると、minValue以上、maxValue未満の範囲でint64のidを割り当ててくれる。割り当ては常にminValueから順番に探索していき、使用していない最も小さい値を返す。 要らなくなったidをreleaseに渡すとプールに戻してくれて再利用可能な状態にしてくれる。
こんなところでしょうか。
ざっくりした割り当ての方法はここで実装されていそうです。しかしint64という型のままだとIPv4の場合はまだおさまるとして、IPv6の時には困りますね。 このあたりの型変換部分はきっとIPAllocator側でなんとかしているに違いありません。 見てみましょう。
func NewIPAllocator(cidr string) (*IPAllocator, error) {
allocator := &IPAllocator{}
if _, ipnet, err := net.ParseCIDR(cidr); err != nil {
return nil, err
} else {
allocator.ipNetwork = ipnet
}
allocator.g = newIDPool(1, 1<<int64(32-maskBits(allocator.ipNetwork.Mask))-2)
return allocator, nil
}
newIDPoolの引数がめちゃくちゃ怪しいですね。 第一引数がminで第二引数がmaxです。 minに1を指定しているのはいいとして、maxに指定しているのはなんでしょうか。 ネットワークアドレスのマスク値から算出しているようです。 よくみると、これはホストアドレス部分のmax値を最大でも32bitとしてint64の型にしているようです。 IPv6であってもどうやらIPv4と同じ範囲しか割り当てできなさそうな気配ですね。
IPv6の場合は見なかったことにして(え?)、アロケータの初期化の部分で無理やりint64の範囲におさまるようにしていることがわかりました。
ネットワークアドレスはどこで指定しているかというと、smfcfg.yamlの中の以下の>>>
の部分です。
userplane_information: # list of userplane information
up_nodes: # information of userplane node (AN or UPF)
gNB1: # the name of the node
type: AN # the type of the node (AN or UPF)
UPF: # the name of the node
type: UPF # the type of the node (AN or UPF)
node_id: 127.0.0.8 # the IP/FQDN of N4 interface on this UPF (PFCP)
sNssaiUpfInfos: # S-NSSAI information list for this UPF
- sNssai: # S-NSSAI (Single Network Slice Selection Assistance Information)
sst: 1 # Slice/Service Type (uinteger, range: 0~255)
sd: 010203 # Slice Differentiator (3 bytes hex string, range: 000000~FFFFFF)
dnnUpfInfoList: # DNN information list for this S-NSSAI
- dnn: internet
pools:
>>> - cidr: 60.60.0.0/16
まとめ
- free5GCでは、DHCPでもRADIUSサーバーでもなく、SMFが独自の方式でUEのIPアドレスの割り当てを行っている。
- free5GCのSMFのIPアドレス割り当ての実装では、IPアドレスプールの中で最も小さい値が割り当てられるようになっている。
おまけ
私(hirono)だったらisUsedのマップじゃなくてfreeリスト方式にします。 そうすれば割り当ての計算量もO(1)で済みますし解放もO(1)で済みます。
例えばこんな感じです。 https://gist.github.com/khirono/3c7b80e10e309006c4a0ec890b13dbc5
int64をやめて[]byteにするとかまだまだ改善の余地はあります。
Test
BLOG TEST
- list