blob: d564dc73deab0e0353648cad57ab16dae86d6bb4 [file] [log] [blame]
Elia Battiston4750d3c2022-07-14 13:24:56 +00001/*
2* Copyright 2022-present Open Networking Foundation
3
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7
8* http://www.apache.org/licenses/LICENSE-2.0
9
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15 */
16
17package sysrepo
18
19//#cgo LDFLAGS: -lsysrepo -lyang -Wl,--allow-multiple-definition
20//#include "plugin.c"
21import "C"
22import (
23 "context"
24 "fmt"
25 "unsafe"
26
27 "github.com/opencord/voltha-lib-go/v7/pkg/log"
28 "github.com/opencord/voltha-northbound-bbf-adapter/internal/core"
29)
30
31//srErrorMsg provides a description of a sysrepo error code
32func srErrorMsg(code C.int) string {
33 return C.GoString(C.sr_strerror(code))
34}
35
36//lyErrorMsg provides the last libyang error message
37func lyErrorMsg(ly_ctx *C.ly_ctx) string {
38 lyErrString := C.ly_errmsg(ly_ctx)
39 defer freeCString(lyErrString)
40
41 return C.GoString(lyErrString)
42}
43
44func freeCString(str *C.char) {
45 if str != nil {
46 C.free(unsafe.Pointer(str))
47 str = nil
48 }
49}
50
51//Creates a new libyang nodes tree from a set of new paths.
52//The tree must bee manually freed after its use with C.lyd_free_all or
53//an equivalent function
54func createYangTree(ctx context.Context, session *C.sr_session_ctx_t, items []core.YangItem) (*C.lyd_node, error) {
55 if len(items) == 0 {
56 return nil, fmt.Errorf("no-items")
57 }
58
59 conn := C.sr_session_get_connection(session)
60 if conn == nil {
61 return nil, fmt.Errorf("null-connection")
62 }
63
64 //libyang context
65 ly_ctx := C.sr_acquire_context(conn)
66 if ly_ctx == nil {
67 return nil, fmt.Errorf("null-libyang-context")
68 }
69 defer C.sr_release_context(conn)
70
71 //Create parent node
72 parentPath := C.CString(items[0].Path)
73 parentValue := C.CString(items[0].Value)
74
75 var parent *C.lyd_node
76 lyErr := C.lyd_new_path(nil, ly_ctx, parentPath, parentValue, 0, &parent)
77 if lyErr != C.LY_SUCCESS {
78 err := fmt.Errorf("libyang-new-path-failed: %d %s", lyErr, lyErrorMsg(ly_ctx))
79 return nil, err
80 }
81 logger.Debugw(ctx, "creating-yang-item", log.Fields{"item": items[0]})
82
83 freeCString(parentPath)
84 freeCString(parentValue)
85
86 //Add remaining nodes
87 for _, item := range items[1:] {
88 logger.Debugw(ctx, "creating-yang-item", log.Fields{"item": item})
89
90 path := C.CString(item.Path)
91 value := C.CString(item.Value)
92
93 lyErr := C.lyd_new_path(parent, ly_ctx, path, value, 0, nil)
94 if lyErr != C.LY_SUCCESS {
95 freeCString(path)
96 freeCString(value)
97
98 //Free the partially created tree
99 C.lyd_free_all(parent)
100
101 err := fmt.Errorf("libyang-new-path-failed: %d %s", lyErr, lyErrorMsg(ly_ctx))
102
103 return nil, err
104 }
105
106 freeCString(path)
107 freeCString(value)
108 }
109
110 return parent, nil
111}
112
113//Creates a set of new paths under an existing libyang tree parent node
114func updateYangTree(ctx context.Context, session *C.sr_session_ctx_t, parent **C.lyd_node, items []core.YangItem) error {
115 if len(items) == 0 {
116 //Nothing to do
117 return nil
118 }
119
120 conn := C.sr_session_get_connection(session)
121 if conn == nil {
122 return fmt.Errorf("null-connection")
123 }
124
125 //libyang context
126 ly_ctx := C.sr_acquire_context(conn)
127 if ly_ctx == nil {
128 return fmt.Errorf("null-libyang-context")
129 }
130 defer C.sr_release_context(conn)
131
132 for _, item := range items {
133 logger.Debugw(ctx, "updating-yang-item", log.Fields{"item": item})
134
135 path := C.CString(item.Path)
136 value := C.CString(item.Value)
137
138 lyErr := C.lyd_new_path(*parent, ly_ctx, path, value, 0, nil)
139 if lyErr != C.LY_SUCCESS {
140 freeCString(path)
141 freeCString(value)
142
143 err := fmt.Errorf("libyang-new-path-failed: %d %s", lyErr, lyErrorMsg(ly_ctx))
144
145 return err
146 }
147
148 freeCString(path)
149 freeCString(value)
150 }
151
152 return nil
153}
154
155//Merges the content of a yang tree with the content of the datastore.
156//The target datastore is the one on which the session has been created
157func editDatastore(ctx context.Context, session *C.sr_session_ctx_t, editsTree *C.lyd_node) error {
158 errCode := C.sr_edit_batch(session, editsTree, C.mergeOperation)
159 if errCode != C.SR_ERR_OK {
160 err := fmt.Errorf("failed-to-edit-datastore")
161 logger.Errorw(ctx, err.Error(), log.Fields{"errCode": errCode, "errMsg": srErrorMsg(errCode)})
162 return err
163 }
164
165 errCode = C.sr_apply_changes(session, 0)
166 if errCode != C.SR_ERR_OK {
167 err := fmt.Errorf("failed-to-apply-datastore-changes")
168 logger.Errorw(ctx, err.Error(), log.Fields{"errCode": errCode, "errMsg": srErrorMsg(errCode)})
169 return err
170 }
171
172 return nil
173}