blob: 5275b123c97d3d2ad6db8bdfe94960c09bb8725a [file] [log] [blame]
Elia Battistone1cecb22022-03-21 10:05:25 +01001/*
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 core
18
19import (
20 "fmt"
Elia Battistona1333642022-07-27 12:17:24 +000021 "strconv"
Elia Battiston4750d3c2022-07-14 13:24:56 +000022 "time"
Elia Battistone1cecb22022-03-21 10:05:25 +010023
Elia Battistona1333642022-07-27 12:17:24 +000024 "github.com/opencord/voltha-northbound-bbf-adapter/internal/clients"
Elia Battiston589addb2022-04-04 16:40:01 +020025 "github.com/opencord/voltha-protos/v5/go/common"
Elia Battistone1cecb22022-03-21 10:05:25 +010026 "github.com/opencord/voltha-protos/v5/go/voltha"
27)
28
29const (
Elia Battiston4750d3c2022-07-14 13:24:56 +000030 DeviceAggregationModule = "bbf-device-aggregation"
31 DevicesPath = "/" + DeviceAggregationModule + ":devices"
Elia Battiston589addb2022-04-04 16:40:01 +020032
Elia Battistona1333642022-07-27 12:17:24 +000033 ServiceProfileModule = "bbf-nt-service-profile"
34 ServiceProfilesPath = "/" + ServiceProfileModule + ":service-profiles"
35
36 VlansModule = "bbf-l2-access-attributes"
37 VlansPath = "/" + VlansModule + ":vlan-translation-profiles"
38
39 BandwidthProfileModule = "bbf-nt-line-profile"
40 BandwidthProfilesPath = "/" + BandwidthProfileModule + ":line-bandwidth-profiles"
41
Elia Battiston589addb2022-04-04 16:40:01 +020042 //Device types
43 DeviceTypeOlt = "bbf-device-types:olt"
44 DeviceTypeOnu = "bbf-device-types:onu"
45
46 //Admin states
47 ietfAdminStateUnknown = "unknown"
48 ietfAdminStateLocked = "locked"
49 ietfAdminStateUnlocked = "unlocked"
50
51 //Oper states
52 ietfOperStateUnknown = "unknown"
53 ietfOperStateDisabled = "disabled"
54 ietfOperStateEnabled = "enabled"
55 ietfOperStateTesting = "testing"
Elia Battiston4750d3c2022-07-14 13:24:56 +000056 ietfOperStateUp = "up"
57 ietfOperStateDown = "down"
58
59 //Keys of useful values in device events
60 eventContextKeyPonId = "pon-id"
61 eventContextKeyOnuSn = "serial-number"
62 eventContextKeyOltSn = "olt-serial-number"
Elia Battistona1333642022-07-27 12:17:24 +000063
64 //Values to allow any VLAN ID
65 YangVlanIdAny = "any"
66 VolthaVlanIdAny = 4096
Elia Battistone1cecb22022-03-21 10:05:25 +010067)
68
69type YangItem struct {
70 Path string
71 Value string
72}
73
74//getDevicePath returns the yang path to the root of the device with a specific ID
75func getDevicePath(id string) string {
76 return fmt.Sprintf("%s/device[name='%s']", DevicesPath, id)
77}
78
Elia Battiston589addb2022-04-04 16:40:01 +020079//getDevicePath returns the yang path to the root of the device's hardware module in its data mountpoint
80func getDeviceHardwarePath(id string) string {
Elia Battiston4750d3c2022-07-14 13:24:56 +000081 return fmt.Sprintf("%s/device[name='%s']/data/ietf-hardware:hardware/component[name='%s']", DevicesPath, id, id)
Elia Battiston589addb2022-04-04 16:40:01 +020082}
83
Elia Battistona1333642022-07-27 12:17:24 +000084//GetServicePortPath returns the yang path to a service's port node
85func GetServicePortPath(serviceName string, portName string) string {
86 return fmt.Sprintf("%s/service-profile[name='%s']/ports/port[name='%s']", ServiceProfilesPath, serviceName, portName)
87}
88
89//GetVlansPath returns the yang path to a vlan translation profile's root node
90func GetVlansPath(serviceName string) string {
91 return fmt.Sprintf("%s/vlan-translation-profile[name='%s']", VlansPath, serviceName)
92}
93
Elia Battiston589addb2022-04-04 16:40:01 +020094//ietfHardwareAdminState returns the string that represents the ietf-hardware admin state
95//enum value corresponding to the one of VOLTHA
96func ietfHardwareAdminState(volthaAdminState voltha.AdminState_Types) string {
97 //TODO: verify this mapping is correct
98 switch volthaAdminState {
99 case common.AdminState_UNKNOWN:
100 return ietfAdminStateUnknown
101 case common.AdminState_PREPROVISIONED:
102 case common.AdminState_DOWNLOADING_IMAGE:
103 case common.AdminState_ENABLED:
104 return ietfAdminStateUnlocked
105 case common.AdminState_DISABLED:
106 return ietfAdminStateLocked
107 }
108
109 //TODO: does something map to "shutting-down" ?
110
111 return ietfAdminStateUnknown
112}
113
114//ietfHardwareOperState returns the string that represents the ietf-hardware oper state
115//enum value corresponding to the one of VOLTHA
116func ietfHardwareOperState(volthaOperState voltha.OperStatus_Types) string {
117 //TODO: verify this mapping is correct
118 switch volthaOperState {
119 case common.OperStatus_UNKNOWN:
120 return ietfOperStateUnknown
121 case common.OperStatus_TESTING:
122 return ietfOperStateTesting
123 case common.OperStatus_ACTIVE:
124 return ietfOperStateEnabled
125 case common.OperStatus_DISCOVERED:
126 case common.OperStatus_ACTIVATING:
127 case common.OperStatus_FAILED:
128 case common.OperStatus_RECONCILING:
129 case common.OperStatus_RECONCILING_FAILED:
130 return ietfOperStateDisabled
131 }
132
133 return ietfOperStateUnknown
134}
135
Elia Battiston4750d3c2022-07-14 13:24:56 +0000136//ietfHardwareOperState returns the string that represents the ietf-interfaces oper state
137//enum value corresponding to the one of VOLTHA
138func ietfInterfacesOperState(volthaOperState voltha.OperStatus_Types) string {
139 //TODO: verify this mapping is correct
140 switch volthaOperState {
141 case common.OperStatus_UNKNOWN:
142 return ietfOperStateUnknown
143 case common.OperStatus_TESTING:
144 return ietfOperStateTesting
145 case common.OperStatus_ACTIVE:
146 return ietfOperStateUp
147 case common.OperStatus_DISCOVERED:
148 case common.OperStatus_ACTIVATING:
149 case common.OperStatus_FAILED:
150 case common.OperStatus_RECONCILING:
151 case common.OperStatus_RECONCILING_FAILED:
152 return ietfOperStateDown
153 }
154
155 return ietfOperStateUnknown
156}
157
Elia Battistone1cecb22022-03-21 10:05:25 +0100158//translateDevice returns a slice of yang items that represent a voltha device
Elia Battiston4750d3c2022-07-14 13:24:56 +0000159func translateDevice(device *voltha.Device) []YangItem {
Elia Battistone1cecb22022-03-21 10:05:25 +0100160 devicePath := getDevicePath(device.Id)
Elia Battiston589addb2022-04-04 16:40:01 +0200161 hardwarePath := getDeviceHardwarePath(device.Id)
Elia Battistone1cecb22022-03-21 10:05:25 +0100162
Elia Battiston589addb2022-04-04 16:40:01 +0200163 result := []YangItem{}
Elia Battistone1cecb22022-03-21 10:05:25 +0100164
Elia Battiston589addb2022-04-04 16:40:01 +0200165 //Device type
Elia Battistone1cecb22022-03-21 10:05:25 +0100166 if device.Root {
Elia Battiston4750d3c2022-07-14 13:24:56 +0000167 //OLT
Elia Battiston589addb2022-04-04 16:40:01 +0200168 result = append(result, YangItem{
Elia Battiston4750d3c2022-07-14 13:24:56 +0000169 Path: devicePath + "/type",
Elia Battiston589addb2022-04-04 16:40:01 +0200170 Value: DeviceTypeOlt,
171 })
Elia Battistone1cecb22022-03-21 10:05:25 +0100172 } else {
Elia Battiston4750d3c2022-07-14 13:24:56 +0000173 //ONU
Elia Battistona1333642022-07-27 12:17:24 +0000174 result = append(result, []YangItem{
175 {
176 Path: devicePath + "/type",
177 Value: DeviceTypeOnu,
178 },
179 {
180 Path: hardwarePath + "/parent",
181 Value: device.ParentId,
182 },
183 {
184 Path: hardwarePath + "/parent-rel-pos",
185 Value: strconv.FormatUint(uint64(device.ParentPortNo), 10),
186 },
187 }...)
Elia Battistone1cecb22022-03-21 10:05:25 +0100188 }
189
Elia Battiston589addb2022-04-04 16:40:01 +0200190 //Vendor name
191 result = append(result, YangItem{
Elia Battiston4750d3c2022-07-14 13:24:56 +0000192 Path: hardwarePath + "/mfg-name",
Elia Battiston589addb2022-04-04 16:40:01 +0200193 Value: device.Vendor,
194 })
195
196 //Model
197 result = append(result, YangItem{
Elia Battiston4750d3c2022-07-14 13:24:56 +0000198 Path: hardwarePath + "/model-name",
Elia Battiston589addb2022-04-04 16:40:01 +0200199 Value: device.Model,
200 })
201
202 //Hardware version
203 result = append(result, YangItem{
Elia Battiston4750d3c2022-07-14 13:24:56 +0000204 Path: hardwarePath + "/hardware-rev",
Elia Battiston589addb2022-04-04 16:40:01 +0200205 Value: device.HardwareVersion,
206 })
207
208 //Firmware version
209 result = append(result, YangItem{
Elia Battiston4750d3c2022-07-14 13:24:56 +0000210 Path: hardwarePath + "/firmware-rev",
Elia Battiston589addb2022-04-04 16:40:01 +0200211 Value: device.FirmwareVersion,
212 })
213
214 //Serial number
215 result = append(result, YangItem{
Elia Battiston4750d3c2022-07-14 13:24:56 +0000216 Path: hardwarePath + "/serial-num",
Elia Battiston589addb2022-04-04 16:40:01 +0200217 Value: device.SerialNumber,
218 })
219
220 //Administrative state
221 //Translates VOLTHA admin state enum to ietf-hardware enum
222 result = append(result, YangItem{
Elia Battiston4750d3c2022-07-14 13:24:56 +0000223 Path: hardwarePath + "/state/admin-state",
Elia Battiston589addb2022-04-04 16:40:01 +0200224 Value: ietfHardwareAdminState(device.AdminState),
225 })
226
227 //Operative state
228 result = append(result, YangItem{
Elia Battiston4750d3c2022-07-14 13:24:56 +0000229 Path: hardwarePath + "/state/oper-state",
Elia Battiston589addb2022-04-04 16:40:01 +0200230 Value: ietfHardwareOperState(device.OperStatus),
231 })
232
233 return result
Elia Battistone1cecb22022-03-21 10:05:25 +0100234}
235
Elia Battiston4750d3c2022-07-14 13:24:56 +0000236//translateOnuPorts returns a slice of yang items that represent the UNIs of an ONU
237func translateOnuPorts(deviceId string, ports *voltha.Ports) ([]YangItem, error) {
238 interfacesPath := getDevicePath(deviceId) + "/data/ietf-interfaces:interfaces"
Elia Battistone1cecb22022-03-21 10:05:25 +0100239 result := []YangItem{}
240
Elia Battiston4750d3c2022-07-14 13:24:56 +0000241 for _, port := range ports.Items {
242 if port.Type == voltha.Port_ETHERNET_UNI {
243 if port.OfpPort == nil {
244 return nil, fmt.Errorf("no-ofp-port-in-uni: %s %d", deviceId, port.PortNo)
245 }
246
247 interfacePath := fmt.Sprintf("%s/interface[name='%s']", interfacesPath, port.OfpPort.Name)
248
249 result = append(result, []YangItem{
250 {
251 Path: interfacePath + "/type",
252 Value: "bbf-xpon-if-type:onu-v-vrefpoint",
253 },
254 {
255 Path: interfacePath + "/oper-status",
256 Value: ietfInterfacesOperState(port.OperStatus),
257 },
258 }...)
259 }
Elia Battistone1cecb22022-03-21 10:05:25 +0100260 }
261
Elia Battiston4750d3c2022-07-14 13:24:56 +0000262 return result, nil
263}
264
265//TranslateOnuActivatedEvent returns a slice of yang items and the name of the channel termination to populate
266//an ONU discovery notification with data from ONU_ACTIVATED_RAISE_EVENT coming from the Kafka bus
267func TranslateOnuActivatedEvent(eventHeader *voltha.EventHeader, deviceEvent *voltha.DeviceEvent) (notification []YangItem, channelTermination []YangItem, err error) {
268
269 //TODO: the use of this notification, which requires the creation of a dummy channel termination node,
270 //is temporary, and will be substituted with a more fitting one as soon as it will be defined
271
272 //Check if the needed information is present
273 ponId, ok := deviceEvent.Context[eventContextKeyPonId]
274 if !ok {
275 return nil, nil, fmt.Errorf("missing-key-from-event-context: %s", eventContextKeyPonId)
276 }
277 oltId, ok := deviceEvent.Context[eventContextKeyOltSn]
278 if !ok {
279 return nil, nil, fmt.Errorf("missing-key-from-event-context: %s", eventContextKeyPonId)
280 }
281 ponName := oltId + "-pon-" + ponId
282
283 onuSn, ok := deviceEvent.Context[eventContextKeyOnuSn]
284 if !ok {
285 return nil, nil, fmt.Errorf("missing-key-from-event-context: %s", eventContextKeyOnuSn)
286 }
287
288 notificationPath := "/bbf-xpon-onu-states:onu-state-change"
289
290 notification = []YangItem{
291 {
292 Path: notificationPath + "/detected-serial-number",
293 Value: onuSn,
294 },
295 {
296 Path: notificationPath + "/channel-termination-ref",
297 Value: ponName,
298 },
299 {
300 Path: notificationPath + "/onu-state-last-change",
301 Value: eventHeader.RaisedTs.AsTime().Format(time.RFC3339),
302 },
303 {
304 Path: notificationPath + "/onu-state",
305 Value: "bbf-xpon-onu-types:onu-present",
306 },
307 {
308 Path: notificationPath + "/detected-registration-id",
309 Value: deviceEvent.ResourceId,
310 },
311 }
312
313 channelTermination = []YangItem{
314 {
315 Path: fmt.Sprintf("/ietf-interfaces:interfaces/interface[name='%s']/type", ponName),
316 Value: "bbf-if-type:vlan-sub-interface",
317 },
318 }
319
320 return notification, channelTermination, nil
Elia Battistone1cecb22022-03-21 10:05:25 +0100321}
Elia Battistona1333642022-07-27 12:17:24 +0000322
Elia Battistonaa7a0482022-08-17 12:24:02 +0000323//translateService returns a slice of yang items that represent a programmed service
324func translateService(tagInfo clients.SadisUniTag, alias ServiceAlias) ([]YangItem, error) {
Elia Battistona1333642022-07-27 12:17:24 +0000325 result := []YangItem{}
326
Elia Battistonaa7a0482022-08-17 12:24:02 +0000327 portPath := GetServicePortPath(alias.ServiceName, alias.Key.Port)
Elia Battistona1333642022-07-27 12:17:24 +0000328
Elia Battistonaa7a0482022-08-17 12:24:02 +0000329 if tagInfo.ConfiguredMacAddress != "" {
330 result = append(result, YangItem{
331 Path: portPath + "/bbf-nt-service-profile-voltha:configured-mac-address",
332 Value: tagInfo.ConfiguredMacAddress,
333 })
Elia Battistona1333642022-07-27 12:17:24 +0000334 }
335
Elia Battistonaa7a0482022-08-17 12:24:02 +0000336 result = append(result, []YangItem{
337 {
338 Path: fmt.Sprintf("%s/port-vlans/port-vlan[name='%s']", portPath, alias.VlansName),
339 Value: "",
340 },
341 {
342 Path: portPath + "/bbf-nt-service-profile-voltha:technology-profile-id",
343 Value: strconv.Itoa(tagInfo.TechnologyProfileID),
344 },
345 {
346 Path: portPath + "/bbf-nt-service-profile-voltha:mac-learning-enabled",
347 Value: strconv.FormatBool(tagInfo.EnableMacLearning),
348 },
349 {
350 Path: portPath + "/bbf-nt-service-profile-voltha:dhcp-required",
351 Value: strconv.FormatBool(tagInfo.IsDhcpRequired),
352 },
353 {
354 Path: portPath + "/bbf-nt-service-profile-voltha:igmp-required",
355 Value: strconv.FormatBool(tagInfo.IsIgmpRequired),
356 },
357 {
358 Path: portPath + "/bbf-nt-service-profile-voltha:pppoe-required",
359 Value: strconv.FormatBool(tagInfo.IsPPPoERequired),
360 },
361 }...)
362
363 // TODO: The creation of leaves for Bandwidth Profiles has been temporarily
364 // removed to avoid validation issues during reconciliation, until the translation
365 // of Bandwidth Profiles is agreed.
366 // See translateBandwidthProfiles()
367
Elia Battistona1333642022-07-27 12:17:24 +0000368 return result, nil
369}
370
Elia Battistonaa7a0482022-08-17 12:24:02 +0000371//translateVlans returns a slice of yang items that represent the vlans used by a programmed service
372func translateVlans(tagInfo clients.SadisUniTag, alias ServiceAlias) ([]YangItem, error) {
Elia Battistona1333642022-07-27 12:17:24 +0000373 result := []YangItem{}
374
Elia Battistonaa7a0482022-08-17 12:24:02 +0000375 vlansPath := GetVlansPath(alias.VlansName)
Elia Battistona1333642022-07-27 12:17:24 +0000376
Elia Battistonaa7a0482022-08-17 12:24:02 +0000377 uniTagMatch := YangVlanIdAny
378 sTag := YangVlanIdAny
379 cTag := YangVlanIdAny
Elia Battistona1333642022-07-27 12:17:24 +0000380
Elia Battistonaa7a0482022-08-17 12:24:02 +0000381 if tagInfo.UniTagMatch != VolthaVlanIdAny {
382 uniTagMatch = strconv.Itoa(tagInfo.UniTagMatch)
383 }
384 if tagInfo.PonSTag != VolthaVlanIdAny {
385 sTag = strconv.Itoa(tagInfo.PonSTag)
386 }
387 if tagInfo.PonCTag != VolthaVlanIdAny {
388 cTag = strconv.Itoa(tagInfo.PonCTag)
389 }
Elia Battistona1333642022-07-27 12:17:24 +0000390
Elia Battistonaa7a0482022-08-17 12:24:02 +0000391 if tagInfo.UniTagMatch > 0 {
Elia Battistona1333642022-07-27 12:17:24 +0000392 result = append(result, []YangItem{
393 {
Elia Battistonaa7a0482022-08-17 12:24:02 +0000394 Path: vlansPath + "/match-criteria/outer-tag/vlan-id",
395 Value: uniTagMatch,
Elia Battistona1333642022-07-27 12:17:24 +0000396 },
397 {
Elia Battistonaa7a0482022-08-17 12:24:02 +0000398 Path: vlansPath + "/match-criteria/second-tag/vlan-id",
399 Value: "any",
Elia Battistona1333642022-07-27 12:17:24 +0000400 },
401 }...)
402 }
403
Elia Battistonaa7a0482022-08-17 12:24:02 +0000404 if tagInfo.UsPonSTagPriority >= 0 {
405 result = append(result, YangItem{
406 Path: vlansPath + "/ingress-rewrite/push-outer-tag/pbit",
407 Value: strconv.Itoa(tagInfo.UsPonSTagPriority),
408 })
409 }
410 if tagInfo.DsPonSTagPriority >= 0 {
411 result = append(result, YangItem{
412 Path: vlansPath + "/ingress-rewrite/push-outer-tag/bbf-voltha-vlan-translation:dpbit",
413 Value: strconv.Itoa(tagInfo.DsPonSTagPriority),
414 })
415 }
416 if tagInfo.UsPonCTagPriority >= 0 {
417 result = append(result, YangItem{
418 Path: vlansPath + "/ingress-rewrite/push-second-tag/pbit",
419 Value: strconv.Itoa(tagInfo.UsPonCTagPriority),
420 })
421 }
422 if tagInfo.DsPonCTagPriority >= 0 {
423 result = append(result, YangItem{
424 Path: vlansPath + "/ingress-rewrite/push-second-tag/bbf-voltha-vlan-translation:dpbit",
425 Value: strconv.Itoa(tagInfo.DsPonCTagPriority),
426 })
427 }
428
429 result = append(result, []YangItem{
430 {
431 Path: vlansPath + "/ingress-rewrite/push-outer-tag/vlan-id",
432 Value: sTag,
433 },
434 {
435 Path: vlansPath + "/ingress-rewrite/push-second-tag/vlan-id",
436 Value: cTag,
437 },
438 }...)
439
Elia Battistona1333642022-07-27 12:17:24 +0000440 return result, nil
441}
442
443//translateBandwidthProfiles returns a slice of yang items that represent the bandwidth profiles used by programmed services
444func translateBandwidthProfiles(bwProfiles []clients.BandwidthProfile) ([]YangItem, error) {
445 result := []YangItem{}
446
447 //TODO: The best way to translate this information is still under discussion, but the code
448 // to retrieve it is ready. Since this is not fundamental at the moment, an empty slice is
449 // returned, and the correct translation can be added here at a later time.
450
451 return result, nil
452}