2 ==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
26 "github.com/spf13/viper"
27 "github.com/valyala/fastjson"
32 "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
33 "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/sbi"
37 #cgo LDFLAGS: -lsysrepo -lyang
42 #include <sysrepo/values.h>
47 var sbiClient sbi.SBIClientInterface
51 func NewNbi(s sbi.SBIClientInterface) *Nbi {
55 schemas: viper.GetStringSlice("nbi.schemas"),
56 cleanupChan: make(chan bool),
61 func (n *Nbi) Start() bool {
62 if ok := n.Setup(n.schemas); !ok {
63 log.Error("NBI: SYSREPO initialization failed, bailing out!")
66 log.Info("NBI: SYSREPO initialization done ... processing O1 requests!")
71 func (n *Nbi) Stop() {
72 C.sr_unsubscribe(n.subscription)
73 C.sr_session_stop(n.session)
74 C.sr_disconnect(n.connection)
76 log.Info("NBI: SYSREPO cleanup done gracefully!")
79 func (n *Nbi) Setup(schemas []string) bool {
80 rc := C.sr_connect(0, &n.connection)
81 if C.SR_ERR_OK != rc {
82 log.Error("NBI: sr_connect failed: %s", C.GoString(C.sr_strerror(rc)))
86 rc = C.sr_session_start(n.connection, C.SR_DS_RUNNING, &n.session)
87 if C.SR_ERR_OK != rc {
88 log.Error("NBI: sr_session_start failed: %s", C.GoString(C.sr_strerror(rc)))
93 if ok := n.DoSubscription(schemas); ok == true {
96 time.Sleep(time.Duration(5 * time.Second))
101 func (n *Nbi) DoSubscription(schemas []string) bool {
102 log.Info("Subscribing YANG modules ... %v", schemas)
103 for _, module := range schemas {
104 modName := C.CString(module)
105 defer C.free(unsafe.Pointer(modName))
107 if done := n.SubscribeModule(modName); !done {
111 return n.SubscribeStatusData()
114 func (n *Nbi) SubscribeModule(module *C.char) bool {
115 rc := C.sr_module_change_subscribe(n.session, module, nil, C.sr_module_change_cb(C.module_change_cb), nil, 0, 0, &n.subscription)
116 if C.SR_ERR_OK != rc {
117 log.Info("NBI: sr_module_change_subscribe failed: %s", C.GoString(C.sr_strerror(rc)))
123 func (n *Nbi) SubscribeStatusData() bool {
124 mod := C.CString("o-ran-sc-ric-gnb-status-v1")
125 path := C.CString("/o-ran-sc-ric-gnb-status-v1:ric/nodes")
126 defer C.free(unsafe.Pointer(mod))
127 defer C.free(unsafe.Pointer(path))
129 rc := C.sr_oper_get_items_subscribe(n.session, mod, path, C.sr_oper_get_items_cb(C.gnb_status_cb), nil, 0, &n.subscription)
130 if C.SR_ERR_OK != rc {
131 log.Error("NBI: sr_oper_get_items_subscribe failed: %s", C.GoString(C.sr_strerror(rc)))
137 //export nbiModuleChangeCB
138 func nbiModuleChangeCB(session *C.sr_session_ctx_t, module *C.char, xpath *C.char, event C.sr_event_t, reqId C.int) C.int {
139 changedModule := C.GoString(module)
140 changedXpath := C.GoString(xpath)
142 log.Info("NBI: Module change callback - event='%d' module=%s xpath=%s reqId=%d", event, changedModule, changedXpath, reqId)
144 if C.SR_EV_CHANGE == event {
145 configJson := C.yang_data_sr2json(session, module, event, &nbiClient.oper)
146 err := nbiClient.ManageXapps(changedModule, C.GoString(configJson), int(nbiClient.oper))
148 return C.SR_ERR_OPERATION_FAILED
152 if C.SR_EV_DONE == event {
153 configJson := C.get_data_json(session, module)
154 err := nbiClient.ManageConfigmaps(changedModule, C.GoString(configJson), int(nbiClient.oper))
156 return C.SR_ERR_OPERATION_FAILED
163 func (n *Nbi) ManageXapps(module, configJson string, oper int) error {
164 log.Info("ManageXapps: module=%s configJson=%s", module, configJson)
166 if configJson == "" || module != "o-ran-sc-ric-xapp-desc-v1" {
170 root := fmt.Sprintf("%s:ric", module)
171 jsonList, err := n.ParseJsonArray(configJson, root, "xapps", "xapp")
176 for _, m := range jsonList {
177 xappName := string(m.GetStringBytes("name"))
178 namespace := string(m.GetStringBytes("namespace"))
179 relName := string(m.GetStringBytes("release-name"))
180 version := string(m.GetStringBytes("version"))
182 desc := sbiClient.BuildXappDescriptor(xappName, namespace, relName, version)
184 case C.SR_OP_CREATED:
185 return sbiClient.DeployXapp(desc)
186 case C.SR_OP_DELETED:
187 return sbiClient.UndeployXapp(desc)
189 return errors.New(fmt.Sprintf("Operation '%d' not supported!", oper))
195 func (n *Nbi) ManageConfigmaps(module, configJson string, oper int) error {
196 log.Info("ManageConfig: module=%s configJson=%s", module, configJson)
198 if configJson == "" || module != "o-ran-sc-ric-ueec-config-v1" {
202 if oper != C.SR_OP_MODIFIED {
203 return errors.New(fmt.Sprintf("Operation '%d' not supported!", oper))
206 value, err := n.ParseJson(configJson)
211 root := fmt.Sprintf("%s:ric", module)
212 appName := string(value.GetStringBytes(root, "config", "name"))
213 namespace := string(value.GetStringBytes(root, "config", "namespace"))
214 control := value.Get(root, "config", "control").String()
217 err = json.Unmarshal([]byte(strings.ReplaceAll(control, "\\", "")), &f)
219 log.Info("json.Unmarshal failed: %v", err)
223 xappConfig := sbiClient.BuildXappConfig(appName, namespace, f)
224 return sbiClient.ModifyXappConfig(xappConfig)
227 func (n *Nbi) ParseJson(dsContent string) (*fastjson.Value, error) {
228 var p fastjson.Parser
229 v, err := p.Parse(dsContent)
231 log.Info("fastjson.Parser failed: %v", err)
236 func (n *Nbi) ParseJsonArray(dsContent, model, top, elem string) ([]*fastjson.Value, error) {
237 v, err := n.ParseJson(dsContent)
241 return v.GetArray(model, top, elem), nil
244 //export nbiGnbStateCB
245 func nbiGnbStateCB(session *C.sr_session_ctx_t, module *C.char, xpath *C.char, req_xpath *C.char, reqid C.uint32_t, parent **C.char) C.int {
246 log.Info("NBI: Module state data for module='%s' path='%s' rpath='%s' requested [id=%d]", C.GoString(module), C.GoString(xpath), C.GoString(req_xpath), reqid)
248 gnbs, err := xapp.Rnib.GetListGnbIds()
249 if err != nil || len(gnbs) == 0 {
250 log.Info("Rnib.GetListGnbIds() returned elementCount=%d err:%v", len(gnbs), err)
254 for _, gnb := range gnbs {
255 ranName := gnb.GetInventoryName()
256 info, err := xapp.Rnib.GetNodeb(ranName)
258 log.Error("GetNodeb() failed for ranName=%s: %v", ranName, err)
262 prot := nbiClient.E2APProt2Str(int(info.E2ApplicationProtocol))
263 connStat := nbiClient.ConnStatus2Str(int(info.ConnectionStatus))
264 ntype := nbiClient.NodeType2Str(int(info.NodeType))
266 log.Info("gNB info: %s -> %s %s %s -> %s %s", ranName, prot, connStat, ntype, gnb.GetGlobalNbId().GetPlmnId(), gnb.GetGlobalNbId().GetNbId())
268 nbiClient.CreateNewElement(session, parent, ranName, "ran-name", ranName)
269 nbiClient.CreateNewElement(session, parent, ranName, "ip", info.Ip)
270 nbiClient.CreateNewElement(session, parent, ranName, "port", fmt.Sprintf("%d", info.Port))
271 nbiClient.CreateNewElement(session, parent, ranName, "plmn-id", gnb.GetGlobalNbId().GetPlmnId())
272 nbiClient.CreateNewElement(session, parent, ranName, "nb-id", gnb.GetGlobalNbId().GetNbId())
273 nbiClient.CreateNewElement(session, parent, ranName, "e2ap-protocol", prot)
274 nbiClient.CreateNewElement(session, parent, ranName, "connection-status", connStat)
275 nbiClient.CreateNewElement(session, parent, ranName, "node", ntype)
280 func (n *Nbi) CreateNewElement(session *C.sr_session_ctx_t, parent **C.char, key, name, value string) {
281 basePath := fmt.Sprintf("/o-ran-sc-ric-gnb-status-v1:ric/nodes/node[ran-name='%s']/%s", key, name)
282 log.Info("%s -> %s", basePath, value)
284 cPath := C.CString(basePath)
285 defer C.free(unsafe.Pointer(cPath))
286 cValue := C.CString(value)
287 defer C.free(unsafe.Pointer(cValue))
289 C.create_new_path(session, parent, cPath, cValue)
292 func (n *Nbi) ConnStatus2Str(connStatus int) string {
295 return "not-specified"
299 return "disconnected"
301 return "setup-failed"
305 return "shutting-down"
309 return "not-specified"
312 func (n *Nbi) E2APProt2Str(prot int) string {
315 return "not-specified"
317 return "x2-setup-request"
319 return "endc-x2-setup-request"
321 return "not-specified"
324 func (n *Nbi) NodeType2Str(ntype int) string {
327 return "not-specified"
333 return "not-specified"