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

feat: propagate DG changes to all IMSIs #283

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

dariofaccin
Copy link

@dariofaccin dariofaccin commented Jan 14, 2025

This PR aims to fix the issue for which Access Mobility Data, Session Management Data, SMF Selection Data and Policy Data for subscribers are not refreshed when the Device Group is updated.

Before this PR, only subscribers that are added in the same API call of the Device Group update take the new information. This PR extends the refresh to all the subscribers currently belonging to the DG.

Current behaviour
A device group is created and its representation (only relevant part) in database is the following:

{
    [...]
    "imsis" : [ 
        "208930100007487"
    ],
    "ip-domain-expanded" : {
        "ue-dnn-qos" : {
            "dnn-mbr-uplink" : 20000000.0,
            "dnn-mbr-downlink" : 200000000.0,
            "bitrate-unit" : "bps",
            [...]
        },
        [...]
    }
}

The representation (only relevant part) of the subscriber associated to the device group is the following:

{
    [...]
    "subscribedUeAmbr" : {
        "uplink" : "20 Mbps",
        "downlink" : "200 Mbps"
    }
}

After updating the device group with new MBR data, the representation is the following:

{
    [...]
    "imsis" : [ 
        "208930100007487"
    ],
    "ip-domain-expanded" : {
        "ue-dnn-qos" : {
            "dnn-mbr-uplink" : 20000000.0,
            "dnn-mbr-downlink" : 300000000.0,
            "bitrate-unit" : "bps",
            [...]
        },
        [...]
    }
}

But subscriber data in all the collections is not updated:

{
    [...]
    "subscribedUeAmbr" : {
        "uplink" : "20 Mbps",
        "downlink" : "200 Mbps"
    }
}

The example is taken from the amData collection, but it applies also to smData and the others.

@patriciareinoso
Copy link
Contributor

I created an issue to better understand the problem and the purpose of the PR. Please add the reference to it in the PR description. Would it be possible to capture a before and after of the DB content ? like this it would be clearer which fields we are talking about.

@patriciareinoso
Copy link
Contributor

What do you mean by "only subscribers that are added in the same API call of the Device Group update take the new information" ? if the update api call does not include the list of subscribers it means that we are overwriting that list

@patriciareinoso
Copy link
Contributor

patriciareinoso commented Jan 15, 2025

What do you mean by "only subscribers that are added in the same API call of the Device Group update take the new information" ? if the update api call does not include the list of subscribers it means that we are overwriting that list

ok, looking at the code I think I understood. But I am worried about the case in which you add a DG and add a reference to a Subscriber in the imsis list but you haven't created the actual Subscriber yet, it will create entries in subscriptionData.provisionedData.amData, subscriptionData.provisionedData.smData, subscriptionData.provisionedData.smfSelectionSubscriptionData but not in subscriptionData.authenticationData.authenticationSubscription

Copy link
Contributor

@patriciareinoso patriciareinoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I thought I did not have permission to request changes. Please see the comments I added

@dariofaccin dariofaccin force-pushed the TELCO-1401-fix-editing-mbr branch from 240599b to cca215e Compare January 20, 2025 08:57
updateSmfSelectionProviosionedData(snssai, slice.SiteInfo.Plmn.Mcc, slice.SiteInfo.Plmn.Mnc, dnn, imsi)
for _, imsi := range confData.Msg.DevGroup.Imsis {
/* update only if the imsi is provisioned */
if imsiData[imsi] != nil {
Copy link
Contributor

@patriciareinoso patriciareinoso Jan 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if imsiData is kept in memory. What happens if we add Subscriber A, B , C. and they exist in the DevGroup.Imsis. Then the pod dies and then we update the MBR ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue looks to me independent from this PR, as the same logic is already in place. I can try to fix it in this same PR or open a new one, I don't have a strong opinion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to me it's part of this PR. the fix would not be completed if we do not handle this edge case

Copy link
Contributor

@patriciareinoso patriciareinoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I try to build I get the error:

proto/server/clientEvtHandler.go:978:21: undefined: imsiData

@dariofaccin dariofaccin force-pushed the TELCO-1401-fix-editing-mbr branch from 94b81a1 to 4e2bb9d Compare January 21, 2025 13:33
updateAmProvisionedData(snssai, confData.Msg.DevGroup.IpDomainExpanded.UeDnnQos, slice.SiteInfo.Plmn.Mcc, slice.SiteInfo.Plmn.Mnc, imsi)
updateSmProvisionedData(snssai, confData.Msg.DevGroup.IpDomainExpanded.UeDnnQos, slice.SiteInfo.Plmn.Mcc, slice.SiteInfo.Plmn.Mnc, dnn, imsi)
updateSmfSelectionProviosionedData(snssai, slice.SiteInfo.Plmn.Mcc, slice.SiteInfo.Plmn.Mnc, dnn, imsi)
for _, imsi := range confData.Msg.DevGroup.Imsis {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is shared between the DELETE and the POST operation. In the delete operation confData.Msg.DevGroup is nil, so the program crashes if we try to delete a DG.

Copy link
Contributor

@patriciareinoso patriciareinoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These modifications change the initial behavior of the following workflow in the NMS:

  1. Create a NS
  2. DG is automatically created
  3. Create a Subscriber

Before

subscriptionData.provisionedData.amData, subscriptionData.provisionedData.smData, subscriptionData.provisionedData.smfSelectionSubscriptionData are filled

Now

subscriptionData.provisionedData.amData, subscriptionData.provisionedData.smData, subscriptionData.provisionedData.smfSelectionSubscriptionData are not filled

@@ -607,6 +631,7 @@ func Config5GUpdateHandle(confChan chan *Update5GSubscriberMsg) {
/* is this devicegroup part of any existing slice */
slice := isDeviceGroupExistInSlice(confData)
if slice != nil {
provisionedSubscribers := getProvisionedSubscribers()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would make this in line 646: after the if and before the loop. In case of delete operation we would unnecessarily retrieving the list of subscribers

return provisionedSubscribers
}

func getSubscriberAuthDataByUeId(ueId string) *models.AuthenticationSubscription {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would move this function to clientEvtHandler.go since it is only used there

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In clientEvtHandler we are not istantiating the DBClient, therefore moving this function there will increase the imports and in general the complexity. In the client handler we are also already importing getAddedImsisList() func from configEvtHandler

func getProvisionedSubscribers() []string {
rawProvisionedSubscribers, errGetMany := dbadapter.AuthDBClient.RestfulAPIGetMany(authSubsDataColl, nil)
if errGetMany != nil {
logger.DbLog.Warnln(errGetMany)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can inmmediately return here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, if we continue rawProvisionedSubscribers might be uninitialized and return an nil pointer dereference in line 405.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can return an empty slice.

filter := bson.M{"ueId": ueId}
subscriberAuthDataInterface, errGetOne := dbadapter.AuthDBClient.RestfulAPIGetOne(authSubsDataColl, filter)
if errGetOne != nil {
logger.DbLog.Warnln(errGetOne)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can immediately return here

@@ -355,9 +348,10 @@ func getAddedImsisList(group, prevGroup *configmodels.DeviceGroups) (aimsis []st
if group == nil {
return
}
provisionedSubscribers := getProvisionedSubscribers()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am concerned that here you are using the information in authSubsDataColl but that table is only filled up in factory.WebUIConfig.Configuration.Mode5G Do you know what happens in all the function in clientEvtHandler that use getAddedImsisList? are all of them used when factory.WebUIConfig.Configuration.Mode5G ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In clientEvtHandler when 5GMode is disabled there are other functions (in this case, postConfigHss) that take care of the subscribers and these are using another functions (in this case, addedImsis() and deletedImsis()).

func getProvisionedSubscribers() []string {
rawProvisionedSubscribers, errGetMany := dbadapter.AuthDBClient.RestfulAPIGetMany(authSubsDataColl, nil)
if errGetMany != nil {
logger.DbLog.Warnln(errGetMany)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, if we continue rawProvisionedSubscribers might be uninitialized and return an nil pointer dereference in line 405.

Comment on lines 407 to 409
if !ok {
logger.DbLog.Warnf("cannot retrieve ueId for subscriber: %v", rawProvisionedSubscriber)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if !ok {
logger.DbLog.Warnf("cannot retrieve ueId for subscriber: %v", rawProvisionedSubscriber)
}
if !ok {
logger.DbLog.Warnf("cannot retrieve ueId for subscriber: %v", rawProvisionedSubscriber)
continue
}

If we can not get a proper ueId, we can skip it.

func getProvisionedSubscribers() []string {
rawProvisionedSubscribers, errGetMany := dbadapter.AuthDBClient.RestfulAPIGetMany(authSubsDataColl, nil)
if errGetMany != nil {
logger.DbLog.Warnln(errGetMany)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can return an empty slice.

Comment on lines 423 to 425
if err != nil {
logger.DbLog.Errorf("could not unmarshall subscriber %v", subscriberAuthDataInterface)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if err != nil {
logger.DbLog.Errorf("could not unmarshall subscriber %v", subscriberAuthDataInterface)
}
if err != nil {
logger.DbLog.Errorf("could not unmarshall subscriber %v", subscriberAuthDataInterface)
return nil
}

We can return here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the point of adding return nil here: in line 427 we are returning the pointer (return &subscriberAuthData) which will already be nil if the unmarshalling failed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the project L978 this function is called like below:

				authSubsData := getSubscriberAuthDataByUeId("imsi-" + imsi)
				if authSubsData == nil {
					client.clientLog.Infoln("SIM card details not found for IMSI ", imsi)
					continue
				}

They do a nil check to skip or continue to execution.
If json.Unmarshal fails, &subscriberAuthData pointer will keep the location of an empty AuthenticationSubscription struct looking like:
{Opc:{...} PermanentKey:{...} SequenceNumber: ""}
And it will not be nil. Execution continue and In L983 config.Opc = authSubsData.Opc.OpcValue will cause a panic as OpcValue is not reachable.
Hence, instead of returning a pointer of empty struct, we can return nil in L428.

@@ -616,14 +641,19 @@ func Config5GUpdateHandle(confChan chan *Update5GSubscriberMsg) {
Sst: int32(sVal),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shoud return after line 637. If strconv.ParseUint fails, we can not calculate snssai properly.

updateSmProvisionedData(snssai, confData.Msg.DevGroup.IpDomainExpanded.UeDnnQos, slice.SiteInfo.Plmn.Mcc, slice.SiteInfo.Plmn.Mnc, dnn, imsi)
updateSmfSelectionProviosionedData(snssai, slice.SiteInfo.Plmn.Mcc, slice.SiteInfo.Plmn.Mnc, dnn, imsi)
/* skip delete case */
if confData.Msg.DevGroup != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can move the first if clause outside of this block to increase readability.

if confData.Msg.DevGroup == nil {
logger.DbLog.Warn("DevGroup is nil in confData.Msg")
return
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If DevGroup is nil we want to remove the subscribers data from the collections, but not update them. I don't fully understand the comment however.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's talk about it. I will ping you.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please disregard my comment.

@gab-arrobo
Copy link
Contributor

@dariofaccin, I guess you have tested these changes, correct? I am asking this because I was running a test and I do not see these changes being used, or am I missing something?

@dariofaccin
Copy link
Author

@gab-arrobo, these changes are used to update the subscriber data of a device group whenever the device group is updated. To see the changes the flow is the following:

  1. create a device group (and network slice if needed)
  2. create a subscriber associated to such device group
  3. edit the device group
  4. changes are reflected in the subscriber data (collections and data returned by GET /subscribers/{imsi})

Let me know, thanks

@@ -975,7 +975,7 @@ func postConfigHss(client *clientNF, lastDevGroup *configmodels.DeviceGroups, la
}
config.StartImsi = uint64(num)
config.EndImsi = uint64(num)
authSubsData := imsiData[imsi]
authSubsData := getSubscriberAuthDataByUeId("imsi-" + imsi)
Copy link
Contributor

@patriciareinoso patriciareinoso Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this piece of code is executed by the 4G configuration , in which case the authSubsDataColl used in getSubscriberAuthDataByUeId will not be filled and authSubsData will be nil

And it's not 100% clear to me if getAddedImsisList if only used by 5G code since the code is shared between both configurations so I wouldn't touch it.

please do not merge these changes until thi is fixed

@dariofaccin dariofaccin marked this pull request as draft January 29, 2025 14:05
@thakurajayL
Copy link
Contributor

Is this ready for review? I see its in draft state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants