blob: 32768821be01f9ab1b6901ba73e59f7fbf792a7c [file] [log] [blame]
Girish Gowdrae09a6202021-01-12 18:10:59 -08001/*
2 * Copyright 2021-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
17//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
19
20import (
21 "context"
Girish Gowdra0e533642021-03-02 22:02:51 -080022 "encoding/json"
Girish Gowdrae09a6202021-01-12 18:10:59 -080023 "fmt"
Holger Hildebrandt44a0d4f2021-03-18 14:00:54 +000024 "math"
25 "sync"
26 "time"
27
Girish Gowdrae0140f02021-02-02 16:55:09 -080028 "github.com/looplab/fsm"
Girish Gowdrae09a6202021-01-12 18:10:59 -080029 "github.com/opencord/omci-lib-go"
30 me "github.com/opencord/omci-lib-go/generated"
Girish Gowdra50e56422021-06-01 16:46:04 -070031 "github.com/opencord/voltha-lib-go/v5/pkg/db"
32 "github.com/opencord/voltha-lib-go/v5/pkg/db/kvstore"
33 "github.com/opencord/voltha-lib-go/v5/pkg/log"
Girish Gowdrae09a6202021-01-12 18:10:59 -080034 "github.com/opencord/voltha-protos/v4/go/voltha"
Girish Gowdrae09a6202021-01-12 18:10:59 -080035)
36
Girish Gowdrae0140f02021-02-02 16:55:09 -080037const (
38 // events of L2 PM FSM
39 l2PmEventInit = "l2PmEventInit"
40 l2PmEventTick = "l2PmEventTick"
41 l2PmEventSuccess = "l2PmEventSuccess"
42 l2PmEventFailure = "l2PmEventFailure"
43 l2PmEventAddMe = "l2PmEventAddMe"
44 l2PmEventDeleteMe = "l2PmEventDeleteMe"
45 l2PmEventStop = "l2PmEventStop"
46)
47const (
48 // states of L2 PM FSM
49 l2PmStNull = "l2PmStNull"
50 l2PmStStarting = "l2PmStStarting"
51 l2PmStSyncTime = "l2PmStSyncTime"
52 l2PmStIdle = "l2PmStIdle"
53 l2PmStCreatePmMe = "l2PmStCreatePm"
54 l2PmStDeletePmMe = "l2PmStDeletePmMe"
55 l2PmStCollectData = "l2PmStCollectData"
56)
57
58const cL2PmFsmIdleState = l2PmStIdle
59
Girish Gowdra5a7c4922021-01-22 18:33:41 -080060// general constants used for overall Metric Collection management
61const (
62 DefaultMetricCollectionFrequency = 15 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
63 GroupMetricEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
64 DefaultFrequencyOverrideEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
65 FrequencyGranularity = 5 // The frequency (in seconds) has to be multiple of 5. This setting cannot changed later.
66)
67
68// OpticalPowerGroupMetrics are supported optical pm names
69var OpticalPowerGroupMetrics = map[string]voltha.PmConfig_PmType{
Girish Gowdrae20a4f62021-03-09 16:06:23 -080070 "ani_g_instance_id": voltha.PmConfig_CONTEXT,
71 "transmit_power_dBm": voltha.PmConfig_GAUGE,
72 "receive_power_dBm": voltha.PmConfig_GAUGE,
Girish Gowdra5a7c4922021-01-22 18:33:41 -080073}
74
75// OpticalPowerGroupMetrics specific constants
76const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080077 OpticalPowerGroupMetricName = "PON_Optical"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080078 OpticalPowerGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
79 OpticalPowerMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
80)
81
82// UniStatusGroupMetrics are supported UNI status names
83var UniStatusGroupMetrics = map[string]voltha.PmConfig_PmType{
84 "uni_port_no": voltha.PmConfig_CONTEXT,
Girish Gowdrada3a52f2021-03-17 11:24:11 -070085 "me_class_id": voltha.PmConfig_CONTEXT,
Girish Gowdra0e533642021-03-02 22:02:51 -080086 "entity_id": voltha.PmConfig_CONTEXT,
Girish Gowdrada3a52f2021-03-17 11:24:11 -070087 "sensed_type": voltha.PmConfig_GAUGE,
Girish Gowdra5a7c4922021-01-22 18:33:41 -080088 "oper_status": voltha.PmConfig_GAUGE,
89 "uni_admin_state": voltha.PmConfig_GAUGE,
90}
91
92// UniStatusGroupMetrics specific constants
93const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080094 UniStatusGroupMetricName = "UNI_Status"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080095 UniStatusGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
96 UniStatusMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
97)
98
Girish Gowdrae0140f02021-02-02 16:55:09 -080099// *** Classical L2 PM Counters begin ***
100
101// EthernetBridgeHistory are supported ethernet bridge history counters fetched from
102// Ethernet Frame Performance Monitoring History Data Downstream and Ethernet Frame Performance Monitoring History Data Upstream MEs.
103var EthernetBridgeHistory = map[string]voltha.PmConfig_PmType{
104 "class_id": voltha.PmConfig_CONTEXT,
105 "entity_id": voltha.PmConfig_CONTEXT,
106 "interval_end_time": voltha.PmConfig_CONTEXT,
107 "parent_class_id": voltha.PmConfig_CONTEXT,
108 "parent_entity_id": voltha.PmConfig_CONTEXT,
109 "upstream": voltha.PmConfig_CONTEXT,
110
111 "drop_events": voltha.PmConfig_COUNTER,
112 "octets": voltha.PmConfig_COUNTER,
113 "packets": voltha.PmConfig_COUNTER,
114 "broadcast_packets": voltha.PmConfig_COUNTER,
115 "multicast_packets": voltha.PmConfig_COUNTER,
116 "crc_errored_packets": voltha.PmConfig_COUNTER,
117 "undersize_packets": voltha.PmConfig_COUNTER,
118 "oversize_packets": voltha.PmConfig_COUNTER,
119 "64_octets": voltha.PmConfig_COUNTER,
120 "65_to_127_octets": voltha.PmConfig_COUNTER,
121 "128_to_255_octets": voltha.PmConfig_COUNTER,
122 "256_to_511_octets": voltha.PmConfig_COUNTER,
123 "512_to_1023_octets": voltha.PmConfig_COUNTER,
124 "1024_to_1518_octets": voltha.PmConfig_COUNTER,
125}
126
127// EthernetUniHistory are supported ethernet uni history counters fetched from
128// Ethernet Performance Monitoring History Data ME.
129var EthernetUniHistory = map[string]voltha.PmConfig_PmType{
130 "class_id": voltha.PmConfig_CONTEXT,
131 "entity_id": voltha.PmConfig_CONTEXT,
132 "interval_end_time": voltha.PmConfig_CONTEXT,
133
134 "fcs_errors": voltha.PmConfig_COUNTER,
135 "excessive_collision_counter": voltha.PmConfig_COUNTER,
136 "late_collision_counter": voltha.PmConfig_COUNTER,
137 "frames_too_long": voltha.PmConfig_COUNTER,
138 "buffer_overflows_on_rx": voltha.PmConfig_COUNTER,
139 "buffer_overflows_on_tx": voltha.PmConfig_COUNTER,
140 "single_collision_frame_counter": voltha.PmConfig_COUNTER,
141 "multiple_collisions_frame_counter": voltha.PmConfig_COUNTER,
142 "sqe_counter": voltha.PmConfig_COUNTER,
143 "deferred_tx_counter": voltha.PmConfig_COUNTER,
144 "internal_mac_tx_error_counter": voltha.PmConfig_COUNTER,
145 "carrier_sense_error_counter": voltha.PmConfig_COUNTER,
146 "alignment_error_counter": voltha.PmConfig_COUNTER,
147 "internal_mac_rx_error_counter": voltha.PmConfig_COUNTER,
148}
149
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800150// FecHistory is supported FEC Performance Monitoring History Data related metrics
151var FecHistory = map[string]voltha.PmConfig_PmType{
152 "class_id": voltha.PmConfig_CONTEXT,
153 "entity_id": voltha.PmConfig_CONTEXT,
154 "interval_end_time": voltha.PmConfig_CONTEXT,
155
156 "corrected_bytes": voltha.PmConfig_COUNTER,
157 "corrected_code_words": voltha.PmConfig_COUNTER,
158 "uncorrectable_code_words": voltha.PmConfig_COUNTER,
159 "total_code_words": voltha.PmConfig_COUNTER,
160 "fec_seconds": voltha.PmConfig_COUNTER,
161}
162
163// GemPortHistory is supported GEM Port Network Ctp Performance Monitoring History Data
164// related metrics
165var GemPortHistory = map[string]voltha.PmConfig_PmType{
166 "class_id": voltha.PmConfig_CONTEXT,
167 "entity_id": voltha.PmConfig_CONTEXT,
168 "interval_end_time": voltha.PmConfig_CONTEXT,
169
170 "transmitted_gem_frames": voltha.PmConfig_COUNTER,
171 "received_gem_frames": voltha.PmConfig_COUNTER,
172 "received_payload_bytes": voltha.PmConfig_COUNTER,
173 "transmitted_payload_bytes": voltha.PmConfig_COUNTER,
174 "encryption_key_errors": voltha.PmConfig_COUNTER,
175}
176
Girish Gowdrae0140f02021-02-02 16:55:09 -0800177// Constants specific for L2 PM collection
178const (
179 L2PmCollectionInterval = 15 * 60 // Unit in seconds. Do not change this as this fixed by OMCI specification for L2 PM counters
180 SyncTimeRetryInterval = 15 // Unit seconds
181 L2PmCreateAttempts = 3
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800182 L2PmDeleteAttempts = 3
Girish Gowdrae0140f02021-02-02 16:55:09 -0800183 L2PmCollectAttempts = 3
Girish Gowdra453750f2021-02-16 16:36:46 -0800184 // Per Table 11.2.9-1 – OMCI baseline message limitations in G.988 spec, the max GET Response
185 // payload size is 25. We define 24 (one less) to allow for dynamic insertion of IntervalEndTime
186 // attribute (1 byte) in L2 PM GET Requests.
187 MaxL2PMGetPayLoadSize = 24
Girish Gowdrae0140f02021-02-02 16:55:09 -0800188)
189
190// EthernetUniHistoryName specific constants
191const (
192 EthernetBridgeHistoryName = "Ethernet_Bridge_Port_History"
193 EthernetBridgeHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
194 EthernetBridgeHistoryFrequency = L2PmCollectionInterval
195)
196
197// EthernetBridgeHistory specific constants
198const (
199 EthernetUniHistoryName = "Ethernet_UNI_History"
200 EthernetUniHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
201 EthernetUniHistoryFrequency = L2PmCollectionInterval
202)
203
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800204// FecHistory specific constants
205const (
206 FecHistoryName = "FEC_History"
207 FecHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
208 FecHistoryFrequency = L2PmCollectionInterval
209)
210
211// GemPortHistory specific constants
212const (
213 GemPortHistoryName = "GEM_Port_History"
214 GemPortHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
215 GemPortHistoryFrequency = L2PmCollectionInterval
216)
217
Girish Gowdra0e533642021-03-02 22:02:51 -0800218// KV Store related constants
219const (
220 cPmKvStorePrefix = "%s/openonu/pm-data/%s" // <some-base-path>/openonu/pm-data/<onu-device-id>
221 cPmAdd = "add"
222 cPmAdded = "added"
223 cPmRemove = "remove"
224 cPmRemoved = "removed"
225)
226
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800227// Defines the type for generic metric population function
228type groupMetricPopulateFunc func(context.Context, me.ClassID, uint16, me.AttributeValueMap, me.AttributeValueMap, map[string]float32, *int) error
229
Girish Gowdrae0140f02021-02-02 16:55:09 -0800230// *** Classical L2 PM Counters end ***
231
Girish Gowdra0e533642021-03-02 22:02:51 -0800232type pmMEData struct {
233 InstancesActive []uint16 `json:"instances_active"` // list of active ME instance IDs for the group
234 InstancesToDelete []uint16 `json:"instances_to_delete"` // list of ME instance IDs marked for deletion for the group
235 InstancesToAdd []uint16 `json:"instances_to_add"` // list of ME instance IDs marked for addition for the group
236}
237
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800238type groupMetric struct {
239 groupName string
240 enabled bool
241 frequency uint32 // valid only if FrequencyOverride is enabled.
242 metricMap map[string]voltha.PmConfig_PmType
243 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
Girish Gowdrae0140f02021-02-02 16:55:09 -0800244 isL2PMCounter bool // true for only L2 PM counters
245 collectAttempts uint32 // number of attempts to collect L2 PM data
Girish Gowdra0e533642021-03-02 22:02:51 -0800246 pmMEData *pmMEData
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800247}
248
249type standaloneMetric struct {
250 metricName string
251 enabled bool
252 frequency uint32 // valid only if FrequencyOverride is enabled.
253 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
254}
255
Girish Gowdrae09a6202021-01-12 18:10:59 -0800256type onuMetricsManager struct {
257 pDeviceHandler *deviceHandler
Girish Gowdrae0140f02021-02-02 16:55:09 -0800258 pAdaptFsm *AdapterFsm
Girish Gowdrae09a6202021-01-12 18:10:59 -0800259
Girish Gowdrae0140f02021-02-02 16:55:09 -0800260 opticalMetricsChan chan me.AttributeValueMap
261 uniStatusMetricsChan chan me.AttributeValueMap
262 l2PmChan chan me.AttributeValueMap
263 syncTimeResponseChan chan bool // true is success, false is fail
264 l2PmCreateOrDeleteResponseChan chan bool // true is success, false is fail
265
266 activeL2Pms []string // list of active l2 pm MEs created on the ONU.
267 l2PmToDelete []string // list of L2 PMs to delete
268 l2PmToAdd []string // list of L2 PM to add
Girish Gowdrae09a6202021-01-12 18:10:59 -0800269
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800270 groupMetricMap map[string]*groupMetric
271 standaloneMetricMap map[string]*standaloneMetric
272
Girish Gowdrae09a6202021-01-12 18:10:59 -0800273 stopProcessingOmciResponses chan bool
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -0700274 omciProcessingActive bool
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800275
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -0700276 stopTicks chan bool
277 tickGenerationActive bool
Girish Gowdrae0140f02021-02-02 16:55:09 -0800278
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800279 nextGlobalMetricCollectionTime time.Time // valid only if pmConfig.FreqOverride is set to false.
280
281 onuMetricsManagerLock sync.RWMutex
Girish Gowdra0e533642021-03-02 22:02:51 -0800282
283 pmKvStore *db.Backend
Girish Gowdrae09a6202021-01-12 18:10:59 -0800284}
285
286// newonuMetricsManager returns a new instance of the newonuMetricsManager
Girish Gowdra0e533642021-03-02 22:02:51 -0800287// The metrics manager module is responsible for configuration and management of individual and group metrics.
288// Currently all the metrics are managed as a group which fall into two categories - L2 PM and "all others"
289// The L2 PM counters have a fixed 15min interval for PM collection while all other group counters have
290// the collection interval configurable.
291// The global PM config is part of the voltha.Device struct and is backed up on KV store (by rw-core).
292// This module also implements resiliency for L2 PM ME instances that are active/pending-delete/pending-add.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800293func newonuMetricsManager(ctx context.Context, dh *deviceHandler) *onuMetricsManager {
294
295 var metricsManager onuMetricsManager
296 logger.Debugw(ctx, "init-onuMetricsManager", log.Fields{"device-id": dh.deviceID})
297 metricsManager.pDeviceHandler = dh
298
Girish Gowdrae0140f02021-02-02 16:55:09 -0800299 commMetricsChan := make(chan Message)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800300 metricsManager.opticalMetricsChan = make(chan me.AttributeValueMap)
301 metricsManager.uniStatusMetricsChan = make(chan me.AttributeValueMap)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800302 metricsManager.l2PmChan = make(chan me.AttributeValueMap)
303
304 metricsManager.syncTimeResponseChan = make(chan bool)
305 metricsManager.l2PmCreateOrDeleteResponseChan = make(chan bool)
306
Girish Gowdrae09a6202021-01-12 18:10:59 -0800307 metricsManager.stopProcessingOmciResponses = make(chan bool)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800308 metricsManager.stopTicks = make(chan bool)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800309
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800310 metricsManager.groupMetricMap = make(map[string]*groupMetric)
311 metricsManager.standaloneMetricMap = make(map[string]*standaloneMetric)
312
313 if dh.pmConfigs == nil { // dh.pmConfigs is NOT nil if adapter comes back from a restart. We should NOT go back to defaults in this case
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800314 metricsManager.initializeAllGroupMetrics()
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800315 }
316
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800317 metricsManager.populateLocalGroupMetricData(ctx)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800318
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800319 if err := metricsManager.initializeL2PmFsm(ctx, commMetricsChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800320 return nil
321 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800322
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800323 // initialize the next metric collection intervals.
324 metricsManager.initializeMetricCollectionTime(ctx)
Girish Gowdra0e533642021-03-02 22:02:51 -0800325
326 baseKvStorePath := fmt.Sprintf(cPmKvStorePrefix, dh.pOpenOnuAc.cm.Backend.PathPrefix, dh.deviceID)
327 metricsManager.pmKvStore = dh.setBackend(ctx, baseKvStorePath)
328 if metricsManager.pmKvStore == nil {
329 logger.Errorw(ctx, "Can't initialize pmKvStore - no backend connection to PM module",
330 log.Fields{"device-id": dh.deviceID, "service": baseKvStorePath})
331 return nil
332 }
Girish Gowdra50e56422021-06-01 16:46:04 -0700333 // restore data from KV store
334 if err := metricsManager.restorePmData(ctx); err != nil {
335 logger.Errorw(ctx, "error restoring pm data", log.Fields{"err": err})
336 // we continue given that it does not effect the actual services for the ONU,
337 // but there may be some negative effect on PM collection (there may be some mismatch in
338 // the actual PM config and what is present on the device).
339 }
Girish Gowdra0e533642021-03-02 22:02:51 -0800340
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800341 logger.Info(ctx, "init-onuMetricsManager completed", log.Fields{"device-id": dh.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800342 return &metricsManager
343}
344
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800345func (mm *onuMetricsManager) initializeMetricCollectionTime(ctx context.Context) {
346 if mm.pDeviceHandler.pmConfigs.FreqOverride {
347 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to true, then group/standalone metric specific interval applies
348 mm.onuMetricsManagerLock.Lock()
349 defer mm.onuMetricsManagerLock.Unlock()
350 for _, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800351 if v.enabled && !v.isL2PMCounter { // L2 PM counter collection is managed in a L2PmFsm
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800352 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
353 }
354 }
355
356 for _, v := range mm.standaloneMetricMap {
357 if v.enabled {
358 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
359 }
360 }
361 } else {
362 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to false, then overall metric specific interval applies
363 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
364 }
365 logger.Infow(ctx, "initialized standalone group/metric collection time", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
366}
367
368func (mm *onuMetricsManager) updateDefaultFrequency(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
369 // Verify that the configured DefaultFrequency is > 0 and is a multiple of FrequencyGranularity
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800370 if pmConfigs.DefaultFreq == 0 || (pmConfigs.DefaultFreq > 0 && pmConfigs.DefaultFreq%FrequencyGranularity != 0) {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800371 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", pmConfigs.DefaultFreq, FrequencyGranularity)
372 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", pmConfigs.DefaultFreq, FrequencyGranularity)
373 }
374 mm.pDeviceHandler.pmConfigs.DefaultFreq = pmConfigs.DefaultFreq
375 // re-set the nextGlobalMetricCollectionTime based on the new DefaultFreq
376 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
377 logger.Debugw(ctx, "frequency-updated--new-frequency", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "frequency": mm.pDeviceHandler.pmConfigs.DefaultFreq})
378 return nil
379}
380
381func (mm *onuMetricsManager) updateGroupFreq(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
382 var newGroupFreq uint32
383 found := false
384 groupSliceIdx := 0
385 var group *voltha.PmGroupConfig
386 for groupSliceIdx, group = range pmConfigs.Groups {
387 if group.GroupName == aGroupName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800388 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
389 if group.GroupFreq == 0 || (group.GroupFreq > 0 && group.GroupFreq%FrequencyGranularity != 0) {
390 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", group.GroupFreq, FrequencyGranularity)
391 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", group.GroupFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800392 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800393 newGroupFreq = group.GroupFreq
394 found = true
395 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800396 }
397 }
398 // if not found update group freq and next collection interval for the group
399 if !found {
400 logger.Errorw(ctx, "group name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
401 return fmt.Errorf("group-name-not-found-%v", aGroupName)
402 }
403
404 updated := false
405 mm.onuMetricsManagerLock.Lock()
406 defer mm.onuMetricsManagerLock.Unlock()
407 for k, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800408 if k == aGroupName && !v.isL2PMCounter { // We cannot allow the L2 PM counter frequency to be updated. It is 15min fixed by OMCI spec
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800409 v.frequency = newGroupFreq
410 // update internal pm config
411 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].GroupFreq = newGroupFreq
412 // Also updated the next group metric collection time from now
413 v.nextCollectionInterval = time.Now().Add(time.Duration(newGroupFreq) * time.Second)
414 updated = true
415 logger.Infow(ctx, "group frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800416 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800417 }
418 }
419 if !updated {
420 logger.Errorw(ctx, "group frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
421 return fmt.Errorf("internal-error-during-group-freq-update--groupname-%s-freq-%d", aGroupName, newGroupFreq)
422 }
423 return nil
424}
425
426func (mm *onuMetricsManager) updateMetricFreq(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
427 var newMetricFreq uint32
428 found := false
429 metricSliceIdx := 0
430 var metric *voltha.PmConfig
431 for metricSliceIdx, metric = range pmConfigs.Metrics {
432 if metric.Name == aMetricName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800433 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
434 if metric.SampleFreq == 0 || (metric.SampleFreq > 0 && metric.SampleFreq%FrequencyGranularity != 0) {
435 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", metric.SampleFreq, FrequencyGranularity)
436 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", metric.SampleFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800437 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800438 newMetricFreq = metric.SampleFreq
439 found = true
440 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800441 }
442 }
443 if !found {
444 logger.Errorw(ctx, "metric name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
445 return fmt.Errorf("metric-name-not-found-%v", aMetricName)
446 }
447
448 updated := false
449 mm.onuMetricsManagerLock.Lock()
450 defer mm.onuMetricsManagerLock.Unlock()
451 for k, v := range mm.groupMetricMap {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800452 if k == aMetricName {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800453 v.frequency = newMetricFreq
454 // update internal pm config
455 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].SampleFreq = newMetricFreq
456 // Also updated the next standalone metric collection time from now
457 v.nextCollectionInterval = time.Now().Add(time.Duration(newMetricFreq) * time.Second)
458 updated = true
459 logger.Infow(ctx, "metric frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800460 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800461 }
462 }
463 if !updated {
464 logger.Errorw(ctx, "metric frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
465 return fmt.Errorf("internal-error-during-standalone-metric-update--matricnane-%s-freq-%d", aMetricName, newMetricFreq)
466 }
467 return nil
468}
469
470func (mm *onuMetricsManager) updateGroupSupport(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
471 groupSliceIdx := 0
472 var group *voltha.PmGroupConfig
473
474 for groupSliceIdx, group = range pmConfigs.Groups {
475 if group.GroupName == aGroupName {
476 break
477 }
478 }
479 if group == nil {
480 logger.Errorw(ctx, "group metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
481 return fmt.Errorf("group-not-found--groupName-%s", aGroupName)
482 }
483
484 updated := false
485 mm.onuMetricsManagerLock.Lock()
486 defer mm.onuMetricsManagerLock.Unlock()
487 for k, v := range mm.groupMetricMap {
488 if k == aGroupName && v.enabled != group.Enabled {
489 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].Enabled = group.Enabled
490 v.enabled = group.Enabled
Girish Gowdrae0140f02021-02-02 16:55:09 -0800491 if group.Enabled {
492 if v.isL2PMCounter {
493 // If it is a L2 PM counter we need to mark the PM to be added
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800494 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800495 // If the group support flag toggles too soon, we need to delete the group name from l2PmToDelete slice
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800496 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, v.groupName)
497
498 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
499 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
500 // take further action
501 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800502 mm.updateGemPortNTPInstanceToAddForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800503 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800504 } else if mm.pDeviceHandler.pmConfigs.FreqOverride { // otherwise just update the next collection interval
505 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
506 }
507 } else { // group counter is disabled
508 if v.isL2PMCounter {
509 // If it is a L2 PM counter we need to mark the PM to be deleted
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800510 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800511 // If the group support flag toggles too soon, we need to delete the group name from l2PmToAdd slice
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800512 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, v.groupName)
513
514 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
515 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
516 // take further action
517 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800518 mm.updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800519 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800520 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800521 }
522 updated = true
Girish Gowdrae0140f02021-02-02 16:55:09 -0800523 if v.isL2PMCounter {
524 logger.Infow(ctx, "l2 pm group metric support updated",
525 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled, "l2PmToAdd": mm.l2PmToAdd, "l2PmToDelete": mm.l2PmToDelete})
526 } else {
527 logger.Infow(ctx, "group metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled})
528 }
529 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800530 }
531 }
532
533 if !updated {
534 logger.Errorw(ctx, "group metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
535 return fmt.Errorf("internal-error-during-group-support-update--groupName-%s", aGroupName)
536 }
537 return nil
538}
539
540func (mm *onuMetricsManager) updateMetricSupport(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
541 metricSliceIdx := 0
542 var metric *voltha.PmConfig
543
544 for metricSliceIdx, metric = range pmConfigs.Metrics {
545 if metric.Name == aMetricName {
546 break
547 }
548 }
549
550 if metric == nil {
551 logger.Errorw(ctx, "standalone metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
552 return fmt.Errorf("metric-not-found--metricname-%s", aMetricName)
553 }
554
555 updated := false
556 mm.onuMetricsManagerLock.Lock()
557 defer mm.onuMetricsManagerLock.Unlock()
558 for k, v := range mm.standaloneMetricMap {
559 if k == aMetricName && v.enabled != metric.Enabled {
560 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].Enabled = metric.Enabled
561 v.enabled = metric.Enabled
562 // If the standalone metric is now enabled and frequency override is enabled, set the next metric collection time
563 if metric.Enabled && mm.pDeviceHandler.pmConfigs.FreqOverride {
564 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
565 }
566 updated = true
567 logger.Infow(ctx, "standalone metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName, "enabled": metric.Enabled})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800568 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800569 }
570 }
571 if !updated {
572 logger.Errorw(ctx, "standalone metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
573 return fmt.Errorf("internal-error-during-standalone-support-update--metricname-%s", aMetricName)
574 }
575 return nil
576}
577
578func (mm *onuMetricsManager) collectAllGroupAndStandaloneMetrics(ctx context.Context) {
579 if mm.pDeviceHandler.pmConfigs.Grouped { // metrics are managed as a group.
580 go mm.collectAllGroupMetrics(ctx)
581 } else {
582 go mm.collectAllStandaloneMetrics(ctx)
583 }
584}
585
586func (mm *onuMetricsManager) collectAllGroupMetrics(ctx context.Context) {
587 go func() {
588 logger.Debug(ctx, "startCollector before collecting optical metrics")
ozgecanetsiab36ed572021-04-01 10:38:48 +0300589 metricInfo, err := mm.collectOpticalMetrics(ctx)
590 if err != nil {
591 logger.Errorw(ctx, "collectOpticalMetrics failed",
592 log.Fields{"device-id": mm.pAdaptFsm.deviceID, "Error": err})
593 return
594 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800595 if metricInfo != nil {
596 mm.publishMetrics(ctx, metricInfo)
597 }
598 }()
599
600 go func() {
601 logger.Debug(ctx, "startCollector before collecting uni metrics")
ozgecanetsiab36ed572021-04-01 10:38:48 +0300602 metricInfo, err := mm.collectUniStatusMetrics(ctx)
603 if err != nil {
604 logger.Errorw(ctx, "collectOpticalMetrics failed",
605 log.Fields{"device-id": mm.pAdaptFsm.deviceID, "Error": err})
606 return
607 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800608 if metricInfo != nil {
609 mm.publishMetrics(ctx, metricInfo)
610 }
611 }()
612
613 // Add more here
614}
615
616func (mm *onuMetricsManager) collectAllStandaloneMetrics(ctx context.Context) {
617 // None exists as of now, add when available here
618}
619
620func (mm *onuMetricsManager) collectGroupMetric(ctx context.Context, groupName string) {
621 switch groupName {
622 case OpticalPowerGroupMetricName:
623 go func() {
ozgecanetsiab36ed572021-04-01 10:38:48 +0300624 if mi, _ := mm.collectOpticalMetrics(ctx); mi != nil {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800625 mm.publishMetrics(ctx, mi)
626 }
627 }()
628 case UniStatusGroupMetricName:
629 go func() {
ozgecanetsiab36ed572021-04-01 10:38:48 +0300630 if mi, _ := mm.collectUniStatusMetrics(ctx); mi != nil {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800631 mm.publishMetrics(ctx, mi)
632 }
633 }()
634 default:
635 logger.Errorw(ctx, "unhandled group metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName})
636 }
637}
638
639func (mm *onuMetricsManager) collectStandaloneMetric(ctx context.Context, metricName string) {
640 switch metricName {
641 // None exist as of now, add when available
642 default:
643 logger.Errorw(ctx, "unhandled standalone metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName})
644 }
645}
646
647// collectOpticalMetrics collects groups metrics related to optical power from ani-g ME.
ozgecanetsiab36ed572021-04-01 10:38:48 +0300648func (mm *onuMetricsManager) collectOpticalMetrics(ctx context.Context) ([]*voltha.MetricInformation, error) {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800649 logger.Debugw(ctx, "collectOpticalMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800650
651 mm.onuMetricsManagerLock.RLock()
652 if !mm.groupMetricMap[OpticalPowerGroupMetricName].enabled {
653 mm.onuMetricsManagerLock.RUnlock()
654 logger.Debugw(ctx, "optical power group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
ozgecanetsiab36ed572021-04-01 10:38:48 +0300655 return nil, nil
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800656 }
657 mm.onuMetricsManagerLock.RUnlock()
658
Girish Gowdrae09a6202021-01-12 18:10:59 -0800659 var metricInfoSlice []*voltha.MetricInformation
660 metricsContext := make(map[string]string)
661 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
662 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
663 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
664
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800665 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800666 mmd := voltha.MetricMetaData{
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800667 Title: OpticalPowerGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800668 Ts: float64(raisedTs),
669 Context: metricsContext,
670 DeviceId: mm.pDeviceHandler.deviceID,
671 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
672 SerialNo: mm.pDeviceHandler.device.SerialNumber,
673 }
674
Girish Gowdrae09a6202021-01-12 18:10:59 -0800675 // get the ANI-G instance IDs
676 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
677loop:
678 for _, anigInstID := range anigInstKeys {
679 var meAttributes me.AttributeValueMap
680 opticalMetrics := make(map[string]float32)
681 // Get the ANI-G instance optical power attributes
682 requestedAttributes := me.AttributeValueMap{"OpticalSignalLevel": 0, "TransmitOpticalLevel": 0}
ozgecanetsiab36ed572021-04-01 10:38:48 +0300683 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.AniGClassID, anigInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
684 if err != nil {
685 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
686 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
687 return nil, err
688 }
689
690 if meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800691 select {
692 case meAttributes = <-mm.opticalMetricsChan:
693 logger.Debugw(ctx, "received optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +0000694 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800695 logger.Errorw(ctx, "timeout waiting for omci-get response for optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800696 // The metrics will be empty in this case
697 break loop
698 }
699 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800700 for k := range OpticalPowerGroupMetrics {
701 switch k {
702 case "ani_g_instance_id":
703 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
704 opticalMetrics[k] = float32(val.(uint16))
705 }
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800706 case "transmit_power_dBm":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800707 if val, ok := meAttributes["TransmitOpticalLevel"]; ok && val != nil {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700708 opticalMetrics[k] = float32(math.Round((float64(TwosComplementToSignedInt16(val.(uint16)))/500.0)*10) / 10) // convert to dBm rounded of to single decimal place
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800709 }
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800710 case "receive_power_dBm":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800711 if val, ok := meAttributes["OpticalSignalLevel"]; ok && val != nil {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700712 opticalMetrics[k] = float32(math.Round((float64(TwosComplementToSignedInt16(val.(uint16)))/500.0)*10) / 10) // convert to dBm rounded of to single decimal place
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800713 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800714 default:
715 // do nothing
716 }
717 }
718 }
719 // create slice of metrics given that there could be more than one ANI-G instance and
720 // optical metrics are collected per ANI-G instance
721 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: opticalMetrics}
722 metricInfoSlice = append(metricInfoSlice, &metricInfo)
723 }
724
ozgecanetsiab36ed572021-04-01 10:38:48 +0300725 return metricInfoSlice, nil
Girish Gowdrae09a6202021-01-12 18:10:59 -0800726}
727
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800728// collectUniStatusMetrics collects UNI status group metric from various MEs (uni-g, pptp and veip).
Girish Gowdrae09a6202021-01-12 18:10:59 -0800729// nolint: gocyclo
ozgecanetsiab36ed572021-04-01 10:38:48 +0300730func (mm *onuMetricsManager) collectUniStatusMetrics(ctx context.Context) ([]*voltha.MetricInformation, error) {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800731 logger.Debugw(ctx, "collectUniStatusMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800732 mm.onuMetricsManagerLock.RLock()
733 if !mm.groupMetricMap[UniStatusGroupMetricName].enabled {
734 mm.onuMetricsManagerLock.RUnlock()
735 logger.Debugw(ctx, "uni status group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
ozgecanetsiab36ed572021-04-01 10:38:48 +0300736 return nil, nil
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800737 }
738 mm.onuMetricsManagerLock.RUnlock()
739
Girish Gowdrae09a6202021-01-12 18:10:59 -0800740 var metricInfoSlice []*voltha.MetricInformation
741 metricsContext := make(map[string]string)
742 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
743 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
744 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
745
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800746 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800747 mmd := voltha.MetricMetaData{
Girish Gowdra9b1577b2021-04-21 12:56:13 -0700748 Title: UniStatusGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800749 Ts: float64(raisedTs),
750 Context: metricsContext,
751 DeviceId: mm.pDeviceHandler.deviceID,
752 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
753 SerialNo: mm.pDeviceHandler.device.SerialNumber,
754 }
755
Girish Gowdrae09a6202021-01-12 18:10:59 -0800756 // get the UNI-G instance IDs
757 unigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.UniGClassID)
758loop1:
759 for _, unigInstID := range unigInstKeys {
760 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
761 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
762 unigMetrics := make(map[string]float32)
763 var meAttributes me.AttributeValueMap
764 // Get the UNI-G instance optical power attributes
765 requestedAttributes := me.AttributeValueMap{"AdministrativeState": 0}
ozgecanetsiab36ed572021-04-01 10:38:48 +0300766 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.UniGClassID, unigInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
767 if err != nil {
768 logger.Errorw(ctx, "UNI-G failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
769 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
770 return nil, err
771 }
772 if meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800773 // Wait for metrics or timeout
774 select {
775 case meAttributes = <-mm.uniStatusMetricsChan:
776 logger.Debugw(ctx, "received uni-g metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +0000777 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800778 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
779 // The metrics could be empty in this case
780 break loop1
781 }
782 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800783 for k := range UniStatusGroupMetrics {
784 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800785 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800786 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
787 unigMetrics[k] = float32(val.(byte))
788 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800789 default:
790 // do nothing
791 }
792 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800793 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800794 entityID := val.(uint16)
795 unigMetrics["entity_id"] = float32(entityID)
796 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
797 for _, uni := range mm.pDeviceHandler.uniEntityMap {
798 if uni.entityID == entityID {
799 unigMetrics["uni_port_no"] = float32(uni.portNo)
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700800 break
Girish Gowdra0e533642021-03-02 22:02:51 -0800801 }
802 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800803 }
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700804 unigMetrics["me_class_id"] = float32(me.UniGClassID)
Girish Gowdra0e533642021-03-02 22:02:51 -0800805
Girish Gowdrae09a6202021-01-12 18:10:59 -0800806 // create slice of metrics given that there could be more than one UNI-G instance
807 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: unigMetrics}
808 metricInfoSlice = append(metricInfoSlice, &metricInfo)
809 }
810 }
811
812 // get the PPTP instance IDs
813 pptpInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.PhysicalPathTerminationPointEthernetUniClassID)
814loop2:
815 for _, pptpInstID := range pptpInstKeys {
816 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
817 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
818 var meAttributes me.AttributeValueMap
819 pptpMetrics := make(map[string]float32)
820
821 requestedAttributes := me.AttributeValueMap{"SensedType": 0, "OperationalState": 0, "AdministrativeState": 0}
ozgecanetsiab36ed572021-04-01 10:38:48 +0300822 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.PhysicalPathTerminationPointEthernetUniClassID, pptpInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
823 if err != nil {
824 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
825 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
826 return nil, err
827 }
828 if meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800829 // Wait for metrics or timeout
830 select {
831 case meAttributes = <-mm.uniStatusMetricsChan:
832 logger.Debugw(ctx, "received pptp metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +0000833 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800834 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
835 // The metrics could be empty in this case
836 break loop2
837 }
838
839 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800840 for k := range UniStatusGroupMetrics {
841 switch k {
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700842 case "sensed_type":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800843 if val, ok := meAttributes["SensedType"]; ok && val != nil {
844 pptpMetrics[k] = float32(val.(byte))
845 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800846 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800847 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
848 pptpMetrics[k] = float32(val.(byte))
849 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800850 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800851 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
852 pptpMetrics[k] = float32(val.(byte))
853 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800854 default:
855 // do nothing
856 }
857 }
858 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800859 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800860 entityID := val.(uint16)
861 pptpMetrics["entity_id"] = float32(entityID)
862 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
863 for _, uni := range mm.pDeviceHandler.uniEntityMap {
864 if uni.entityID == entityID {
865 pptpMetrics["uni_port_no"] = float32(uni.portNo)
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700866 break
Girish Gowdra0e533642021-03-02 22:02:51 -0800867 }
868 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800869 }
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700870 pptpMetrics["me_class_id"] = float32(me.PhysicalPathTerminationPointEthernetUniClassID)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800871
Girish Gowdrae09a6202021-01-12 18:10:59 -0800872 // create slice of metrics given that there could be more than one PPTP instance and
873 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: pptpMetrics}
874 metricInfoSlice = append(metricInfoSlice, &metricInfo)
875 }
876
877 // get the VEIP instance IDs
878 veipInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.VirtualEthernetInterfacePointClassID)
879loop3:
880 for _, veipInstID := range veipInstKeys {
881 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
882 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
883 var meAttributes me.AttributeValueMap
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800884 veipMetrics := make(map[string]float32)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800885
886 requestedAttributes := me.AttributeValueMap{"OperationalState": 0, "AdministrativeState": 0}
ozgecanetsiab36ed572021-04-01 10:38:48 +0300887 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.VirtualEthernetInterfacePointClassID, veipInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
888 if err != nil {
889 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
890 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
891 return nil, err
892 }
893 if meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800894 // Wait for metrics or timeout
895 select {
896 case meAttributes = <-mm.uniStatusMetricsChan:
897 logger.Debugw(ctx, "received veip metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +0000898 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800899 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
900 // The metrics could be empty in this case
901 break loop3
902 }
903
904 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800905 for k := range UniStatusGroupMetrics {
906 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800907 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800908 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
909 veipMetrics[k] = float32(val.(byte))
910 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800911 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800912 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
913 veipMetrics[k] = float32(val.(byte))
914 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800915 default:
916 // do nothing
917 }
918 }
919 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800920
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800921 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800922 entityID := val.(uint16)
923 veipMetrics["entity_id"] = float32(entityID)
924 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
925 for _, uni := range mm.pDeviceHandler.uniEntityMap {
926 if uni.entityID == entityID {
927 veipMetrics["uni_port_no"] = float32(uni.portNo)
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700928 break
Girish Gowdra0e533642021-03-02 22:02:51 -0800929 }
930 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800931 }
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700932 veipMetrics["me_class_id"] = float32(me.VirtualEthernetInterfacePointClassID)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800933
Girish Gowdrae09a6202021-01-12 18:10:59 -0800934 // create slice of metrics given that there could be more than one VEIP instance
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800935 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: veipMetrics}
Girish Gowdrae09a6202021-01-12 18:10:59 -0800936 metricInfoSlice = append(metricInfoSlice, &metricInfo)
937 }
938
ozgecanetsiab36ed572021-04-01 10:38:48 +0300939 return metricInfoSlice, nil
Girish Gowdrae09a6202021-01-12 18:10:59 -0800940}
941
942// publishMetrics publishes the metrics on kafka
943func (mm *onuMetricsManager) publishMetrics(ctx context.Context, metricInfo []*voltha.MetricInformation) {
944 var ke voltha.KpiEvent2
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800945 ts := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800946 ke.SliceData = metricInfo
947 ke.Type = voltha.KpiEventType_slice
948 ke.Ts = float64(ts)
949
950 if err := mm.pDeviceHandler.EventProxy.SendKpiEvent(ctx, "STATS_EVENT", &ke, voltha.EventCategory_EQUIPMENT, voltha.EventSubCategory_ONU, ts); err != nil {
951 logger.Errorw(ctx, "failed-to-send-pon-stats", log.Fields{"err": err})
952 }
953}
954
955func (mm *onuMetricsManager) processOmciMessages(ctx context.Context) {
956 logger.Infow(ctx, "Start routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
957 // Flush metric collection channels to be safe.
958 // It is possible that there is stale data on this channel if the processOmciMessages routine
959 // is stopped right after issuing a OMCI-GET request and started again.
960 // The processOmciMessages routine will get stopped if startCollector routine (in device_handler.go)
961 // is stopped - as a result of ONU going down.
962 mm.flushMetricCollectionChannels(ctx)
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -0700963 mm.updateOmciProcessingStatus(true)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800964 for {
965 select {
966 case <-mm.stopProcessingOmciResponses: // stop this routine
967 logger.Infow(ctx, "Stop routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -0700968 mm.updateOmciProcessingStatus(false)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800969 return
Girish Gowdrae0140f02021-02-02 16:55:09 -0800970 case message, ok := <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -0800971 if !ok {
972 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
973 continue
974 }
975 logger.Debugw(ctx, "Received message on ONU metrics channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
976
977 switch message.Type {
978 case OMCI:
979 msg, _ := message.Data.(OmciMessage)
980 mm.handleOmciMessage(ctx, msg)
981 default:
982 logger.Warn(ctx, "Unknown message type received", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "message.Type": message.Type})
983 }
984 }
985 }
986}
987
988func (mm *onuMetricsManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
989 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
990 "msgType": msg.OmciMsg.MessageType, "msg": msg})
991 switch msg.OmciMsg.MessageType {
992 case omci.GetResponseType:
993 //TODO: error handling
994 _ = mm.handleOmciGetResponseMessage(ctx, msg)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800995 case omci.SynchronizeTimeResponseType:
996 _ = mm.handleOmciSynchronizeTimeResponseMessage(ctx, msg)
997 case omci.CreateResponseType:
998 _ = mm.handleOmciCreateResponseMessage(ctx, msg)
999 case omci.DeleteResponseType:
1000 _ = mm.handleOmciDeleteResponseMessage(ctx, msg)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001001 default:
1002 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
1003
1004 }
1005}
1006
1007func (mm *onuMetricsManager) handleOmciGetResponseMessage(ctx context.Context, msg OmciMessage) error {
1008 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
1009 if msgLayer == nil {
1010 logger.Errorw(ctx, "omci Msg layer could not be detected for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1011 return fmt.Errorf("omci Msg layer could not be detected for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
1012 }
1013 msgObj, msgOk := msgLayer.(*omci.GetResponse)
1014 if !msgOk {
1015 logger.Errorw(ctx, "omci Msg layer could not be assigned for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1016 return fmt.Errorf("omci Msg layer could not be assigned for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
1017 }
1018 logger.Debugw(ctx, "OMCI GetResponse Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1019 if msgObj.Result == me.Success {
1020 meAttributes := msgObj.Attributes
1021 switch msgObj.EntityClass {
1022 case me.AniGClassID:
1023 mm.opticalMetricsChan <- meAttributes
1024 return nil
1025 case me.UniGClassID:
1026 mm.uniStatusMetricsChan <- meAttributes
1027 return nil
1028 case me.PhysicalPathTerminationPointEthernetUniClassID:
1029 mm.uniStatusMetricsChan <- meAttributes
1030 return nil
1031 case me.VirtualEthernetInterfacePointClassID:
1032 mm.uniStatusMetricsChan <- meAttributes
1033 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001034 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
1035 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001036 me.EthernetPerformanceMonitoringHistoryDataClassID,
1037 me.FecPerformanceMonitoringHistoryDataClassID,
1038 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001039 mm.l2PmChan <- meAttributes
Girish Gowdrae09a6202021-01-12 18:10:59 -08001040 default:
1041 logger.Errorw(ctx, "unhandled omci get response message",
1042 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1043 }
1044 }
1045
Girish Gowdrae0140f02021-02-02 16:55:09 -08001046 return fmt.Errorf("unhandled-omci-get-response-message")
1047}
1048
1049func (mm *onuMetricsManager) handleOmciSynchronizeTimeResponseMessage(ctx context.Context, msg OmciMessage) error {
1050 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSynchronizeTimeResponse)
1051 if msgLayer == nil {
1052 logger.Errorw(ctx, "omci Msg layer could not be detected for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1053 return fmt.Errorf("omci Msg layer could not be detected for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1054 }
1055 msgObj, msgOk := msgLayer.(*omci.SynchronizeTimeResponse)
1056 if !msgOk {
1057 logger.Errorw(ctx, "omci Msg layer could not be assigned for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1058 return fmt.Errorf("omci Msg layer could not be assigned for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1059 }
1060 logger.Debugw(ctx, "OMCI synchronize time response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1061 if msgObj.Result == me.Success {
1062 switch msgObj.EntityClass {
1063 case me.OnuGClassID:
1064 logger.Infow(ctx, "omci synchronize time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1065 mm.syncTimeResponseChan <- true
1066 return nil
1067 default:
1068 logger.Errorw(ctx, "unhandled omci message",
1069 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1070 }
1071 }
1072 mm.syncTimeResponseChan <- false
1073 logger.Errorf(ctx, "unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
1074 return fmt.Errorf("unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001075}
1076
1077// flushMetricCollectionChannels flushes all metric collection channels for any stale OMCI responses
1078func (mm *onuMetricsManager) flushMetricCollectionChannels(ctx context.Context) {
1079 // flush commMetricsChan
1080 select {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001081 case <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -08001082 logger.Debug(ctx, "flushed common metrics channel")
1083 default:
1084 }
1085
1086 // flush opticalMetricsChan
1087 select {
1088 case <-mm.opticalMetricsChan:
1089 logger.Debug(ctx, "flushed optical metrics channel")
1090 default:
1091 }
1092
1093 // flush uniStatusMetricsChan
1094 select {
1095 case <-mm.uniStatusMetricsChan:
1096 logger.Debug(ctx, "flushed uni status metrics channel")
1097 default:
1098 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001099
1100 // flush syncTimeResponseChan
1101 select {
1102 case <-mm.syncTimeResponseChan:
1103 logger.Debug(ctx, "flushed sync time response channel")
1104 default:
1105 }
1106
1107 // flush l2PmChan
1108 select {
1109 case <-mm.l2PmChan:
1110 logger.Debug(ctx, "flushed L2 PM collection channel")
1111 default:
1112 }
1113
1114 // flush stopTicks
1115 select {
1116 case <-mm.stopTicks:
1117 logger.Debug(ctx, "flushed stopTicks channel")
1118 default:
1119 }
1120
1121}
1122
1123// ** L2 PM FSM Handlers start **
1124
1125func (mm *onuMetricsManager) l2PMFsmStarting(ctx context.Context, e *fsm.Event) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001126
Girish Gowdrae0140f02021-02-02 16:55:09 -08001127 // Loop through all the group metrics
1128 // If it is a L2 PM Interval metric and it is enabled, then if it is not in the
1129 // list of active L2 PM list then mark it for creation
1130 // It it is a L2 PM Interval metric and it is disabled, then if it is in the
1131 // list of active L2 PM list then mark it for deletion
1132 mm.onuMetricsManagerLock.Lock()
1133 for n, g := range mm.groupMetricMap {
1134 if g.isL2PMCounter { // it is a l2 pm counter
1135 if g.enabled { // metric enabled.
1136 found := false
1137 inner1:
1138 for _, v := range mm.activeL2Pms {
1139 if v == n {
1140 found = true // metric already present in active l2 pm list
1141 break inner1
1142 }
1143 }
1144 if !found { // metric not in active l2 pm list. Mark this to be added later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001145 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001146 }
1147 } else { // metric not enabled.
1148 found := false
1149 inner2:
1150 for _, v := range mm.activeL2Pms {
1151 if v == n {
1152 found = true // metric is found in active l2 pm list
1153 break inner2
1154 }
1155 }
1156 if found { // metric is found in active l2 pm list. Mark this to be deleted later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001157 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001158 }
1159 }
1160 }
1161 }
1162 mm.onuMetricsManagerLock.Unlock()
1163 logger.Debugw(ctx, "pms to add and delete",
1164 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd, "pms-to-delete": mm.l2PmToDelete})
1165 go func() {
1166 // push a tick event to move to next state
1167 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1168 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1169 }
1170 }()
1171}
1172
1173func (mm *onuMetricsManager) l2PMFsmSyncTime(ctx context.Context, e *fsm.Event) {
1174 // Sync time with the ONU to establish 15min boundary for PM collection.
1175 if err := mm.syncTime(ctx); err != nil {
1176 go func() {
1177 time.Sleep(SyncTimeRetryInterval * time.Second) // retry to sync time after this timeout
1178 // This will result in FSM attempting to sync time again
1179 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventFailure); err != nil {
1180 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1181 }
1182 }()
1183 }
1184 // Initiate a tick generation routine every L2PmCollectionInterval
1185 go mm.generateTicks(ctx)
1186
1187 go func() {
1188 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1189 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1190 }
1191 }()
1192}
1193
1194func (mm *onuMetricsManager) l2PMFsmNull(ctx context.Context, e *fsm.Event) {
1195 // We need to reset the local data so that the L2 PM MEs are re-provisioned once the ONU is back up based on the latest PM CONFIG
1196 mm.onuMetricsManagerLock.Lock()
1197 mm.activeL2Pms = nil
1198 mm.l2PmToAdd = nil
1199 mm.l2PmToDelete = nil
1200 mm.onuMetricsManagerLock.Unlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001201 // If the FSM was stopped, then clear PM data from KV store
1202 // The FSM is stopped when ONU goes down. It is time to clear its data from store
1203 if e.Event == l2PmEventStop {
1204 _ = mm.clearPmGroupData(ctx) // ignore error
1205 }
1206
Girish Gowdrae0140f02021-02-02 16:55:09 -08001207}
1208func (mm *onuMetricsManager) l2PMFsmIdle(ctx context.Context, e *fsm.Event) {
1209 logger.Debugw(ctx, "Enter state idle", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1210
1211 mm.onuMetricsManagerLock.RLock()
1212 numOfPmToDelete := len(mm.l2PmToDelete)
1213 numOfPmToAdd := len(mm.l2PmToAdd)
1214 mm.onuMetricsManagerLock.RUnlock()
1215
1216 if numOfPmToDelete > 0 {
1217 logger.Debugw(ctx, "state idle - pms to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": numOfPmToDelete})
1218 go func() {
1219 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
1220 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1221 }
1222 }()
1223 } else if numOfPmToAdd > 0 {
1224 logger.Debugw(ctx, "state idle - pms to add", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": numOfPmToAdd})
1225 go func() {
1226 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
1227 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1228 }
1229 }()
1230 }
1231}
1232
1233func (mm *onuMetricsManager) l2PmFsmCollectData(ctx context.Context, e *fsm.Event) {
1234 logger.Debugw(ctx, "state collect data", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1235 // Copy the activeL2Pms for which we want to collect the metrics since activeL2Pms can change dynamically
1236 mm.onuMetricsManagerLock.RLock()
1237 copyOfActiveL2Pms := make([]string, len(mm.activeL2Pms))
1238 _ = copy(copyOfActiveL2Pms, mm.activeL2Pms)
1239 mm.onuMetricsManagerLock.RUnlock()
1240
1241 for _, n := range copyOfActiveL2Pms {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001242 var metricInfoSlice []*voltha.MetricInformation
Girish Gowdra0e533642021-03-02 22:02:51 -08001243
1244 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1245 mm.onuMetricsManagerLock.RLock()
1246 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1247 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1248 mm.onuMetricsManagerLock.RUnlock()
1249
Girish Gowdrae0140f02021-02-02 16:55:09 -08001250 switch n {
1251 case EthernetBridgeHistoryName:
1252 logger.Debugw(ctx, "state collect data - collecting data for EthernetFramePerformanceMonitoringHistoryData ME", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0e533642021-03-02 22:02:51 -08001253 for _, entityID := range copyOfEntityIDs {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001254 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, true, entityID); metricInfo != nil { // upstream
1255 metricInfoSlice = append(metricInfoSlice, metricInfo)
1256 }
1257 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, false, entityID); metricInfo != nil { // downstream
1258 metricInfoSlice = append(metricInfoSlice, metricInfo)
1259 }
1260 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001261 case EthernetUniHistoryName:
1262 logger.Debugw(ctx, "state collect data - collecting data for EthernetPerformanceMonitoringHistoryData ME", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0e533642021-03-02 22:02:51 -08001263 for _, entityID := range copyOfEntityIDs {
1264 if metricInfo := mm.collectEthernetUniHistoryData(ctx, entityID); metricInfo != nil { // upstream
1265 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001266 }
1267 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001268
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001269 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001270 for _, entityID := range copyOfEntityIDs {
1271 if metricInfo := mm.collectFecHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001272 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001273 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001274 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001275 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001276 for _, entityID := range copyOfEntityIDs {
1277 if metricInfo := mm.collectGemHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001278 metricInfoSlice = append(metricInfoSlice, metricInfo)
1279 }
1280 }
1281
Girish Gowdrae0140f02021-02-02 16:55:09 -08001282 default:
1283 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1284 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001285 mm.handleMetricsPublish(ctx, n, metricInfoSlice)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001286 }
1287 // Does not matter we send success or failure here.
1288 // Those PMs that we failed to collect data will be attempted to collect again in the next PM collection cycle (assuming
1289 // we have not exceed max attempts to collect the PM data)
1290 go func() {
1291 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1292 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1293 }
1294 }()
1295}
1296
Girish Gowdra0e533642021-03-02 22:02:51 -08001297// nolint: gocyclo
ozgecanetsiab36ed572021-04-01 10:38:48 +03001298func (mm *onuMetricsManager) l2PmFsmCreatePM(ctx context.Context, e *fsm.Event) error {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001299 // Copy the l2PmToAdd for which we want to collect the metrics since l2PmToAdd can change dynamically
1300 mm.onuMetricsManagerLock.RLock()
1301 copyOfL2PmToAdd := make([]string, len(mm.l2PmToAdd))
1302 _ = copy(copyOfL2PmToAdd, mm.l2PmToAdd)
1303 mm.onuMetricsManagerLock.RUnlock()
1304
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001305 logger.Debugw(ctx, "state create pm - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": copyOfL2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001306 for _, n := range copyOfL2PmToAdd {
1307 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001308 atLeastOneSuccess := false // flag indicates if at least one ME instance of the PM was successfully created.
1309 cnt := 0
Girish Gowdrae0140f02021-02-02 16:55:09 -08001310 switch n {
1311 case EthernetBridgeHistoryName:
1312 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1313 boolForDirection = append(boolForDirection, true, false)
1314 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1315 for _, direction := range boolForDirection {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001316 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1317 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
Mahir Gunyel6781f962021-05-16 23:30:08 -07001318 entityID := macBridgePortAniBaseEID + uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001319 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1320 inner1:
1321 // retry L2PmCreateAttempts times to create the instance of PM
1322 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001323 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001324 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, true, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001325 if err != nil {
1326 logger.Errorw(ctx, "EthernetPerformanceMonitoringHistoryME create or delete failed, failure PM FSM!",
1327 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1328 pPMFsm := mm.pAdaptFsm
1329 if pPMFsm != nil {
1330 go func(p_pmFsm *AdapterFsm) {
1331 _ = p_pmFsm.pFsm.Event(l2PmEventFailure)
1332 }(pPMFsm)
1333 }
1334 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteEthernetPerformanceMonitoringHistoryMe-failed-%s-%s",
1335 mm.pDeviceHandler.deviceID, err))
1336 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001337 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetFramePerformanceMonitoringHistoryData"); resp {
1338 atLeastOneSuccess = true
1339 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1340 break inner1
1341 }
1342 }
1343 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1344 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001345 }
1346 }
1347 }
1348 case EthernetUniHistoryName:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001349 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1350 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
Girish Gowdra0e533642021-03-02 22:02:51 -08001351 // Attach the EthernetPerformanceMonitoringHistoryData ME to PPTP port instance
Girish Gowdrae0140f02021-02-02 16:55:09 -08001352 entityID := uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001353 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1354 inner2:
1355 // retry L2PmCreateAttempts times to create the instance of PM
1356 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001357 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001358 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001359 if err != nil {
1360 logger.Errorw(ctx, "CreateOrDeleteEthernetUNIHistoryME failed, failure PM FSM!",
1361 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1362 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1363 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteEthernetUniHistoryMe-failed-%s-%s",
1364 mm.pDeviceHandler.deviceID, err))
1365 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001366 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetPerformanceMonitoringHistoryData"); resp {
1367 atLeastOneSuccess = true
1368 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1369 break inner2
1370 }
1371 }
1372 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1373 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001374 }
1375 }
1376 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001377 case FecHistoryName:
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001378 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001379 // Attach the FecPerformanceMonitoringHistoryData ME to the ANI-G ME instance
ozgecanetsiab36ed572021-04-01 10:38:48 +03001380 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001381 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, anigInstID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001382 if err != nil {
1383 logger.Errorw(ctx, "CreateOrDeleteFecHistoryME failed, failure PM FSM!",
1384 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1385 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1386 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteFecHistoryMe-failed-%s-%s",
1387 mm.pDeviceHandler.deviceID, err))
1388 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001389 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdd) // TODO: ignore error for now
1390 inner3:
1391 // retry L2PmCreateAttempts times to create the instance of PM
1392 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1393 if resp = mm.waitForResponseOrTimeout(ctx, true, anigInstID, "FecPerformanceMonitoringHistoryData"); resp {
1394 atLeastOneSuccess = true
1395 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdded) // TODO: ignore error for now
1396 break inner3
1397 }
1398 }
1399 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1400 _ = mm.updatePmData(ctx, n, anigInstID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001401 }
1402 }
1403 case GemPortHistoryName:
1404
1405 mm.onuMetricsManagerLock.RLock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001406 copyOfGemPortInstIDsToAdd := make([]uint16, len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd))
1407 _ = copy(copyOfGemPortInstIDsToAdd, mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001408 mm.onuMetricsManagerLock.RUnlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001409
1410 if len(copyOfGemPortInstIDsToAdd) == 0 {
1411 // If there are no gemport history MEs to be created, just skip further processing
1412 // Otherwise down below (after 'switch' case handling) we assume the ME creation failed because resp and atLeastOneSuccess flag are false.
1413 // Normally there are no GemPortHistory MEs to create at start up. They come in only after provisioning service on the ONU.
1414 mm.onuMetricsManagerLock.Lock()
1415 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1416 mm.onuMetricsManagerLock.Unlock()
1417 continue
1418 }
1419
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001420 for _, v := range copyOfGemPortInstIDsToAdd {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001421 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001422 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, v)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001423 if err != nil {
1424 logger.Errorw(ctx, "CreateOrDeleteGemPortHistoryME failed, failure PM FSM!",
1425 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1426 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1427 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteGemPortHistoryMe-failed-%s-%s",
1428 mm.pDeviceHandler.deviceID, err))
1429 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001430 _ = mm.updatePmData(ctx, n, v, cPmAdd) // TODO: ignore error for now
1431 inner4:
1432 // retry L2PmCreateAttempts times to create the instance of PM
1433 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1434 if resp = mm.waitForResponseOrTimeout(ctx, true, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); resp {
1435 atLeastOneSuccess = true
1436 _ = mm.updatePmData(ctx, n, v, cPmAdded) // TODO: ignore error for now
1437 break inner4
1438 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001439 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001440 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1441 _ = mm.updatePmData(ctx, n, v, cPmRemoved) // TODO: ignore error for now
1442 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001443 }
1444
Girish Gowdrae0140f02021-02-02 16:55:09 -08001445 default:
1446 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1447 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001448 // On success of at least one instance of the PM for a given ME, update the local list maintained for active PMs and PMs to add
1449 if atLeastOneSuccess {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001450 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001451 mm.activeL2Pms = mm.appendIfMissingString(mm.activeL2Pms, n)
Girish Gowdra69570d92021-04-22 18:26:20 -07001452 // gem ports can be added dynamically for perf monitoring. We want to clear the GemPortHistoryName from mm.l2PmToAdd
1453 // only if no more new gem port instances created.
1454 if n != GemPortHistoryName || (n == GemPortHistoryName && len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd) == 0) {
1455 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1456 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001457 logger.Debugw(ctx, "success-resp", log.Fields{"pm-name": n, "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001458 mm.onuMetricsManagerLock.Unlock()
1459 } else {
Girish Gowdra0e533642021-03-02 22:02:51 -08001460 // If we are here then no instance of the PM of the given ME were created successfully, so locally disable the PM
Girish Gowdrae0140f02021-02-02 16:55:09 -08001461 // and also remove it from l2PmToAdd slice so that we do not try to create the PM ME anymore
1462 mm.onuMetricsManagerLock.Lock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001463 logger.Debugw(ctx, "exceeded-max-add-retry-attempts--disabling-group", log.Fields{"groupName": n})
1464 mm.groupMetricMap[n].enabled = false
1465 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001466
Girish Gowdrae0140f02021-02-02 16:55:09 -08001467 logger.Warnw(ctx, "state create pm - failed to create pm",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001468 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
Girish Gowdra0e533642021-03-02 22:02:51 -08001469 "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001470 mm.onuMetricsManagerLock.Unlock()
1471 }
1472 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001473 logger.Debugw(ctx, "state create pm - done", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001474 // Does not matter we send success or failure here.
1475 // Those PMs that we failed to create will be attempted to create again in the next PM creation cycle (assuming
1476 // we have not exceed max attempts to create the PM ME)
1477 go func() {
1478 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1479 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1480 }
1481 }()
ozgecanetsiab36ed572021-04-01 10:38:48 +03001482 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001483}
1484
Girish Gowdra0e533642021-03-02 22:02:51 -08001485// nolint: gocyclo
ozgecanetsiab36ed572021-04-01 10:38:48 +03001486func (mm *onuMetricsManager) l2PmFsmDeletePM(ctx context.Context, e *fsm.Event) error {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001487 // Copy the l2PmToDelete for which we want to collect the metrics since l2PmToDelete can change dynamically
1488 mm.onuMetricsManagerLock.RLock()
1489 copyOfL2PmToDelete := make([]string, len(mm.l2PmToDelete))
1490 _ = copy(copyOfL2PmToDelete, mm.l2PmToDelete)
1491 mm.onuMetricsManagerLock.RUnlock()
1492
1493 logger.Debugw(ctx, "state delete pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": mm.l2PmToDelete})
1494 for _, n := range copyOfL2PmToDelete {
1495 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001496 cnt := 0
1497 atLeastOneDeleteFailure := false
1498
1499 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1500 mm.onuMetricsManagerLock.RLock()
1501 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1502 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1503 mm.onuMetricsManagerLock.RUnlock()
1504
1505 if len(copyOfEntityIDs) == 0 {
1506 // if there are no enityIDs to remove for the PM ME just clear the PM name entry from cache and continue
1507 mm.onuMetricsManagerLock.Lock()
1508 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1509 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1510 logger.Debugw(ctx, "success-resp", log.Fields{"pm-name": n, "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1511 mm.onuMetricsManagerLock.Unlock()
1512 continue
1513 }
1514 logger.Debugw(ctx, "entities to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n, "entityIDs": copyOfEntityIDs})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001515 switch n {
1516 case EthernetBridgeHistoryName:
1517 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1518 boolForDirection = append(boolForDirection, true, false)
1519 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1520 for _, direction := range boolForDirection {
Girish Gowdra0e533642021-03-02 22:02:51 -08001521 for _, entityID := range copyOfEntityIDs {
1522 inner1:
1523 // retry L2PmDeleteAttempts times to delete the instance of PM
1524 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001525 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001526 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, false, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001527 if err != nil {
1528 logger.Errorw(ctx, "CreateOrDeleteEthernetPerformanceMonitoringHistoryME failed, failure PM FSM!",
1529 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1530 pPMFsm := mm.pAdaptFsm
1531 if pPMFsm != nil {
1532 go func(p_pmFsm *AdapterFsm) {
1533 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1534 }(pPMFsm)
1535 }
1536 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteEthernetPerformanceMonitoringHistoryMe-failed-%s-%s",
1537 mm.pDeviceHandler.deviceID, err))
1538 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001539 _ = mm.updatePmData(ctx, n, entityID, cPmRemove) // TODO: ignore error for now
1540 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1541 atLeastOneDeleteFailure = true
1542 } else {
1543 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1544 break inner1
1545 }
1546 }
1547 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1548 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001549 }
1550 }
1551 }
1552 case EthernetUniHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001553 for _, entityID := range copyOfEntityIDs {
1554 inner2:
1555 // retry L2PmDeleteAttempts times to delete the instance of PM
1556 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001557 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001558 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001559 if err != nil {
1560 logger.Errorw(ctx, "CreateOrDeleteEthernetUniHistoryME failed, failure PM FSM!",
1561 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1562 pmFsm := mm.pAdaptFsm
1563 if pmFsm != nil {
1564 go func(p_pmFsm *AdapterFsm) {
1565 _ = p_pmFsm.pFsm.Event(l2PmEventFailure)
1566 }(pmFsm)
1567 return err
1568 }
1569 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteEthernetUniHistoryMe-failed-%s-%s",
1570 mm.pDeviceHandler.deviceID, err))
1571 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001572 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
Girish Gowdra0e533642021-03-02 22:02:51 -08001573 atLeastOneDeleteFailure = true
1574 } else {
1575 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001576 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001577 }
1578 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001579 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1580 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1581 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001582 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001583 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001584 for _, entityID := range copyOfEntityIDs {
1585 inner3:
1586 // retry L2PmDeleteAttempts times to delete the instance of PM
1587 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001588 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001589 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001590 if err != nil {
1591 logger.Errorw(ctx, "CreateOrDeleteFecHistoryME failed, failure PM FSM!",
1592 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1593 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1594 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteFecHistoryMe-failed-%s-%s",
1595 mm.pDeviceHandler.deviceID, err))
1596 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001597 if resp := mm.waitForResponseOrTimeout(ctx, false, entityID, "FecPerformanceMonitoringHistoryData"); !resp {
1598 atLeastOneDeleteFailure = true
1599 } else {
1600 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1601 break inner3
1602 }
1603 }
1604 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1605 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001606 }
1607 }
1608 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001609 for _, entityID := range copyOfEntityIDs {
1610 inner4:
1611 // retry L2PmDeleteAttempts times to delete the instance of PM
1612 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001613 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001614 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001615 if err != nil {
1616 logger.Errorw(ctx, "CreateOrDeleteGemPortHistoryME failed, failure PM FSM!",
1617 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1618 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1619 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteGemPortHistoryMe-failed-%s-%s",
1620 mm.pDeviceHandler.deviceID, err))
1621 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001622 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1623 atLeastOneDeleteFailure = true
1624 } else {
1625 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1626 break inner4
1627 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001628 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001629 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1630 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1631 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001632 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001633 default:
1634 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1635 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001636 // If we could not completely clean up the PM ME then just give up.
1637 if atLeastOneDeleteFailure {
1638 logger.Warnw(ctx, "state delete pm - failed to delete at least one instance of the PM ME",
1639 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
1640 "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1641 mm.onuMetricsManagerLock.Lock()
1642 logger.Debugw(ctx, "exceeded-max-delete-retry-attempts--disabling-group", log.Fields{"groupName": n})
1643 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1644 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1645 mm.groupMetricMap[n].enabled = false
1646 mm.onuMetricsManagerLock.Unlock()
1647 } else { // success case
Girish Gowdrae0140f02021-02-02 16:55:09 -08001648 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001649 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
Girish Gowdra69570d92021-04-22 18:26:20 -07001650 // gem ports can be deleted dynamically from perf monitoring. We want to clear the GemPortHistoryName from mm.l2PmToDelete
1651 // only if no more new gem port instances removed.
1652 if n != GemPortHistoryName || (n == GemPortHistoryName && len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete) == 0) {
1653 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1654 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001655 logger.Debugw(ctx, "success-resp", log.Fields{"pm-name": n, "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001656 mm.onuMetricsManagerLock.Unlock()
1657 }
1658 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001659 logger.Debugw(ctx, "state delete pm - done", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001660 // Does not matter we send success or failure here.
1661 // Those PMs that we failed to delete will be attempted to create again in the next PM collection cycle
1662 go func() {
1663 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1664 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1665 }
1666 }()
ozgecanetsiab36ed572021-04-01 10:38:48 +03001667 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001668}
1669
1670// ** L2 PM FSM Handlers end **
1671
1672// syncTime synchronizes time with the ONU to establish a 15 min boundary for PM collection and reporting.
1673func (mm *onuMetricsManager) syncTime(ctx context.Context) error {
Girish Gowdra0b235842021-03-09 13:06:46 -08001674 if err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendSyncTime(ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001675 logger.Errorw(ctx, "cannot send sync time request", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1676 return err
1677 }
1678
1679 select {
Holger Hildebrandt366ef192021-05-05 11:07:44 +00001680 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07001681 logger.Errorw(ctx, "timed out waiting for sync time response from onu", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001682 return fmt.Errorf("timed-out-waiting-for-sync-time-response-%v", mm.pDeviceHandler.deviceID)
1683 case syncTimeRes := <-mm.syncTimeResponseChan:
1684 if !syncTimeRes {
1685 return fmt.Errorf("failed-to-sync-time-%v", mm.pDeviceHandler.deviceID)
1686 }
1687 logger.Infow(ctx, "sync time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1688 return nil
1689 }
1690}
1691
1692func (mm *onuMetricsManager) collectEthernetFramePerformanceMonitoringHistoryData(ctx context.Context, upstream bool, entityID uint16) *voltha.MetricInformation {
1693 var mEnt *me.ManagedEntity
1694 var omciErr me.OmciErrors
1695 var classID me.ClassID
1696 var meAttributes me.AttributeValueMap
1697 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1698 meParam := me.ParamData{EntityID: entityID}
1699 if upstream {
1700 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataUpstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1701 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1702 return nil
1703 }
1704 classID = me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID
1705 } else {
1706 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataDownstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1707 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1708 return nil
1709 }
1710 classID = me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID
1711 }
1712
Girish Gowdrae0140f02021-02-02 16:55:09 -08001713 intervalEndTime := -1
1714 ethPMHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001715 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethPMHistData, &intervalEndTime); err != nil {
1716 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001717 }
1718
1719 // Populate some relevant context for the EthernetFramePerformanceMonitoringHistoryData PM
1720 ethPMHistData["class_id"] = float32(classID)
1721 ethPMHistData["interval_end_time"] = float32(intervalEndTime)
1722 ethPMHistData["parent_class_id"] = float32(me.MacBridgeConfigurationDataClassID) // EthernetFramePerformanceMonitoringHistoryData is attached to MBPCD ME
1723 ethPMHistData["parent_entity_id"] = float32(entityID)
1724 if upstream {
1725 ethPMHistData["upstream"] = float32(1)
1726 } else {
1727 ethPMHistData["upstream"] = float32(0)
1728 }
1729
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001730 metricInfo := mm.populateOnuMetricInfo(EthernetBridgeHistoryName, ethPMHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001731
Girish Gowdrae0140f02021-02-02 16:55:09 -08001732 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData successful",
1733 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream, "metricInfo": metricInfo})
1734 return &metricInfo
1735}
1736
1737func (mm *onuMetricsManager) collectEthernetUniHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1738 var mEnt *me.ManagedEntity
1739 var omciErr me.OmciErrors
1740 var classID me.ClassID
1741 var meAttributes me.AttributeValueMap
1742 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1743 meParam := me.ParamData{EntityID: entityID}
1744 if mEnt, omciErr = me.NewEthernetPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1745 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1746 return nil
1747 }
1748 classID = me.EthernetPerformanceMonitoringHistoryDataClassID
1749
Girish Gowdrae0140f02021-02-02 16:55:09 -08001750 intervalEndTime := -1
1751 ethUniHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001752 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethUniHistData, &intervalEndTime); err != nil {
1753 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001754 }
1755
1756 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1757 ethUniHistData["class_id"] = float32(classID)
1758 ethUniHistData["interval_end_time"] = float32(intervalEndTime)
1759
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001760 metricInfo := mm.populateOnuMetricInfo(EthernetUniHistoryName, ethUniHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001761
Girish Gowdrae0140f02021-02-02 16:55:09 -08001762 logger.Debugw(ctx, "collecting data for EthernetPerformanceMonitoringHistoryData successful",
1763 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1764 return &metricInfo
1765}
1766
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001767func (mm *onuMetricsManager) collectFecHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1768 var mEnt *me.ManagedEntity
1769 var omciErr me.OmciErrors
1770 var classID me.ClassID
1771 var meAttributes me.AttributeValueMap
1772 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1773 meParam := me.ParamData{EntityID: entityID}
1774 if mEnt, omciErr = me.NewFecPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1775 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1776 return nil
1777 }
1778 classID = me.FecPerformanceMonitoringHistoryDataClassID
1779
1780 intervalEndTime := -1
1781 fecHistData := make(map[string]float32)
1782 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, fecHistData, &intervalEndTime); err != nil {
1783 return nil
1784 }
1785
1786 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1787 fecHistData["class_id"] = float32(classID)
1788 fecHistData["interval_end_time"] = float32(intervalEndTime)
1789
1790 metricInfo := mm.populateOnuMetricInfo(FecHistoryName, fecHistData)
1791
1792 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData successful",
1793 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1794 return &metricInfo
1795}
1796
1797func (mm *onuMetricsManager) collectGemHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1798 var mEnt *me.ManagedEntity
1799 var omciErr me.OmciErrors
1800 var classID me.ClassID
1801 var meAttributes me.AttributeValueMap
1802 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1803 meParam := me.ParamData{EntityID: entityID}
1804 if mEnt, omciErr = me.NewGemPortNetworkCtpPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1805 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1806 return nil
1807 }
1808 classID = me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID
1809
1810 intervalEndTime := -1
1811 gemHistData := make(map[string]float32)
1812 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, gemHistData, &intervalEndTime); err != nil {
1813 return nil
1814 }
1815
1816 // Populate some relevant context for the GemPortNetworkCtpPerformanceMonitoringHistoryData PM
1817 gemHistData["class_id"] = float32(classID)
1818 gemHistData["interval_end_time"] = float32(intervalEndTime)
1819
1820 metricInfo := mm.populateOnuMetricInfo(GemPortHistoryName, gemHistData)
1821
1822 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData successful",
1823 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1824 return &metricInfo
1825}
1826
Girish Gowdrae0140f02021-02-02 16:55:09 -08001827// nolint: gocyclo
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001828func (mm *onuMetricsManager) populateEthernetBridgeHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
Girish Gowdrae0140f02021-02-02 16:55:09 -08001829 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001830 upstream := false
1831 if classID == me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID {
1832 upstream = true
1833 }
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07001834 // Insert "IntervalEndTime" as part of the requested attributes as we need this to compare the get responses when get request is multipart
1835 requestedAttributes["IntervalEndTime"] = 0
ozgecanetsiab36ed572021-04-01 10:38:48 +03001836 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
1837 if err != nil {
1838 logger.Errorw(ctx, "GetME failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
1839 pmFsm := mm.pAdaptFsm
1840 if pmFsm != nil {
1841 go func(p_pmFsm *AdapterFsm) {
1842 _ = p_pmFsm.pFsm.Event(l2PmEventFailure)
1843 }(pmFsm)
1844 return err
1845 }
1846 return fmt.Errorf(fmt.Sprintf("GetME-failed-%s-%s", mm.pDeviceHandler.deviceID, err))
1847 }
1848 if meInstance != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001849 select {
1850 case meAttributes = <-mm.l2PmChan:
1851 logger.Debugw(ctx, "received ethernet pm history data metrics",
1852 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +00001853 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001854 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet pm history data",
1855 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1856 // The metrics will be empty in this case
1857 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-bridge-history-%v", mm.pDeviceHandler.deviceID)
1858 }
1859 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001860 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1861 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-ethernet-bridge-history-%v", mm.pDeviceHandler.deviceID)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001862 }
1863 }
1864 for k := range EthernetBridgeHistory {
1865 // populate ethPMHistData only if metric key not already present (or populated), since it is possible that we populate
1866 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1867 if _, ok := ethPMHistData[k]; !ok {
1868 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001869 case "entity_id":
1870 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1871 ethPMHistData[k] = float32(val.(uint16))
1872 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001873 case "drop_events":
1874 if val, ok := meAttributes["DropEvents"]; ok && val != nil {
1875 ethPMHistData[k] = float32(val.(uint32))
1876 }
1877 case "octets":
1878 if val, ok := meAttributes["Octets"]; ok && val != nil {
1879 ethPMHistData[k] = float32(val.(uint32))
1880 }
1881 case "packets":
1882 if val, ok := meAttributes["Packets"]; ok && val != nil {
1883 ethPMHistData[k] = float32(val.(uint32))
1884 }
1885 case "broadcast_packets":
1886 if val, ok := meAttributes["BroadcastPackets"]; ok && val != nil {
1887 ethPMHistData[k] = float32(val.(uint32))
1888 }
1889 case "multicast_packets":
1890 if val, ok := meAttributes["MulticastPackets"]; ok && val != nil {
1891 ethPMHistData[k] = float32(val.(uint32))
1892 }
1893 case "crc_errored_packets":
1894 if val, ok := meAttributes["CrcErroredPackets"]; ok && val != nil {
1895 ethPMHistData[k] = float32(val.(uint32))
1896 }
1897 case "undersize_packets":
1898 if val, ok := meAttributes["UndersizePackets"]; ok && val != nil {
1899 ethPMHistData[k] = float32(val.(uint32))
1900 }
1901 case "oversize_packets":
1902 if val, ok := meAttributes["OversizePackets"]; ok && val != nil {
1903 ethPMHistData[k] = float32(val.(uint32))
1904 }
1905 case "64_octets":
1906 if val, ok := meAttributes["Packets64Octets"]; ok && val != nil {
1907 ethPMHistData[k] = float32(val.(uint32))
1908 }
1909 case "65_to_127_octets":
1910 if val, ok := meAttributes["Packets65To127Octets"]; ok && val != nil {
1911 ethPMHistData[k] = float32(val.(uint32))
1912 }
1913 case "128_to_255_octets":
1914 if val, ok := meAttributes["Packets128To255Octets"]; ok && val != nil {
1915 ethPMHistData[k] = float32(val.(uint32))
1916 }
1917 case "256_to_511_octets":
1918 if val, ok := meAttributes["Packets256To511Octets"]; ok && val != nil {
1919 ethPMHistData[k] = float32(val.(uint32))
1920 }
1921 case "512_to_1023_octets":
1922 if val, ok := meAttributes["Packets512To1023Octets"]; ok && val != nil {
1923 ethPMHistData[k] = float32(val.(uint32))
1924 }
1925 case "1024_to_1518_octets":
1926 if val, ok := meAttributes["Packets1024To1518Octets"]; ok && val != nil {
1927 ethPMHistData[k] = float32(val.(uint32))
1928 }
1929 default:
1930 // do nothing
1931 }
1932 }
1933 }
1934 return nil
1935}
1936
1937// nolint: gocyclo
1938func (mm *onuMetricsManager) populateEthernetUniHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1939 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMUniHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07001940 // Insert "IntervalEndTime" as part of the requested attributes as we need this to compare the get responses when get request is multipart
ozgecanetsiab36ed572021-04-01 10:38:48 +03001941 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1942 requestedAttributes["IntervalEndTime"] = 0
1943 }
1944 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
1945 if err != nil {
1946 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
1947 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1948 return fmt.Errorf(fmt.Sprintf("GetME-failed-%s-%s", mm.pDeviceHandler.deviceID, err))
1949 }
1950 if meInstance != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001951 select {
1952 case meAttributes = <-mm.l2PmChan:
1953 logger.Debugw(ctx, "received ethernet uni history data metrics",
1954 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +00001955 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001956 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet uni history data",
1957 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1958 // The metrics will be empty in this case
1959 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-uni-history-%v", mm.pDeviceHandler.deviceID)
1960 }
1961 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001962 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1963 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-ethernet-uni-history-%v", mm.pDeviceHandler.deviceID)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001964 }
1965 }
1966 for k := range EthernetUniHistory {
1967 // populate ethPMUniHistData only if metric key not already present (or populated), since it is possible that we populate
1968 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1969 if _, ok := ethPMUniHistData[k]; !ok {
1970 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001971 case "entity_id":
1972 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1973 ethPMUniHistData[k] = float32(val.(uint16))
1974 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001975 case "fcs_errors":
1976 if val, ok := meAttributes["FcsErrors"]; ok && val != nil {
1977 ethPMUniHistData[k] = float32(val.(uint32))
1978 }
1979 case "excessive_collision_counter":
1980 if val, ok := meAttributes["ExcessiveCollisionCounter"]; ok && val != nil {
1981 ethPMUniHistData[k] = float32(val.(uint32))
1982 }
1983 case "late_collision_counter":
1984 if val, ok := meAttributes["LateCollisionCounter"]; ok && val != nil {
1985 ethPMUniHistData[k] = float32(val.(uint32))
1986 }
1987 case "frames_too_long":
1988 if val, ok := meAttributes["FramesTooLong"]; ok && val != nil {
1989 ethPMUniHistData[k] = float32(val.(uint32))
1990 }
1991 case "buffer_overflows_on_rx":
1992 if val, ok := meAttributes["BufferOverflowsOnReceive"]; ok && val != nil {
1993 ethPMUniHistData[k] = float32(val.(uint32))
1994 }
1995 case "buffer_overflows_on_tx":
1996 if val, ok := meAttributes["BufferOverflowsOnTransmit"]; ok && val != nil {
1997 ethPMUniHistData[k] = float32(val.(uint32))
1998 }
1999 case "single_collision_frame_counter":
2000 if val, ok := meAttributes["SingleCollisionFrameCounter"]; ok && val != nil {
2001 ethPMUniHistData[k] = float32(val.(uint32))
2002 }
2003 case "multiple_collisions_frame_counter":
2004 if val, ok := meAttributes["MultipleCollisionsFrameCounter"]; ok && val != nil {
2005 ethPMUniHistData[k] = float32(val.(uint32))
2006 }
2007 case "sqe_counter":
2008 if val, ok := meAttributes["SqeCounter"]; ok && val != nil {
2009 ethPMUniHistData[k] = float32(val.(uint32))
2010 }
2011 case "deferred_tx_counter":
2012 if val, ok := meAttributes["DeferredTransmissionCounter"]; ok && val != nil {
2013 ethPMUniHistData[k] = float32(val.(uint32))
2014 }
2015 case "internal_mac_tx_error_counter":
2016 if val, ok := meAttributes["InternalMacTransmitErrorCounter"]; ok && val != nil {
2017 ethPMUniHistData[k] = float32(val.(uint32))
2018 }
2019 case "carrier_sense_error_counter":
2020 if val, ok := meAttributes["CarrierSenseErrorCounter"]; ok && val != nil {
2021 ethPMUniHistData[k] = float32(val.(uint32))
2022 }
2023 case "alignment_error_counter":
2024 if val, ok := meAttributes["AlignmentErrorCounter"]; ok && val != nil {
2025 ethPMUniHistData[k] = float32(val.(uint32))
2026 }
2027 case "internal_mac_rx_error_counter":
2028 if val, ok := meAttributes["InternalMacReceiveErrorCounter"]; ok && val != nil {
2029 ethPMUniHistData[k] = float32(val.(uint32))
2030 }
2031 default:
2032 // do nothing
2033 }
2034 }
2035 }
2036 return nil
2037}
2038
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002039// nolint: gocyclo
2040func (mm *onuMetricsManager) populateFecHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
2041 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, fecHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002042 // Insert "IntervalEndTime" as part of the requested attributes as we need this to compare the get responses when get request is multipart
ozgecanetsiab36ed572021-04-01 10:38:48 +03002043 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
2044 requestedAttributes["IntervalEndTime"] = 0
2045 }
2046 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
2047 if err != nil {
2048 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
2049 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
2050 return fmt.Errorf(fmt.Sprintf("GetME-failed-%s-%s", mm.pDeviceHandler.deviceID, err))
2051 }
2052 if meInstance != nil {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002053 select {
2054 case meAttributes = <-mm.l2PmChan:
2055 logger.Debugw(ctx, "received fec history data metrics",
2056 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +00002057 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002058 logger.Errorw(ctx, "timeout waiting for omci-get response for fec history data",
2059 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
2060 // The metrics will be empty in this case
2061 return fmt.Errorf("timeout-during-l2-pm-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
2062 }
2063 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
2064 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
2065 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
2066 }
2067 }
2068 for k := range FecHistory {
2069 // populate fecHistData only if metric key not already present (or populated), since it is possible that we populate
2070 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
2071 if _, ok := fecHistData[k]; !ok {
2072 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08002073 case "entity_id":
2074 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
2075 fecHistData[k] = float32(val.(uint16))
2076 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002077 case "corrected_bytes":
2078 if val, ok := meAttributes["CorrectedBytes"]; ok && val != nil {
2079 fecHistData[k] = float32(val.(uint32))
2080 }
2081 case "corrected_code_words":
2082 if val, ok := meAttributes["CorrectedCodeWords"]; ok && val != nil {
2083 fecHistData[k] = float32(val.(uint32))
2084 }
2085 case "uncorrectable_code_words":
2086 if val, ok := meAttributes["UncorrectableCodeWords"]; ok && val != nil {
2087 fecHistData[k] = float32(val.(uint32))
2088 }
2089 case "total_code_words":
2090 if val, ok := meAttributes["TotalCodeWords"]; ok && val != nil {
2091 fecHistData[k] = float32(val.(uint32))
2092 }
2093 case "fec_seconds":
2094 if val, ok := meAttributes["FecSeconds"]; ok && val != nil {
2095 fecHistData[k] = float32(val.(uint16))
2096 }
2097 default:
2098 // do nothing
2099 }
2100 }
2101 }
2102 return nil
2103}
2104
2105// nolint: gocyclo
2106func (mm *onuMetricsManager) populateGemPortMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
2107 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, gemPortHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002108 // Insert "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
ozgecanetsiab36ed572021-04-01 10:38:48 +03002109 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
2110 requestedAttributes["IntervalEndTime"] = 0
2111 }
2112 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
2113 if err != nil {
2114 logger.Errorw(ctx, "GetMe failed", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
2115 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
2116 return fmt.Errorf(fmt.Sprintf("GetME-failed-%s-%s", mm.pDeviceHandler.deviceID, err))
2117 }
2118 if meInstance != nil {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002119 select {
2120 case meAttributes = <-mm.l2PmChan:
2121 logger.Debugw(ctx, "received gem port history data metrics",
2122 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +00002123 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002124 logger.Errorw(ctx, "timeout waiting for omci-get response for gem port history data",
2125 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
2126 // The metrics will be empty in this case
2127 return fmt.Errorf("timeout-during-l2-pm-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
2128 }
2129 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
2130 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
2131 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
2132 }
2133 }
2134 for k := range GemPortHistory {
2135 // populate gemPortHistData only if metric key not already present (or populated), since it is possible that we populate
2136 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
2137 if _, ok := gemPortHistData[k]; !ok {
2138 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08002139 case "entity_id":
2140 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
2141 gemPortHistData[k] = float32(val.(uint16))
2142 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002143 case "transmitted_gem_frames":
2144 if val, ok := meAttributes["TransmittedGemFrames"]; ok && val != nil {
2145 gemPortHistData[k] = float32(val.(uint32))
2146 }
2147 case "received_gem_frames":
2148 if val, ok := meAttributes["ReceivedGemFrames"]; ok && val != nil {
2149 gemPortHistData[k] = float32(val.(uint32))
2150 }
2151 case "received_payload_bytes":
2152 if val, ok := meAttributes["ReceivedPayloadBytes"]; ok && val != nil {
2153 gemPortHistData[k] = float32(val.(uint64))
2154 }
2155 case "transmitted_payload_bytes":
2156 if val, ok := meAttributes["TransmittedPayloadBytes"]; ok && val != nil {
2157 gemPortHistData[k] = float32(val.(uint64))
2158 }
2159 case "encryption_key_errors":
2160 if val, ok := meAttributes["EncryptionKeyErrors"]; ok && val != nil {
2161 gemPortHistData[k] = float32(val.(uint32))
2162 }
2163 default:
2164 // do nothing
2165 }
2166 }
2167 }
2168 return nil
2169}
2170
Girish Gowdrae0140f02021-02-02 16:55:09 -08002171func (mm *onuMetricsManager) handleOmciCreateResponseMessage(ctx context.Context, msg OmciMessage) error {
2172 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
2173 if msgLayer == nil {
2174 logger.Errorw(ctx, "omci Msg layer could not be detected for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2175 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2176 }
2177 msgObj, msgOk := msgLayer.(*omci.CreateResponse)
2178 if !msgOk {
2179 logger.Errorw(ctx, "omci Msg layer could not be assigned for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2180 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2181 }
2182 logger.Debugw(ctx, "OMCI create response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2183 switch msgObj.EntityClass {
2184 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2185 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002186 me.EthernetPerformanceMonitoringHistoryDataClassID,
2187 me.FecPerformanceMonitoringHistoryDataClassID,
2188 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002189 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
2190 if msgObj.Result == me.Success || msgObj.Result == me.InstanceExists {
2191 mm.l2PmCreateOrDeleteResponseChan <- true
2192 } else {
2193 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2194 mm.l2PmCreateOrDeleteResponseChan <- false
2195 }
2196 return nil
2197 default:
2198 logger.Errorw(ctx, "unhandled omci create response message",
2199 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2200 }
2201 return fmt.Errorf("unhandled-omci-create-response-message-%v", mm.pDeviceHandler.deviceID)
2202}
2203
2204func (mm *onuMetricsManager) handleOmciDeleteResponseMessage(ctx context.Context, msg OmciMessage) error {
2205 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDeleteResponse)
2206 if msgLayer == nil {
2207 logger.Errorw(ctx, "omci Msg layer could not be detected for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2208 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2209 }
2210 msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
2211 if !msgOk {
2212 logger.Errorw(ctx, "omci Msg layer could not be assigned for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2213 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2214 }
2215 logger.Debugw(ctx, "OMCI delete response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2216 switch msgObj.EntityClass {
2217 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2218 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002219 me.EthernetPerformanceMonitoringHistoryDataClassID,
2220 me.FecPerformanceMonitoringHistoryDataClassID,
2221 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002222 // If the result is me.UnknownInstance it means the entity was already deleted. It is ok handled that as success
2223 if msgObj.Result == me.Success || msgObj.Result == me.UnknownInstance {
2224 mm.l2PmCreateOrDeleteResponseChan <- true
2225 } else {
2226 logger.Warnw(ctx, "failed to delete me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2227 mm.l2PmCreateOrDeleteResponseChan <- false
2228 }
2229 return nil
2230 default:
2231 logger.Errorw(ctx, "unhandled omci delete response message",
2232 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2233 }
2234 return fmt.Errorf("unhandled-omci-delete-response-message-%v", mm.pDeviceHandler.deviceID)
2235}
2236
2237func (mm *onuMetricsManager) generateTicks(ctx context.Context) {
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07002238 mm.updateTickGenerationStatus(true)
Girish Gowdrae0140f02021-02-02 16:55:09 -08002239 for {
2240 select {
2241 case <-time.After(L2PmCollectionInterval * time.Second):
2242 go func() {
2243 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
2244 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2245 }
2246 }()
2247 case <-mm.stopTicks:
2248 logger.Infow(ctx, "stopping ticks", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07002249 mm.updateTickGenerationStatus(false)
Girish Gowdrae0140f02021-02-02 16:55:09 -08002250 return
2251 }
2252 }
2253}
2254
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002255func (mm *onuMetricsManager) handleMetricsPublish(ctx context.Context, metricName string, metricInfoSlice []*voltha.MetricInformation) {
2256 // Publish metrics if it is valid
2257 if metricInfoSlice != nil {
2258 mm.publishMetrics(ctx, metricInfoSlice)
2259 } else {
2260 // If collectAttempts exceeds L2PmCollectAttempts then remove it from activeL2Pms
2261 // slice so that we do not collect data from that PM ME anymore
2262 mm.onuMetricsManagerLock.Lock()
2263 mm.groupMetricMap[metricName].collectAttempts++
2264 if mm.groupMetricMap[metricName].collectAttempts > L2PmCollectAttempts {
2265 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, metricName)
2266 }
2267 logger.Warnw(ctx, "state collect data - no metrics collected",
2268 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName, "collectAttempts": mm.groupMetricMap[metricName].collectAttempts})
2269 mm.onuMetricsManagerLock.Unlock()
2270 }
2271}
2272
2273func (mm *onuMetricsManager) populateGroupSpecificMetrics(ctx context.Context, mEnt *me.ManagedEntity, classID me.ClassID, entityID uint16,
2274 meAttributes me.AttributeValueMap, data map[string]float32, intervalEndTime *int) error {
2275 var grpFunc groupMetricPopulateFunc
2276 switch classID {
2277 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID, me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID:
2278 grpFunc = mm.populateEthernetBridgeHistoryMetrics
2279 case me.EthernetPerformanceMonitoringHistoryDataClassID:
2280 grpFunc = mm.populateEthernetUniHistoryMetrics
2281 case me.FecPerformanceMonitoringHistoryDataClassID:
2282 grpFunc = mm.populateFecHistoryMetrics
2283 case me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
2284 grpFunc = mm.populateGemPortMetrics
2285 default:
2286 return fmt.Errorf("unknown-classid-%v", classID)
2287 }
2288
2289 size := 0
2290 requestedAttributes := make(me.AttributeValueMap)
2291 for _, v := range mEnt.GetAttributeDefinitions() {
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002292 if v.Name == "ManagedEntityId" || v.Name == "IntervalEndTime" || v.Name == "ThresholdData12Id" {
2293 // Exclude the ManagedEntityId , it will be inserted by omci library based on 'entityID' information
2294 // Exclude IntervalEndTime. It will be inserted by the group PM populater function.
2295 // Exclude ThresholdData12Id as that is of no particular relevance for metrics collection.
2296 continue
2297 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002298 if (v.Size + size) <= MaxL2PMGetPayLoadSize {
2299 requestedAttributes[v.Name] = v.DefValue
2300 size = v.Size + size
2301 } else { // We exceeded the allow omci get size
2302 // Let's collect the attributes via get now and collect remaining in the next iteration
2303 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2304 logger.Errorw(ctx, "error during metric collection",
2305 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2306 return err
2307 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002308 requestedAttributes = make(me.AttributeValueMap) // reset map
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002309 requestedAttributes[v.Name] = v.DefValue // populate the metric that was missed in the current iteration
2310 size = v.Size // reset size
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002311 }
2312 }
2313 // Collect the omci get attributes for the last bunch of attributes.
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002314 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2315 logger.Errorw(ctx, "error during metric collection",
2316 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2317 return err
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002318 }
2319 return nil
2320}
2321
2322func (mm *onuMetricsManager) populateOnuMetricInfo(title string, data map[string]float32) voltha.MetricInformation {
2323 metricsContext := make(map[string]string)
2324 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
2325 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
2326 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
2327
2328 raisedTs := time.Now().Unix()
2329 mmd := voltha.MetricMetaData{
2330 Title: title,
2331 Ts: float64(raisedTs),
2332 Context: metricsContext,
2333 DeviceId: mm.pDeviceHandler.deviceID,
2334 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
2335 SerialNo: mm.pDeviceHandler.device.SerialNumber,
2336 }
2337
2338 // create slice of metrics given that there could be more than one VEIP instance
2339 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: data}
2340 return metricInfo
2341}
2342
2343func (mm *onuMetricsManager) updateAndValidateIntervalEndTime(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap, intervalEndTime *int) bool {
2344 valid := false
2345 if *intervalEndTime == -1 { // first time
2346 // Update the interval end time
2347 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2348 *intervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2349 valid = true
2350 }
2351 } else {
2352 var currIntervalEndTime int
2353 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2354 currIntervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2355 }
2356 if currIntervalEndTime != *intervalEndTime { // interval end time changed during metric collection
2357 logger.Errorw(ctx, "interval end time changed during metrics collection for ethernet pm history data",
2358 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID,
2359 "currIntervalEndTime": *intervalEndTime, "newIntervalEndTime": currIntervalEndTime})
2360 } else {
2361 valid = true
2362 }
2363 }
2364 return valid
2365}
2366
2367func (mm *onuMetricsManager) waitForResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassName string) bool {
2368 logger.Debugw(ctx, "waitForResponseOrTimeout", log.Fields{"create": create, "instID": instID, "meClassName": meClassName})
2369 select {
2370 case resp := <-mm.l2PmCreateOrDeleteResponseChan:
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002371 logger.Debugw(ctx, "received l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002372 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassName": meClassName, "instID": instID})
2373 return resp
Holger Hildebrandt366ef192021-05-05 11:07:44 +00002374 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002375 logger.Errorw(ctx, "timeout waiting for l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002376 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassName": meClassName, "instID": instID})
2377 }
2378 return false
2379}
2380
2381func (mm *onuMetricsManager) initializeGroupMetric(grpMtrcs map[string]voltha.PmConfig_PmType, grpName string, grpEnabled bool, grpFreq uint32) {
2382 var pmConfigSlice []*voltha.PmConfig
2383 for k, v := range grpMtrcs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002384 pmConfigSlice = append(pmConfigSlice,
2385 &voltha.PmConfig{
2386 Name: k,
2387 Type: v,
2388 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2389 SampleFreq: grpFreq})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002390 }
2391 groupMetric := voltha.PmGroupConfig{
2392 GroupName: grpName,
2393 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2394 GroupFreq: grpFreq,
2395 Metrics: pmConfigSlice,
2396 }
2397 mm.pDeviceHandler.pmConfigs.Groups = append(mm.pDeviceHandler.pmConfigs.Groups, &groupMetric)
2398
2399}
2400
2401func (mm *onuMetricsManager) initializeL2PmFsm(ctx context.Context, aCommChannel chan Message) error {
2402 mm.pAdaptFsm = NewAdapterFsm("L2PmFSM", mm.pDeviceHandler.deviceID, aCommChannel)
2403 if mm.pAdaptFsm == nil {
2404 logger.Errorw(ctx, "L2PMFsm AdapterFsm could not be instantiated!!", log.Fields{
2405 "device-id": mm.pDeviceHandler.deviceID})
2406 return fmt.Errorf("nil-adapter-fsm")
2407 }
2408 // L2 PM FSM related state machine
2409 mm.pAdaptFsm.pFsm = fsm.NewFSM(
2410 l2PmStNull,
2411 fsm.Events{
2412 {Name: l2PmEventInit, Src: []string{l2PmStNull}, Dst: l2PmStStarting},
2413 {Name: l2PmEventTick, Src: []string{l2PmStStarting}, Dst: l2PmStSyncTime},
Girish Gowdra69570d92021-04-22 18:26:20 -07002414 {Name: l2PmEventTick, Src: []string{l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe}, Dst: l2PmStCollectData},
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002415 {Name: l2PmEventSuccess, Src: []string{l2PmStSyncTime, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2416 {Name: l2PmEventFailure, Src: []string{l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2417 {Name: l2PmEventFailure, Src: []string{l2PmStSyncTime}, Dst: l2PmStSyncTime},
2418 {Name: l2PmEventAddMe, Src: []string{l2PmStIdle}, Dst: l2PmStCreatePmMe},
2419 {Name: l2PmEventDeleteMe, Src: []string{l2PmStIdle}, Dst: l2PmStDeletePmMe},
2420 {Name: l2PmEventStop, Src: []string{l2PmStNull, l2PmStStarting, l2PmStSyncTime, l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStNull},
2421 },
2422 fsm.Callbacks{
2423 "enter_state": func(e *fsm.Event) { mm.pAdaptFsm.logFsmStateChange(ctx, e) },
2424 "enter_" + l2PmStNull: func(e *fsm.Event) { mm.l2PMFsmNull(ctx, e) },
2425 "enter_" + l2PmStIdle: func(e *fsm.Event) { mm.l2PMFsmIdle(ctx, e) },
2426 "enter_" + l2PmStStarting: func(e *fsm.Event) { mm.l2PMFsmStarting(ctx, e) },
2427 "enter_" + l2PmStSyncTime: func(e *fsm.Event) { mm.l2PMFsmSyncTime(ctx, e) },
2428 "enter_" + l2PmStCollectData: func(e *fsm.Event) { mm.l2PmFsmCollectData(ctx, e) },
ozgecanetsiab36ed572021-04-01 10:38:48 +03002429 "enter_" + l2PmStCreatePmMe: func(e *fsm.Event) { _ = mm.l2PmFsmCreatePM(ctx, e) },
2430 "enter_" + l2PmStDeletePmMe: func(e *fsm.Event) { _ = mm.l2PmFsmDeletePM(ctx, e) },
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002431 },
2432 )
2433 return nil
2434}
2435
2436func (mm *onuMetricsManager) initializeAllGroupMetrics() {
2437 mm.pDeviceHandler.pmConfigs = &voltha.PmConfigs{}
2438 mm.pDeviceHandler.pmConfigs.Id = mm.pDeviceHandler.deviceID
2439 mm.pDeviceHandler.pmConfigs.DefaultFreq = DefaultMetricCollectionFrequency
2440 mm.pDeviceHandler.pmConfigs.Grouped = GroupMetricEnabled
2441 mm.pDeviceHandler.pmConfigs.FreqOverride = DefaultFrequencyOverrideEnabled
2442
2443 // Populate group metrics.
2444 // Lets populate irrespective of GroupMetricEnabled is true or not.
2445 // The group metrics collection will decided on this flag later
2446
2447 mm.initializeGroupMetric(OpticalPowerGroupMetrics, OpticalPowerGroupMetricName,
2448 OpticalPowerGroupMetricEnabled, OpticalPowerMetricGroupCollectionFrequency)
2449
2450 mm.initializeGroupMetric(UniStatusGroupMetrics, UniStatusGroupMetricName,
2451 UniStatusGroupMetricEnabled, UniStatusMetricGroupCollectionFrequency)
2452
2453 // classical l2 pm counter start
2454
2455 mm.initializeGroupMetric(EthernetBridgeHistory, EthernetBridgeHistoryName,
2456 EthernetBridgeHistoryEnabled, EthernetBridgeHistoryFrequency)
2457
2458 mm.initializeGroupMetric(EthernetUniHistory, EthernetUniHistoryName,
2459 EthernetUniHistoryEnabled, EthernetUniHistoryFrequency)
2460
2461 mm.initializeGroupMetric(FecHistory, FecHistoryName,
2462 FecHistoryEnabled, FecHistoryFrequency)
2463
2464 mm.initializeGroupMetric(GemPortHistory, GemPortHistoryName,
2465 GemPortHistoryEnabled, GemPortHistoryFrequency)
2466
2467 // classical l2 pm counter end
2468
2469 // Add standalone metric (if present) after this (will be added to dh.pmConfigs.Metrics)
2470}
2471
2472func (mm *onuMetricsManager) populateLocalGroupMetricData(ctx context.Context) {
2473 // Populate local group metric structures
2474 for _, g := range mm.pDeviceHandler.pmConfigs.Groups {
2475 mm.groupMetricMap[g.GroupName] = &groupMetric{
2476 groupName: g.GroupName,
2477 enabled: g.Enabled,
2478 frequency: g.GroupFreq,
2479 }
2480 switch g.GroupName {
2481 case OpticalPowerGroupMetricName:
2482 mm.groupMetricMap[g.GroupName].metricMap = OpticalPowerGroupMetrics
2483 case UniStatusGroupMetricName:
2484 mm.groupMetricMap[g.GroupName].metricMap = UniStatusGroupMetrics
2485 case EthernetBridgeHistoryName:
2486 mm.groupMetricMap[g.GroupName].metricMap = EthernetBridgeHistory
2487 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2488 case EthernetUniHistoryName:
2489 mm.groupMetricMap[g.GroupName].metricMap = EthernetUniHistory
2490 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2491 case FecHistoryName:
2492 mm.groupMetricMap[g.GroupName].metricMap = FecHistory
2493 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2494 case GemPortHistoryName:
2495 mm.groupMetricMap[g.GroupName].metricMap = GemPortHistory
2496 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2497 default:
2498 logger.Errorw(ctx, "unhandled-group-name", log.Fields{"groupName": g.GroupName})
2499 }
2500 }
2501
2502 // Populate local standalone metric structures
2503 for _, m := range mm.pDeviceHandler.pmConfigs.Metrics {
2504 mm.standaloneMetricMap[m.Name] = &standaloneMetric{
2505 metricName: m.Name,
2506 enabled: m.Enabled,
2507 frequency: m.SampleFreq,
2508 }
2509 switch m.Name {
2510 // None exist as of now. Add when available.
2511 default:
2512 logger.Errorw(ctx, "unhandled-metric-name", log.Fields{"metricName": m.Name})
2513 }
2514 }
2515}
2516
Girish Gowdra69570d92021-04-22 18:26:20 -07002517func (mm *onuMetricsManager) AddGemPortForPerfMonitoring(ctx context.Context, gemPortNTPInstID uint16) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002518 mm.onuMetricsManagerLock.Lock()
2519 defer mm.onuMetricsManagerLock.Unlock()
Girish Gowdra69570d92021-04-22 18:26:20 -07002520 logger.Debugw(ctx, "add gemport for perf monitoring - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "gemPortID": gemPortNTPInstID})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002521 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002522 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002523 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002524 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002525
2526 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, GemPortHistoryName)
2527 // We do not need to remove from l2PmToDelete slice as we could have Add and Delete of
2528 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2529 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2530 // gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra69570d92021-04-22 18:26:20 -07002531
2532 logger.Debugw(ctx, "add gemport for perf monitoring - end",
2533 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd,
2534 "instances-to-add": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd})
2535 go func() {
2536 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
2537 // log at warn level as the gem port for monitoring is going to be added eventually
2538 logger.Warnw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2539 }
2540 }()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002541}
2542
Girish Gowdra69570d92021-04-22 18:26:20 -07002543func (mm *onuMetricsManager) RemoveGemPortForPerfMonitoring(ctx context.Context, gemPortNTPInstID uint16) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002544 mm.onuMetricsManagerLock.Lock()
2545 defer mm.onuMetricsManagerLock.Unlock()
Girish Gowdra69570d92021-04-22 18:26:20 -07002546 logger.Debugw(ctx, "remove gemport for perf monitoring - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "gemPortID": gemPortNTPInstID})
Girish Gowdra0e533642021-03-02 22:02:51 -08002547 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002548 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002549 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002550
2551 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, GemPortHistoryName)
2552 // We do not need to remove from l2PmToAdd slice as we could have Add and Delete of
2553 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2554 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2555 // gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra69570d92021-04-22 18:26:20 -07002556
2557 logger.Debugw(ctx, "remove gemport from perf monitoring - end",
2558 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": mm.l2PmToDelete,
2559 "instances-to-delete": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
2560 go func() {
2561 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
2562 // log at warn level as the gem port for monitoring is going to be removed eventually
2563 logger.Warnw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2564 }
2565 }()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002566}
2567
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002568func (mm *onuMetricsManager) updateGemPortNTPInstanceToAddForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002569 if mm.pDeviceHandler.pOnuTP != nil {
2570 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002571 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002572 for _, v := range gemPortInstIDs {
2573 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002574 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002575 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002576 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002577 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002578 logger.Debugw(ctx, "updateGemPortNTPInstanceToAddForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002579 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, "gemToDel": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002580 }
2581}
2582
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002583func (mm *onuMetricsManager) updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002584 if mm.pDeviceHandler.pOnuTP != nil {
2585 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002586 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002587 for _, v := range gemPortInstIDs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002588 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002589 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002590 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002591 }
2592 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002593 logger.Debugw(ctx, "updateGemPortNTPInstanceToDeleteForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002594 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, "gemToDel": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
2595}
2596
2597// restorePmData restores any PM data available on the KV store to local cache
2598func (mm *onuMetricsManager) restorePmData(ctx context.Context) error {
2599 logger.Debugw(ctx, "restorePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2600 if mm.pmKvStore == nil {
2601 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2602 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2603 }
2604 var errorsList []error
2605 for groupName, group := range mm.groupMetricMap {
2606 group.pmMEData = &pmMEData{}
2607 Value, err := mm.pmKvStore.Get(ctx, groupName)
2608 if err == nil {
2609 if Value != nil {
2610 logger.Debugw(ctx, "PM data read",
2611 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2612 tmpBytes, _ := kvstore.ToByte(Value.Value)
2613
2614 if err = json.Unmarshal(tmpBytes, &group.pmMEData); err != nil {
2615 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2616 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-unmarshal-PM-data-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2617 continue
2618 }
2619 logger.Debugw(ctx, "restorePmData - success", log.Fields{"pmData": group.pmMEData, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2620 } else {
2621 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2622 continue
2623 }
2624 } else {
2625 logger.Errorw(ctx, "restorePmData - fail", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "err": err})
2626 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-read-from-KVstore-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2627 continue
2628 }
2629 }
2630 if len(errorsList) > 0 {
2631 return fmt.Errorf("errors-restoring-pm-data-for-one-or-more-groups--errors:%v", errorsList)
2632 }
2633 logger.Debugw(ctx, "restorePmData - complete success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2634 return nil
2635}
2636
2637// getPmData gets pmMEData from cache. Since we have write through cache implementation for pmMEData,
2638// the data must be available in cache.
2639// Note, it is expected that caller of this function manages the required synchronization (like using locks etc.).
2640func (mm *onuMetricsManager) getPmData(ctx context.Context, groupName string) (*pmMEData, error) {
2641 if grp, ok := mm.groupMetricMap[groupName]; ok {
2642 return grp.pmMEData, nil
2643 }
2644 // Data not in cache, try to fetch from kv store.
2645 data := &pmMEData{}
2646 if mm.pmKvStore == nil {
2647 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2648 return data, fmt.Errorf("pmKvStore not set. device-id - %s", mm.pDeviceHandler.deviceID)
2649 }
2650 Value, err := mm.pmKvStore.Get(ctx, groupName)
2651 if err == nil {
2652 if Value != nil {
2653 logger.Debugw(ctx, "PM data read",
2654 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2655 tmpBytes, _ := kvstore.ToByte(Value.Value)
2656
2657 if err = json.Unmarshal(tmpBytes, data); err != nil {
2658 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2659 return data, err
2660 }
2661 logger.Debugw(ctx, "PM data", log.Fields{"pmData": data, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2662 } else {
2663 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2664 return data, err
2665 }
2666 } else {
2667 logger.Errorw(ctx, "unable to read from KVstore", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2668 return data, err
2669 }
2670
2671 return data, nil
2672}
2673
2674// updatePmData update pmMEData to store. It is write through cache, i.e., write to cache first and then update store
2675func (mm *onuMetricsManager) updatePmData(ctx context.Context, groupName string, meInstanceID uint16, pmAction string) error {
2676 logger.Debugw(ctx, "updatePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "entityID": meInstanceID, "pmAction": pmAction})
2677 mm.onuMetricsManagerLock.Lock()
2678 defer mm.onuMetricsManagerLock.Unlock()
2679
2680 if mm.pmKvStore == nil {
2681 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2682 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2683 }
2684
2685 pmMEData, err := mm.getPmData(ctx, groupName)
2686 if err != nil || pmMEData == nil {
2687 // error already logged in called function.
2688 return err
2689 }
2690 switch pmAction {
2691 case cPmAdd:
2692 pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(pmMEData.InstancesToAdd, meInstanceID)
2693 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2694 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2695 case cPmAdded:
2696 pmMEData.InstancesActive = mm.appendIfMissingUnt16(pmMEData.InstancesActive, meInstanceID)
2697 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2698 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2699 case cPmRemove:
2700 pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(pmMEData.InstancesToDelete, meInstanceID)
2701 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2702 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2703 case cPmRemoved:
2704 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2705 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2706 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2707 default:
2708 logger.Errorw(ctx, "unknown pm action", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pmAction": pmAction, "groupName": groupName})
2709 return fmt.Errorf(fmt.Sprintf("unknown-pm-action-deviceid-%s-groupName-%s-pmaction-%s", mm.pDeviceHandler.deviceID, groupName, pmAction))
2710 }
2711 // write through cache
2712 mm.groupMetricMap[groupName].pmMEData = pmMEData
2713
2714 Value, err := json.Marshal(*pmMEData)
2715 if err != nil {
2716 logger.Errorw(ctx, "unable to marshal PM data", log.Fields{"groupName": groupName, "pmAction": pmAction, "pmData": *pmMEData, "err": err})
2717 return err
2718 }
2719 // Update back to kv store
2720 if err = mm.pmKvStore.Put(ctx, groupName, Value); err != nil {
2721 logger.Errorw(ctx, "unable to put PM data to kv store", log.Fields{"groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction, "err": err})
2722 return err
2723 }
2724 logger.Debugw(ctx, "updatePmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction})
2725
2726 return nil
2727}
2728
2729// clearPmGroupData cleans PM Group data from store
2730func (mm *onuMetricsManager) clearPmGroupData(ctx context.Context) error {
2731 mm.onuMetricsManagerLock.Lock()
2732 defer mm.onuMetricsManagerLock.Unlock()
2733 logger.Debugw(ctx, "clearPmGroupData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2734 if mm.pmKvStore == nil {
2735 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2736 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2737 }
2738
2739 for n := range mm.groupMetricMap {
2740 if err := mm.pmKvStore.Delete(ctx, n); err != nil {
2741 logger.Errorw(ctx, "clearPmGroupData - fail", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "groupName": n, "err": err})
2742 // do not abort this procedure. continue to delete next group.
2743 } else {
2744 logger.Debugw(ctx, "clearPmGroupData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": n})
2745 }
2746 }
2747
2748 return nil
2749}
2750
2751// clearAllPmData clears all PM data associated with the device from KV store
2752func (mm *onuMetricsManager) clearAllPmData(ctx context.Context) error {
2753 mm.onuMetricsManagerLock.Lock()
2754 defer mm.onuMetricsManagerLock.Unlock()
2755 logger.Debugw(ctx, "clearAllPmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2756 if mm.pmKvStore == nil {
2757 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2758 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2759 }
Holger Hildebrandt44a0d4f2021-03-18 14:00:54 +00002760 var value error
2761 for n := range mm.groupMetricMap {
2762 if err := mm.pmKvStore.Delete(ctx, n); err != nil {
2763 logger.Errorw(ctx, "clearPmGroupData - fail", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "groupName": n, "err": err})
2764 value = err
2765 // do not abort this procedure - continue to delete next group.
2766 } else {
2767 logger.Debugw(ctx, "clearPmGroupData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": n})
2768 }
Girish Gowdra0e533642021-03-02 22:02:51 -08002769 }
Holger Hildebrandt44a0d4f2021-03-18 14:00:54 +00002770 if value == nil {
2771 logger.Debugw(ctx, "clearAllPmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2772 }
2773 return value
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002774}
2775
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07002776func (mm *onuMetricsManager) updateOmciProcessingStatus(status bool) {
2777 mm.onuMetricsManagerLock.Lock()
2778 defer mm.onuMetricsManagerLock.Unlock()
2779 mm.omciProcessingActive = status
2780}
2781
2782func (mm *onuMetricsManager) updateTickGenerationStatus(status bool) {
2783 mm.onuMetricsManagerLock.Lock()
2784 defer mm.onuMetricsManagerLock.Unlock()
2785 mm.tickGenerationActive = status
2786}
2787
2788func (mm *onuMetricsManager) getOmciProcessingStatus() bool {
2789 mm.onuMetricsManagerLock.RLock()
2790 defer mm.onuMetricsManagerLock.RUnlock()
2791 return mm.omciProcessingActive
2792}
2793
2794func (mm *onuMetricsManager) getTickGenerationStatus() bool {
2795 mm.onuMetricsManagerLock.RLock()
2796 defer mm.onuMetricsManagerLock.RUnlock()
2797 return mm.tickGenerationActive
2798}
2799
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002800func (mm *onuMetricsManager) appendIfMissingString(slice []string, n string) []string {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002801 for _, ele := range slice {
2802 if ele == n {
2803 return slice
2804 }
2805 }
2806 return append(slice, n)
2807}
2808
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002809func (mm *onuMetricsManager) removeIfFoundString(slice []string, n string) []string {
2810 for i, ele := range slice {
2811 if ele == n {
2812 return append(slice[:i], slice[i+1:]...)
2813 }
2814 }
2815 return slice
2816}
2817
2818func (mm *onuMetricsManager) appendIfMissingUnt16(slice []uint16, n uint16) []uint16 {
2819 for _, ele := range slice {
2820 if ele == n {
2821 return slice
2822 }
2823 }
2824 return append(slice, n)
2825}
2826
2827func (mm *onuMetricsManager) removeIfFoundUint16(slice []uint16, n uint16) []uint16 {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002828 for i, ele := range slice {
2829 if ele == n {
2830 return append(slice[:i], slice[i+1:]...)
2831 }
2832 }
2833 return slice
Girish Gowdrae09a6202021-01-12 18:10:59 -08002834}