Skip to content

Commit

Permalink
Add support for SDM Subscription and Unsubscription
Browse files Browse the repository at this point in the history
Code refactoring to move all SDM Handling in one place
  • Loading branch information
saileshvvr authored and andy89923 committed Feb 20, 2024
1 parent 9600d25 commit 615531c
Show file tree
Hide file tree
Showing 5 changed files with 318 additions and 44 deletions.
4 changes: 4 additions & 0 deletions internal/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ type SMFContext struct {
UEPreConfigPathPool map[string]*UEPreConfigPaths
UEDefaultPathPool map[string]*UEDefaultPaths
LocalSEIDCount uint64

Ues *Ues
}

func ResolveIP(host string) net.IP {
Expand Down Expand Up @@ -244,6 +246,8 @@ func InitSmfContext(config *factory.Config) {
SetupNFProfile(config)

smfContext.Locality = configuration.Locality

smfContext.Ues = InitSmfUeData()
}

func InitSMFUERouting(routingConfig *factory.RoutingConfig) {
Expand Down
100 changes: 100 additions & 0 deletions internal/context/sm_ue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package context

import "sync"

type UeData struct {
PduSessionCount int // store number of PDU Sessions for each UE
SdmSubscriptionId string // store SDM Subscription ID per UE
}

type Ues struct {
ues map[string]UeData // map to store UE data with SUPI as key
mu sync.Mutex // mutex for concurrent access
}

func InitSmfUeData() *Ues {
return &Ues{
ues: make(map[string]UeData),
}
}

// IncrementPduSessionCount increments the PDU session count for a given UE.
func (u *Ues) IncrementPduSessionCount(ueId string) {
u.mu.Lock()
defer u.mu.Unlock()

ueData := u.ues[ueId]
ueData.PduSessionCount++
u.ues[ueId] = ueData
}

// DecrementPduSessionCount decrements the PDU session count for a given UE.
func (u *Ues) DecrementPduSessionCount(ueId string) {
u.mu.Lock()
defer u.mu.Unlock()

ueData := u.ues[ueId]
if ueData.PduSessionCount > 0 {
ueData.PduSessionCount--
u.ues[ueId] = ueData
}
}

// SetSubscriptionId sets the SDM subscription ID for a given UE.
func (u *Ues) SetSubscriptionId(ueId, subscriptionId string) {
u.mu.Lock()
defer u.mu.Unlock()

ueData := u.ues[ueId]
ueData.SdmSubscriptionId = subscriptionId
u.ues[ueId] = ueData
}

// GetSubscriptionId returns the SDM subscription ID for a given UE.
func (u *Ues) GetSubscriptionId(ueId string) string {
u.mu.Lock()
defer u.mu.Unlock()

return u.ues[ueId].SdmSubscriptionId
}

// GetUeData returns the data for a given UE.
func (u *Ues) GetUeData(ueId string) UeData {
u.mu.Lock()
defer u.mu.Unlock()

return u.ues[ueId]
}

// DeleteUe deletes a UE.
func (u *Ues) DeleteUe(ueId string) {
u.mu.Lock()
defer u.mu.Unlock()

delete(u.ues, ueId)
}

// UeExists checks if a UE already exists.
func (u *Ues) UeExists(ueId string) bool {
u.mu.Lock()
defer u.mu.Unlock()

_, exists := u.ues[ueId]
return exists
}

// IsLastPduSession checks if it is the last PDU session for a given UE.
func (u *Ues) IsLastPduSession(ueID string) bool {
u.mu.Lock()
defer u.mu.Unlock()

return u.ues[ueID].PduSessionCount == 1
}

// GetPduSessionCount returns the number of sessions for a given UE.
func (u *Ues) GetPduSessionCount(ueId string) int {
u.mu.Lock()
defer u.mu.Unlock()

return u.ues[ueId].PduSessionCount
}
162 changes: 162 additions & 0 deletions internal/sbi/consumer/subscriber_data_management.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package consumer

import (
"context"

"github.com/antihax/optional"
"github.com/free5gc/openapi"
"github.com/free5gc/openapi/Nudm_SubscriberDataManagement"
"github.com/free5gc/openapi/models"
smf_context "github.com/free5gc/smf/internal/context"
"github.com/free5gc/smf/internal/logger"
"github.com/free5gc/smf/internal/util"
"github.com/pkg/errors"
)

func SDMGetSmData(smCtx *smf_context.SMContext,
smPlmnID *models.PlmnId) (problemDetails *models.ProblemDetails, err error) {
// Query UDM
if problemDetails, err := SendNFDiscoveryUDM(); err != nil {
smCtx.Log.Warnf("Send NF Discovery Serving UDM Error[%v]", err)
} else if problemDetails != nil {
smCtx.Log.Warnf("Send NF Discovery Serving UDM Problem[%+v]", problemDetails)
} else {
smCtx.Log.Infoln("Send NF Discovery Serving UDM Successfully")
}

smDataParams := &Nudm_SubscriberDataManagement.GetSmDataParamOpts{
Dnn: optional.NewString(smCtx.Dnn),
PlmnId: optional.NewInterface(openapi.MarshToJsonString(smPlmnID)),
SingleNssai: optional.NewInterface(openapi.MarshToJsonString(smCtx.SNssai)),
}

SubscriberDataManagementClient := smf_context.GetSelf().SubscriberDataManagementClient

sessSubData, rsp, localErr := SubscriberDataManagementClient.
SessionManagementSubscriptionDataRetrievalApi.
GetSmData(context.Background(), smCtx.Supi, smDataParams)
if localErr == nil {
defer func() {
if rspCloseErr := rsp.Body.Close(); rspCloseErr != nil {
logger.ConsumerLog.Errorf("GetSmData response body cannot close: %+v", rspCloseErr)
}
}()
if len(sessSubData) > 0 {
smCtx.DnnConfiguration = sessSubData[0].DnnConfigurations[smCtx.Dnn]
// UP Security info present in session management subscription data
if smCtx.DnnConfiguration.UpSecurity != nil {
smCtx.UpSecurity = smCtx.DnnConfiguration.UpSecurity
}
} else {
logger.ConsumerLog.Errorln("SessionManagementSubscriptionData from UDM is nil")
err = openapi.ReportError("SmData is nil")
}
} else if rsp != nil {
if rsp.Status != localErr.Error() {
err = localErr
return
}
problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails)
problemDetails = &problem
} else {
logger.ConsumerLog.Errorln("Get SessionManagementSubscriptionData error:", localErr)
err = localErr
}

return
}

func SDMSubscribe(smCtx *smf_context.SMContext, smPlmnID *models.PlmnId) (
problemDetails *models.ProblemDetails, err error) {

if !smf_context.GetSelf().Ues.UeExists(smCtx.Supi) {
sdmUri := util.SearchNFServiceUri(smf_context.GetSelf().UDMProfile, models.ServiceName_NUDM_SDM,
models.NfServiceStatus_REGISTERED)
if sdmUri == "" {
return nil, errors.Errorf("SMF can not select an UDM by NRF: SearchNFServiceUri failed")
}

configuration := Nudm_SubscriberDataManagement.NewConfiguration()
configuration.SetBasePath(sdmUri)
client := Nudm_SubscriberDataManagement.NewAPIClient(configuration)

sdmSubscription := models.SdmSubscription{
NfInstanceId: smf_context.GetSelf().NfInstanceID,
PlmnId: smPlmnID,
}

resSubscription, httpResp, localErr := client.SubscriptionCreationApi.Subscribe(
context.Background(), smCtx.Supi, sdmSubscription)
defer func() {
if httpResp != nil {
if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil {
logger.ConsumerLog.Errorf("Subscribe response body cannot close: %+v",
rspCloseErr)
}
}
}()

if localErr == nil {
smf_context.GetSelf().Ues.SetSubscriptionId(smCtx.Supi, resSubscription.SubscriptionId)
logger.ConsumerLog.Infoln("SDM Subscription Successful UE:", smCtx.Supi, "SubscriptionId:",
resSubscription.SubscriptionId)
} else if httpResp != nil {
if httpResp.Status != localErr.Error() {
err = localErr
return problemDetails, err
}
problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails)
problemDetails = &problem
} else {
err = openapi.ReportError("server no response")
}
}

smf_context.GetSelf().Ues.IncrementPduSessionCount(smCtx.Supi)
return problemDetails, err
}

func SDMUnSubscribe(smCtx *smf_context.SMContext) (problemDetails *models.ProblemDetails,
err error) {
if smf_context.GetSelf().Ues.IsLastPduSession(smCtx.Supi) {
sdmUri := util.SearchNFServiceUri(smf_context.GetSelf().UDMProfile, models.ServiceName_NUDM_SDM,
models.NfServiceStatus_REGISTERED)
if sdmUri == "" {
return nil, errors.Errorf("SMF can not select an UDM by NRF: SearchNFServiceUri failed")
}
configuration := Nudm_SubscriberDataManagement.NewConfiguration()
configuration.SetBasePath(sdmUri)

client := Nudm_SubscriberDataManagement.NewAPIClient(configuration)

subscriptionId := smf_context.GetSelf().Ues.GetSubscriptionId(smCtx.Supi)

httpResp, localErr := client.SubscriptionDeletionApi.Unsubscribe(context.Background(), smCtx.Supi, subscriptionId)
defer func() {
if httpResp != nil {
if rspCloseErr := httpResp.Body.Close(); rspCloseErr != nil {
logger.ConsumerLog.Errorf("Unsubscribe response body cannot close: %+v",
rspCloseErr)
}
}
}()
if localErr == nil {
logger.ConsumerLog.Infoln("SDM UnSubscription Successful UE:", smCtx.Supi, "SubscriptionId:",
subscriptionId)
return problemDetails, err
} else if httpResp != nil {
if httpResp.Status != localErr.Error() {
err = localErr
return problemDetails, err
}
problem := localErr.(openapi.GenericOpenAPIError).Model().(models.ProblemDetails)
problemDetails = &problem
} else {
err = openapi.ReportError("server no response")
}
smf_context.GetSelf().Ues.DeleteUe(smCtx.Supi)
} else {
smf_context.GetSelf().Ues.DecrementPduSessionCount(smCtx.Supi)
}
return
}
Loading

0 comments on commit 615531c

Please sign in to comment.