Skip to content

Commit

Permalink
fix: removing NRF cache data after checking notification event type (#…
Browse files Browse the repository at this point in the history
…325)

* fix removing NRFcache without checking notification event type

Signed-off-by: gatici <[email protected]>

* chore: adding licence header

Signed-off-by: gatici <[email protected]>

---------

Signed-off-by: gatici <[email protected]>
  • Loading branch information
gatici authored Oct 5, 2024
1 parent 7cf2630 commit 0357c97
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 14 deletions.
2 changes: 1 addition & 1 deletion consumer/nnrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func SendNrfForNfInstance(nrfUri string, targetNfType, requestNfType models.NfTy
for _, nfProfile := range result.NfInstances {
if _, ok := smfSelf.NfStatusSubscriptions.Load(nfProfile.NfInstanceId); !ok {
nrfSubscriptionData := models.NrfSubscriptionData{
NfStatusNotificationUri: fmt.Sprintf("%s://%s:%d/nsmf-callback/nf-status-notify",
NfStatusNotificationUri: fmt.Sprintf("%s://%s:%d/nsmf-callback/v1/nf-status-notify",
smfSelf.URIScheme,
smfSelf.RegisterIPv4,
smfSelf.SBIPort),
Expand Down
2 changes: 2 additions & 0 deletions logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var (
ConsumerLog *zap.SugaredLogger
GinLog *zap.SugaredLogger
GrpcLog *zap.SugaredLogger
ProducerLog *zap.SugaredLogger
UPNodeLog *zap.SugaredLogger
FsmLog *zap.SugaredLogger
TxnFsmLog *zap.SugaredLogger
Expand Down Expand Up @@ -69,6 +70,7 @@ func init() {
ConsumerLog = log.Sugar().With("component", "SMF", "category", "Consumer")
GinLog = log.Sugar().With("component", "SMF", "category", "GIN")
GrpcLog = log.Sugar().With("component", "SMF", "category", "GRPC")
ProducerLog = log.Sugar().With("component", "SMF", "category", "Producer")
UPNodeLog = log.Sugar().With("component", "SMF", "category", "UPNode")
FsmLog = log.Sugar().With("component", "SMF", "category", "Fsm")
TxnFsmLog = log.Sugar().With("component", "SMF", "category", "TxnFsm")
Expand Down
2 changes: 1 addition & 1 deletion pdusession/api_individual_sm_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"strings"

"github.com/gin-gonic/gin"
mi "github.com/omec-project/util/metricinfo"
"github.com/omec-project/openapi"
"github.com/omec-project/openapi/models"
smf_context "github.com/omec-project/smf/context"
Expand All @@ -28,6 +27,7 @@ import (
"github.com/omec-project/smf/msgtypes/svcmsgtypes"
"github.com/omec-project/smf/transaction"
"github.com/omec-project/util/httpwrapper"
mi "github.com/omec-project/util/metricinfo"
)

// HTTPReleaseSmContext - Release SM Context
Expand Down
2 changes: 1 addition & 1 deletion pdusession/api_sm_contexts_collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"strings"

"github.com/gin-gonic/gin"
mi "github.com/omec-project/util/metricinfo"
"github.com/omec-project/openapi"
"github.com/omec-project/openapi/models"
smf_context "github.com/omec-project/smf/context"
Expand All @@ -28,6 +27,7 @@ import (
"github.com/omec-project/smf/msgtypes/svcmsgtypes"
"github.com/omec-project/smf/transaction"
"github.com/omec-project/util/httpwrapper"
mi "github.com/omec-project/util/metricinfo"
)

// HTTPPostSmContexts - Create SM Context
Expand Down
48 changes: 37 additions & 11 deletions producer/callback.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,28 @@ import (

"github.com/omec-project/openapi/models"
nrfCache "github.com/omec-project/openapi/nrfcache"
smf_context "github.com/omec-project/smf/context"
"github.com/omec-project/smf/consumer"
smfContext "github.com/omec-project/smf/context"
"github.com/omec-project/smf/logger"
"github.com/omec-project/smf/qos"
"github.com/omec-project/smf/transaction"
"github.com/omec-project/util/httpwrapper"
)

var (
NRFCacheRemoveNfProfileFromNrfCache = nrfCache.RemoveNfProfileFromNrfCache
SendRemoveSubscription = consumer.SendRemoveSubscription
)

func HandleSMPolicyUpdateNotify(eventData interface{}) error {
txn := eventData.(*transaction.Transaction)
request := txn.Req.(models.SmPolicyNotification)
smContext := txn.Ctxt.(*smf_context.SMContext)
smContext := txn.Ctxt.(*smfContext.SMContext)

logger.PduSessLog.Infoln("In HandleSMPolicyUpdateNotify")
pcfPolicyDecision := request.SmPolicyDecision

if smContext.SMContextState != smf_context.SmStateActive {
if smContext.SMContextState != smfContext.SmStateActive {
// Wait till the state becomes SmStateActive again
// TODO: implement waiting in concurrent architecture
logger.PduSessLog.Warnf("SMContext[%s-%02d] should be SmStateActive, but actual %s",
Expand Down Expand Up @@ -67,7 +73,7 @@ func HandleSMPolicyUpdateNotify(eventData interface{}) error {
return nil
}

func BuildAndSendQosN1N2TransferMsg(smContext *smf_context.SMContext) error {
func BuildAndSendQosN1N2TransferMsg(smContext *smfContext.SMContext) error {
// N1N2 Request towards AMF
n1n2Request := models.N1N2MessageTransferRequest{}

Expand Down Expand Up @@ -96,15 +102,15 @@ func BuildAndSendQosN1N2TransferMsg(smContext *smf_context.SMContext) error {
n1n2Request.JsonData = &models.N1N2MessageTransferReqData{PduSessionId: smContext.PDUSessionID}

// N1 Msg
if smNasBuf, err := smf_context.BuildGSMPDUSessionModificationCommand(smContext); err != nil {
if smNasBuf, err := smfContext.BuildGSMPDUSessionModificationCommand(smContext); err != nil {
logger.PduSessLog.Errorf("build GSM BuildGSMPDUSessionModificationCommand failed: %s", err)
} else {
n1n2Request.BinaryDataN1Message = smNasBuf
n1n2Request.JsonData.N1MessageContainer = &n1MsgContainer
}

// N2 Msg
n2Pdu, err := smf_context.BuildPDUSessionResourceModifyRequestTransfer(smContext)
n2Pdu, err := smfContext.BuildPDUSessionResourceModifyRequestTransfer(smContext)
if err != nil {
smContext.SubPduSessLog.Errorf("SMPolicyUpdate, build PDUSession Resource Modify Request Transfer Error(%s)", err.Error())
} else {
Expand Down Expand Up @@ -142,8 +148,11 @@ func HandleNfSubscriptionStatusNotify(request *httpwrapper.Request) *httpwrapper
}
}

// NfSubscriptionStatusNotifyProcedure is handler method of notification procedure.
// According to event type retrieved in the notification data, it performs some actions.
// For example, if event type is deregistered, it deletes cached NF profile and performs an NF discovery.
func NfSubscriptionStatusNotifyProcedure(notificationData models.NotificationData) *models.ProblemDetails {
logger.PduSessLog.Debugf("NfSubscriptionStatusNotify: %+v", notificationData)
logger.ProducerLog.Debugf("NfSubscriptionStatusNotify: %+v", notificationData)

if notificationData.Event == "" || notificationData.NfInstanceUri == "" {
problemDetails := &models.ProblemDetails{
Expand All @@ -155,11 +164,28 @@ func NfSubscriptionStatusNotifyProcedure(notificationData models.NotificationDat
}
nfInstanceId := notificationData.NfInstanceUri[strings.LastIndex(notificationData.NfInstanceUri, "/")+1:]

logger.ProducerLog.Infof("Received Subscription Status Notification from NRF: %v", notificationData.Event)
// If nrf caching is enabled, go ahead and delete the entry from the cache.
// This will force the smf to do nf discovery and get the updated nf profile from the nrf.
if smf_context.SMF_Self().EnableNrfCaching {
ok := nrfCache.RemoveNfProfileFromNrfCache(nfInstanceId)
logger.PduSessLog.Debugf("nfinstance %v deleted from cache: %v", nfInstanceId, ok)
// This will force the PCF to do nf discovery and get the updated nf profile from the NRF.
if notificationData.Event == models.NotificationEventType_DEREGISTERED {
if smfContext.SMF_Self().EnableNrfCaching {
ok := NRFCacheRemoveNfProfileFromNrfCache(nfInstanceId)
logger.ProducerLog.Debugf("nfinstance %v deleted from cache: %v", nfInstanceId, ok)
}
if subscriptionId, ok := smfContext.SMF_Self().NfStatusSubscriptions.Load(nfInstanceId); ok {
logger.ConsumerLog.Debugf("SubscriptionId of nfInstance %v is %v", nfInstanceId, subscriptionId.(string))
problemDetails, err := SendRemoveSubscription(subscriptionId.(string))
if problemDetails != nil {
logger.ConsumerLog.Errorf("Remove NF Subscription Failed Problem[%+v]", problemDetails)
} else if err != nil {
logger.ConsumerLog.Errorf("Remove NF Subscription Error[%+v]", err)
} else {
logger.ConsumerLog.Infoln("Remove NF Subscription successful")
smfContext.SMF_Self().NfStatusSubscriptions.Delete(nfInstanceId)
}
} else {
logger.ProducerLog.Infof("nfinstance %v not found in map", nfInstanceId)
}
}

return nil
Expand Down
189 changes: 189 additions & 0 deletions producer/subscription_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// Copyright 2024 Canonical Ltd.
//
// SPDX-License-Identifier: Apache-2.0

package producer

import (
"fmt"
"net/http"
"os"
"testing"

"github.com/omec-project/openapi/models"
smfContext "github.com/omec-project/smf/context"
"github.com/omec-project/smf/factory"
"github.com/stretchr/testify/assert"
)

var (
nfInstanceID = "34343-4343-43-434-343"
subscriptionID = "46326-232353-2323"
)

func setupTest() {
if err := factory.InitConfigFactory("../config/smfcfg.yaml"); err != nil {
fmt.Printf("Could not InitConfigFactory: %+v", err)
}
}

func TestNfSubscriptionStatusNotify(t *testing.T) {
t.Logf("test cases fore NfSubscriptionStatusNotify")
callCountSendRemoveSubscription := 0
callCountNRFCacheRemoveNfProfileFromNrfCache := 0
origSendRemoveSubscription := SendRemoveSubscription
origNRFCacheRemoveNfProfileFromNrfCache := NRFCacheRemoveNfProfileFromNrfCache
defer func() {
SendRemoveSubscription = origSendRemoveSubscription
NRFCacheRemoveNfProfileFromNrfCache = origNRFCacheRemoveNfProfileFromNrfCache
}()
SendRemoveSubscription = func(subscriptionId string) (problemDetails *models.ProblemDetails, err error) {
t.Logf("test SendRemoveSubscription called")
callCountSendRemoveSubscription++
return nil, nil
}
NRFCacheRemoveNfProfileFromNrfCache = func(nfInstanceId string) bool {
t.Logf("test NRFCacheRemoveNfProfileFromNrfCache called")
callCountNRFCacheRemoveNfProfileFromNrfCache++
return true
}
udmProfile := models.NfProfileNotificationData{
UdrInfo: &models.UdrInfo{
SupportedDataSets: []models.DataSetId{
models.DataSetId_SUBSCRIPTION,
},
},
NfInstanceId: nfInstanceID,
NfType: "UDM",
NfStatus: "DEREGISTERED",
}
badRequestProblem := models.ProblemDetails{
Status: http.StatusBadRequest,
Cause: "MANDATORY_IE_MISSING",
Detail: "Missing IE [Event]/[NfInstanceUri] in NotificationData",
}
parameters := []struct {
expectedProblem *models.ProblemDetails
testName string
result string
nfInstanceId string
nfInstanceIdForSubscription string
subscriptionID string
notificationEventType string
expectedCallCountSendRemoveSubscription int
expectedCallCountNRFCacheRemoveNfProfileFromNrfCache int
enableNrfCaching bool
}{
{
nil,
"Notification event type DEREGISTERED NRF caching is enabled",
"NF profile removed from cache and subscription is removed",
nfInstanceID,
nfInstanceID,
subscriptionID,
"NF_DEREGISTERED",
1,
1,
true,
},
{
nil,
"Notification event type DEREGISTERED NRF caching is enabled Subscription is not found",
"NF profile removed from cache and subscription is not removed",
nfInstanceID,
"",
"",
"NF_DEREGISTERED",
0,
1,
true,
},
{
nil,
"Notification event type DEREGISTERED NRF caching is disabled",
"NF profile is not removed from cache and subscription is removed",
nfInstanceID,
nfInstanceID,
subscriptionID,
"NF_DEREGISTERED",
1,
0,
false,
},
{
nil,
"Notification event type REGISTERED NRF caching is enabled",
"NF profile is not removed from cache and subscription is not removed",
nfInstanceID,
nfInstanceID,
subscriptionID,
"NF_REGISTERED",
0,
0,
true,
},
{
nil,
"Notification event type DEREGISTERED NRF caching is enabled NfInstanceUri in notificationData is different",
"NF profile removed from cache and subscription is not removed",
nfInstanceID,
nfInstanceID,
subscriptionID,
"NF_DEREGISTERED",
1,
1,
true,
},
{
&badRequestProblem,
"Notification event type DEREGISTERED NRF caching is enabled NfInstanceUri in notificationData is empty",
"Return StatusBadRequest with cause MANDATORY_IE_MISSING",
"",
"",
subscriptionID,
"NF_DEREGISTERED",
0,
0,
true,
},
{
&badRequestProblem,
"Notification event type empty NRF caching is enabled",
"Return StatusBadRequest with cause MANDATORY_IE_MISSING",
nfInstanceID,
nfInstanceID,
subscriptionID,
"",
0,
0,
true,
},
}
for i := range parameters {
t.Run(fmt.Sprintf("NfSubscriptionStatusNotify testname %v result %v", parameters[i].testName, parameters[i].result), func(t *testing.T) {
smfContext.SMF_Self().EnableNrfCaching = parameters[i].enableNrfCaching
smfContext.SMF_Self().NfStatusSubscriptions.Store(parameters[i].nfInstanceIdForSubscription, parameters[i].subscriptionID)
notificationData := models.NotificationData{
Event: models.NotificationEventType(parameters[i].notificationEventType),
NfInstanceUri: parameters[i].nfInstanceId,
NfProfile: &udmProfile,
ProfileChanges: []models.ChangeItem{},
}
err := NfSubscriptionStatusNotifyProcedure(notificationData)
assert.Equal(t, parameters[i].expectedProblem, err, "NfSubscriptionStatusNotifyProcedure is failed.")
// Subscription is removed.
assert.Equal(t, parameters[i].expectedCallCountSendRemoveSubscription, callCountSendRemoveSubscription, "Subscription is not removed.")
// NF Profile is removed from NRF cache.
assert.Equal(t, parameters[i].expectedCallCountNRFCacheRemoveNfProfileFromNrfCache, callCountNRFCacheRemoveNfProfileFromNrfCache, "NF Profile is not removed from NRF cache.")
callCountSendRemoveSubscription = 0
callCountNRFCacheRemoveNfProfileFromNrfCache = 0
smfContext.SMF_Self().NfStatusSubscriptions.Delete(parameters[i].nfInstanceIdForSubscription)
})
}
}

func TestMain(m *testing.M) {
setupTest()
exitVal := m.Run()
os.Exit(exitVal)
}

0 comments on commit 0357c97

Please sign in to comment.