【5G核心网】 free5gc Handover procedures切换流程源码分析
? ? 主要觸發過程如下:
? ? 1) UE 已經在 5G 注冊并建立一個 PDU 會話正在上網,并且通過源 gNB 接入到 5GC
? ? 2) UE 發生位置變換,離開源 gNB 服務區,即將進入新 gNB 服務區
? ? 3) UE 發送測量報告給源 gNB,gNB 根據測量報告,通過 N2 通知 S-AMF 發起切換流程?
結構體 HandoverRequiredIEsValue
type HandoverRequiredIEsValue struct {Present intAMFUENGAPID *AMFUENGAPID `aper:"referenceFieldValue:10"`RANUENGAPID *RANUENGAPID `aper:"referenceFieldValue:85"`HandoverType *HandoverType `aper:"referenceFieldValue:29"`Cause *Cause `aper:"referenceFieldValue:15,valueLB:0,valueUB:5"`TargetID *TargetID `aper:"referenceFieldValue:105,valueLB:0,valueUB:2"`DirectForwardingPathAvailability *DirectForwardingPathAvailability `aper:"referenceFieldValue:22"`PDUSessionResourceListHORqd *PDUSessionResourceListHORqd `aper:"referenceFieldValue:61"`SourceToTargetTransparentContainer *SourceToTargetTransparentContainer `aper:"referenceFieldValue:101"` }? ? ?結構體定義根據 TS 38413 9.2.3.1 定義
S-RAN-->S-AMF 9.2.3.1 HANDOVER REQUIREDR?
1.?Handover Required (S-RAN -> S-AMF)
? ??BuildHandoverRequired 創建 NGAP 消息,類型為?NGAPPDUPresentInitiatingMessage,ProcedureCode 設置為 ProcedureCodeHandoverPreparation,InitiatingMessagePresentHandoverRequired,包括的 IE 如下:
? ? -??AMF UE NGAP ID
? ? -??RAN UE NGAP ID
? ? -??Handover Type? (TS 38413 9.3.1.22)?Intra5GS, 5GStoEPS, EPSto5GS
? ? -? Cause? (TS 38413 9.3.1.2)
? ? -??Target ID(TS 38413 9.3.1.25)?
? ? -??Direct Forwarding Path Availability [optional]
? ? -??PDU Session Resource List
? ? -??Source to Target Transparent Container
NGAP?S-RAN -> S-AMF?Handover Required? ?1.1 AMF 處理 Handover Required 請求
func HandleHandoverRequired(ran *context.AmfRan, message *ngapType.NGAPPDU) {var aMFUENGAPID *ngapType.AMFUENGAPIDvar rANUENGAPID *ngapType.RANUENGAPIDvar handoverType *ngapType.HandoverTypevar cause *ngapType.Causevar targetID *ngapType.TargetIDvar pDUSessionResourceListHORqd *ngapType.PDUSessionResourceListHORqdvar sourceToTargetTransparentContainer *ngapType.SourceToTargetTransparentContainervar iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList? ? 根據目標 RAN 如果未緩存則需要(未實現),缺少 T-AMF 選擇
var aMFSelf = context.AMF_Self() targetRanNodeId := ngapConvert.RanIdToModels(targetID.TargetRANNodeID.GlobalRANNodeID) targetRan := aMFSelf.AmfRanFindByRanId(targetRanNodeId) if targetRan == nil {// handover between different AMFlogger.NgapLog.Warnf("Handover required : cannot find target Ran Node Id[%+v] in this AMF", targetRanNodeId)logger.NgapLog.Error("Handover between different AMF has not been implemented yet")return// TODO: Send to T-AMF// Described in (23.502 4.9.1.3.2) step 3.Namf_Communication_CreateUEContext Request}? ? 1.1.1?在同一個?AMF 切換
? ? 如果存在 PDU 會話則更新 SMF 會話上下文,BuildUpdateSmContextRequsetHandover 實例化 SmContextUpdateData,向 SMF 發送?Nsmf_PDUSession_UpdateSMContext 請求 (/sm-contexts/{smContextRef}/modify),結構體為?SmContextUpdateData
// Handover in same AMF sourceUe.HandOverType.Value = handoverType.Value tai := ngapConvert.TaiToModels(targetID.TargetRANNodeID.SelectedTAI) targetId := models.NgRanTargetId{RanNodeId: &targetRanNodeId,Tai: &tai, } var pduSessionReqList ngapType.PDUSessionResourceSetupListHOReq for _, pDUSessionResourceHoItem := range pDUSessionResourceListHORqd.List {pduSessionId := int32(pDUSessionResourceHoItem.PDUSessionID.Value)if smContext, exist := amfUe.SmContextList[pduSessionId]; exist {response, _, _, _ := consumer.SendUpdateSmContextN2HandoverPreparing(amfUe, pduSessionId, models.N2SmInfoType_HANDOVER_REQUIRED, pDUSessionResourceHoItem.HandoverRequiredTransfer, "", &targetId)if response == nil {logger.NgapLog.Errorf("SendUpdateSmContextN2HandoverPreparing Error for PduSessionId[%d]", pduSessionId)continue} else if response.BinaryDataN2SmInformation != nil {ngap_message.AppendPDUSessionResourceSetupListHOReq(&pduSessionReqList, pduSessionId, *smContext.PduSessionContext.SNssai, response.BinaryDataN2SmInformation)}}} Figure 5.2.2.3.4.2-1: N2 Handover Preparation? ? NF 服務通過發送 POST 請求 SMF 來準備切換 PDU 會話,使用如下信息:
? -? 將 SMF 中的各個 SM 上下文資源的 hoState 屬性更新為 PREPAREING;
? -? targetId,標識從源 NG-RAN 接收到的“需要切換”中接收到的目標 RAN 節點ID和TAI;
? -? targetServingNfId 設置為目標 AMF ID,以進行 AMF 更改的 N2 切換;
? -??從源 NG-RAN 接收到的 N2 SM 信息(請參閱3GPP TS 38.413 [9]的第9.3.4.14節中的“需要切換的傳輸IE”),指示直接路徑是否可用。
? -??其他信息(如有必要)。
AMF-->SMF??/sm-contexts/{smContextRef}/modify? ?1.2. SMF 處理上下文更新操作
? ??UpdateSmContext 函數設置消息類型為 PDUSessionSMContextUpdate,丟進隊列進行處理,定位到函數?HandlePDUSessionSMContextUpdate,根據 AMF 只設置 N2 信息,
func HandlePDUSessionSMContextUpdate(smContextRef string, body models.UpdateSmContextRequest) *http_wrapper.Response {//GSM State//PDU Session Modification Reject(Cause Value == 43 || Cause Value != 43)/Complete//PDU Session Release Command/Completelogger.PduSessLog.Infoln("In HandlePDUSessionSMContextUpdate")smContext := smf_context.GetSMContext(smContextRef)? ? 根據 N2SmInfoType 設置為 HANDOVER_REQUIRED,修改 SM 上下文狀態?ModificationPending
switch smContextUpdateData.N2SmInfoType { case models.N2SmInfoType_HANDOVER_REQUIRED:if smContext.SMContextState != smf_context.Active {//Wait till the state becomes Active again//TODO: implement sleep wait in concurrent architecturelogger.PduSessLog.Infoln("The SMContext State should be Active State")logger.PduSessLog.Infoln("SMContext state: ", smContext.SMContextState.String())}smContext.SMContextState = smf_context.ModificationPendinglogger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())response.JsonData.N2SmInfo = &models.RefToBinaryData{ContentId: "Handover"} }? ? 根據 hoState 為?HoState_PREPARING,設置 SMContextState 為 ModificationPending,設置 Response N2SmInfoType 為?N2SmInfoType_PDU_RES_SETUP_REQ
switch smContextUpdateData.HoState { case models.HoState_PREPARING:logger.PduSessLog.Traceln("In HoState_PREPARING")smContext.SMContextState = smf_context.ModificationPendinglogger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())smContext.HoState = models.HoState_PREPARINGif err := smf_context.HandleHandoverRequiredTransfer(body.BinaryDataN2SmInformation, smContext); err != nil {logger.PduSessLog.Errorf("Handle HandoverRequiredTransfer failed: %+v", err)}response.JsonData.N2SmInfoType = models.N2SmInfoType_PDU_RES_SETUP_REQ? ? 根據 SMContextState 為 ModificationPending 更新 Active 狀態,response 向 SMF 進行響應?
var httpResponse *http_wrapper.Response //Check FSM and take corresponding action switch smContext.SMContextState { case smf_context.ModificationPending:logger.CtxLog.Traceln("In case ModificationPending")smContext.SMContextState = smf_context.Activelogger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())httpResponse = &http_wrapper.Response{Status: http.StatusOK,Body: response,} SMF -> AMF, response SM Context Update2. Handover Request?
? ? 切換資源分配過程的目的是在目標 NG-RAN 節點上預留資源以用于 UE 的切換。AMF 在函數?HandleHandoverRequired 向 SMF 處理完所有 PDU 會話,發起 Handover Request 請求
/*The PGW-C+SMF (V-SMF in the case of home-routed roaming scenario only) sends a Nsmf_PDUSession_CreateSMContext Response(N2 SM Information (PDU Session ID, cause code)) to the AMF.*/ // Cause is from SMF // pduSessionResourceSetupList provided by AMF, and the transfer data is from SMF // sourceToTargetTransparentContainer is received from S-RAN // nsci: new security context indicator, if amfUe has updated security context, set nsci to true, otherwise set to false // N2 handover in same AMF func SendHandoverRequest(sourceUe *context.RanUe, targetRan *context.AmfRan, cause ngapType.Cause,pduSessionResourceSetupListHOReq ngapType.PDUSessionResourceSetupListHOReq,sourceToTargetTransparentContainer ngapType.SourceToTargetTransparentContainer, nsci bool) {ngaplog.Info("[AMF] Send Handover Request")? ? BuildHandoverRequest 函數創建 NGAP 消息,類型為?NGAPPDUPresentInitiatingMessage,ProcedureCode 設置為 ProcedureCodeHandoverResourceAllocation,InitiatingMessagePresentHandoverRequest
? ? AMF -> RAN 包括的信息:
? ? -??Source to Target transparent container
? ? -? N2?MM?Information? [?security information and Mobility?Restriction List ]
? ? -? N2?SM?Information list
? ? -? [ Tracing Requirements ]? ?
HandoverRequest HandoverRequest3. Handover Request Acknlowledge? ?
? ? NG-RAN -> AMF,創建 NGAP 消息類型為?NGAPPDUPresentSuccessfulOutcome,ProcedureCode 設置為?ProcedureCodeHandoverResourceAllocation,SuccessfulOutcomePresentHandoverRequestAcknowledge,包括 IE
? ? -??AMF UE NGAP ID
? ? -??RAN UE NGAP ID
? ? -??PDU Session Resource Admitted List
? ? -??PDU SessionResource Admittedy Item
? ? -??PDU Session Resource Failed to setup Item
? ? -??Target To Source TransparentContainer
? ??-??Criticality Diagnostics (optional)
HANDOVER REQUEST ACKNOWLEDGE Handpver Request Acknlowledge? ?3.1 AMF 處理?Handpver Request Acknlowledge
func HandleHandoverRequestAcknowledge(ran *context.AmfRan, message *ngapType.NGAPPDU) {var aMFUENGAPID *ngapType.AMFUENGAPIDvar rANUENGAPID *ngapType.RANUENGAPIDvar pDUSessionResourceAdmittedList *ngapType.PDUSessionResourceAdmittedListvar pDUSessionResourceFailedToSetupListHOAck *ngapType.PDUSessionResourceFailedToSetupListHOAckvar targetToSourceTransparentContainer *ngapType.TargetToSourceTransparentContainervar criticalityDiagnostics *ngapType.CriticalityDiagnosticsvar iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList PDUSessionResourceAdmittedList? ? 3.1.1?SendUpdateSmContextN2HandoverPrepared
? ? N2SmInfoType_HANDOVER_REQ_ACK,BuildUpdateSmContextRequsetHandover 函數創建更新數據,將 HoState 設置為?models.HoState_PREPARED,調用?Nsmf_PDUSession_UpdateSMContext?Request
Nsmf_PDUSession_UpdateSMContext? ?3.2 SMF 處理?Nsmf_PDUSession_UpdateSMContext
? ? N2 SM 信息類型為 HANDOVER_REQ_ACK,hoState 為 PREPARED
func HandlePDUSessionSMContextUpdate(smContextRef string, body models.UpdateSmContextRequest) *http_wrapper.Response {//GSM State//PDU Session Modification Reject(Cause Value == 43 || Cause Value != 43)/Complete//PDU Session Release Command/Completelogger.PduSessLog.Infoln("In HandlePDUSessionSMContextUpdate")smContext := smf_context.GetSMContext(smContextRef)? ? 3.2.1 處理 HoState 為 PREPARED
? ? HandleHandoverRequestAcknowledgeTransfer 函數根據 gTPTunnel 設置 GTP 添加信息,設置 response 的信息,N2 SM Info 類型設置為??HANDOVER_CMD,hoState 設置為 PREPARING
switch smContextUpdateData.HoState { case models.HoState_PREPARED:logger.PduSessLog.Traceln("In HoState_PREPARED")if smContext.SMContextState != smf_context.Active {//Wait till the state becomes Active again//TODO: implement sleep wait in concurrent architecturelogger.PduSessLog.Infoln("The SMContext State should be Active State")logger.PduSessLog.Infoln("SMContext state: ", smContext.SMContextState.String())}smContext.SMContextState = smf_context.ModificationPendinglogger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())smContext.HoState = models.HoState_PREPAREDresponse.JsonData.HoState = models.HoState_PREPAREDif err :=smf_context.HandleHandoverRequestAcknowledgeTransfer(body.BinaryDataN2SmInformation, smContext); err != nil {logger.PduSessLog.Errorf("Handle HandoverRequestAcknowledgeTransfer failed: %+v", err)}if n2Buf, err := smf_context.BuildHandoverCommandTransfer(smContext); err != nil {logger.PduSessLog.Errorf("Build PDUSession Resource Setup Request Transfer Error(%s)", err.Error())} else {response.BinaryDataN2SmInformation = n2Buf}response.JsonData.N2SmInfoType = models.N2SmInfoType_HANDOVER_CMDresponse.JsonData.N2SmInfo = &models.RefToBinaryData{ContentId: "HANDOVER_CMD",}response.JsonData.HoState = models.HoState_PREPARING? ? 3.2.2 根據 SMContextState 為?ModificationPending
? ? 根新狀態為 Active 向 SMF 響應
Nsmf_PDUSession_UpdateSMContext?Response4. Handover Command
? ? AMF 向 RAN 發送 Handover Command 請求,NGAP 消息類型為?NGAPPDUPresentSuccessfulOutcome,ProcedureCode 為?ProcedureCodeHandoverPreparation,包括的 IE?
? ? -??AMF?UE NGAP ID
? ? -??RAN?UE NGAP ID
? ? -??Handover Type
? ? -??PDU Session Resource Handover List
? ? -??Target to Source Transparent Container
Handover Command5. Handover Notify
? ??由 T-NG-RAN 發送的消息來通知 AMF UE 已經在目標小區標識,切換已經完成。NGAP 消息類型為?NGAPPDUPresentInitiatingMessage,ProcedureCode 設置為?ProcedureCodeHandoverNotification, InitiatingMessagePresentHandoverNotify,包括的 IE:
? ? -??AMF UE NGAP ID
? ? -??RAN UE NGAP ID
? ? -??User Location Information
NGAP Handover Notify? ? 5.1. AMF 處理 Handover Notification 消息
func HandleHandoverNotify(ran *context.AmfRan, message *ngapType.NGAPPDU) {var aMFUENGAPID *ngapType.AMFUENGAPIDvar rANUENGAPID *ngapType.RANUENGAPIDvar userLocationInformation *ngapType.UserLocationInformation? ? ?5.1.1 未實現步驟?6a.Namf_Communication_N2InfoNotify
amfUe := targetUe.AmfUe if amfUe == nil {Ngaplog.Error("AmfUe is nil")return } sourceUe := targetUe.SourceUe if sourceUe == nil {// TODO: Send to S-AMF// Desciibed in (23.502 4.9.1.3.3) [conditional] 6a.Namf_Communication_N2InfoNotify.Ngaplog.Error("N2 Handover between AMF has not been implemented yet") }? ?5.2 Handover notification 完成
? ? 對所有成功的 PDU 會話執行?SendUpdateSmContextN2HandoverComplete,BuildUpdateSmContextRequsetHandover 實例化 SmContextUpdateData,設置?HoState_COMPLETED
case UpdateSmContextPresentN2HandoverComplete:updateData.HoState = models.HoState_COMPLETEDif param.amfid != "" {updateData.ServingNfId = param.amfidupdateData.ServingNetwork = param.guami.PlmnIdupdateData.Guami = param.guami}if ladn, ok := context.LadnPool[smContext.PduSessionContext.Dnn]; ok {if amf_context.InTaiList(ue.Tai, ladn.TaiLists) {updateData.PresenceInLadn = models.PresenceState_IN_AREA} else {updateData.PresenceInLadn = models.PresenceState_OUT_OF_AREA}}? ??SendUpdateSmContextRequest 向 SMF 發送?Nsmf_PDUSession_UpdateSMContext (/sm-contexts/{smContextRef}/modify)? 向每一個 PDU 會話對應的 SMF 發送 Handover Complete 來指示 N2 切換成功
? ? 對應 Handover 執行階段步驟 7(T-AMF->SMF)
Nsmf_PDUSession_UpdateSMContext? ?5.3 SMF 處理?Nsmf_PDUSession_UpdateSMContext 請求
func HandlePDUSessionSMContextUpdate(smContextRef string, body models.UpdateSmContextRequest) *http_wrapper.Response {//GSM State//PDU Session Modification Reject(Cause Value == 43 || Cause Value != 43)/Complete//PDU Session Release Command/Completelogger.PduSessLog.Infoln("In HandlePDUSessionSMContextUpdate")smContext := smf_context.GetSMContext(smContextRef)? ? 5.3.1 根據 HoState 狀態為?HoState_COMPLETED
switch smContextUpdateData.HoState { case models.HoState_COMPLETED:logger.PduSessLog.Traceln("In HoState_COMPLETED")if smContext.SMContextState != smf_context.Active {//Wait till the state becomes Active again//TODO: implement sleep wait in concurrent architecturelogger.PduSessLog.Infoln("The SMContext State should be Active State")logger.PduSessLog.Infoln("SMContext state: ", smContext.SMContextState.String())}smContext.SMContextState = smf_context.ModificationPendinglogger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())smContext.HoState = models.HoState_COMPLETEDresponse.JsonData.HoState = models.HoState_COMPLETED }? ?5.4 S-AMF 向 S-RAN 發送 UE Context Release Command
UEContextReleaseCommand? ?5.5 S-RAN 向 S-AMF 發送 UEContextReleaseComplete
UEContextReleaseComplete? ? ?5.6 S-AMF 處理?UEContextReleaseComplete
func HandleUEContextReleaseComplete(ran *context.AmfRan, message *ngapType.NGAPPDU) {var aMFUENGAPID *ngapType.AMFUENGAPIDvar rANUENGAPID *ngapType.RANUENGAPIDvar userLocationInformation *ngapType.UserLocationInformationvar infoOnRecommendedCellsAndRANNodesForPaging *ngapType.InfoOnRecommendedCellsAndRANNodesForPagingvar pDUSessionResourceList *ngapType.PDUSessionResourceListCxtRelCplvar criticalityDiagnostics *ngapType.CriticalityDiagnostics? ? 5.6.1 向 SMF 發送 update SM Context
// for each pduSessionID invoke Nsmf_PDUSession_UpdateSMContext Request var cause context.CauseAll if tmp, exist := amfUe.ReleaseCause[ran.AnType]; exist {cause = *tmp } if amfUe.State[ran.AnType].Is(context.Registered) {Ngaplog.Info("[NGAP] Rel Ue Context in GMM-Registered")if pDUSessionResourceList != nil {for _, pduSessionReourceItem := range pDUSessionResourceList.List {pduSessionID := int32(pduSessionReourceItem.PDUSessionID.Value)response, _, _, err := consumer.SendUpdateSmContextDeactivateUpCnxState(amfUe, pduSessionID, cause)if err != nil {logger.NgapLog.Errorf("Send Update SmContextDeactivate UpCnxState Error[%s]", err.Error())} else if response == nil {logger.NgapLog.Errorln("Send Update SmContextDeactivate UpCnxState Error")}}} } Nsmf_PDUSession_UpdateSMContext? ?5.7 SMF 處理?update SM Context
? ? 向 UPF 發送 PFCP Session Modification Request, 釋放 N3,主要是關閉了 N3 轉發能力
switch smContextUpdateData.UpCnxState { case models.UpCnxState_DEACTIVATED:if smContext.SMContextState != smf_context.Active {//Wait till the state becomes Active again//TODO: implement sleep wait in concurrent architecturelogger.PduSessLog.Infoln("The SMContext State should be Active State")logger.PduSessLog.Infoln("SMContext state: ", smContext.SMContextState.String())}smContext.SMContextState = smf_context.ModificationPendinglogger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())response.JsonData.UpCnxState = models.UpCnxState_DEACTIVATEDsmContext.UpCnxState = body.JsonData.UpCnxStatesmContext.UeLocation = body.JsonData.UeLocationsmContext.PendingUPF = make(smf_context.PendingUPF)for _, dataPath := range smContext.Tunnel.DataPathPool {ANUPF := dataPath.FirstDPNodeDLPDR := ANUPF.DownLinkTunnel.PDRif DLPDR == nil {logger.PduSessLog.Errorf("AN Release Error")} else {DLPDR.FAR.State = smf_context.RULE_UPDATEDLPDR.FAR.ApplyAction.Forw = falseDLPDR.FAR.ApplyAction.Buff = trueDLPDR.FAR.ApplyAction.Nocp = truesmContext.PendingUPF[ANUPF.GetNodeIP()] = true}farList = append(farList, DLPDR.FAR)} PFCP Session Modification Request??
? 開始步驟 12 Registration Procedure
6. InitialUEMessage,Registration Request
InitialUEMessage,Registration Request?
? ? 之后按照注冊請求流程處理, 就不分析了,最后的 PFCP Session Mofidication Request,在把 N3 接上,開啟轉發 flag
?
總結
以上是生活随笔為你收集整理的【5G核心网】 free5gc Handover procedures切换流程源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我与世界杯足球那些事——世界杯征文
- 下一篇: 云架构师进阶攻略(1)