【5G核心网】 free5gc Handover procedures切换流程源码分析

 

结构体 HandoverRequiredIEsValue

type HandoverRequiredIEsValue struct {
	Present                            int
	AMFUENGAPID                        *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 定义

IE/Group Name

Presence

Range

IE type and reference

Semantics description

Criticality

Assigned Criticality

Message Type

M

9.3.1.1

YES

reject

AMF UE NGAP ID

M

9.3.3.1

YES

reject

RAN UE NGAP ID

M

9.3.3.2

YES

reject

Handover Type

M

9.3.1.22

YES

reject

Cause

M

9.3.1.2

YES

ignore

Target ID

M

9.3.1.25

YES

reject

Direct Forwarding Path Availability

O

9.3.1.64

YES

ignore

PDU Session Resource List

1

YES

reject

>PDU Session Resource Item

1..<maxnoofPDUSessions>

-

>>PDU Session ID

M

9.3.1.50

-

>>Handover Required Transfer

M

OCTET STRING

Containing the Handover Required Transfer IE specified in subclause 9.3.4.14.

-

Source to Target Transparent Container

M

9.3.1.20

YES

reject

1. Handover Required (S-RAN -> S-AMF)

    BuildHandoverRequired 创建 NGAP 消息,类型为 NGAPPDUPresentInitiatingMessage,ProcedureCode 设置为 ProcedureCodeHandoverPreparationInitiatingMessagePresentHandoverRequired,包括的 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

   1.1 AMF 处理 Handover Required 请求

    根据目标 RAN 如果未缓存则需要(未实现),缺少 T-AMF 选择

var aMFSelf = context.AMF_Self()
targetRanNodeId := ngapConvert.RanIdToModels(targetID.TargetRANNodeID.GlobalRANNodeID)
targetRan := aMFSelf.AmfRanFindByRanId(targetRanNodeId)
if targetRan == nil {
	// handover between different AMF
	logger.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.2 在同一个 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)
		}
	}

}

   1.3. SMF 处理上下文更新操作

    UpdateSmContext 函数设置消息类型为 PDUSessionSMContextUpdate,丢进队列进行处理,定位到函数 HandlePDUSessionSMContextUpdate,根据 AMF 只设置 N2 信息,

{
    "hoState":"PREPARING",
    "n2SmInfo":{
        "contentId":"N2SmInfo"
    },
    "n2SmInfoType":"HANDOVER_REQUIRED",
    "targetId":{
        "ranNodeId":{
            "plmnId":{
                "mcc":"208",
                "mnc":"93"
            },
            "gNbId":{
                "bitLength":24,
                "gNBValue":"000102"
            }
        },
        "tai":{
            "plmnId":{
                "mcc":"208",
                "mnc":"93"
            },
            "tac":"303399"
        }
    }
}

    根据 hoState 为 HoState_PREPARING,设置 N2SmInfoType 为 N2SmInfoType_PDU_RES_SETUP_REQ

switch smContextUpdateData.HoState {
case models.HoState_PREPARING:
	smContext.HoState = models.HoState_PREPARING
	err = smf_context.HandleHandoverRequiredTransfer(body.BinaryDataN2SmInformation, smContext)
	response.JsonData.N2SmInfoType = models.N2SmInfoType_PDU_RES_SETUP_REQ

	n2Buf, err := smf_context.BuildPDUSessionResourceSetupRequestTransfer(smContext)
	if err != nil {
		logger.PduSessLog.Errorf("Build PDUSession Resource Setup Request Transfer Error(%s)", err.Error())
	}
	response.BinaryDataN2SmInformation = n2Buf
	response.JsonData.N2SmInfoType = models.N2SmInfoType_PDU_RES_SETUP_REQ
	response.JsonData.N2SmInfo = &models.RefToBinaryData{
		ContentId: "PDU_RES_SETUP_REQ",
	}
	response.JsonData.HoState = models.HoState_PREPARING

   1.3.1 SendPfcpSessionModificationRequest

     BuildPfcpSessionModificationRequest 实例化 PFCPSessionModificationRequest,包括 Update PDR, Update FAR,Update BAR,CP F-SEID,消息头类型设置为 PFCP_SESSION_MODIFICATION_REQUEST

    向 UPF 发送 N4 Session Modification Request

seqNum = getSeqNumber()
nodeIDtoIP := upNodeID.ResolveNodeIdToIp().String()
remoteSEID := ctx.PFCPContext[nodeIDtoIP].RemoteSEID
message := pfcp.Message{
	Header: pfcp.Header{
		Version:         pfcp.PfcpVersion,
		MP:              1,
		S:               pfcp.SEID_PRESENT,
		MessageType:     pfcp.PFCP_SESSION_MODIFICATION_REQUEST,
		SEID:            remoteSEID,
		SequenceNumber:  seqNum,
		MessagePriority: 12,
	},
	Body: pfcpMsg,
}

   1.3.2 UPF 处理 N4 Session Modification Request

Status UpfN4HandleSessionModificationRequest(UpfSession *session, PfcpXact *xact,
                                             PFCPSessionModificationRequest *request) {
    UTLT_Assert(session, return STATUS_ERROR, "Session error");
    UTLT_Assert(xact, return STATUS_ERROR, "xact error");

    Status status;
    PfcpHeader header;
    Bufblk *bufBlk;

    UpfN4HandleCreateFar

    UpfN4HandleCreatePdr

    响应消息 N4 Session Modification Response,设置头类型为 PFCP_SESSION_MODIFICATION_RESPONSE

    调用 UpfN4BuildSessionModificationResponse 向 SMF 回复请求,设置 cause 为 PFCP_CAUSE_REQUEST_ACCEPTED

   1.3.3 SMF 接收处理  N4 Session Modification Response

func HandlePfcpSessionModificationResponse(msg *pfcpUdp.Message) {
	pfcpRsp := msg.PfcpMessage.Body.(pfcp.PFCPSessionModificationResponse)

	SEID := msg.PfcpMessage.Header.SEID
	seqNum := msg.PfcpMessage.Header.SequenceNumber
	smContext := smf_context.GetSMContextBySEID(SEID)

    2.3.1如果 SMF 支持 ULCL 功能

    AddPDUSessionAnchorAndULCL (待分析)

if smf_context.SMF_Self().ULCLSupport && smContext.BPManager != nil {
	if smContext.BPManager.BPStatus == smf_context.AddingPSA {
		logger.PfcpLog.Infoln("Keep Adding PSAAndULCL")

		upfNodeID := smContext.GetNodeIDByLocalSEID(SEID)
		producer.AddPDUSessionAnchorAndULCL(smContext, upfNodeID)
	}
}

   

2. SendHandoverRequest (AMF 向 RAN 发送)

/*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")

    AMF -> RAN 包括的信息:

    -  Source to Target transparent container

    -  N2 MM Information  [ security information and Mobility Restriction List ]

    -  N2 SM Information list

    -  [ Tracing Requirements ]

    2.1 BuildHandoverRequest 实例化 NGAP 消息

    类型为 NGAPPDUPresentInitiatingMessage,ProcedureCode 设置为 ProcedureCodeHandoverResourceAllocation,InitiatingMessagePresentHandoverRequest

3. T-RAN 发送 Handover Request 确认消息

    创建 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)

4. AMF 处理 Handover Request 确认消息

func HandleHandoverRequestAcknowledge(ran *context.AmfRan, message *ngapType.NGAPPDU) {

	var aMFUENGAPID *ngapType.AMFUENGAPID
	var rANUENGAPID *ngapType.RANUENGAPID
	var pDUSessionResourceAdmittedList *ngapType.PDUSessionResourceAdmittedList
	var pDUSessionResourceFailedToSetupListHOAck *ngapType.PDUSessionResourceFailedToSetupListHOAck
	var targetToSourceTransparentContainer *ngapType.TargetToSourceTransparentContainer
	var criticalityDiagnostics *ngapType.CriticalityDiagnostics

    4.1 对于 pDUSessionResourceAdmittedList 不为空时

     SendUpdateSmContextN2HandoverPrepared 由 T-AMF 到 SMF (Nsmf_PDUSession_UpdateSMContext Request)

     BuildUpdateSmContextRequsetHandover 函数

case UpdateSmContextPresentN2HandoverPreparing:
	updateData.HoState = models.HoState_PREPARING
	updateData.TargetId = param.targetId
	// amf changed in same plmn
	if param.amfid != "" {
		updateData.TargetServingNfId = param.amfid
	}

    向 SMF 发送 Nsmf_PDUSession_UpdateSMContext (/sm-contexts/{smContextRef}/modify)

    又走 N4 接口 N4 Session Modification Request/Response 等(分析待定)

5. SendHandoverCommand 函数

    AMF 向 RAN 发送 Handover Command 请求,NGAP 消息类型为 NGAPPDUPresentSuccessfulOutcome,ProcedureCode 为 ProcedureCodeHandoverPreparation,包括的 IE 

    -  AMF UE NGAP ID

    -  RAN UE NGAP ID

    -  Handover Type

    -  NAS Security Parameters from NG-RAN [C-iftoEPS]

    -  PDU Session Resource Handover List

    -  PDU Session Resource to Release List

    -  Target to Source Transparent Container

6. RAN 发起 Handover Notification 到 AMF

    

    由 T-NG-RAN 发送的消息来通知 AMF UE 已经在目标小区标识,切换已经完成。NGAP 消息类型为 NGAPPDUPresentInitiatingMessage,ProcedureCode 设置为 ProcedureCodeHandoverNotification, InitiatingMessagePresentHandoverNotify,包括的 IE:

    -  AMF UE NGAP ID

    -  RAN UE NGAP ID

    -  User Location Information

7. AMF 处理 Handover Notification 消息

   7.1 如果 AMF 不存在 UE 情况

    未实现步骤 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")
} 

   7.2 Handover notification 完成

    对所有成功的 PDU 会话执行 SendUpdateSmContextN2HandoverComplete,BuildUpdateSmContextRequsetHandover 实例化 SmContextUpdateData,设置 HoState_COMPLETED

case UpdateSmContextPresentN2HandoverComplete:
	updateData.HoState = models.HoState_COMPLETED
	if param.amfid != "" {
		updateData.ServingNfId = param.amfid
		updateData.ServingNetwork = param.guami.PlmnId
		updateData.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)

8. SMF 处理 Nsmf_PDUSession_UpdateSMContext    

猜你喜欢

转载自blog.csdn.net/zhonglinzhang/article/details/107667475