blob: 27c83624fbee149078cdeaa5974e7c7d87d0fdd0 [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"
Elia Battistona1333642022-07-27 12:17:24 +000024 "fmt"
25 "strconv"
Elia Battiston4750d3c2022-07-14 13:24:56 +000026
27 "github.com/opencord/voltha-lib-go/v7/pkg/log"
28 "github.com/opencord/voltha-northbound-bbf-adapter/internal/core"
29)
30
31//export get_devices_cb
32func get_devices_cb(session *C.sr_session_ctx_t, parent **C.lyd_node) C.sr_error_t {
33 //This function is a callback for the retrieval of devices from sysrepo
34 //The "export" comment instructs CGO to create a C function for it
35
36 ctx := context.Background()
37 logger.Debug(ctx, "processing-get-devices-request")
38
39 if session == nil {
40 logger.Error(ctx, "sysrepo-get-devices-null-session")
41 return C.SR_ERR_OPERATION_FAILED
42 }
43
44 if parent == nil {
45 logger.Error(ctx, "sysrepo-get-devices-null-parent-node")
46 return C.SR_ERR_OPERATION_FAILED
47 }
48
49 if core.AdapterInstance == nil {
50 logger.Error(ctx, "sysrepo-get-devices-nil-translator")
51 return C.SR_ERR_OPERATION_FAILED
52 }
53
54 devices, err := core.AdapterInstance.GetDevices(ctx)
55 if err != nil {
56 logger.Errorw(ctx, "sysrepo-get-devices-translator-error", log.Fields{"err": err})
57 return C.SR_ERR_OPERATION_FAILED
58 }
59
60 err = updateYangTree(ctx, session, parent, devices)
61 if err != nil {
62 logger.Errorw(ctx, "sysrepo-get-devices-update-error", log.Fields{"err": err})
63 return C.SR_ERR_OPERATION_FAILED
64 }
65
66 logger.Info(ctx, "devices-information-request-served")
67
68 return C.SR_ERR_OK
69}
Elia Battistona1333642022-07-27 12:17:24 +000070
71//export get_services_cb
72func get_services_cb(session *C.sr_session_ctx_t, parent **C.lyd_node) C.sr_error_t {
73 //This function is a callback for the retrieval of devices from sysrepo
74 //The "export" comment instructs CGO to create a C function for it
75
76 ctx := context.Background()
77 logger.Debug(ctx, "processing-get-services-request")
78
79 if session == nil {
80 logger.Error(ctx, "sysrepo-get-services-null-session")
81 return C.SR_ERR_OPERATION_FAILED
82 }
83
84 if parent == nil {
85 logger.Error(ctx, "sysrepo-get-services-null-parent-node")
86 return C.SR_ERR_OPERATION_FAILED
87 }
88
89 if core.AdapterInstance == nil {
90 logger.Error(ctx, "sysrepo-get-services-nil-translator")
91 return C.SR_ERR_OPERATION_FAILED
92 }
93
94 services, err := core.AdapterInstance.GetServices(ctx)
95 if err != nil {
96 logger.Errorw(ctx, "sysrepo-get-services-translation-error", log.Fields{"err": err})
97 return C.SR_ERR_OPERATION_FAILED
98 }
99
100 err = updateYangTree(ctx, session, parent, services)
101 if err != nil {
102 logger.Errorw(ctx, "sysrepo-get-services-update-error", log.Fields{"err": err})
103 return C.SR_ERR_OPERATION_FAILED
104 }
105
106 logger.Info(ctx, "services-information-request-served")
107
108 return C.SR_ERR_OK
109}
110
111//export get_vlans_cb
112func get_vlans_cb(session *C.sr_session_ctx_t, parent **C.lyd_node) C.sr_error_t {
113 //This function is a callback for the retrieval of vlans from sysrepo
114 //The "export" comment instructs CGO to create a C function for it
115
116 ctx := context.Background()
117 logger.Debug(ctx, "processing-get-vlans-request")
118
119 if session == nil {
120 logger.Error(ctx, "sysrepo-get-vlans-null-session")
121 return C.SR_ERR_OPERATION_FAILED
122 }
123
124 if parent == nil {
125 logger.Error(ctx, "sysrepo-get-vlans-null-parent-node")
126 return C.SR_ERR_OPERATION_FAILED
127 }
128
129 if core.AdapterInstance == nil {
130 logger.Error(ctx, "sysrepo-get-vlans-nil-translator")
131 return C.SR_ERR_OPERATION_FAILED
132 }
133
134 vlans, err := core.AdapterInstance.GetVlans(ctx)
135 if err != nil {
136 logger.Errorw(ctx, "sysrepo-get-vlans-translation-error", log.Fields{"err": err})
137 return C.SR_ERR_OPERATION_FAILED
138 }
139
140 err = updateYangTree(ctx, session, parent, vlans)
141 if err != nil {
142 logger.Errorw(ctx, "sysrepo-get-vlans-update-error", log.Fields{"err": err})
143 return C.SR_ERR_OPERATION_FAILED
144 }
145
146 logger.Info(ctx, "vlans-information-request-served")
147
148 return C.SR_ERR_OK
149}
150
151//export get_bandwidth_profiles_cb
152func get_bandwidth_profiles_cb(session *C.sr_session_ctx_t, parent **C.lyd_node) C.sr_error_t {
153 //This function is a callback for the retrieval of bandwidth profiles from sysrepo
154 //The "export" comment instructs CGO to create a C function for it
155
156 ctx := context.Background()
157 logger.Debug(ctx, "processing-get-bandwidth-profiles-request")
158
159 if session == nil {
160 logger.Error(ctx, "sysrepo-get-bandwidth-profiles-null-session")
161 return C.SR_ERR_OPERATION_FAILED
162 }
163
164 if parent == nil {
165 logger.Error(ctx, "sysrepo-get-bandwidth-profiles-null-parent-node")
166 return C.SR_ERR_OPERATION_FAILED
167 }
168
169 if core.AdapterInstance == nil {
170 logger.Error(ctx, "sysrepo-get-bandwidth-profiles-nil-translator")
171 return C.SR_ERR_OPERATION_FAILED
172 }
173
174 bwProfiles, err := core.AdapterInstance.GetBandwidthProfiles(ctx)
175 if err != nil {
176 logger.Errorw(ctx, "sysrepo-get-bandwidth-profiles-translation-error", log.Fields{"err": err})
177 return C.SR_ERR_OPERATION_FAILED
178 }
179
180 err = updateYangTree(ctx, session, parent, bwProfiles)
181 if err != nil {
182 logger.Errorw(ctx, "sysrepo-get-bandwidth-profiles-update-error", log.Fields{"err": err})
183 return C.SR_ERR_OPERATION_FAILED
184 }
185
186 logger.Info(ctx, "bandwidth-profiles-information-request-served")
187
188 return C.SR_ERR_OK
189}
190
191//export edit_service_profiles_cb
192func edit_service_profiles_cb(editSession *C.sr_session_ctx_t, runningSession *C.sr_session_ctx_t, event C.sr_event_t) C.sr_error_t {
193 //This function is a callback for changes on service profiles
194 //The "export" comment instructs CGO to create a C function for it
195
196 if event != C.SR_EV_CHANGE {
197 return C.SR_ERR_OK
198 }
199
200 ctx := context.Background()
201 logger.Debug(ctx, "processing-service-profile-changes")
202
203 serviceNamesChanges, err := getChangesList(ctx, editSession, core.ServiceProfilesPath+"/service-profile/name")
204 if err != nil {
205 logger.Errorw(ctx, "cannot-get-service-profile-names-changes", log.Fields{"err": err})
206 return C.SR_ERR_OPERATION_FAILED
207 }
208
209 for _, n := range serviceNamesChanges {
210 switch n.Operation {
211 case C.SR_OP_CREATED:
212 if errCode := edit_service_create(ctx, editSession, runningSession, n.Value); errCode != C.SR_ERR_OK {
213 return errCode
214 }
215 case C.SR_OP_DELETED:
216 if errCode := edit_service_delete(ctx, editSession, runningSession, n.Value); errCode != C.SR_ERR_OK {
217 return errCode
218 }
219 default:
220 return C.SR_ERR_UNSUPPORTED
221 }
222 }
223
224 return C.SR_ERR_OK
225}
226
227func edit_service_create(ctx context.Context, editSession *C.sr_session_ctx_t, runningSession *C.sr_session_ctx_t, serviceName string) C.sr_error_t {
228 portName, err := getSingleChangeValue(ctx, editSession, fmt.Sprintf("%s/service-profile[name='%s']/ports/port/name", core.ServiceProfilesPath, serviceName))
229 if err != nil {
230 logger.Errorw(ctx, "cannot-get-service-profile-port-changes", log.Fields{"err": err, "service": serviceName})
231 return C.SR_ERR_OPERATION_FAILED
232 }
233
234 servicePortPath := core.GetServicePortPath(serviceName, portName)
235
236 tpId, err := getSingleChangeValue(ctx, editSession, servicePortPath+"/bbf-nt-service-profile-voltha:technology-profile-id")
237 if err != nil {
238 logger.Errorw(ctx, "cannot-get-service-profile-tp-id-change", log.Fields{"err": err, "service": serviceName})
239 return C.SR_ERR_OPERATION_FAILED
240 }
241
242 vlanName, err := getSingleChangeValue(ctx, editSession, servicePortPath+"/port-vlans/port-vlan/name")
243 if err != nil {
244 logger.Errorw(ctx, "cannot-get-service-profile-vlan-change", log.Fields{"err": err, "service": serviceName})
245 return C.SR_ERR_OPERATION_FAILED
246 }
247
248 vlansPath := core.GetVlansPath(vlanName)
249
250 sTag, err := getSingleChangeValue(ctx, editSession, vlansPath+"/ingress-rewrite/push-outer-tag/vlan-id")
251 if err != nil {
252 logger.Errorw(ctx, "cannot-get-service-profile-stag-changes", log.Fields{"err": err, "service": serviceName})
253 return C.SR_ERR_OPERATION_FAILED
254 }
255 if sTag == core.YangVlanIdAny {
256 sTag = strconv.Itoa(core.VolthaVlanIdAny)
257 }
258
259 cTag, err := getSingleChangeValue(ctx, editSession, vlansPath+"/ingress-rewrite/push-second-tag/vlan-id")
260 if err != nil {
261 logger.Errorw(ctx, "cannot-get-service-profile-stag-changes", log.Fields{"err": err, "service": serviceName})
262 return C.SR_ERR_OPERATION_FAILED
263 }
264 if cTag == core.YangVlanIdAny {
265 cTag = strconv.Itoa(core.VolthaVlanIdAny)
266 }
267
268 logger.Infow(ctx, "new-service-profile-information", log.Fields{
269 "service": serviceName,
270 "port": portName,
271 "vlanName": vlanName,
272 "tpId": tpId,
273 "sTag": sTag,
274 "cTag": cTag,
275 })
276
277 if core.AdapterInstance == nil {
278 logger.Error(ctx, "sysrepo-service-changes-nil-translator")
279 return C.SR_ERR_OPERATION_FAILED
280 }
281
282 if err := core.AdapterInstance.ProvisionService(portName, sTag, cTag, tpId); err != nil {
283 logger.Errorw(ctx, "service-provisioning-error", log.Fields{
284 "service": serviceName,
285 "err": err,
286 })
287 return C.SR_ERR_OPERATION_FAILED
288 }
289
290 logger.Infow(ctx, "service-profile-creation-request-served", log.Fields{
291 "service": serviceName,
292 })
293
294 return C.SR_ERR_OK
295}
296
297func edit_service_delete(ctx context.Context, editSession *C.sr_session_ctx_t, runningSession *C.sr_session_ctx_t, serviceName string) C.sr_error_t {
298 portName, err := getDatastoreLeafValue(ctx, runningSession, fmt.Sprintf("%s/service-profile[name='%s']/ports/port/name", core.ServiceProfilesPath, serviceName))
299 if err != nil {
300 logger.Errorw(ctx, "cannot-get-service-profile-port-leaf", log.Fields{"err": err, "service": serviceName})
301 return C.SR_ERR_OPERATION_FAILED
302 }
303
304 servicePortPath := core.GetServicePortPath(serviceName, portName)
305
306 tpId, err := getDatastoreLeafValue(ctx, runningSession, servicePortPath+"/bbf-nt-service-profile-voltha:technology-profile-id")
307 if err != nil {
308 logger.Errorw(ctx, "cannot-get-service-profile-tp-id-leaf", log.Fields{"err": err, "service": serviceName})
309 return C.SR_ERR_OPERATION_FAILED
310 }
311
312 vlanName, err := getDatastoreLeafValue(ctx, runningSession, servicePortPath+"/port-vlans/port-vlan/name")
313 if err != nil {
314 logger.Errorw(ctx, "cannot-get-service-profile-vlan-leaf", log.Fields{"err": err, "service": serviceName})
315 return C.SR_ERR_OPERATION_FAILED
316 }
317
318 vlansPath := core.GetVlansPath(vlanName)
319
320 sTag, err := getDatastoreLeafValue(ctx, runningSession, vlansPath+"/ingress-rewrite/push-outer-tag/vlan-id")
321 if err != nil {
322 logger.Errorw(ctx, "cannot-get-service-profile-stag-leaf", log.Fields{"err": err, "service": serviceName})
323 return C.SR_ERR_OPERATION_FAILED
324 }
325 if sTag == core.YangVlanIdAny {
326 sTag = strconv.Itoa(core.VolthaVlanIdAny)
327 }
328
329 cTag, err := getDatastoreLeafValue(ctx, runningSession, vlansPath+"/ingress-rewrite/push-second-tag/vlan-id")
330 if err != nil {
331 logger.Errorw(ctx, "cannot-get-service-profile-stag-leaf", log.Fields{"err": err, "service": serviceName})
332 return C.SR_ERR_OPERATION_FAILED
333 }
334 if cTag == core.YangVlanIdAny {
335 cTag = strconv.Itoa(core.VolthaVlanIdAny)
336 }
337
338 logger.Infow(ctx, "service-profile-deletion-information", log.Fields{
339 "service": serviceName,
340 "port": portName,
341 "vlanName": vlanName,
342 "tpId": tpId,
343 "sTag": sTag,
344 "cTag": cTag,
345 })
346
347 if err := core.AdapterInstance.RemoveService(portName, sTag, cTag, tpId); err != nil {
348 logger.Errorw(ctx, "service-removal-error", log.Fields{
349 "service": serviceName,
350 "err": err,
351 })
352 return C.SR_ERR_OPERATION_FAILED
353 }
354
355 logger.Infow(ctx, "service-profile-removal-request-served", log.Fields{
356 "service": serviceName,
357 })
358
359 return C.SR_ERR_OK
360}
361
362//export edit_vlans_cb
363func edit_vlans_cb(editSession *C.sr_session_ctx_t, event C.sr_event_t) C.sr_error_t {
364 //This function is a callback for changes on VLANs
365 //The "export" comment instructs CGO to create a C function for it
366
367 if event != C.SR_EV_CHANGE {
368 return C.SR_ERR_OK
369 }
370
371 ctx := context.Background()
372 logger.Debug(ctx, "processing-vlans-changes")
373
374 vlanChanges, err := getChangesList(ctx, editSession, core.VlansPath+"//.")
375 if err != nil {
376 logger.Errorw(ctx, "cannot-get-vlans-changes", log.Fields{"err": err})
377 return C.SR_ERR_OPERATION_FAILED
378 }
379
380 for _, n := range vlanChanges {
381 //VLANs must be defined through creation (for service provisioning)
382 //or deletion (for service removal). Changes to the VLAN values
383 //are not supported, because VOLTHA does not support dynamic changes
384 //to the service.
385 switch n.Operation {
386 case C.SR_OP_CREATED:
387 case C.SR_OP_DELETED:
388 //Everything will be handled in the services callback
389 //Just approve the change here
390 return C.SR_ERR_OK
391 default:
392 return C.SR_ERR_UNSUPPORTED
393 }
394 }
395
396 return C.SR_ERR_OK
397}