本文分析 Free5GC Service request procedure 业务请求流程
1. UE Context Release Request (NG-RAN node initiated)UE上下文释放请求过程的目的是由于 NG-RAN 节点的原因,请求 AMF 释放与 UE 相关的逻辑 NG 连接。该过程使用 UE 相关的信令。UE 上下文释放请求消息应指示释放的适当原因值,例如“ TXnRELOCOverall Expiry”,“ Redirection”。
Figure 8.3.2.2-1: UE context release request
NGAP 消息, Present:NGAPPDUPresentInitiatingMessage,Procedure: ProcedureCodeUEContextReleaseRequest
UEContextReleaseRequest
NGAP.Dispatch
–> HandleUEContextReleaseRequest
如果 ue 在 AMF 状态是已经注册的, PDU 会话资源列表不空,则 SendUpdateSmContextDeactivateUpCnxState 更新上下文 Deactivate 状态
if amfUe.State[ran.AnType].Is(context.Registered) {
Ngaplog.Info("[NGAP] Ue Context in GMM-Registered")
if pDUSessionResourceList != nil {
for _, pduSessionReourceItem := range pDUSessionResourceList.List {
pduSessionID := int32(pduSessionReourceItem.PDUSessionID.Value)
response, _, _, err := consumer.SendUpdateSmContextDeactivateUpCnxState(amfUe, pduSessionID, causeAll)
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")
}
}
}
如果 ue 在 AMF 是未注册,则释放上下文
Ngaplog.Info("[NGAP] Ue Context in Non GMM-Registered")
for pduSessionId := range amfUe.SmContextList {
releaseData := consumer.BuildReleaseSmContextRequest(amfUe, &causeAll, "", nil)
detail, err := consumer.SendReleaseSmContextRequest(amfUe, pduSessionId, releaseData)
if err != nil {
logger.NgapLog.Errorf("Send ReleaseSmContextRequest Error[%s]", err.Error())
} else if detail != nil {
logger.NgapLog.Errorf("Send ReleaseSmContextRequeste Error[%s]", detail.Cause)
}
}
ngap_message.SendUEContextReleaseCommand(ranUe, context.UeContextReleaseUeContext, causeGroup, causeValue)
return
BuildUpdateSmContextRequest 函数更新 SmContextUpdateData,SMF API 为 /sm-contexts/{smContextRef}/modify
AMF->SMF 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/Complete
logger.PduSessLog.Infoln("In HandlePDUSessionSMContextUpdate")
smContext := smf_context.GetSMContext(smContextRef)
既不包含 N1 也不包含 N2 信息,简单多了,UpCnxState 为 Deactivated
case models.UpCnxState_DEACTIVATED:
if smContext.SMContextState != smf_context.Active {
//Wait till the state becomes Active again
//TODO: implement sleep wait in concurrent architecture
logger.PduSessLog.Infoln("The SMContext State should be Active State")
logger.PduSessLog.Infoln("SMContext state: ", smContext.SMContextState.String())
}
smContext.SMCOntextState= smf_context.ModificationPending
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())
response.JsonData.UpCnxState = models.UpCnxState_DEACTIVATED
smContext.UpCnxState = body.JsonData.UpCnxState
smContext.UeLocation = body.JsonData.UeLocation
// TODO: Deactivate N2 downlink tunnel
//Set FAR and An, N3 Release Info
farList = []*smf_context.FAR{}
smContext.PendingUPF = make(smf_context.PendingUPF)
for _, dataPath := range smContext.Tunnel.DataPathPool {
ANUPF := dataPath.FirstDPNode
DLPDR := ANUPF.DownLinkTunnel.PDR
if DLPDR == nil {
logger.PduSessLog.Errorf("AN Release Error")
} else {
DLPDR.FAR.State = smf_context.RULE_UPDATE
DLPDR.FAR.ApplyAction.Forw = false
DLPDR.FAR.ApplyAction.Buff = true
DLPDR.FAR.ApplyAction.Nocp = true
smContext.PendingUPF[ANUPF.GetNodeIP()] = true
}
farList = append(farList, DLPDR.FAR)
}
sendPFCPModification = true
smContext.SMCOntextState= smf_context.PFCPModification
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())
PFCP Session Modification Request
UEContextReleaseCommand
UEContextReleaseComplete
删除 UE 上下文
2. UE 发送 Service Request
Gmm 消息类型设置为 MsgTypeServiceRequest
NAS Table 8.2.16.1.1: SERVICE REQUEST message content
NGAP 消息设置 Present 为 NGAPPDUPresentInitiatingMessage,ProcedureCode 为 ProcedureCodeInitialUEMessage
InitialUEMEssage, Service request
3. AMF 处理 Service Requestfunc HandleInitialUEMessage(ran *context.AmfRan, message *ngapType.NGAPPDU) {
amfSelf := context.AMF_Self()
var rANUENGAPID *ngapType.RANUENGAPID
var nASPDU *ngapType.NASPDU
var userLocationInformation *ngapType.UserLocationInformation
var rRCEstablishmentCause *ngapType.RRCEstablishmentCause
var fiveGSTMSI *ngapType.FiveGSTMSI
// var aMFSetID *ngapType.AMFSetID
var uEContextRequest *ngapType.UEContextRequest
// var allowedNSSAI *ngapType.AllowedNSSAI
if ranUe == nil {
var err error
ranUe, err = ran.NewRanUe(rANUENGAPID.Value)
if err != nil {
logger.NgapLog.Errorf("NewRanUe Error: %+v", err)
}
Ngaplog.Debugf("New RanUe [RanUeNgapID: %d]", ranUe.RanUeNgapId)
if fiveGSTMSI != nil {
Ngaplog.Debug("Receive 5G-S-TMSI")
servedGuami := amfSelf.ServedGuamiList[0]
// TS 24501 5.6.1
func HandleServiceRequest(ue *context.AmfUe, anType models.AccessType,
serviceRequest *nasMessage.ServiceRequest) error {
logger.GmmLog.Info("Handle Service Reqeust")
if ue == nil {
return fmt.Errorf("AmfUe is nil")
}
util.StopT3513(ue)
util.StopT3565(ue)
SendUpdateSmContextActivateUpCnState 函数向 SMF 发送激活会话上下文请求
if serviceRequest.UplinkDataStatus != nil {
uplinkDataPsi := nasConvert.PSIToBooleanArray(serviceRequest.UplinkDataStatus.Buffer)
reactivatiOnResult= new([16]bool)
for pduSessionId, smContext := range ue.SmContextList {
if pduSessiOnId== targetPduSessionId {
continue
}
if uplinkDataPsi[pduSessionId] && smContext.PduSessionContext.AccessType == models.AccessType__3_GPP_ACCESS {
response, errRes, _, err := consumer.SendUpdateSmContextActivateUpCnxState(
ue, pduSessionId, models.AccessType__3_GPP_ACCESS)
AMF-SMF UpdateSmContextActivateUpCnState
5. SMF 处理函数 HandlePDUSessionSMContextUpdate
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/Complete
logger.PduSessLog.Infoln("In HandlePDUSessionSMContextUpdate")
smContext := smf_context.GetSMContext(smContextRef)
根据 N2 会话信息类型为 N2SmInfoType_PDU_RES_SETUP_RSP
switch smContextUpdateData.N2SmInfoType {
case models.N2SmInfoType_PDU_RES_SETUP_RSP:
if smContext.SMContextState != smf_context.Active {
//Wait till the state becomes Active again
//TODO: implement sleep wait in concurrent architecture
logger.PduSessLog.Infoln("The SMContext State should be Active State")
logger.PduSessLog.Infoln("SMContext state: ", smContext.SMContextState.String())
}
smContext.SMCOntextState= smf_context.ModificationPending
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())
pdrList = []*smf_context.PDR{}
farList = []*smf_context.FAR{}
SMF 向 UPF 发送 PFCP Session Modification Request 将 N3 RAN 与 UPF 建立 GTP 隧道
PFCP Session Modification Request
SMF->AMF response UpdateSmContextActivateUpCnState
6. AMF 发送 Service Accept
InitialContextSetupRequest,Service request
7. NGAP InitialContextSetupResponse
NGAP InitialContextSetupResponse
8. AMF 函数 HandleInitialContextSetupResponse
根据 PDU 会话资源列表更新发向 SMF,这里不分析了,还有 SMF 向 UPF 更新
if pDUSessionResourceSetupResponseList != nil {
Ngaplog.Trace("[NGAP] Send PDUSessionResourceSetupResponseTransfer to SMF")
for _, item := range pDUSessionResourceSetupResponseList.List {
pduSessionID := int32(item.PDUSessionID.Value)
transfer := item.PDUSessionResourceSetupResponseTransfer
// response, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, pduSessionID,
_, _, _, err := consumer.SendUpdateSmContextN2Info(amfUe, pduSessionID,
models.N2SmInfoType_PDU_RES_SETUP_RSP, transfer)
if err != nil {
Ngaplog.Errorf("SendUpdateSmContextN2Info[PDUSessionResourceSetupResponseTransfer] Error:\n%s", err.Error())
}
// RAN initiated QoS Flow Mobility in subclause 5.2.2.3.7
// if response != nil && response.BinaryDataN2SmInformation != nil {
// TODO: n2SmInfo send to RAN
// } else if respOnse== nil {
// TODO: error handling
// }
}
}