Skip to content
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

SMF check duplicated SMContext #34

Merged
merged 2 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions consumer/sm_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package consumer
import (
"context"
"fmt"
"regexp"

"github.com/pkg/errors"

Expand All @@ -12,9 +13,9 @@ import (
)

// SendSMPolicyAssociationCreate create the session management association to the PCF
func SendSMPolicyAssociationCreate(smContext *smf_context.SMContext) (*models.SmPolicyDecision, error) {
func SendSMPolicyAssociationCreate(smContext *smf_context.SMContext) (string, *models.SmPolicyDecision, error) {
if smContext.SMPolicyClient == nil {
return nil, errors.Errorf("smContext not selected PCF")
return "", nil, errors.Errorf("smContext not selected PCF")
}

smPolicyData := models.SmPolicyContextData{}
Expand All @@ -41,13 +42,43 @@ func SendSMPolicyAssociationCreate(smContext *smf_context.SMContext) (*models.Sm
}
smPolicyData.SuppFeat = "F"

var smPolicyID string
var smPolicyDecision *models.SmPolicyDecision
if smPolicyDecisionFromPCF, _, err := smContext.SMPolicyClient.
if smPolicyDecisionFromPCF, httpRsp, err := smContext.SMPolicyClient.
DefaultApi.SmPoliciesPost(context.Background(), smPolicyData); err != nil {
return nil, err
return "", nil, err
} else {
smPolicyDecision = &smPolicyDecisionFromPCF

loc := httpRsp.Header.Get("Location")
if smPolicyID = extractSMPolicyIDFromLocation(loc); len(smPolicyID) == 0 {
return "", nil, fmt.Errorf("SMPolicy ID parse failed")
}
}

return smPolicyID, smPolicyDecision, nil
}

var smPolicyRegexp = regexp.MustCompile(`http[s]?\://.*/npcf-smpolicycontrol/v\d+/sm-policies/(.*)`)

func extractSMPolicyIDFromLocation(location string) string {
match := smPolicyRegexp.FindStringSubmatch(location)
if len(match) > 1 {
return match[1]
}
// not match submatch
return ""
}

func SendSMPolicyAssociationTermination(smContext *smf_context.SMContext) error {
if smContext.SMPolicyClient == nil {
return errors.Errorf("smContext not selected PCF")
}

if _, err := smContext.SMPolicyClient.DefaultApi.SmPoliciesSmPolicyIdDeletePost(
context.Background(), smContext.SMPolicyID, models.SmPolicyDeleteData{}); err != nil {
return fmt.Errorf("SM Policy termination failed: %v", err)
}

return smPolicyDecision, nil
return nil
}
11 changes: 11 additions & 0 deletions context/sm_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ type SMContext struct {

DnnConfiguration models.DnnConfiguration

SMPolicyID string

// UP Security support TS 29.502 R16 6.1.6.2.39
UpSecurity *models.UpSecurity
MaximumDataRatePerUEForUserPlaneIntegrityProtectionForUpLink models.MaxIntegrityProtectedDataRate
Expand Down Expand Up @@ -131,6 +133,15 @@ func canonicalName(identifier string, pduSessID int32) (canonical string) {
return fmt.Sprintf("%s-%d", identifier, pduSessID)
}

func CheckDuplicate(createData *models.SmContextCreateData) (bool, *SMContext) {
if value, ok := canonicalRef.Load(canonicalName(createData.Supi, createData.PduSessionId)); ok {
smContext := GetSMContext(value.(string))
logger.CtxLog.Warningf("Duplicated SM Context: [%s]", value.(string))
return true, smContext
}
return false, nil
}

func ResolveRef(identifier string, pduSessID int32) (ref string, err error) {
if value, ok := canonicalRef.Load(canonicalName(identifier, pduSessID)); ok {
ref = value.(string)
Expand Down
80 changes: 79 additions & 1 deletion producer/pdu_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@ func HandlePDUSessionSMContextCreate(request models.PostSmContextsRequest) *http
return httpResponse
}

// Check duplicate SM Context
createData := request.JsonData
if check, duplicated_smContext := smf_context.CheckDuplicate(createData); check {
HandlePDUSessionSMContextLocalRelease(duplicated_smContext, createData)
}

smContext := smf_context.NewSMContext(createData.Supi, createData.PduSessionId)
smContext.SMContextState = smf_context.ActivePending
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())
Expand Down Expand Up @@ -152,7 +157,7 @@ func HandlePDUSessionSMContextCreate(request models.PostSmContextsRequest) *http
}

var smPolicyDecision *models.SmPolicyDecision
if smPolicyDecisionRsp, err := consumer.SendSMPolicyAssociationCreate(smContext); err != nil {
if smPolicyID, smPolicyDecisionRsp, err := consumer.SendSMPolicyAssociationCreate(smContext); err != nil {
openapiError := err.(openapi.GenericOpenAPIError)
problemDetails := openapiError.Model().(models.ProblemDetails)
logger.PduSessLog.Errorln("setup sm policy association failed:", err, problemDetails)
Expand All @@ -167,6 +172,7 @@ func HandlePDUSessionSMContextCreate(request models.PostSmContextsRequest) *http
}
} else {
smPolicyDecision = smPolicyDecisionRsp
smContext.SMPolicyID = smPolicyID
}

// dataPath selection
Expand Down Expand Up @@ -306,6 +312,16 @@ func HandlePDUSessionSMContextUpdate(smContextRef string, body models.UpdateSmCo
smContext.Supi, smContext.PDUSessionID, smContext.PDUAddress.String())
smf_context.GetUserPlaneInformation().ReleaseUEIP(smContext.SelectedUPF, smContext.PDUAddress)
}

// remove SM Policy Association
if smContext.SMPolicyID != "" {
if err := consumer.SendSMPolicyAssociationTermination(smContext); err != nil {
logger.PduSessLog.Errorf("SM Policy Termination failed: %s", err)
} else {
smContext.SMPolicyID = ""
}
}

if buf, err := smf_context.BuildGSMPDUSessionReleaseCommand(smContext); err != nil {
logger.PduSessLog.Errorf("Build GSM PDUSessionReleaseCommand failed: %+v", err)
} else {
Expand Down Expand Up @@ -809,6 +825,15 @@ func HandlePDUSessionSMContextRelease(smContextRef string, body models.ReleaseSm
smContext.SMLock.Lock()
defer smContext.SMLock.Unlock()

// remove SM Policy Association
if smContext.SMPolicyID != "" {
if err := consumer.SendSMPolicyAssociationTermination(smContext); err != nil {
logger.PduSessLog.Errorf("SM Policy Termination failed: %s", err)
} else {
smContext.SMPolicyID = ""
}
}

smContext.SMContextState = smf_context.PFCPModification
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())

Expand Down Expand Up @@ -886,6 +911,59 @@ func HandlePDUSessionSMContextRelease(smContextRef string, body models.ReleaseSm
return httpResponse
}

func HandlePDUSessionSMContextLocalRelease(smContext *smf_context.SMContext, createData *models.SmContextCreateData) {
smContext.SMLock.Lock()
defer smContext.SMLock.Unlock()

// remove SM Policy Association
if smContext.SMPolicyID != "" {
if err := consumer.SendSMPolicyAssociationTermination(smContext); err != nil {
logger.PduSessLog.Errorf("SM Policy Termination failed: %s", err)
} else {
smContext.SMPolicyID = ""
}
}

smContext.SMContextState = smf_context.PFCPModification
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())

releaseTunnel(smContext)

PFCPResponseStatus := <-smContext.SBIPFCPCommunicationChan
switch PFCPResponseStatus {
case smf_context.SessionReleaseSuccess:
logger.CtxLog.Traceln("In case SessionReleaseSuccess")
smContext.SMContextState = smf_context.InActivePending
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())
if createData.SmContextStatusUri != smContext.SmStatusNotifyUri {
problemDetails, err := consumer.SendSMContextStatusNotification(smContext.SmStatusNotifyUri)
if problemDetails != nil || err != nil {
if problemDetails != nil {
logger.PduSessLog.Warnf("Send SMContext Status Notification Problem[%+v]", problemDetails)
}

if err != nil {
logger.PduSessLog.Warnf("Send SMContext Status Notification Error[%v]", err)
}
} else {
logger.PduSessLog.Traceln("Send SMContext Status Notification successfully")
}
}
smf_context.RemoveSMContext(smContext.Ref)

case smf_context.SessionReleaseFailed:
logger.CtxLog.Traceln("In case SessionReleaseFailed")
smContext.SMContextState = smf_context.Active
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())

default:
logger.CtxLog.Warnf("The state shouldn't be [%s]\n", PFCPResponseStatus)
logger.CtxLog.Traceln("In case Unknown")
smContext.SMContextState = smf_context.Active
logger.CtxLog.Traceln("SMContextState Change State: ", smContext.SMContextState.String())
}
}

func releaseTunnel(smContext *smf_context.SMContext) {
deletedPFCPNode := make(map[string]bool)
smContext.PendingUPF = make(smf_context.PendingUPF)
Expand Down