Skip to content

Commit

Permalink
Feature/implicit deregistration (#107)
Browse files Browse the repository at this point in the history
* Add IE, universal time, in the configuration update command message:
* Add TimeZone field in the AMFContext.

* Fix bug: the format of time zone is wrong

* Modify BuildConfigurationUpdateCommand

* Update go module

* Complete the HTTPAmfHandleDeregistrationNotification
* It is a callback function for handling the Deregistration Notify from UDM.

* Modify RegistrationStatusUpdateProcedure:
* if amfue has completed UeCmRegisteration, RemoveAmfUe should be done in AmfHandleDeregistrationNotification.

* Modify RegistrationStatusUpdateProcedure:
* currently only consider the 3GPP access type

* Modify HTTPAmfHandleDeregistrationNotification:
* Use API to replace the duplicate code.
* Add BackupAmfInfo to the AmfUe structure for UeCmDeregistration.
* Expose the function "PurgeSubscriberData" from "gmm/common" package for purging the subscriber data with the specified access type.

* Modify HTTPAmfHandleDeregistrationNotification
* (R15) Old AMF always execute Nudm_SDM to unsubscribes with UDM. (don't consider access type)
* Old AMF will determine whether to execute Nudm_UECM de-registration with UDM based on the dereg cause.

* Modify HTTPAmfHandleDeregistrationNotification
* Old AMF will delete the AM policy with PCF

* Modify UeCmRegistration
* Modify DeregCallbackUri to differentiate the access type.
* Modify the file name for consistency.

* Modify HTTPHandleDeregistrationNotification
* Modify the structure of the handler function.
* Add query parameter to differential the deregistration type is implicit or explicit.

* Modify DeregistrationNotificationProcedure
- Remove the query parameter
- DeregistrationNotifcation and UECM_Deregistration are mutually exclusive

* Leave TODO comment about policy association termination.

---------

Co-authored-by: iamelisahi <[email protected]>
  • Loading branch information
YouShengLiu and iamelisahi authored Oct 28, 2023
1 parent ce9ce4e commit aebc9fc
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 11 deletions.
15 changes: 14 additions & 1 deletion internal/context/amf_ue.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ type AmfUe struct {
UdmGroupId string
SubscribedNssai []models.SubscribedSnssai
AccessAndMobilitySubscriptionData *models.AccessAndMobilitySubscriptionData
BackupAmfInfo []models.BackupAmfInfo
/* contex abut ausf */
AusfGroupId string
AusfId string
Expand Down Expand Up @@ -850,7 +851,6 @@ func (ue *AmfUe) CopyDataFromUeContextModel(ueContext models.UeContext) {
}

// SM Context realted function

func (ue *AmfUe) StoreSmContext(pduSessionID int32, smContext *SmContext) {
ue.SmContextList.Store(pduSessionID, smContext)
}
Expand All @@ -862,6 +862,19 @@ func (ue *AmfUe) SmContextFindByPDUSessionID(pduSessionID int32) (*SmContext, bo
return nil, false
}

func (ue *AmfUe) UpdateBackupAmfInfo(backupAmfInfo models.BackupAmfInfo) {
isExist := false
for _, amfInfo := range ue.BackupAmfInfo {
if amfInfo.BackupAmf == backupAmfInfo.BackupAmf {
isExist = true
break
}
}
if !isExist {
ue.BackupAmfInfo = append(ue.BackupAmfInfo, backupAmfInfo)
}
}

func (ue *AmfUe) StopT3513() {
if ue.T3513 == nil {
return
Expand Down
12 changes: 6 additions & 6 deletions internal/gmm/common/user_profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ func RemoveAmfUe(ue *context.AmfUe, notifyNF bool) {

func PurgeAmfUeSubscriberData(ue *context.AmfUe) {
if ue.RanUe[models.AccessType__3_GPP_ACCESS] != nil {
err := purgeSubscriberData(ue, models.AccessType__3_GPP_ACCESS)
err := PurgeSubscriberData(ue, models.AccessType__3_GPP_ACCESS)
if err != nil {
logger.GmmLog.Errorf("Purge subscriber data Error[%v]", err.Error())
}
}
if ue.RanUe[models.AccessType_NON_3_GPP_ACCESS] != nil {
err := purgeSubscriberData(ue, models.AccessType_NON_3_GPP_ACCESS)
err := PurgeSubscriberData(ue, models.AccessType_NON_3_GPP_ACCESS)
if err != nil {
logger.GmmLog.Errorf("Purge subscriber data Error[%v]", err.Error())
}
Expand All @@ -69,8 +69,8 @@ func AttachRanUeToAmfUeAndReleaseOldIfAny(ue *context.AmfUe, ranUe *context.RanU
ue.AttachRanUe(ranUe)
}

func purgeSubscriberData(ue *context.AmfUe, accessType models.AccessType) error {
logger.GmmLog.Debugln("purgeSubscriberData")
func PurgeSubscriberData(ue *context.AmfUe, accessType models.AccessType) error {
logger.GmmLog.Debugln("PurgeSubscriberData")

if !ue.ContextValid {
return nil
Expand All @@ -89,9 +89,9 @@ func purgeSubscriberData(ue *context.AmfUe, accessType models.AccessType) error
if ue.UeCmRegistered[accessType] {
problemDetails, err := consumer.UeCmDeregistration(ue, accessType)
if problemDetails != nil {
logger.GmmLog.Errorf("UECM_Registration Failed Problem[%+v]", problemDetails)
logger.GmmLog.Errorf("UECM Deregistration Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.GmmLog.Errorf("UECM_Registration Error[%+v]", err)
logger.GmmLog.Errorf("UECM Deregistration Error[%+v]", err)
}
ue.UeCmRegistered[accessType] = false
}
Expand Down
5 changes: 5 additions & 0 deletions internal/gmm/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,11 @@ func HandleInitialRegistration(ue *context.AmfUe, anType models.AccessType) erro
param.PreferredLocality = optional.NewString(amfSelf.Locality)
}

// TODO: (step 15) Should use PCF ID to select PCF
// Retrieve PCF ID from old AMF
// if ue.PcfId != "" {

// }
for {
resp, err := consumer.SendSearchNFInstances(amfSelf.NrfUri, models.NfType_PCF, models.NfType_AMF, &param)
if err != nil {
Expand Down
9 changes: 9 additions & 0 deletions internal/sbi/consumer/ue_context_management.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package consumer

import (
"context"
"fmt"

amf_context "github.com/free5gc/amf/internal/context"
"github.com/free5gc/amf/internal/logger"
"github.com/free5gc/amf/pkg/factory"
"github.com/free5gc/openapi"
"github.com/free5gc/openapi/Nudm_UEContextManagement"
"github.com/free5gc/openapi/models"
Expand All @@ -21,11 +23,18 @@ func UeCmRegistration(ue *amf_context.AmfUe, accessType models.AccessType, initi

switch accessType {
case models.AccessType__3_GPP_ACCESS:
deregCallbackUri := fmt.Sprintf("%s%s/deregistration/%s",
amfSelf.GetIPv4Uri(),
factory.AmfCallbackResUriPrefix,
ue.Supi,
)

registrationData := models.Amf3GppAccessRegistration{
AmfInstanceId: amfSelf.NfId,
InitialRegistrationInd: initialRegistrationInd,
Guami: &amfSelf.ServedGuamiList[0],
RatType: ue.RatType,
DeregCallbackUri: deregCallbackUri,
// TODO: not support Homogenous Support of IMS Voice over PS Sessions this stage
ImsVoPs: models.ImsVoPs_HOMOGENEOUS_NON_SUPPORT,
}
Expand Down
126 changes: 126 additions & 0 deletions internal/sbi/httpcallback/api_handle_dereg_notification.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package httpcallback

import (
"net/http"

"github.com/gin-gonic/gin"

amf_context "github.com/free5gc/amf/internal/context"
"github.com/free5gc/amf/internal/logger"
"github.com/free5gc/amf/internal/sbi/consumer"
"github.com/free5gc/openapi"
"github.com/free5gc/openapi/models"
)

func HTTPHandleDeregistrationNotification(c *gin.Context) {
// TS 23.502 - 4.2.2.2.2 - step 14d
logger.CallbackLog.Infoln("Handle Deregistration Notification")

var deregData models.DeregistrationData

requestBody, err := c.GetRawData()
if err != nil {
logger.CallbackLog.Errorf("Get Request Body error: %+v", err)
problemDetails := models.ProblemDetails{
Title: "System failure",
Status: http.StatusInternalServerError,
Detail: err.Error(),
Cause: "SYSTEM_FAILURE",
}
c.JSON(http.StatusInternalServerError, problemDetails)
return
}

err = openapi.Deserialize(&deregData, requestBody, "application/json")
if err != nil {
problemDetails := models.ProblemDetails{
Title: "Malformed request syntax",
Status: http.StatusBadRequest,
Detail: "[Request Body] " + err.Error(),
}
logger.CallbackLog.Errorln(problemDetails.Detail)
c.JSON(http.StatusBadRequest, problemDetails)
return
}

ueid := c.Param("ueid")
ue, ok := amf_context.GetSelf().AmfUeFindByUeContextID(ueid)
if !ok {
logger.CallbackLog.Errorf("AmfUe Context[%s] not found", ueid)
problemDetails := models.ProblemDetails{
Status: http.StatusNotFound,
Cause: "CONTEXT_NOT_FOUND",
}
c.JSON(http.StatusNotFound, problemDetails)
return
}

problemDetails, err := DeregistrationNotificationProcedure(ue, deregData)
if problemDetails != nil {
ue.GmmLog.Errorf("Deregistration Notification Procedure Failed Problem[%+v]", problemDetails)
} else if err != nil {
ue.GmmLog.Errorf("Deregistration Notification Procedure Error[%v]", err.Error())
}
// TS 23.503 - 5.3.2.3.2 UDM initiated NF Deregistration
// The AMF acknowledges the Nudm_UECM_DeRegistrationNotification to the UDM.
c.JSON(http.StatusNoContent, nil)
}

// TS 23.502 - 4.2.2.3.3 Network-initiated Deregistration
// The AMF can initiate this procedure for either explicit (e.g. by O&M intervention) or
// implicit (e.g. expiring of Implicit Deregistration timer)
func DeregistrationNotificationProcedure(ue *amf_context.AmfUe, deregData models.DeregistrationData) (
problemDetails *models.ProblemDetails, err error,
) {
// The AMF does not send the Deregistration Request message to the UE for Implicit Deregistration.
switch deregData.DeregReason {
case models.DeregistrationReason_UE_INITIAL_REGISTRATION:
// TS 23.502 - 4.2.2.2.2 General Registration
// Invokes the Nsmf_PDUSession_ReleaseSMContext for the corresponding access type
ue.SmContextList.Range(func(key, value interface{}) bool {
smContext := value.(*amf_context.SmContext)
if smContext.AccessType() == deregData.AccessType {
problemDetails, err = consumer.SendReleaseSmContextRequest(ue, smContext, nil, "", nil)
if problemDetails != nil {
ue.GmmLog.Errorf("Release SmContext Failed Problem[%+v]", problemDetails)
} else if err != nil {
ue.GmmLog.Errorf("Release SmContext Error[%v]", err.Error())
}
}
return true
})
}
// TS 23.502 - 4.2.2.2.2 General Registration - 14e
// TODO: (R16) If old AMF does not have UE context for another access type (i.e. non-3GPP access),
// the Old AMF unsubscribes with the UDM for subscription data using Nudm_SDM_unsubscribe
if ue.SdmSubscriptionId != "" {
problemDetails, err = consumer.SDMUnsubscribe(ue)
if problemDetails != nil {
logger.GmmLog.Errorf("SDM Unubscribe Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.GmmLog.Errorf("SDM Unubscribe Error[%+v]", err)
}
ue.SdmSubscriptionId = ""
}

// TS 23.502 - 4.2.2.2.2 General Registration - 20 AMF-Initiated Policy Association Termination
// For UE_INITIAL_REGISTRATION and SUBSCRIPTION_WITHDRAW, do AMF-Initiated Policy Association Termination directly.
if ue.PolicyAssociationId != "" {
// TODO: For REGISTRATION_AREA_CHANGE, old AMF performs an AMF-initiated Policy Association Termination
// procedure if the old AMF has established an AM Policy Association and a UE Policy Association with the PCF(s)
// and the old AMF did not transfer the PCF ID(s) to the new AMF. (Ref: TS 23.502 - 4.2.2.2.2)
// Currently, old AMF will transfer the PCF ID but new AMF will not utilize the PCF ID
problemDetails, err := consumer.AMPolicyControlDelete(ue)
if problemDetails != nil {
logger.GmmLog.Errorf("Delete AM policy Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.GmmLog.Errorf("Delete AM policy Error[%+v]", err)
}
}

// The old AMF should clean the UE context
// TODO: (R16) Only remove the target access UE context
ue.Remove()

return nil, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,11 @@ var routes = Routes{
"/n1-message-notify",
HTTPN1MessageNotify,
},

{
"HandleDeregistrationNotification",
strings.ToUpper("Post"),
"/deregistration/:ueid",
HTTPHandleDeregistrationNotification,
},
}
11 changes: 7 additions & 4 deletions internal/sbi/producer/ue_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,9 @@ func UEContextTransferProcedure(ueContextID string, ueContextTransferRequest mod
ue.Lock.Lock()
defer ue.Lock.Unlock()

ueContextTransferResponse := new(models.UeContextTransferResponse)
ueContextTransferResponse.JsonData = new(models.UeContextTransferRspData)
ueContextTransferResponse := &models.UeContextTransferResponse{
JsonData: new(models.UeContextTransferRspData),
}
ueContextTransferRspData := ueContextTransferResponse.JsonData

//if ue.GetAnType() != UeContextTransferReqData.AccessType {
Expand Down Expand Up @@ -603,8 +604,10 @@ func RegistrationStatusUpdateProcedure(ueContextID string, ueRegStatusUpdateReqD
logger.GmmLog.Errorf("AM Policy Control Delete Error[%v]", err.Error())
}
}

gmm_common.RemoveAmfUe(ue, false)
// TODO: Currently only consider the 3GPP access type
if !ue.UeCmRegistered[models.AccessType__3_GPP_ACCESS] {
gmm_common.RemoveAmfUe(ue, false)
}
} else {
// NOT_TRANSFERRED
logger.CommLog.Debug("[AMF] RegistrationStatusUpdate: NOT_TRANSFERRED")
Expand Down

0 comments on commit aebc9fc

Please sign in to comment.