| /* |
| ================================================================================== |
| Copyright (c) 2019 AT&T Intellectual Property. |
| Copyright (c) 2019 Nokia |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ================================================================================== |
| */ |
| |
| package control |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "strings" |
| "sync" |
| |
| "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp" |
| ) |
| |
| type XappRnibIf struct { |
| XappRnibInterface |
| } |
| |
| func (x *XappRnibIf) XappRnibSubscribe(NotificationCb func(string, ...string), channel string) error { |
| return xapp.Rnib.Subscribe(NotificationCb, channel) |
| } |
| |
| func (x *XappRnibIf) XappRnibGetListGnbIds() ([]*xapp.RNIBNbIdentity, xapp.RNIBIRNibError) { |
| return xapp.Rnib.GetListGnbIds() |
| } |
| func (x *XappRnibIf) XappRnibGetNodeb(inventoryName string) (*xapp.RNIBNodebInfo, xapp.RNIBIRNibError) { |
| nodeInfo, err := xapp.Rnib.GetNodeb(inventoryName) |
| return nodeInfo, err |
| } |
| |
| func CreateXappRnibIfInstance() XappRnibInterface { |
| return new(XappRnibIf) |
| } |
| |
| type E2IfState struct { |
| mutex sync.Mutex |
| control *Control |
| NbIdMap map[string]string |
| NbIdStatusMap map[string]string |
| } |
| |
| func (e *E2IfState) Init(c *Control) { |
| e.control = c |
| e.NbIdMap = make(map[string]string, 0) |
| e.NbIdStatusMap = make(map[string]string, 0) |
| e.ReadE2ConfigurationFromRnib() |
| err := e.SubscribeChannels() |
| if err != nil { |
| xapp.Logger.Error("Init(): SubscribeChannels() failed: %v", err) |
| } |
| } |
| |
| func (e *E2IfState) GetE2NodesJson() []byte { |
| |
| e.mutex.Lock() |
| defer e.mutex.Unlock() |
| |
| // Map contains something like this{"RAN_NAME_1":"RAN_NAME_1","RAN_NAME_11":"RAN_NAME_11","RAN_NAME_2":"RAN_NAME_2"} |
| var ranNameList []string |
| for _, ranName := range e.NbIdMap { |
| ranNameList = append(ranNameList, ranName) |
| } |
| |
| e2NodesJson, err := json.Marshal(ranNameList) |
| if err != nil { |
| xapp.Logger.Error("GetE2Node() json.Marshal error: %v", err) |
| } |
| return e2NodesJson |
| } |
| |
| func (e *E2IfState) GetAllE2Nodes() map[string]string { |
| |
| e.mutex.Lock() |
| defer e.mutex.Unlock() |
| return e.NbIdMap |
| } |
| |
| func (e *E2IfState) NotificationCb(ch string, events ...string) { |
| |
| xapp.Logger.Debug("SDL notification received from channel=%s, event=%v", ch, events[0]) |
| if len(events) == 0 { |
| xapp.Logger.Error("Invalid SDL notification received: %d", len(events)) |
| return |
| } |
| |
| if strings.Contains(events[0], "_CONNECTED") && !strings.Contains(events[0], "_CONNECTED_SETUP_FAILED") { |
| e.control.UpdateCounter(cE2StateChangedToUp) |
| nbId, err := ExtractNbiIdFromString(events[0]) |
| if err != nil { |
| xapp.Logger.Error("NotificationCb CONNECTED len(nbId) == 0 ") |
| return |
| } |
| xapp.Logger.Debug("E2 CONNECTED. NbId=%s", nbId) |
| e.NbIdMap[nbId] = nbId |
| e.NbIdStatusMap[nbId] = "CONNECTED" |
| } else if strings.Contains(events[0], "_DISCONNECTED") { |
| e.control.UpdateCounter(cE2StateChangedToDown) |
| nbId, err := ExtractNbiIdFromString(events[0]) |
| if err != nil { |
| xapp.Logger.Error("NotificationCb DISCONNECTED len(nbId) == 0 ") |
| return |
| } |
| xapp.Logger.Debug("E2 DISCONNECTED. NbId=%s", nbId) |
| if _, ok := e.NbIdMap[nbId]; ok { |
| e.NbIdStatusMap[nbId] = "DISCONNECTED" |
| delete(e.NbIdMap, nbId) |
| e.control.registry.DeleteAllE2Subscriptions(nbId, e.control) |
| } |
| } else if strings.Contains(events[0], "_UNDER_RESET") { |
| xapp.Logger.Debug("NotificationCb UNDER_RESET len(nbId) == 0 ") |
| e.control.UpdateCounter(cE2StateUnderReset) |
| nbId, err := ExtractNbiIdFromString(events[0]) |
| if err != nil { |
| xapp.Logger.Error("NotificationCb _UNDER_RESET %v ", err) |
| return |
| } |
| e.NbIdStatusMap[nbId] = "UNDER_RESET" |
| xapp.Logger.Debug("E2 Under Reset. NbId=%s", nbId) |
| if _, ok := e.NbIdMap[nbId]; ok { |
| e.control.registry.DeleteAllE2Subscriptions(nbId, e.control) |
| } |
| } |
| } |
| |
| func (e *E2IfState) SubscribeChannels() error { |
| |
| if err := e.control.e2IfStateDb.XappRnibSubscribe(e.NotificationCb, "RAN_CONNECTION_STATUS_CHANGE"); err != nil { |
| xapp.Logger.Error("Sdl.SubscribeChannel failed: %v", err) |
| return err |
| } |
| xapp.Logger.Debug("Subscription to RAN state changes done!") |
| return nil |
| } |
| |
| func (e *E2IfState) ReadE2ConfigurationFromRnib() { |
| |
| xapp.Logger.Debug("ReadE2ConfigurationFromRnib()") |
| nbIdentities, err := e.control.e2IfStateDb.XappRnibGetListGnbIds() |
| if err != nil || len(nbIdentities) == 0 { |
| xapp.Logger.Debug("There are no active NodeBs available: %v", err) |
| e.NbIdMap = make(map[string]string, 0) |
| return |
| } |
| |
| for _, nbIdentity := range nbIdentities { |
| if e.isNodeBActive(nbIdentity.InventoryName) == false { |
| if _, ok := e.NbIdMap[nbIdentity.InventoryName]; ok { |
| delete(e.NbIdMap, nbIdentity.InventoryName) |
| xapp.Logger.Debug("E2 connection DISCONNETED: %v", nbIdentity.InventoryName) |
| |
| // Delete all subscriptions related to InventoryName/nbId |
| e.control.registry.DeleteAllE2Subscriptions(nbIdentity.InventoryName, e.control) |
| } |
| continue |
| } |
| |
| if _, ok := e.NbIdMap[nbIdentity.InventoryName]; !ok { |
| e.NbIdMap[nbIdentity.InventoryName] = nbIdentity.InventoryName |
| xapp.Logger.Debug("E2 connection CONNECTED: %v", nbIdentity.InventoryName) |
| } |
| } |
| } |
| |
| func (e *E2IfState) isNodeBActive(inventoryName string) bool { |
| nodeInfo, err := e.control.e2IfStateDb.XappRnibGetNodeb(inventoryName) |
| if err != nil { |
| xapp.Logger.Error("GetNodeb() failed for inventoryName=%s: %v", inventoryName, err) |
| return false |
| } |
| xapp.Logger.Debug("NodeB['%s'] connection status = %d", inventoryName, nodeInfo.ConnectionStatus) |
| return nodeInfo.ConnectionStatus == 1 |
| } |
| |
| func (e *E2IfState) IsE2ConnectionUp(nbId *string) bool { |
| |
| if checkE2State == "false" { |
| return true |
| } |
| |
| if _, ok := e.NbIdMap[*nbId]; ok { |
| return true |
| } else { |
| return false |
| } |
| } |
| |
| func (e *E2IfState) IsE2ConnectionUnderReset(nbId *string) bool { |
| |
| if status := e.NbIdStatusMap[*nbId]; status == "UNDER_RESET" { |
| return true |
| } else { |
| return false |
| } |
| } |
| |
| func ExtractNbiIdFromString(s string) (string, error) { |
| |
| // Expected string formats are below |
| // gnb_208_092_303030_CONNECTED |
| // gnb_208_092_303030_DISCONNECTED |
| // ... |
| |
| var nbId string |
| var err error |
| if strings.Contains(s, "_CONNECTED") { |
| splitStringTbl := strings.Split(s, "_CONNECTED") |
| nbId = splitStringTbl[0] |
| } else if strings.Contains(s, "_DISCONNECTED") { |
| splitStringTbl := strings.Split(s, "_DISCONNECTED") |
| nbId = splitStringTbl[0] |
| } else if strings.Contains(s, "_UNDER_RESET") { |
| splitStringTbl := strings.Split(s, "_UNDER_RESET") |
| nbId = splitStringTbl[0] |
| } |
| if len(nbId) == 0 { |
| return "", fmt.Errorf("ExtractNbiIdFromString(): len(nbId) == 0 ") |
| } |
| return nbId, err |
| } |