-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/implicit deregistration #107
Changes from all commits
375383a
0bc5ed3
0299827
f99bc6d
77cd10c
a765317
05b0cef
8ae1897
bde9459
2c3ff59
39ecf3d
d36f9e6
d713f96
d1b9609
6b1b1ad
e832b89
281fb39
db09490
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 != "" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ianchen0119 check udm implementation to make sure old amf will not unsubscribe new amf's subscription |
||
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 != "" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ianchen0119 check pcf implementation to make sure old amf will not unsubscribe new amf's ampolicy association |
||
// 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) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Original RemoveAmfUe at dereg when notifyNf is true also considers AMPolicyControlDelete. Should AMPolicyControlDelete be included here according to TS 23.502 4.2.2.2.2 14d? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't find the description in R15 - TS 23.502 - 4.2.2.2.2 - 14d and I am not sure if we need to delete AmPolicy here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I think that's step 20. in R15.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For UE_INITIAL_REGISTRATION and SUBSCRIPTION_WITHDRAW, it is fine to do AMF-Initiated Policy Association Termination directly. However, if it is REGISTRATION_AREA_CHANGE, it is possible that the new AMF reuses the associated PCF ID, which hence should not be terminated.
R16 has clearer instructions:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree with that, however, free5GC currently doesn't utilize the PCF ID to select the PCF, therefore, I leave the TODO comments for it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is fine to leave for a new PR. Lastly, please help to change the TODO comments (
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK |
||
|
||
// 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 |
---|---|---|
|
@@ -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 { | ||
|
@@ -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] { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will 3gpp and non-3gpp have different behavior here? I think a better implementation here is to remove the context according to different access type (which is specified during context transfer procedure), but I understand it seems that currently we can only remove the complete AmfUe context (3gpp+non-3gpp). In this case, I don't quite understand why non-3gpp is excluded here😂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because we are not sure how to deal with the non-3GPP case, we temporarily considered the 3GPP case. |
||
gmm_common.RemoveAmfUe(ue, false) | ||
} | ||
} else { | ||
// NOT_TRANSFERRED | ||
logger.CommLog.Debug("[AMF] RegistrationStatusUpdate: NOT_TRANSFERRED") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SendReleaseSmContextRequest()
needs to read the attribute of theue
, it will occur the concurrent read/write if another ngap/nas message for the same ue is sent to AMF.Please help to check do we need a mutex lock here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moreover, it seems like the behavior of AMF in this case is the same with
gmm_common.RemoveAmfUe(amfUe, false)
.@iamelisahi @YouShengLiu
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SendReleaseSmContextRequest()
will only use the ue.TimeZone and smContext.Since the smContext is stored in ue.SmContextList and protected under the sync.Map, we can leave it alone.
However, the ue.TimeZone is not protected, it may need mutex lock to protect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is very similar but there are still some differences.
According to the TS 29.503 - Table 6.2.6.2.7-1: Definition of type Amf3GppAccessRegistrationModification - backupAmfInfo:
We think we should provide the BackupAmfInfo but the
UeCmDeregistration()
didn't.Should we need to modify
UeCmDeregistration()
, e.g. add one more parameter to decide if it needs to put the BackupAmfInfo into Amf3GppAccessRegistrationModification?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@YouShengLiu
Is it possible to reuse the duplicated part?
I think you are right, please help to fill the BackupAmfInfo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does spec mention to use old amf as the backup amf? I think it's strange to notify UDM that the backup amf of e.g. amf1 is amf1 itself😂 Backup AMF may be a pre-config field to this AMF's config in my opnion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spec didn't mention using old AMF as the backup AMF directly. I was thinking that the old AMF could be one of the backup AMFs when the new AMF is serving the UE.
I checked the data stored in the database, the serving AMF was the new AMF, and the old AMF became the backup AMF:
I agree that using pre-config is a better solution.