16
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

free5GCソースコード理解に向けた基礎知識

Last updated at Posted at 2022-03-11

What is free5GC

free5GCは、第5世代(5G)モバイルコアネットワーク向けのオープンソースプロジェクトです。
最終的な目標は、3GPPリリース15(R15)以降で定義されている5Gコアネットワーク(5GC)を実装することだそうです。

そもそも、5GCoreの特徴は?

5GCoreを構成する機能群NF(Network Function)は、以下の図のようになっています。
そして、free5GCでは、RAN、UEを除く基本ソフトウェアモジュールを提供するものだそうです。

5G system architecture.png

そして、5Gモバイル端末が、RANを経由して、5GCoreに登録する手順は、こんな感じのシーケンスになるようです。
3gpp_ts_23_501.png

5GCore動作を理解するには?

もちろん、実際に、free5GCが動作する環境を自前で準備して、色々と手元で動作を確認するのが早道だと思います。
そして、次のステップとしては、「どのようなfree5GCがメカニズムで動作しているのか?」を学習するのが王道でしょうか。
幸い、free5GCは、golangで実装されているので、ソースコードリーディングも行いやすいと思います。(UPFを除く)

free5GCのソースコードを理解するための事前知識

ここでは、UPFの話は、対象外とさせて頂きます。
free5GC動作については、基本的に、Webアプリ基盤をベースとした、マイクロサービス的なアプローチで各NF(Network Function)を構成しています。従って、「どのような条件で、NF(Network Function)が動作するのか?」を理解するのが、free5GCのソースコード理解の早道になるわけです。

free5GCの特徴1「OpenAPI活用」

5GCoreでのAPI仕様を、OpenAPIで定義されたドキュメントをベースとして、Webアプリ基盤をベースのコード実装を行なっています。
ちなみに、UDMモジュールが提供するサービスは、下表のように規定されています。
udm.png

例えば、5GCoreでのAPI仕様をYAMLファイルで定義したOpenAPIは、こちらのWebサイトで確認できます。

そして、Nudm_UECMサービスに関わるインタフェースは、こんな感じで確認できます。
swagger editor.png

free5GCのWebアプリ基盤では、OpenAPIとして定義されたYAMLファイルを活用したOpenAPI Generatorツールを活用しています。
従って、OpenAPI Generatorでのコード自動生成ツールを習熟しておくことが、free5GCのWebアプリ基盤の理解の助けになるはずです。

ちなみに、OpenAPI Generatorツールの使い方のサンプルは、こちらのリポジトリが参考になると思います。

free5GCの特徴2「独自FSMなステート管理」

5GCoreでのRegistration Procedureをもう一度再掲します。
3gpp_ts_23_501.png

5GCoreでのRegistration Procedureでの、技術サイト"RAN〜AMF間でのNASメッセージのやりとりについては5G NR SA Registration/Attach Call Flow"が参考になりました。

着目すべきポイントは、「AMFが、RANからNASメッセージを受信した時に、如何に適切な処理を実装するか?」になります。
free5GCでは、「独自FSMなステート管理」を実装することによって対応しているようです。
5G-Call-Flow.png

free5GCのfsmリポジトリがその役割を担うわけですが、その活用方法については、READMEファイル含め、何の情報も公開されていないので、free5GCのソースコードリーディングに向けた乗り越えるべき最大の課題だと思います。

free5GCでのfsm機構を理解する

ちなみに、free5GCでのfsm機構のスペックとしては、

  • STATE情報の状態遷移を定義して、SendEvent関数の発動条件と紐付けることができる
  • 状態遷移の保持状態に応じた、適切な挙動を定義できる
  • STATE情報の状態遷移には、SendEvent関数を使用する
  • RANから、NASメッセージを受信した時には、SendEvent関数を起動することによって、fsm機構を動作させる

free5GCの特徴2「独自FSMなステート管理」を理解するために、サンプルアプリを別途、準備して挙動を確認しました。

まず、やりたいことは、5GCoreでのRegistration Procedureにて、AMFが、以下の4つのNASメッセージを受信した場合に、AMF内部で保持しているSTATE情報に応じて、適切な挙動を行う仕組みを理解したいという点です。

  • [NAS-PDU: Registration request]
  • [NAS-PDU: Authentication Response]
  • [NAS-PDU: Security mode complete]
  • [NAS-PDU: Registration complete]

(1)STATE情報の状態遷移を定義して、SendEvent関数の発動条件と紐付ける

free5gc-fsm-sample/gmm/init.go
package gmm

import (
	"fmt"
	"github.com/free5gc/fsm"
	"github.com/ttsubo/free5gc-fsm-sample/context"
)

const (
	GmmMessageEvent          fsm.EventType = "Gmm Message"
	StartAuthEvent           fsm.EventType = "Start Authentication"
	AuthSuccessEvent         fsm.EventType = "Authentication Success"
	AuthRestartEvent         fsm.EventType = "Authentication Restart"
	SecurityModeSuccessEvent fsm.EventType = "SecurityMode Success"
	ContextSetupSuccessEvent fsm.EventType = "ContextSetup Success"
)

var transitions = fsm.Transitions{
	{Event: GmmMessageEvent, From: context.Deregistered, To: context.Deregistered},
	{Event: GmmMessageEvent, From: context.Authentication, To: context.Authentication},
	{Event: GmmMessageEvent, From: context.SecurityMode, To: context.SecurityMode},
	{Event: GmmMessageEvent, From: context.ContextSetup, To: context.ContextSetup},
	{Event: GmmMessageEvent, From: context.Registered, To: context.Registered},
	{Event: StartAuthEvent, From: context.Deregistered, To: context.Authentication},
	{Event: AuthSuccessEvent, From: context.Authentication, To: context.SecurityMode},
	{Event: SecurityModeSuccessEvent, From: context.SecurityMode, To: context.ContextSetup},
	{Event: ContextSetupSuccessEvent, From: context.ContextSetup, To: context.Registered},
}

var callbacks = fsm.Callbacks{
	context.Deregistered:   DeRegistered,
	context.Authentication: Authentication,
	context.SecurityMode:   SecurityMode,
	context.ContextSetup:   ContextSetup,
	context.Registered:     Registered,
}

var GmmFSM *fsm.FSM

func init() {
	if f, err := fsm.NewFSM(transitions, callbacks); err != nil {
		fmt.Printf("Initialize Gmm FSM Error: %+v", err)
	} else {
		GmmFSM = f
	}
}

(2)状態遷移の保持状態に応じた、適切な挙動を定義する

free5gc-fsm-sample/blob/main/gmm/sm.go
package gmm

import (
	"fmt"
	"github.com/free5gc/fsm"
)

func DeRegistered(state *fsm.State, event fsm.EventType, args fsm.ArgsType) {
	switch event {
	case fsm.EntryEvent:
		fmt.Printf("# Receiving Event: [%+v] on DeRegistered\n", event)
	case GmmMessageEvent:
		fmt.Printf("# Receiving Event: [%+v] on DeRegistered\n", event)
		fmt.Println("... Send Event: StartAuthEvent")
		GmmFSM.SendEvent(state, StartAuthEvent, fsm.ArgsType{})
	case StartAuthEvent:
		fmt.Printf("# Receiving Event: [%+v] on DeRegistered\n", event)
	case fsm.ExitEvent:
		fmt.Printf("# Receiving Event: [%+v] on DeRegistered\n", event)
	default:
		fmt.Println("Unknown event [%+v]", event)
	}
}

func Authentication(state *fsm.State, event fsm.EventType, args fsm.ArgsType) {
	switch event {
	case fsm.EntryEvent:
		fmt.Printf("## Receiving Event: [%+v] on Authentication\n", event)
		fallthrough
	case AuthRestartEvent:
		fmt.Printf("## (Receiving Event: AuthRestartEvent on Authentication)\n")
	case GmmMessageEvent:
		fmt.Printf("## Receiving Event: [%+v] on Authentication\n", event)
		fmt.Println("... Send Event: AuthSuccessEvent")
		GmmFSM.SendEvent(state, AuthSuccessEvent, fsm.ArgsType{})
	case AuthSuccessEvent:
		fmt.Printf("## Receiving Event: [%+v] on Authentication\n", event)
	case fsm.ExitEvent:
		fmt.Printf("## Receiving Event: [%+v] on Authentication\n", event)
	default:
		fmt.Println("Unknown event [%+v]", event)
	}
}

func SecurityMode(state *fsm.State, event fsm.EventType, args fsm.ArgsType) {
	switch event {
	case fsm.EntryEvent:
		fmt.Printf("### Receiving Event: [%+v] on SecurityMode\n", event)
	case GmmMessageEvent:
		fmt.Printf("### Receiving Event: [%+v] on SecurityMode\n", event)
		fmt.Println("... Send Event: SecurityModeSuccessEvent")
		GmmFSM.SendEvent(state, SecurityModeSuccessEvent, fsm.ArgsType{})
	case SecurityModeSuccessEvent:
		fmt.Printf("### Receiving Event: [%+v] on SecurityMode\n", event)
	case fsm.ExitEvent:
		fmt.Printf("### Receiving Event: [%+v] on SecurityMode\n", event)
	default:
		fmt.Println("Unknown event [%+v]", event)
	}
}

func ContextSetup(state *fsm.State, event fsm.EventType, args fsm.ArgsType) {
	switch event {
	case fsm.EntryEvent:
		fmt.Printf("#### Receiving Event: [%+v] on ContextSetup\n", event)
	case GmmMessageEvent:
		fmt.Printf("#### Receiving Event: [%+v] on ContextSetup\n", event)
		fmt.Println("... Send Event: ContextSetupSuccessEvent")
		GmmFSM.SendEvent(state, ContextSetupSuccessEvent, fsm.ArgsType{})
	case ContextSetupSuccessEvent:
		fmt.Printf("#### Receiving Event: [%+v] on ContextSetup\n", event)
	case fsm.ExitEvent:
		fmt.Printf("#### Receiving Event: [%+v] on ContextSetup\n", event)
	default:
		fmt.Printf("Unknown event [%+v]", event)
	}
}

func Registered(state *fsm.State, event fsm.EventType, args fsm.ArgsType) {
	switch event {
	case fsm.EntryEvent:
		fmt.Printf("##### Receiving Event: [%+v] on Registered\n", event)
	default:
		fmt.Printf("Unknown event [%+v]", event)
	}
}

(3)RANから、NASメッセージを受信した時には、SendEvent関数を起動することによって、fsm機構を動作させる

free5gc-fsm-sample/main.go
package main

import (
	"fmt"
	"github.com/free5gc/fsm"
	"github.com/ttsubo/free5gc-fsm-sample/context"
	"github.com/ttsubo/free5gc-fsm-sample/gmm"
	"time"
)

func main() {
	ue := context.NewDummyAmfUe()

	time.Sleep(2 * time.Second)
	fmt.Println("... Send Event: [GmmMessageEvent], after receiving [NAS-PDU: Registration request]")
	gmm.GmmFSM.SendEvent(ue.State, gmm.GmmMessageEvent, fsm.ArgsType{})
	fmt.Println("")

	time.Sleep(5 * time.Second)
	fmt.Println("... Send Event: [GmmMessageEvent], after receiving [NAS-PDU: Authentication Response]")
	gmm.GmmFSM.SendEvent(ue.State, gmm.GmmMessageEvent, fsm.ArgsType{})
	fmt.Println("")

	time.Sleep(5 * time.Second)
	fmt.Println("... Send Event: [GmmMessageEvent], after receiving [NAS-PDU: Security mode complete]")
	gmm.GmmFSM.SendEvent(ue.State, gmm.GmmMessageEvent, fsm.ArgsType{})
	fmt.Println("")

	time.Sleep(5 * time.Second)
	fmt.Println("... Send Event: [GmmMessageEvent], after receiving [NAS-PDU: Registration complete]")
	gmm.GmmFSM.SendEvent(ue.State, gmm.GmmMessageEvent, fsm.ArgsType{})
}

あと、状態管理を担うコンテキストも定義します

free5gc-fsm-sample/context/context.go
package context

import (
	"github.com/free5gc/fsm"
)

const (
	Deregistered            fsm.StateType = "Deregistered"
	DeregistrationInitiated fsm.StateType = "DeregistrationInitiated"
	Authentication          fsm.StateType = "Authentication"
	SecurityMode            fsm.StateType = "SecurityMode"
	ContextSetup            fsm.StateType = "ContextSetup"
	Registered              fsm.StateType = "Registered"
)

type DummyAmfUe struct {
	State *fsm.State
}

func (ue *DummyAmfUe) init() {
	ue.State = fsm.NewState(Deregistered)
}

func NewDummyAmfUe() *DummyAmfUe {
	ue := DummyAmfUe{}
	ue.init()
	return &ue
}

実際に、動かしてみる

コマンドの実行結果に基づき、サンプルアプリ実装をトレースすれば、fsm機構の習熟も可能だと思います。

% go run main.go
... Send Event: [GmmMessageEvent], after receiving [NAS-PDU: Registration request]
Receiving Event: [Gmm Message] on DeRegistered
... Send Event: StartAuthEvent
Receiving Event: [Exit event] on DeRegistered
Receiving Event: [Start Authentication] on DeRegistered
Receiving Event: [Entry event] on Authentication
(Receiving Event: AuthRestartEvent on Authentication)

... Send Event: [GmmMessageEvent], after receiving [NAS-PDU: Authentication Response]
Receiving Event: [Gmm Message] on Authentication
... Send Event: AuthSuccessEvent
Receiving Event: [Exit event] on Authentication
Receiving Event: [Authentication Success] on Authentication
Receiving Event: [Entry event] on SecurityMode

... Send Event: [GmmMessageEvent], after receiving [NAS-PDU: Security mode complete]
Receiving Event: [Gmm Message] on SecurityMode
... Send Event: SecurityModeSuccessEvent
Receiving Event: [Exit event] on SecurityMode
Receiving Event: [SecurityMode Success] on SecurityMode
Receiving Event: [Entry event] on ContextSetup

... Send Event: [GmmMessageEvent], after receiving [NAS-PDU: Registration complete]
Receiving Event: [Gmm Message] on ContextSetup
... Send Event: ContextSetupSuccessEvent
Receiving Event: [Exit event] on ContextSetup
Receiving Event: [ContextSetup Success] on ContextSetup
Receiving Event: [Entry event] on Registered

以上、free5GCのソースコードを理解するため、「どのようなfree5GCがメカニズムで動作しているのか?」の必要最低限なトピックを基礎知識としてまとめてみました。

16
10
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?