diff --git a/backend/WebUI/api_webui.go b/backend/WebUI/api_webui.go index e7031eff..02d70823 100644 --- a/backend/WebUI/api_webui.go +++ b/backend/WebUI/api_webui.go @@ -10,6 +10,8 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" + "strings" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" @@ -18,6 +20,7 @@ import ( "github.com/free5gc/openapi/models" "github.com/free5gc/webconsole/backend/logger" "github.com/free5gc/webconsole/backend/webui_context" + gServ "github.com/omec-project/webconsole/proto/server" ) const ( @@ -407,7 +410,7 @@ func PostSubscriberByID(c *gin.Context) { AllowedSessionTypes: []models.PduSessionType{models.PduSessionType_IPV4}, }, SscModes: &models.SscModes{ - DefaultSscMode: models.SscMode__1, + DefaultSscMode: models.SscMode__1, AllowedSscModes: []models.SscMode{ "SSC_MODE_2", "SSC_MODE_3", @@ -420,7 +423,7 @@ func PostSubscriberByID(c *gin.Context) { Var5gQosProfile: &models.SubscribedDefaultQos{ Var5qi: 9, Arp: &models.Arp{ - PriorityLevel: 8, + PriorityLevel: 8, }, PriorityLevel: 8, }, @@ -431,7 +434,7 @@ func PostSubscriberByID(c *gin.Context) { AllowedSessionTypes: []models.PduSessionType{models.PduSessionType_IPV4}, }, SscModes: &models.SscModes{ - DefaultSscMode: models.SscMode__1, + DefaultSscMode: models.SscMode__1, AllowedSscModes: []models.SscMode{ "SSC_MODE_2", "SSC_MODE_3", @@ -444,7 +447,7 @@ func PostSubscriberByID(c *gin.Context) { Var5gQosProfile: &models.SubscribedDefaultQos{ Var5qi: 9, Arp: &models.Arp{ - PriorityLevel: 8, + PriorityLevel: 8, }, PriorityLevel: 8, }, @@ -463,7 +466,7 @@ func PostSubscriberByID(c *gin.Context) { AllowedSessionTypes: []models.PduSessionType{models.PduSessionType_IPV4}, }, SscModes: &models.SscModes{ - DefaultSscMode: models.SscMode__1, + DefaultSscMode: models.SscMode__1, AllowedSscModes: []models.SscMode{ "SSC_MODE_2", "SSC_MODE_3", @@ -487,7 +490,7 @@ func PostSubscriberByID(c *gin.Context) { AllowedSessionTypes: []models.PduSessionType{models.PduSessionType_IPV4}, }, SscModes: &models.SscModes{ - DefaultSscMode: models.SscMode__1, + DefaultSscMode: models.SscMode__1, AllowedSscModes: []models.SscMode{ "SSC_MODE_2", "SSC_MODE_3", @@ -500,7 +503,7 @@ func PostSubscriberByID(c *gin.Context) { Var5gQosProfile: &models.SubscribedDefaultQos{ Var5qi: 9, Arp: &models.Arp{ - PriorityLevel: 8, + PriorityLevel: 8, }, PriorityLevel: 8, }, @@ -551,7 +554,7 @@ func PostSubscriberByID(c *gin.Context) { "internet": { Dnn: "internet", }, - "internet2" : { + "internet2": { Dnn: "internet2", }, }, @@ -565,7 +568,7 @@ func PostSubscriberByID(c *gin.Context) { "internet": { Dnn: "internet", }, - "internet2" : { + "internet2": { Dnn: "internet2", }, }, @@ -587,10 +590,9 @@ func PostSubscriberByID(c *gin.Context) { if subsOverrideData.SequenceNumber != "" { authSubsData.SequenceNumber = subsOverrideData.SequenceNumber } -// if subsOverrideData.DNN != nil { + // if subsOverrideData.DNN != nil { // TODO -// } - + // } authSubsBsonM := toBsonM(authSubsData) authSubsBsonM["ueId"] = ueId @@ -616,23 +618,24 @@ func PostSubscriberByID(c *gin.Context) { smPolicyDataBsonM["ueId"] = ueId // there is no flowRule table in DB, this part of code is not used, uncomment it when need. -/* flowRulesBsonA := make([]interface{}, 0, len(subsData.FlowRules)) - for _, flowRule := range subsData.FlowRules { - flowRuleBsonM := toBsonM(flowRule) - flowRuleBsonM["ueId"] = ueId - flowRuleBsonM["servingPlmnId"] = servingPlmnId - flowRulesBsonA = append(flowRulesBsonA, flowRuleBsonM) - } -*/ + /* flowRulesBsonA := make([]interface{}, 0, len(subsData.FlowRules)) + for _, flowRule := range subsData.FlowRules { + flowRuleBsonM := toBsonM(flowRule) + flowRuleBsonM["ueId"] = ueId + flowRuleBsonM["servingPlmnId"] = servingPlmnId + flowRulesBsonA = append(flowRulesBsonA, flowRuleBsonM) + } + */ MongoDBLibrary.RestfulAPIPost(authSubsDataColl, filterUeIdOnly, authSubsBsonM) MongoDBLibrary.RestfulAPIPost(amDataColl, filterUeIdOnly, amDataBsonM) MongoDBLibrary.RestfulAPIPostMany(smDataColl, filterUeIdOnly, smDatasBsonA) MongoDBLibrary.RestfulAPIPost(smfSelDataColl, filterUeIdOnly, smfSelSubsBsonM) MongoDBLibrary.RestfulAPIPost(amPolicyDataColl, filterUeIdOnly, amPolicyDataBsonM) MongoDBLibrary.RestfulAPIPost(smPolicyDataColl, filterUeIdOnly, smPolicyDataBsonM) -// MongoDBLibrary.RestfulAPIPostMany(flowRuleDataColl, filterUeIdOnly, flowRulesBsonA) + // MongoDBLibrary.RestfulAPIPostMany(flowRuleDataColl, filterUeIdOnly, flowRulesBsonA) c.JSON(http.StatusCreated, gin.H{}) + gServ.HandleSubscriberAdd(ueId) } // Put subscriber by IMSI(ueId) and PlmnID(servingPlmnId) @@ -682,6 +685,7 @@ func PutSubscriberByID(c *gin.Context) { MongoDBLibrary.RestfulAPIPutOne(smPolicyDataColl, filterUeIdOnly, smPolicyDataBsonM) c.JSON(http.StatusNoContent, gin.H{}) + gServ.HandleSubscriberAdd(ueId) } // Patch subscriber by IMSI(ueId) and PlmnID(servingPlmnId) @@ -819,3 +823,86 @@ func GetUEPDUSessionInfo(c *gin.Context) { } } +func compareNssai(sNssai *models.Snssai, + sliceId *models.Snssai) int { + if sNssai.Sst != sliceId.Sst { + return 1 + } + return strings.Compare(sNssai.Sd, sliceId.Sd) +} + +func convertToString(val uint32) string { + var mbVal, gbVal, kbVal uint32 + kbVal = val / 1024 + mbVal = val / 1048576 + gbVal = val / 1073741824 + var retStr string + if gbVal != 0 { + retStr = strconv.FormatUint(uint64(gbVal), 10) + " Gbps" + } else if mbVal != 0 { + retStr = strconv.FormatUint(uint64(mbVal), 10) + " Mbps" + } else if kbVal != 0 { + retStr = strconv.FormatUint(uint64(kbVal), 10) + " Kbps" + } else { + retStr = strconv.FormatUint(uint64(val), 10) + " bps" + } + + return retStr +} + +// SubscriptionUpdateHandle : Handle subscription update +func SubscriptionUpdateHandle(subsUpdateChan chan *gServ.SubsUpdMsg) { + for subsData := range subsUpdateChan { + logger.WebUILog.Infoln("SubscriptionUpdateHandle") + var smDataData []models.SessionManagementSubscriptionData + var smDatasBsonA []interface{} + filterEmpty := bson.M{} + var ueID string + for _, ueID = range subsData.UeIds { + filter := bson.M{"ueId": ueID} + smDataDataInterface := MongoDBLibrary.RestfulAPIGetMany(smDataColl, filter) + var found bool = false + json.Unmarshal(sliceToByte(smDataDataInterface), &smDataData) + if len(smDataData) != 0 { + smDatasBsonA = make([]interface{}, 0, len(smDataData)) + for _, data := range smDataData { + if compareNssai(data.SingleNssai, &subsData.Nssai) == 0 { + logger.WebUILog.Infoln("entry exists for Imsi : with SST: and SD: ", + ueID, subsData.Nssai.Sst, subsData.Nssai.Sd) + found = true + break + } + } + + if !found { + logger.WebUILog.Infoln("entry doesnt exist for Imsi : %v with SST: %v and SD: %v", + ueID, subsData.Nssai.Sst, subsData.Nssai.Sd) + data := smDataData[0] + data.SingleNssai.Sst = subsData.Nssai.Sst + data.SingleNssai.Sd = subsData.Nssai.Sd + data.SingleNssai.Sd = subsData.Nssai.Sd + for idx, dnnCfg := range data.DnnConfigurations { + var sessAmbr models.Ambr + sessAmbr.Uplink = convertToString(uint32(subsData.Qos.Uplink)) + sessAmbr.Downlink = convertToString(uint32(subsData.Qos.Downlink)) + dnnCfg.SessionAmbr = &sessAmbr + data.DnnConfigurations[idx] = dnnCfg + logger.WebUILog.Infoln("uplink mbr ", data.DnnConfigurations[idx].SessionAmbr.Uplink) + logger.WebUILog.Infoln("downlink mbr ", data.DnnConfigurations[idx].SessionAmbr.Downlink) + } + smDataBsonM := toBsonM(data) + smDataBsonM["ueId"] = ueID + smDataBsonM["servingPlmnId"] = subsData.ServingPlmnId + logger.WebUILog.Infoln("servingplmnid ", subsData.ServingPlmnId) + smDatasBsonA = append(smDatasBsonA, smDataBsonM) + } + } else { + logger.WebUILog.Infoln("No imsi entry in db for imsi ", ueID) + } + } + + if len(smDatasBsonA) != 0 { + MongoDBLibrary.RestfulAPIPostMany(smDataColl, filterEmpty, smDatasBsonA) + } + } +} diff --git a/backend/WebUI/model_subs_data.go b/backend/WebUI/model_subs_data.go index dbb13819..13cacc4f 100644 --- a/backend/WebUI/model_subs_data.go +++ b/backend/WebUI/model_subs_data.go @@ -21,8 +21,8 @@ type SubsData struct { FlowRules []FlowRule `json:"FlowRules"` } type SubsOverrideData struct { - PlmnID string `json:"plmnID"` - OPc string `json:"opc"` - Key string `json:"key"` - SequenceNumber string `json:"sequenceNumber"` + PlmnID string `json:"plmnID"` + OPc string `json:"opc"` + Key string `json:"key"` + SequenceNumber string `json:"sequenceNumber"` } diff --git a/backend/webui_service/webui_init.go b/backend/webui_service/webui_init.go index 71c3d8a3..f3c0e36f 100644 --- a/backend/webui_service/webui_init.go +++ b/backend/webui_service/webui_init.go @@ -205,12 +205,15 @@ func (webui *WEBUI) Start() { configapi.AddService(config_router) configMsgChan := make(chan *configmodels.ConfigMessage, 10) configapi.SetChannel(configMsgChan) + subsUpdateChan := make(chan *gServ.SubsUpdMsg, 10) var host string = "0.0.0.0:9876" confServ := &gServ.ConfigServer{} - go gServ.StartServer(host, confServ, configMsgChan) + go gServ.StartServer(host, confServ, + configMsgChan, subsUpdateChan) go fetchConfigAdapater() + go WebUI.SubscriptionUpdateHandle(subsUpdateChan) HTTPAddr := "0.0.0.0:9089" initLog.Infoln("Http address ", HTTPAddr) @@ -279,14 +282,15 @@ func (webui *WEBUI) Exec(c *cli.Context) error { return err } + func fetchConfigAdapater() { for { - if (factory.WebUIConfig.Configuration == nil) || + if (factory.WebUIConfig.Configuration == nil) || (factory.WebUIConfig.Configuration.RocEnd == nil) || (factory.WebUIConfig.Configuration.RocEnd.Enabled == false) || (factory.WebUIConfig.Configuration.RocEnd.SyncUrl == "") { time.Sleep(1 * time.Second) - fmt.Printf("Continue polling config change %v ", factory.WebUIConfig.Configuration) + //fmt.Printf("Continue polling config change %v ", factory.WebUIConfig.Configuration) continue } diff --git a/proto/server/clientEvtHandler.go b/proto/server/clientEvtHandler.go index cae4d258..e6c44648 100644 --- a/proto/server/clientEvtHandler.go +++ b/proto/server/clientEvtHandler.go @@ -1,3 +1,8 @@ +// SPDX-FileCopyrightText: 2021 Open Networking Foundation +// +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: LicenseRef-ONF-Member-Only-1.0 + package server import ( diff --git a/proto/server/configEvtHandler.go b/proto/server/configEvtHandler.go index b9bd1767..55b19ce5 100644 --- a/proto/server/configEvtHandler.go +++ b/proto/server/configEvtHandler.go @@ -1,9 +1,16 @@ +// SPDX-FileCopyrightText: 2021 Open Networking Foundation +// +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: LicenseRef-ONF-Member-Only-1.0 package server import ( + "github.com/free5gc/openapi/models" "github.com/omec-project/webconsole/backend/logger" "github.com/omec-project/webconsole/configmodels" "github.com/sirupsen/logrus" + "strconv" + "strings" ) var configLog *logrus.Entry @@ -12,6 +19,14 @@ func init() { configLog = logger.ConfigLog } +type SubsUpdMsg struct { + UeIds []string + Nssai models.Snssai + ServingPlmnId string + Qos configmodels.SliceQos +} + +var subsChannel chan *SubsUpdMsg var slicesConfigSnapshot map[string]*configmodels.Slice var devgroupsConfigSnapshot map[string]*configmodels.DeviceGroups @@ -20,7 +35,53 @@ func init() { devgroupsConfigSnapshot = make(map[string]*configmodels.DeviceGroups) } -func configHandler(configMsgChan chan *configmodels.ConfigMessage) { +// HandleSubscriberAdd : Update Info of subscriber +func HandleSubscriberAdd(imsiVal string) { + var dgNameVal string + imsiVal = strings.ReplaceAll(imsiVal, "imsi-", "") + configLog.Infoln("UpdateInfo for UE : ", imsiVal) + for key, dvcGrp := range devgroupsConfigSnapshot { + for _, imsi := range dvcGrp.Imsis { + if strings.Compare(imsi, imsiVal) == 0 { + dgNameVal = key + break + } + } + if dgNameVal == "" { + continue + } + + for _, slice := range slicesConfigSnapshot { + var subsMsgData SubsUpdMsg + subsMsgData.UeIds = nil + for _, dgName := range slice.SiteDeviceGroup { + configLog.Infoln("dgName : ", dgName) + if strings.Compare(dgName, dgNameVal) == 0 { + sVal, err := + strconv.ParseUint(slice.SliceId.Sst, + 10, 32) + if err != nil { + sVal = 0 + } + subsMsgData.Nssai.Sst = int32(sVal) + subsMsgData.Nssai.Sd = slice.SliceId.Sd + subsMsgData.ServingPlmnId = slice.SiteInfo.Plmn.Mcc + slice.SiteInfo.Plmn.Mnc + subsMsgData.Qos = slice.Qos + var ueID string = "imsi-" + imsiVal + configLog.Infoln("ueID : ", ueID) + subsMsgData.UeIds = append(subsMsgData.UeIds, ueID) + configLog.Infoln("len of UeIds : ", len(subsMsgData.UeIds)) + subsChannel <- &subsMsgData + break + } + } + } + } +} + +func configHandler(configMsgChan chan *configmodels.ConfigMessage, + subsChannelVal chan *SubsUpdMsg) { + subsChannel = subsChannelVal for { configLog.Infoln("Waiting for configuration event ") select { @@ -38,6 +99,36 @@ func configHandler(configMsgChan chan *configmodels.ConfigMessage) { slicesConfigSnapshot[configMsg.SliceName] = configMsg.Slice } + for _, slice := range slicesConfigSnapshot { + var subsMsgData SubsUpdMsg + sVal, err := + strconv.ParseUint(slice.SliceId.Sst, + 10, 32) + if err != nil { + sVal = 0 + } + subsMsgData.Nssai.Sst = int32(sVal) + subsMsgData.Nssai.Sd = + slice.SliceId.Sd + subsMsgData.ServingPlmnId = slice.SiteInfo.Plmn.Mcc + slice.SiteInfo.Plmn.Mnc + subsMsgData.Qos = slice.Qos + subsMsgData.UeIds = nil + for _, dgName := range slice.SiteDeviceGroup { + configLog.Infoln("dgName : ", dgName) + devGroupConfig := devgroupsConfigSnapshot[dgName] + for _, imsi := range devGroupConfig.Imsis { + var ueID string = "imsi-" + imsi + configLog.Infoln("ueID : ", ueID) + subsMsgData.UeIds = + append(subsMsgData.UeIds, ueID) + } + } + + configLog.Infoln("len of UeIds : ", len(subsMsgData.UeIds)) + configLog.Infoln("slice sst : ", sVal, " sd: ", slice.SliceId.Sd) + subsChannel <- &subsMsgData + } + // loop through all clients and send this message to all clients if len(clientNFPool) == 0 { configLog.Infoln("No client available. No need to send config") diff --git a/proto/server/gServer.go b/proto/server/gServer.go index 58ae828e..aa0f50b6 100644 --- a/proto/server/gServer.go +++ b/proto/server/gServer.go @@ -1,3 +1,8 @@ +// SPDX-FileCopyrightText: 2021 Open Networking Foundation +// +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: LicenseRef-ONF-Member-Only-1.0 + package server import ( @@ -37,11 +42,11 @@ var kasp = keepalive.ServerParameters{ Timeout: 5 * time.Second, // Wait 1 second for the ping ack before assuming the connection is dead } -func StartServer(host string, confServ *ConfigServer, configMsgChan chan *configmodels.ConfigMessage) { - +func StartServer(host string, confServ *ConfigServer, + configMsgChan chan *configmodels.ConfigMessage, subsChannel chan *SubsUpdMsg) { grpcLog.Println("Start grpc config server") - go configHandler(configMsgChan) + go configHandler(configMsgChan, subsChannel) lis, err := net.Listen("tcp", host) if err != nil {