blob: 4a1de70adcf0a363f747205598c939a71a4037ad [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"
Girish Gowdrae0140f02021-02-02 16:55:09 -080024 "github.com/looplab/fsm"
Girish Gowdrae09a6202021-01-12 18:10:59 -080025 "github.com/opencord/omci-lib-go"
26 me "github.com/opencord/omci-lib-go/generated"
Girish Gowdra0e533642021-03-02 22:02:51 -080027 "github.com/opencord/voltha-lib-go/v4/pkg/db"
28 "github.com/opencord/voltha-lib-go/v4/pkg/db/kvstore"
Girish Gowdrae09a6202021-01-12 18:10:59 -080029 "github.com/opencord/voltha-lib-go/v4/pkg/log"
30 "github.com/opencord/voltha-protos/v4/go/voltha"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080031 "sync"
Girish Gowdrae09a6202021-01-12 18:10:59 -080032 "time"
33)
34
Girish Gowdrae0140f02021-02-02 16:55:09 -080035const (
36 // events of L2 PM FSM
37 l2PmEventInit = "l2PmEventInit"
38 l2PmEventTick = "l2PmEventTick"
39 l2PmEventSuccess = "l2PmEventSuccess"
40 l2PmEventFailure = "l2PmEventFailure"
41 l2PmEventAddMe = "l2PmEventAddMe"
42 l2PmEventDeleteMe = "l2PmEventDeleteMe"
43 l2PmEventStop = "l2PmEventStop"
44)
45const (
46 // states of L2 PM FSM
47 l2PmStNull = "l2PmStNull"
48 l2PmStStarting = "l2PmStStarting"
49 l2PmStSyncTime = "l2PmStSyncTime"
50 l2PmStIdle = "l2PmStIdle"
51 l2PmStCreatePmMe = "l2PmStCreatePm"
52 l2PmStDeletePmMe = "l2PmStDeletePmMe"
53 l2PmStCollectData = "l2PmStCollectData"
54)
55
56const cL2PmFsmIdleState = l2PmStIdle
57
Girish Gowdra5a7c4922021-01-22 18:33:41 -080058// general constants used for overall Metric Collection management
59const (
60 DefaultMetricCollectionFrequency = 15 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
61 GroupMetricEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
62 DefaultFrequencyOverrideEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
63 FrequencyGranularity = 5 // The frequency (in seconds) has to be multiple of 5. This setting cannot changed later.
64)
65
66// OpticalPowerGroupMetrics are supported optical pm names
67var OpticalPowerGroupMetrics = map[string]voltha.PmConfig_PmType{
68 "ani_g_instance_id": voltha.PmConfig_CONTEXT,
69 "transmit_power": voltha.PmConfig_GAUGE,
70 "receive_power": voltha.PmConfig_GAUGE,
71}
72
73// OpticalPowerGroupMetrics specific constants
74const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080075 OpticalPowerGroupMetricName = "PON_Optical"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080076 OpticalPowerGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
77 OpticalPowerMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
78)
79
80// UniStatusGroupMetrics are supported UNI status names
81var UniStatusGroupMetrics = map[string]voltha.PmConfig_PmType{
82 "uni_port_no": voltha.PmConfig_CONTEXT,
Girish Gowdra0e533642021-03-02 22:02:51 -080083 "entity_id": voltha.PmConfig_CONTEXT,
Girish Gowdra5a7c4922021-01-22 18:33:41 -080084 "ethernet_type": voltha.PmConfig_GAUGE,
85 "oper_status": voltha.PmConfig_GAUGE,
86 "uni_admin_state": voltha.PmConfig_GAUGE,
87}
88
89// UniStatusGroupMetrics specific constants
90const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080091 UniStatusGroupMetricName = "UNI_Status"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080092 UniStatusGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
93 UniStatusMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
94)
95
Girish Gowdrae0140f02021-02-02 16:55:09 -080096// *** Classical L2 PM Counters begin ***
97
98// EthernetBridgeHistory are supported ethernet bridge history counters fetched from
99// Ethernet Frame Performance Monitoring History Data Downstream and Ethernet Frame Performance Monitoring History Data Upstream MEs.
100var EthernetBridgeHistory = map[string]voltha.PmConfig_PmType{
101 "class_id": voltha.PmConfig_CONTEXT,
102 "entity_id": voltha.PmConfig_CONTEXT,
103 "interval_end_time": voltha.PmConfig_CONTEXT,
104 "parent_class_id": voltha.PmConfig_CONTEXT,
105 "parent_entity_id": voltha.PmConfig_CONTEXT,
106 "upstream": voltha.PmConfig_CONTEXT,
107
108 "drop_events": voltha.PmConfig_COUNTER,
109 "octets": voltha.PmConfig_COUNTER,
110 "packets": voltha.PmConfig_COUNTER,
111 "broadcast_packets": voltha.PmConfig_COUNTER,
112 "multicast_packets": voltha.PmConfig_COUNTER,
113 "crc_errored_packets": voltha.PmConfig_COUNTER,
114 "undersize_packets": voltha.PmConfig_COUNTER,
115 "oversize_packets": voltha.PmConfig_COUNTER,
116 "64_octets": voltha.PmConfig_COUNTER,
117 "65_to_127_octets": voltha.PmConfig_COUNTER,
118 "128_to_255_octets": voltha.PmConfig_COUNTER,
119 "256_to_511_octets": voltha.PmConfig_COUNTER,
120 "512_to_1023_octets": voltha.PmConfig_COUNTER,
121 "1024_to_1518_octets": voltha.PmConfig_COUNTER,
122}
123
124// EthernetUniHistory are supported ethernet uni history counters fetched from
125// Ethernet Performance Monitoring History Data ME.
126var EthernetUniHistory = map[string]voltha.PmConfig_PmType{
127 "class_id": voltha.PmConfig_CONTEXT,
128 "entity_id": voltha.PmConfig_CONTEXT,
129 "interval_end_time": voltha.PmConfig_CONTEXT,
130
131 "fcs_errors": voltha.PmConfig_COUNTER,
132 "excessive_collision_counter": voltha.PmConfig_COUNTER,
133 "late_collision_counter": voltha.PmConfig_COUNTER,
134 "frames_too_long": voltha.PmConfig_COUNTER,
135 "buffer_overflows_on_rx": voltha.PmConfig_COUNTER,
136 "buffer_overflows_on_tx": voltha.PmConfig_COUNTER,
137 "single_collision_frame_counter": voltha.PmConfig_COUNTER,
138 "multiple_collisions_frame_counter": voltha.PmConfig_COUNTER,
139 "sqe_counter": voltha.PmConfig_COUNTER,
140 "deferred_tx_counter": voltha.PmConfig_COUNTER,
141 "internal_mac_tx_error_counter": voltha.PmConfig_COUNTER,
142 "carrier_sense_error_counter": voltha.PmConfig_COUNTER,
143 "alignment_error_counter": voltha.PmConfig_COUNTER,
144 "internal_mac_rx_error_counter": voltha.PmConfig_COUNTER,
145}
146
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800147// FecHistory is supported FEC Performance Monitoring History Data related metrics
148var FecHistory = map[string]voltha.PmConfig_PmType{
149 "class_id": voltha.PmConfig_CONTEXT,
150 "entity_id": voltha.PmConfig_CONTEXT,
151 "interval_end_time": voltha.PmConfig_CONTEXT,
152
153 "corrected_bytes": voltha.PmConfig_COUNTER,
154 "corrected_code_words": voltha.PmConfig_COUNTER,
155 "uncorrectable_code_words": voltha.PmConfig_COUNTER,
156 "total_code_words": voltha.PmConfig_COUNTER,
157 "fec_seconds": voltha.PmConfig_COUNTER,
158}
159
160// GemPortHistory is supported GEM Port Network Ctp Performance Monitoring History Data
161// related metrics
162var GemPortHistory = map[string]voltha.PmConfig_PmType{
163 "class_id": voltha.PmConfig_CONTEXT,
164 "entity_id": voltha.PmConfig_CONTEXT,
165 "interval_end_time": voltha.PmConfig_CONTEXT,
166
167 "transmitted_gem_frames": voltha.PmConfig_COUNTER,
168 "received_gem_frames": voltha.PmConfig_COUNTER,
169 "received_payload_bytes": voltha.PmConfig_COUNTER,
170 "transmitted_payload_bytes": voltha.PmConfig_COUNTER,
171 "encryption_key_errors": voltha.PmConfig_COUNTER,
172}
173
Girish Gowdrae0140f02021-02-02 16:55:09 -0800174// Constants specific for L2 PM collection
175const (
176 L2PmCollectionInterval = 15 * 60 // Unit in seconds. Do not change this as this fixed by OMCI specification for L2 PM counters
177 SyncTimeRetryInterval = 15 // Unit seconds
178 L2PmCreateAttempts = 3
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800179 L2PmDeleteAttempts = 3
Girish Gowdrae0140f02021-02-02 16:55:09 -0800180 L2PmCollectAttempts = 3
Girish Gowdra453750f2021-02-16 16:36:46 -0800181 // Per Table 11.2.9-1 – OMCI baseline message limitations in G.988 spec, the max GET Response
182 // payload size is 25. We define 24 (one less) to allow for dynamic insertion of IntervalEndTime
183 // attribute (1 byte) in L2 PM GET Requests.
184 MaxL2PMGetPayLoadSize = 24
Girish Gowdrae0140f02021-02-02 16:55:09 -0800185)
186
187// EthernetUniHistoryName specific constants
188const (
189 EthernetBridgeHistoryName = "Ethernet_Bridge_Port_History"
190 EthernetBridgeHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
191 EthernetBridgeHistoryFrequency = L2PmCollectionInterval
192)
193
194// EthernetBridgeHistory specific constants
195const (
196 EthernetUniHistoryName = "Ethernet_UNI_History"
197 EthernetUniHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
198 EthernetUniHistoryFrequency = L2PmCollectionInterval
199)
200
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800201// FecHistory specific constants
202const (
203 FecHistoryName = "FEC_History"
204 FecHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
205 FecHistoryFrequency = L2PmCollectionInterval
206)
207
208// GemPortHistory specific constants
209const (
210 GemPortHistoryName = "GEM_Port_History"
211 GemPortHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
212 GemPortHistoryFrequency = L2PmCollectionInterval
213)
214
Girish Gowdra0e533642021-03-02 22:02:51 -0800215// KV Store related constants
216const (
217 cPmKvStorePrefix = "%s/openonu/pm-data/%s" // <some-base-path>/openonu/pm-data/<onu-device-id>
218 cPmAdd = "add"
219 cPmAdded = "added"
220 cPmRemove = "remove"
221 cPmRemoved = "removed"
222)
223
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800224// Defines the type for generic metric population function
225type groupMetricPopulateFunc func(context.Context, me.ClassID, uint16, me.AttributeValueMap, me.AttributeValueMap, map[string]float32, *int) error
226
Girish Gowdrae0140f02021-02-02 16:55:09 -0800227// *** Classical L2 PM Counters end ***
228
Girish Gowdra0e533642021-03-02 22:02:51 -0800229type pmMEData struct {
230 InstancesActive []uint16 `json:"instances_active"` // list of active ME instance IDs for the group
231 InstancesToDelete []uint16 `json:"instances_to_delete"` // list of ME instance IDs marked for deletion for the group
232 InstancesToAdd []uint16 `json:"instances_to_add"` // list of ME instance IDs marked for addition for the group
233}
234
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800235type groupMetric struct {
236 groupName string
237 enabled bool
238 frequency uint32 // valid only if FrequencyOverride is enabled.
239 metricMap map[string]voltha.PmConfig_PmType
240 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
Girish Gowdrae0140f02021-02-02 16:55:09 -0800241 isL2PMCounter bool // true for only L2 PM counters
242 collectAttempts uint32 // number of attempts to collect L2 PM data
Girish Gowdra0e533642021-03-02 22:02:51 -0800243 pmMEData *pmMEData
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800244}
245
246type standaloneMetric struct {
247 metricName string
248 enabled bool
249 frequency uint32 // valid only if FrequencyOverride is enabled.
250 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
251}
252
Girish Gowdrae09a6202021-01-12 18:10:59 -0800253type onuMetricsManager struct {
254 pDeviceHandler *deviceHandler
Girish Gowdrae0140f02021-02-02 16:55:09 -0800255 pAdaptFsm *AdapterFsm
Girish Gowdrae09a6202021-01-12 18:10:59 -0800256
Girish Gowdrae0140f02021-02-02 16:55:09 -0800257 opticalMetricsChan chan me.AttributeValueMap
258 uniStatusMetricsChan chan me.AttributeValueMap
259 l2PmChan chan me.AttributeValueMap
260 syncTimeResponseChan chan bool // true is success, false is fail
261 l2PmCreateOrDeleteResponseChan chan bool // true is success, false is fail
262
263 activeL2Pms []string // list of active l2 pm MEs created on the ONU.
264 l2PmToDelete []string // list of L2 PMs to delete
265 l2PmToAdd []string // list of L2 PM to add
Girish Gowdrae09a6202021-01-12 18:10:59 -0800266
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800267 groupMetricMap map[string]*groupMetric
268 standaloneMetricMap map[string]*standaloneMetric
269
Girish Gowdrae09a6202021-01-12 18:10:59 -0800270 stopProcessingOmciResponses chan bool
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800271
Girish Gowdrae0140f02021-02-02 16:55:09 -0800272 stopTicks chan bool
273
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800274 nextGlobalMetricCollectionTime time.Time // valid only if pmConfig.FreqOverride is set to false.
275
276 onuMetricsManagerLock sync.RWMutex
Girish Gowdra0e533642021-03-02 22:02:51 -0800277
278 pmKvStore *db.Backend
Girish Gowdrae09a6202021-01-12 18:10:59 -0800279}
280
281// newonuMetricsManager returns a new instance of the newonuMetricsManager
Girish Gowdra0e533642021-03-02 22:02:51 -0800282// The metrics manager module is responsible for configuration and management of individual and group metrics.
283// Currently all the metrics are managed as a group which fall into two categories - L2 PM and "all others"
284// The L2 PM counters have a fixed 15min interval for PM collection while all other group counters have
285// the collection interval configurable.
286// The global PM config is part of the voltha.Device struct and is backed up on KV store (by rw-core).
287// This module also implements resiliency for L2 PM ME instances that are active/pending-delete/pending-add.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800288func newonuMetricsManager(ctx context.Context, dh *deviceHandler) *onuMetricsManager {
289
290 var metricsManager onuMetricsManager
291 logger.Debugw(ctx, "init-onuMetricsManager", log.Fields{"device-id": dh.deviceID})
292 metricsManager.pDeviceHandler = dh
293
Girish Gowdrae0140f02021-02-02 16:55:09 -0800294 commMetricsChan := make(chan Message)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800295 metricsManager.opticalMetricsChan = make(chan me.AttributeValueMap)
296 metricsManager.uniStatusMetricsChan = make(chan me.AttributeValueMap)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800297 metricsManager.l2PmChan = make(chan me.AttributeValueMap)
298
299 metricsManager.syncTimeResponseChan = make(chan bool)
300 metricsManager.l2PmCreateOrDeleteResponseChan = make(chan bool)
301
Girish Gowdrae09a6202021-01-12 18:10:59 -0800302 metricsManager.stopProcessingOmciResponses = make(chan bool)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800303 metricsManager.stopTicks = make(chan bool)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800304
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800305 metricsManager.groupMetricMap = make(map[string]*groupMetric)
306 metricsManager.standaloneMetricMap = make(map[string]*standaloneMetric)
307
308 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 -0800309 metricsManager.initializeAllGroupMetrics()
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800310 }
311
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800312 metricsManager.populateLocalGroupMetricData(ctx)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800313
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800314 if err := metricsManager.initializeL2PmFsm(ctx, commMetricsChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800315 return nil
316 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800317
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800318 // initialize the next metric collection intervals.
319 metricsManager.initializeMetricCollectionTime(ctx)
Girish Gowdra0e533642021-03-02 22:02:51 -0800320
321 baseKvStorePath := fmt.Sprintf(cPmKvStorePrefix, dh.pOpenOnuAc.cm.Backend.PathPrefix, dh.deviceID)
322 metricsManager.pmKvStore = dh.setBackend(ctx, baseKvStorePath)
323 if metricsManager.pmKvStore == nil {
324 logger.Errorw(ctx, "Can't initialize pmKvStore - no backend connection to PM module",
325 log.Fields{"device-id": dh.deviceID, "service": baseKvStorePath})
326 return nil
327 }
328
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800329 logger.Info(ctx, "init-onuMetricsManager completed", log.Fields{"device-id": dh.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800330 return &metricsManager
331}
332
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800333func (mm *onuMetricsManager) initializeMetricCollectionTime(ctx context.Context) {
334 if mm.pDeviceHandler.pmConfigs.FreqOverride {
335 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to true, then group/standalone metric specific interval applies
336 mm.onuMetricsManagerLock.Lock()
337 defer mm.onuMetricsManagerLock.Unlock()
338 for _, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800339 if v.enabled && !v.isL2PMCounter { // L2 PM counter collection is managed in a L2PmFsm
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800340 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
341 }
342 }
343
344 for _, v := range mm.standaloneMetricMap {
345 if v.enabled {
346 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
347 }
348 }
349 } else {
350 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to false, then overall metric specific interval applies
351 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
352 }
353 logger.Infow(ctx, "initialized standalone group/metric collection time", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
354}
355
356func (mm *onuMetricsManager) updateDefaultFrequency(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
357 // Verify that the configured DefaultFrequency is > 0 and is a multiple of FrequencyGranularity
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800358 if pmConfigs.DefaultFreq == 0 || (pmConfigs.DefaultFreq > 0 && pmConfigs.DefaultFreq%FrequencyGranularity != 0) {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800359 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", pmConfigs.DefaultFreq, FrequencyGranularity)
360 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", pmConfigs.DefaultFreq, FrequencyGranularity)
361 }
362 mm.pDeviceHandler.pmConfigs.DefaultFreq = pmConfigs.DefaultFreq
363 // re-set the nextGlobalMetricCollectionTime based on the new DefaultFreq
364 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
365 logger.Debugw(ctx, "frequency-updated--new-frequency", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "frequency": mm.pDeviceHandler.pmConfigs.DefaultFreq})
366 return nil
367}
368
369func (mm *onuMetricsManager) updateGroupFreq(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
370 var newGroupFreq uint32
371 found := false
372 groupSliceIdx := 0
373 var group *voltha.PmGroupConfig
374 for groupSliceIdx, group = range pmConfigs.Groups {
375 if group.GroupName == aGroupName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800376 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
377 if group.GroupFreq == 0 || (group.GroupFreq > 0 && group.GroupFreq%FrequencyGranularity != 0) {
378 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", group.GroupFreq, FrequencyGranularity)
379 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", group.GroupFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800380 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800381 newGroupFreq = group.GroupFreq
382 found = true
383 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800384 }
385 }
386 // if not found update group freq and next collection interval for the group
387 if !found {
388 logger.Errorw(ctx, "group name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
389 return fmt.Errorf("group-name-not-found-%v", aGroupName)
390 }
391
392 updated := false
393 mm.onuMetricsManagerLock.Lock()
394 defer mm.onuMetricsManagerLock.Unlock()
395 for k, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800396 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 -0800397 v.frequency = newGroupFreq
398 // update internal pm config
399 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].GroupFreq = newGroupFreq
400 // Also updated the next group metric collection time from now
401 v.nextCollectionInterval = time.Now().Add(time.Duration(newGroupFreq) * time.Second)
402 updated = true
403 logger.Infow(ctx, "group frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800404 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800405 }
406 }
407 if !updated {
408 logger.Errorw(ctx, "group frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
409 return fmt.Errorf("internal-error-during-group-freq-update--groupname-%s-freq-%d", aGroupName, newGroupFreq)
410 }
411 return nil
412}
413
414func (mm *onuMetricsManager) updateMetricFreq(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
415 var newMetricFreq uint32
416 found := false
417 metricSliceIdx := 0
418 var metric *voltha.PmConfig
419 for metricSliceIdx, metric = range pmConfigs.Metrics {
420 if metric.Name == aMetricName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800421 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
422 if metric.SampleFreq == 0 || (metric.SampleFreq > 0 && metric.SampleFreq%FrequencyGranularity != 0) {
423 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", metric.SampleFreq, FrequencyGranularity)
424 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", metric.SampleFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800425 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800426 newMetricFreq = metric.SampleFreq
427 found = true
428 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800429 }
430 }
431 if !found {
432 logger.Errorw(ctx, "metric name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
433 return fmt.Errorf("metric-name-not-found-%v", aMetricName)
434 }
435
436 updated := false
437 mm.onuMetricsManagerLock.Lock()
438 defer mm.onuMetricsManagerLock.Unlock()
439 for k, v := range mm.groupMetricMap {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800440 if k == aMetricName {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800441 v.frequency = newMetricFreq
442 // update internal pm config
443 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].SampleFreq = newMetricFreq
444 // Also updated the next standalone metric collection time from now
445 v.nextCollectionInterval = time.Now().Add(time.Duration(newMetricFreq) * time.Second)
446 updated = true
447 logger.Infow(ctx, "metric frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800448 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800449 }
450 }
451 if !updated {
452 logger.Errorw(ctx, "metric frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
453 return fmt.Errorf("internal-error-during-standalone-metric-update--matricnane-%s-freq-%d", aMetricName, newMetricFreq)
454 }
455 return nil
456}
457
458func (mm *onuMetricsManager) updateGroupSupport(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
459 groupSliceIdx := 0
460 var group *voltha.PmGroupConfig
461
462 for groupSliceIdx, group = range pmConfigs.Groups {
463 if group.GroupName == aGroupName {
464 break
465 }
466 }
467 if group == nil {
468 logger.Errorw(ctx, "group metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
469 return fmt.Errorf("group-not-found--groupName-%s", aGroupName)
470 }
471
472 updated := false
473 mm.onuMetricsManagerLock.Lock()
474 defer mm.onuMetricsManagerLock.Unlock()
475 for k, v := range mm.groupMetricMap {
476 if k == aGroupName && v.enabled != group.Enabled {
477 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].Enabled = group.Enabled
478 v.enabled = group.Enabled
Girish Gowdrae0140f02021-02-02 16:55:09 -0800479 if group.Enabled {
480 if v.isL2PMCounter {
481 // If it is a L2 PM counter we need to mark the PM to be added
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800482 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800483 // 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 -0800484 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, v.groupName)
485
486 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
487 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
488 // take further action
489 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800490 mm.updateGemPortNTPInstanceToAddForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800491 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800492 } else if mm.pDeviceHandler.pmConfigs.FreqOverride { // otherwise just update the next collection interval
493 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
494 }
495 } else { // group counter is disabled
496 if v.isL2PMCounter {
497 // If it is a L2 PM counter we need to mark the PM to be deleted
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800498 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800499 // 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 -0800500 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, v.groupName)
501
502 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
503 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
504 // take further action
505 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800506 mm.updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800507 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800508 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800509 }
510 updated = true
Girish Gowdrae0140f02021-02-02 16:55:09 -0800511 if v.isL2PMCounter {
512 logger.Infow(ctx, "l2 pm group metric support updated",
513 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled, "l2PmToAdd": mm.l2PmToAdd, "l2PmToDelete": mm.l2PmToDelete})
514 } else {
515 logger.Infow(ctx, "group metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled})
516 }
517 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800518 }
519 }
520
521 if !updated {
522 logger.Errorw(ctx, "group metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
523 return fmt.Errorf("internal-error-during-group-support-update--groupName-%s", aGroupName)
524 }
525 return nil
526}
527
528func (mm *onuMetricsManager) updateMetricSupport(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
529 metricSliceIdx := 0
530 var metric *voltha.PmConfig
531
532 for metricSliceIdx, metric = range pmConfigs.Metrics {
533 if metric.Name == aMetricName {
534 break
535 }
536 }
537
538 if metric == nil {
539 logger.Errorw(ctx, "standalone metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
540 return fmt.Errorf("metric-not-found--metricname-%s", aMetricName)
541 }
542
543 updated := false
544 mm.onuMetricsManagerLock.Lock()
545 defer mm.onuMetricsManagerLock.Unlock()
546 for k, v := range mm.standaloneMetricMap {
547 if k == aMetricName && v.enabled != metric.Enabled {
548 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].Enabled = metric.Enabled
549 v.enabled = metric.Enabled
550 // If the standalone metric is now enabled and frequency override is enabled, set the next metric collection time
551 if metric.Enabled && mm.pDeviceHandler.pmConfigs.FreqOverride {
552 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
553 }
554 updated = true
555 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 -0800556 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800557 }
558 }
559 if !updated {
560 logger.Errorw(ctx, "standalone metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
561 return fmt.Errorf("internal-error-during-standalone-support-update--metricname-%s", aMetricName)
562 }
563 return nil
564}
565
566func (mm *onuMetricsManager) collectAllGroupAndStandaloneMetrics(ctx context.Context) {
567 if mm.pDeviceHandler.pmConfigs.Grouped { // metrics are managed as a group.
568 go mm.collectAllGroupMetrics(ctx)
569 } else {
570 go mm.collectAllStandaloneMetrics(ctx)
571 }
572}
573
574func (mm *onuMetricsManager) collectAllGroupMetrics(ctx context.Context) {
575 go func() {
576 logger.Debug(ctx, "startCollector before collecting optical metrics")
577 metricInfo := mm.collectOpticalMetrics(ctx)
578 if metricInfo != nil {
579 mm.publishMetrics(ctx, metricInfo)
580 }
581 }()
582
583 go func() {
584 logger.Debug(ctx, "startCollector before collecting uni metrics")
585 metricInfo := mm.collectUniStatusMetrics(ctx)
586 if metricInfo != nil {
587 mm.publishMetrics(ctx, metricInfo)
588 }
589 }()
590
591 // Add more here
592}
593
594func (mm *onuMetricsManager) collectAllStandaloneMetrics(ctx context.Context) {
595 // None exists as of now, add when available here
596}
597
598func (mm *onuMetricsManager) collectGroupMetric(ctx context.Context, groupName string) {
599 switch groupName {
600 case OpticalPowerGroupMetricName:
601 go func() {
602 if mi := mm.collectOpticalMetrics(ctx); mm != nil {
603 mm.publishMetrics(ctx, mi)
604 }
605 }()
606 case UniStatusGroupMetricName:
607 go func() {
608 if mi := mm.collectUniStatusMetrics(ctx); mm != nil {
609 mm.publishMetrics(ctx, mi)
610 }
611 }()
612 default:
613 logger.Errorw(ctx, "unhandled group metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName})
614 }
615}
616
617func (mm *onuMetricsManager) collectStandaloneMetric(ctx context.Context, metricName string) {
618 switch metricName {
619 // None exist as of now, add when available
620 default:
621 logger.Errorw(ctx, "unhandled standalone metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName})
622 }
623}
624
625// collectOpticalMetrics collects groups metrics related to optical power from ani-g ME.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800626func (mm *onuMetricsManager) collectOpticalMetrics(ctx context.Context) []*voltha.MetricInformation {
627 logger.Debugw(ctx, "collectOpticalMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800628
629 mm.onuMetricsManagerLock.RLock()
630 if !mm.groupMetricMap[OpticalPowerGroupMetricName].enabled {
631 mm.onuMetricsManagerLock.RUnlock()
632 logger.Debugw(ctx, "optical power group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
633 return nil
634 }
635 mm.onuMetricsManagerLock.RUnlock()
636
Girish Gowdrae09a6202021-01-12 18:10:59 -0800637 var metricInfoSlice []*voltha.MetricInformation
638 metricsContext := make(map[string]string)
639 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
640 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
641 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
642
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800643 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800644 mmd := voltha.MetricMetaData{
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800645 Title: OpticalPowerGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800646 Ts: float64(raisedTs),
647 Context: metricsContext,
648 DeviceId: mm.pDeviceHandler.deviceID,
649 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
650 SerialNo: mm.pDeviceHandler.device.SerialNumber,
651 }
652
Girish Gowdrae09a6202021-01-12 18:10:59 -0800653 // get the ANI-G instance IDs
654 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
655loop:
656 for _, anigInstID := range anigInstKeys {
657 var meAttributes me.AttributeValueMap
658 opticalMetrics := make(map[string]float32)
659 // Get the ANI-G instance optical power attributes
660 requestedAttributes := me.AttributeValueMap{"OpticalSignalLevel": 0, "TransmitOpticalLevel": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800661 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.AniGClassID, anigInstID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800662 select {
663 case meAttributes = <-mm.opticalMetricsChan:
664 logger.Debugw(ctx, "received optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
665 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800666 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 -0800667 // The metrics will be empty in this case
668 break loop
669 }
670 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800671 for k := range OpticalPowerGroupMetrics {
672 switch k {
673 case "ani_g_instance_id":
674 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
675 opticalMetrics[k] = float32(val.(uint16))
676 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800677 case "transmit_power":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800678 if val, ok := meAttributes["TransmitOpticalLevel"]; ok && val != nil {
679 opticalMetrics[k] = float32(val.(uint16))
680 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800681 case "receive_power":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800682 if val, ok := meAttributes["OpticalSignalLevel"]; ok && val != nil {
683 opticalMetrics[k] = float32(val.(uint16))
684 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800685 default:
686 // do nothing
687 }
688 }
689 }
690 // create slice of metrics given that there could be more than one ANI-G instance and
691 // optical metrics are collected per ANI-G instance
692 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: opticalMetrics}
693 metricInfoSlice = append(metricInfoSlice, &metricInfo)
694 }
695
696 return metricInfoSlice
697}
698
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800699// collectUniStatusMetrics collects UNI status group metric from various MEs (uni-g, pptp and veip).
Girish Gowdrae09a6202021-01-12 18:10:59 -0800700// nolint: gocyclo
701func (mm *onuMetricsManager) collectUniStatusMetrics(ctx context.Context) []*voltha.MetricInformation {
702 logger.Debugw(ctx, "collectUniStatusMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800703 mm.onuMetricsManagerLock.RLock()
704 if !mm.groupMetricMap[UniStatusGroupMetricName].enabled {
705 mm.onuMetricsManagerLock.RUnlock()
706 logger.Debugw(ctx, "uni status group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
707 return nil
708 }
709 mm.onuMetricsManagerLock.RUnlock()
710
Girish Gowdrae09a6202021-01-12 18:10:59 -0800711 var metricInfoSlice []*voltha.MetricInformation
712 metricsContext := make(map[string]string)
713 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
714 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
715 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
716
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800717 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800718 mmd := voltha.MetricMetaData{
719 Title: "UniStatus", // Is this ok to hard code?
720 Ts: float64(raisedTs),
721 Context: metricsContext,
722 DeviceId: mm.pDeviceHandler.deviceID,
723 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
724 SerialNo: mm.pDeviceHandler.device.SerialNumber,
725 }
726
Girish Gowdrae09a6202021-01-12 18:10:59 -0800727 // get the UNI-G instance IDs
728 unigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.UniGClassID)
729loop1:
730 for _, unigInstID := range unigInstKeys {
731 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
732 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
733 unigMetrics := make(map[string]float32)
734 var meAttributes me.AttributeValueMap
735 // Get the UNI-G instance optical power attributes
736 requestedAttributes := me.AttributeValueMap{"AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800737 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.UniGClassID, unigInstID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800738 // Wait for metrics or timeout
739 select {
740 case meAttributes = <-mm.uniStatusMetricsChan:
741 logger.Debugw(ctx, "received uni-g metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
742 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
743 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
744 // The metrics could be empty in this case
745 break loop1
746 }
747 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800748 for k := range UniStatusGroupMetrics {
749 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800750 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800751 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
752 unigMetrics[k] = float32(val.(byte))
753 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800754 default:
755 // do nothing
756 }
757 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800758 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800759 entityID := val.(uint16)
760 unigMetrics["entity_id"] = float32(entityID)
761 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
762 for _, uni := range mm.pDeviceHandler.uniEntityMap {
763 if uni.entityID == entityID {
764 unigMetrics["uni_port_no"] = float32(uni.portNo)
765 }
766 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800767 }
Girish Gowdra0e533642021-03-02 22:02:51 -0800768
Girish Gowdrae09a6202021-01-12 18:10:59 -0800769 // create slice of metrics given that there could be more than one UNI-G instance
770 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: unigMetrics}
771 metricInfoSlice = append(metricInfoSlice, &metricInfo)
772 }
773 }
774
775 // get the PPTP instance IDs
776 pptpInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.PhysicalPathTerminationPointEthernetUniClassID)
777loop2:
778 for _, pptpInstID := range pptpInstKeys {
779 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
780 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
781 var meAttributes me.AttributeValueMap
782 pptpMetrics := make(map[string]float32)
783
784 requestedAttributes := me.AttributeValueMap{"SensedType": 0, "OperationalState": 0, "AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800785 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.PhysicalPathTerminationPointEthernetUniClassID, pptpInstID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800786 // Wait for metrics or timeout
787 select {
788 case meAttributes = <-mm.uniStatusMetricsChan:
789 logger.Debugw(ctx, "received pptp metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
790 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
791 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
792 // The metrics could be empty in this case
793 break loop2
794 }
795
796 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800797 for k := range UniStatusGroupMetrics {
798 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800799 case "ethernet_type":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800800 if val, ok := meAttributes["SensedType"]; ok && val != nil {
801 pptpMetrics[k] = float32(val.(byte))
802 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800803 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800804 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
805 pptpMetrics[k] = float32(val.(byte))
806 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800807 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800808 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
809 pptpMetrics[k] = float32(val.(byte))
810 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800811 default:
812 // do nothing
813 }
814 }
815 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800816 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800817 entityID := val.(uint16)
818 pptpMetrics["entity_id"] = float32(entityID)
819 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
820 for _, uni := range mm.pDeviceHandler.uniEntityMap {
821 if uni.entityID == entityID {
822 pptpMetrics["uni_port_no"] = float32(uni.portNo)
823 }
824 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800825 }
826
Girish Gowdrae09a6202021-01-12 18:10:59 -0800827 // create slice of metrics given that there could be more than one PPTP instance and
828 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: pptpMetrics}
829 metricInfoSlice = append(metricInfoSlice, &metricInfo)
830 }
831
832 // get the VEIP instance IDs
833 veipInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.VirtualEthernetInterfacePointClassID)
834loop3:
835 for _, veipInstID := range veipInstKeys {
836 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
837 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
838 var meAttributes me.AttributeValueMap
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800839 veipMetrics := make(map[string]float32)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800840
841 requestedAttributes := me.AttributeValueMap{"OperationalState": 0, "AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800842 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.VirtualEthernetInterfacePointClassID, veipInstID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800843 // Wait for metrics or timeout
844 select {
845 case meAttributes = <-mm.uniStatusMetricsChan:
846 logger.Debugw(ctx, "received veip metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
847 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
848 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
849 // The metrics could be empty in this case
850 break loop3
851 }
852
853 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800854 for k := range UniStatusGroupMetrics {
855 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800856 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800857 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
858 veipMetrics[k] = float32(val.(byte))
859 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800860 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800861 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
862 veipMetrics[k] = float32(val.(byte))
863 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800864 default:
865 // do nothing
866 }
867 }
868 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800869
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800870 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800871 entityID := val.(uint16)
872 veipMetrics["entity_id"] = float32(entityID)
873 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
874 for _, uni := range mm.pDeviceHandler.uniEntityMap {
875 if uni.entityID == entityID {
876 veipMetrics["uni_port_no"] = float32(uni.portNo)
877 }
878 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800879 }
880
Girish Gowdrae09a6202021-01-12 18:10:59 -0800881 // create slice of metrics given that there could be more than one VEIP instance
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800882 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: veipMetrics}
Girish Gowdrae09a6202021-01-12 18:10:59 -0800883 metricInfoSlice = append(metricInfoSlice, &metricInfo)
884 }
885
886 return metricInfoSlice
887}
888
889// publishMetrics publishes the metrics on kafka
890func (mm *onuMetricsManager) publishMetrics(ctx context.Context, metricInfo []*voltha.MetricInformation) {
891 var ke voltha.KpiEvent2
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800892 ts := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800893 ke.SliceData = metricInfo
894 ke.Type = voltha.KpiEventType_slice
895 ke.Ts = float64(ts)
896
897 if err := mm.pDeviceHandler.EventProxy.SendKpiEvent(ctx, "STATS_EVENT", &ke, voltha.EventCategory_EQUIPMENT, voltha.EventSubCategory_ONU, ts); err != nil {
898 logger.Errorw(ctx, "failed-to-send-pon-stats", log.Fields{"err": err})
899 }
900}
901
902func (mm *onuMetricsManager) processOmciMessages(ctx context.Context) {
903 logger.Infow(ctx, "Start routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
904 // Flush metric collection channels to be safe.
905 // It is possible that there is stale data on this channel if the processOmciMessages routine
906 // is stopped right after issuing a OMCI-GET request and started again.
907 // The processOmciMessages routine will get stopped if startCollector routine (in device_handler.go)
908 // is stopped - as a result of ONU going down.
909 mm.flushMetricCollectionChannels(ctx)
910
911 for {
912 select {
913 case <-mm.stopProcessingOmciResponses: // stop this routine
914 logger.Infow(ctx, "Stop routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
915 return
Girish Gowdrae0140f02021-02-02 16:55:09 -0800916 case message, ok := <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -0800917 if !ok {
918 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
919 continue
920 }
921 logger.Debugw(ctx, "Received message on ONU metrics channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
922
923 switch message.Type {
924 case OMCI:
925 msg, _ := message.Data.(OmciMessage)
926 mm.handleOmciMessage(ctx, msg)
927 default:
928 logger.Warn(ctx, "Unknown message type received", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "message.Type": message.Type})
929 }
930 }
931 }
932}
933
934func (mm *onuMetricsManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
935 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
936 "msgType": msg.OmciMsg.MessageType, "msg": msg})
937 switch msg.OmciMsg.MessageType {
938 case omci.GetResponseType:
939 //TODO: error handling
940 _ = mm.handleOmciGetResponseMessage(ctx, msg)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800941 case omci.SynchronizeTimeResponseType:
942 _ = mm.handleOmciSynchronizeTimeResponseMessage(ctx, msg)
943 case omci.CreateResponseType:
944 _ = mm.handleOmciCreateResponseMessage(ctx, msg)
945 case omci.DeleteResponseType:
946 _ = mm.handleOmciDeleteResponseMessage(ctx, msg)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800947 default:
948 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
949
950 }
951}
952
953func (mm *onuMetricsManager) handleOmciGetResponseMessage(ctx context.Context, msg OmciMessage) error {
954 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
955 if msgLayer == nil {
956 logger.Errorw(ctx, "omci Msg layer could not be detected for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
957 return fmt.Errorf("omci Msg layer could not be detected for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
958 }
959 msgObj, msgOk := msgLayer.(*omci.GetResponse)
960 if !msgOk {
961 logger.Errorw(ctx, "omci Msg layer could not be assigned for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
962 return fmt.Errorf("omci Msg layer could not be assigned for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
963 }
964 logger.Debugw(ctx, "OMCI GetResponse Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
965 if msgObj.Result == me.Success {
966 meAttributes := msgObj.Attributes
967 switch msgObj.EntityClass {
968 case me.AniGClassID:
969 mm.opticalMetricsChan <- meAttributes
970 return nil
971 case me.UniGClassID:
972 mm.uniStatusMetricsChan <- meAttributes
973 return nil
974 case me.PhysicalPathTerminationPointEthernetUniClassID:
975 mm.uniStatusMetricsChan <- meAttributes
976 return nil
977 case me.VirtualEthernetInterfacePointClassID:
978 mm.uniStatusMetricsChan <- meAttributes
979 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -0800980 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
981 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800982 me.EthernetPerformanceMonitoringHistoryDataClassID,
983 me.FecPerformanceMonitoringHistoryDataClassID,
984 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -0800985 mm.l2PmChan <- meAttributes
Girish Gowdrae09a6202021-01-12 18:10:59 -0800986 default:
987 logger.Errorw(ctx, "unhandled omci get response message",
988 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
989 }
990 }
991
Girish Gowdrae0140f02021-02-02 16:55:09 -0800992 return fmt.Errorf("unhandled-omci-get-response-message")
993}
994
995func (mm *onuMetricsManager) handleOmciSynchronizeTimeResponseMessage(ctx context.Context, msg OmciMessage) error {
996 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSynchronizeTimeResponse)
997 if msgLayer == nil {
998 logger.Errorw(ctx, "omci Msg layer could not be detected for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
999 return fmt.Errorf("omci Msg layer could not be detected for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1000 }
1001 msgObj, msgOk := msgLayer.(*omci.SynchronizeTimeResponse)
1002 if !msgOk {
1003 logger.Errorw(ctx, "omci Msg layer could not be assigned for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1004 return fmt.Errorf("omci Msg layer could not be assigned for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1005 }
1006 logger.Debugw(ctx, "OMCI synchronize time response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1007 if msgObj.Result == me.Success {
1008 switch msgObj.EntityClass {
1009 case me.OnuGClassID:
1010 logger.Infow(ctx, "omci synchronize time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1011 mm.syncTimeResponseChan <- true
1012 return nil
1013 default:
1014 logger.Errorw(ctx, "unhandled omci message",
1015 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1016 }
1017 }
1018 mm.syncTimeResponseChan <- false
1019 logger.Errorf(ctx, "unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
1020 return fmt.Errorf("unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001021}
1022
1023// flushMetricCollectionChannels flushes all metric collection channels for any stale OMCI responses
1024func (mm *onuMetricsManager) flushMetricCollectionChannels(ctx context.Context) {
1025 // flush commMetricsChan
1026 select {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001027 case <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -08001028 logger.Debug(ctx, "flushed common metrics channel")
1029 default:
1030 }
1031
1032 // flush opticalMetricsChan
1033 select {
1034 case <-mm.opticalMetricsChan:
1035 logger.Debug(ctx, "flushed optical metrics channel")
1036 default:
1037 }
1038
1039 // flush uniStatusMetricsChan
1040 select {
1041 case <-mm.uniStatusMetricsChan:
1042 logger.Debug(ctx, "flushed uni status metrics channel")
1043 default:
1044 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001045
1046 // flush syncTimeResponseChan
1047 select {
1048 case <-mm.syncTimeResponseChan:
1049 logger.Debug(ctx, "flushed sync time response channel")
1050 default:
1051 }
1052
1053 // flush l2PmChan
1054 select {
1055 case <-mm.l2PmChan:
1056 logger.Debug(ctx, "flushed L2 PM collection channel")
1057 default:
1058 }
1059
1060 // flush stopTicks
1061 select {
1062 case <-mm.stopTicks:
1063 logger.Debug(ctx, "flushed stopTicks channel")
1064 default:
1065 }
1066
1067}
1068
1069// ** L2 PM FSM Handlers start **
1070
1071func (mm *onuMetricsManager) l2PMFsmStarting(ctx context.Context, e *fsm.Event) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001072 // restore data from KV store
1073 if err := mm.restorePmData(ctx); err != nil {
1074 logger.Errorw(ctx, "error restoring pm data", log.Fields{"err": err})
1075 // we continue given that it does not effect the actual services for the ONU,
1076 // but there may be some negative effect on PM collection (there may be some mismatch in
1077 // the actual PM config and what is present on the device).
1078 }
1079
Girish Gowdrae0140f02021-02-02 16:55:09 -08001080 // Loop through all the group metrics
1081 // If it is a L2 PM Interval metric and it is enabled, then if it is not in the
1082 // list of active L2 PM list then mark it for creation
1083 // It it is a L2 PM Interval metric and it is disabled, then if it is in the
1084 // list of active L2 PM list then mark it for deletion
1085 mm.onuMetricsManagerLock.Lock()
1086 for n, g := range mm.groupMetricMap {
1087 if g.isL2PMCounter { // it is a l2 pm counter
1088 if g.enabled { // metric enabled.
1089 found := false
1090 inner1:
1091 for _, v := range mm.activeL2Pms {
1092 if v == n {
1093 found = true // metric already present in active l2 pm list
1094 break inner1
1095 }
1096 }
1097 if !found { // metric not in active l2 pm list. Mark this to be added later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001098 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001099 }
1100 } else { // metric not enabled.
1101 found := false
1102 inner2:
1103 for _, v := range mm.activeL2Pms {
1104 if v == n {
1105 found = true // metric is found in active l2 pm list
1106 break inner2
1107 }
1108 }
1109 if found { // metric is found in active l2 pm list. Mark this to be deleted later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001110 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001111 }
1112 }
1113 }
1114 }
1115 mm.onuMetricsManagerLock.Unlock()
1116 logger.Debugw(ctx, "pms to add and delete",
1117 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd, "pms-to-delete": mm.l2PmToDelete})
1118 go func() {
1119 // push a tick event to move to next state
1120 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1121 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1122 }
1123 }()
1124}
1125
1126func (mm *onuMetricsManager) l2PMFsmSyncTime(ctx context.Context, e *fsm.Event) {
1127 // Sync time with the ONU to establish 15min boundary for PM collection.
1128 if err := mm.syncTime(ctx); err != nil {
1129 go func() {
1130 time.Sleep(SyncTimeRetryInterval * time.Second) // retry to sync time after this timeout
1131 // This will result in FSM attempting to sync time again
1132 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventFailure); err != nil {
1133 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1134 }
1135 }()
1136 }
1137 // Initiate a tick generation routine every L2PmCollectionInterval
1138 go mm.generateTicks(ctx)
1139
1140 go func() {
1141 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1142 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1143 }
1144 }()
1145}
1146
1147func (mm *onuMetricsManager) l2PMFsmNull(ctx context.Context, e *fsm.Event) {
1148 // 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
1149 mm.onuMetricsManagerLock.Lock()
1150 mm.activeL2Pms = nil
1151 mm.l2PmToAdd = nil
1152 mm.l2PmToDelete = nil
1153 mm.onuMetricsManagerLock.Unlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001154 // If the FSM was stopped, then clear PM data from KV store
1155 // The FSM is stopped when ONU goes down. It is time to clear its data from store
1156 if e.Event == l2PmEventStop {
1157 _ = mm.clearPmGroupData(ctx) // ignore error
1158 }
1159
Girish Gowdrae0140f02021-02-02 16:55:09 -08001160}
1161func (mm *onuMetricsManager) l2PMFsmIdle(ctx context.Context, e *fsm.Event) {
1162 logger.Debugw(ctx, "Enter state idle", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1163
1164 mm.onuMetricsManagerLock.RLock()
1165 numOfPmToDelete := len(mm.l2PmToDelete)
1166 numOfPmToAdd := len(mm.l2PmToAdd)
1167 mm.onuMetricsManagerLock.RUnlock()
1168
1169 if numOfPmToDelete > 0 {
1170 logger.Debugw(ctx, "state idle - pms to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": numOfPmToDelete})
1171 go func() {
1172 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
1173 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1174 }
1175 }()
1176 } else if numOfPmToAdd > 0 {
1177 logger.Debugw(ctx, "state idle - pms to add", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": numOfPmToAdd})
1178 go func() {
1179 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
1180 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1181 }
1182 }()
1183 }
1184}
1185
1186func (mm *onuMetricsManager) l2PmFsmCollectData(ctx context.Context, e *fsm.Event) {
1187 logger.Debugw(ctx, "state collect data", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1188 // Copy the activeL2Pms for which we want to collect the metrics since activeL2Pms can change dynamically
1189 mm.onuMetricsManagerLock.RLock()
1190 copyOfActiveL2Pms := make([]string, len(mm.activeL2Pms))
1191 _ = copy(copyOfActiveL2Pms, mm.activeL2Pms)
1192 mm.onuMetricsManagerLock.RUnlock()
1193
1194 for _, n := range copyOfActiveL2Pms {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001195 var metricInfoSlice []*voltha.MetricInformation
Girish Gowdra0e533642021-03-02 22:02:51 -08001196
1197 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1198 mm.onuMetricsManagerLock.RLock()
1199 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1200 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1201 mm.onuMetricsManagerLock.RUnlock()
1202
Girish Gowdrae0140f02021-02-02 16:55:09 -08001203 switch n {
1204 case EthernetBridgeHistoryName:
1205 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 -08001206 for _, entityID := range copyOfEntityIDs {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001207 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, true, entityID); metricInfo != nil { // upstream
1208 metricInfoSlice = append(metricInfoSlice, metricInfo)
1209 }
1210 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, false, entityID); metricInfo != nil { // downstream
1211 metricInfoSlice = append(metricInfoSlice, metricInfo)
1212 }
1213 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001214 case EthernetUniHistoryName:
1215 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 -08001216 for _, entityID := range copyOfEntityIDs {
1217 if metricInfo := mm.collectEthernetUniHistoryData(ctx, entityID); metricInfo != nil { // upstream
1218 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001219 }
1220 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001221
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001222 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001223 for _, entityID := range copyOfEntityIDs {
1224 if metricInfo := mm.collectFecHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001225 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001226 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001227 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001228 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001229 for _, entityID := range copyOfEntityIDs {
1230 if metricInfo := mm.collectGemHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001231 metricInfoSlice = append(metricInfoSlice, metricInfo)
1232 }
1233 }
1234
Girish Gowdrae0140f02021-02-02 16:55:09 -08001235 default:
1236 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1237 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001238 mm.handleMetricsPublish(ctx, n, metricInfoSlice)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001239 }
1240 // Does not matter we send success or failure here.
1241 // Those PMs that we failed to collect data will be attempted to collect again in the next PM collection cycle (assuming
1242 // we have not exceed max attempts to collect the PM data)
1243 go func() {
1244 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1245 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1246 }
1247 }()
1248}
1249
Girish Gowdra0e533642021-03-02 22:02:51 -08001250// nolint: gocyclo
Girish Gowdrae0140f02021-02-02 16:55:09 -08001251func (mm *onuMetricsManager) l2PmFsmCreatePM(ctx context.Context, e *fsm.Event) {
1252 // Copy the l2PmToAdd for which we want to collect the metrics since l2PmToAdd can change dynamically
1253 mm.onuMetricsManagerLock.RLock()
1254 copyOfL2PmToAdd := make([]string, len(mm.l2PmToAdd))
1255 _ = copy(copyOfL2PmToAdd, mm.l2PmToAdd)
1256 mm.onuMetricsManagerLock.RUnlock()
1257
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001258 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 -08001259 for _, n := range copyOfL2PmToAdd {
1260 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001261 atLeastOneSuccess := false // flag indicates if at least one ME instance of the PM was successfully created.
1262 cnt := 0
Girish Gowdrae0140f02021-02-02 16:55:09 -08001263 switch n {
1264 case EthernetBridgeHistoryName:
1265 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1266 boolForDirection = append(boolForDirection, true, false)
1267 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1268 for _, direction := range boolForDirection {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001269 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1270 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1271 entityID := macBridgePortAniEID + uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001272 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1273 inner1:
1274 // retry L2PmCreateAttempts times to create the instance of PM
1275 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1276 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
1277 ctx, ConstDefaultOmciTimeout, true, direction, true, mm.pAdaptFsm.commChan, entityID)
1278 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetFramePerformanceMonitoringHistoryData"); resp {
1279 atLeastOneSuccess = true
1280 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1281 break inner1
1282 }
1283 }
1284 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1285 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001286 }
1287 }
1288 }
1289 case EthernetUniHistoryName:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001290 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1291 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
Girish Gowdra0e533642021-03-02 22:02:51 -08001292 // Attach the EthernetPerformanceMonitoringHistoryData ME to PPTP port instance
Girish Gowdrae0140f02021-02-02 16:55:09 -08001293 entityID := uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001294 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1295 inner2:
1296 // retry L2PmCreateAttempts times to create the instance of PM
1297 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1298 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
1299 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, entityID)
1300 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetPerformanceMonitoringHistoryData"); resp {
1301 atLeastOneSuccess = true
1302 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1303 break inner2
1304 }
1305 }
1306 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1307 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001308 }
1309 }
1310 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001311 case FecHistoryName:
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001312 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001313 // Attach the FecPerformanceMonitoringHistoryData ME to the ANI-G ME instance
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001314 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
1315 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, anigInstID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001316 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdd) // TODO: ignore error for now
1317 inner3:
1318 // retry L2PmCreateAttempts times to create the instance of PM
1319 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1320 if resp = mm.waitForResponseOrTimeout(ctx, true, anigInstID, "FecPerformanceMonitoringHistoryData"); resp {
1321 atLeastOneSuccess = true
1322 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdded) // TODO: ignore error for now
1323 break inner3
1324 }
1325 }
1326 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1327 _ = mm.updatePmData(ctx, n, anigInstID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001328 }
1329 }
1330 case GemPortHistoryName:
1331
1332 mm.onuMetricsManagerLock.RLock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001333 copyOfGemPortInstIDsToAdd := make([]uint16, len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd))
1334 _ = copy(copyOfGemPortInstIDsToAdd, mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001335 mm.onuMetricsManagerLock.RUnlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001336
1337 if len(copyOfGemPortInstIDsToAdd) == 0 {
1338 // If there are no gemport history MEs to be created, just skip further processing
1339 // Otherwise down below (after 'switch' case handling) we assume the ME creation failed because resp and atLeastOneSuccess flag are false.
1340 // Normally there are no GemPortHistory MEs to create at start up. They come in only after provisioning service on the ONU.
1341 mm.onuMetricsManagerLock.Lock()
1342 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1343 mm.onuMetricsManagerLock.Unlock()
1344 continue
1345 }
1346
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001347 for _, v := range copyOfGemPortInstIDsToAdd {
1348 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
1349 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, v)
Girish Gowdra0e533642021-03-02 22:02:51 -08001350 _ = mm.updatePmData(ctx, n, v, cPmAdd) // TODO: ignore error for now
1351 inner4:
1352 // retry L2PmCreateAttempts times to create the instance of PM
1353 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1354 if resp = mm.waitForResponseOrTimeout(ctx, true, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); resp {
1355 atLeastOneSuccess = true
1356 _ = mm.updatePmData(ctx, n, v, cPmAdded) // TODO: ignore error for now
1357 break inner4
1358 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001359 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001360 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1361 _ = mm.updatePmData(ctx, n, v, cPmRemoved) // TODO: ignore error for now
1362 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001363 }
1364
Girish Gowdrae0140f02021-02-02 16:55:09 -08001365 default:
1366 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1367 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001368 // 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
1369 if atLeastOneSuccess {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001370 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001371 mm.activeL2Pms = mm.appendIfMissingString(mm.activeL2Pms, n)
1372 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1373 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 -08001374 mm.onuMetricsManagerLock.Unlock()
1375 } else {
Girish Gowdra0e533642021-03-02 22:02:51 -08001376 // 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 -08001377 // and also remove it from l2PmToAdd slice so that we do not try to create the PM ME anymore
1378 mm.onuMetricsManagerLock.Lock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001379 logger.Debugw(ctx, "exceeded-max-add-retry-attempts--disabling-group", log.Fields{"groupName": n})
1380 mm.groupMetricMap[n].enabled = false
1381 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001382
Girish Gowdrae0140f02021-02-02 16:55:09 -08001383 logger.Warnw(ctx, "state create pm - failed to create pm",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001384 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
Girish Gowdra0e533642021-03-02 22:02:51 -08001385 "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001386 mm.onuMetricsManagerLock.Unlock()
1387 }
1388 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001389 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 -08001390 // Does not matter we send success or failure here.
1391 // Those PMs that we failed to create will be attempted to create again in the next PM creation cycle (assuming
1392 // we have not exceed max attempts to create the PM ME)
1393 go func() {
1394 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1395 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1396 }
1397 }()
1398}
1399
Girish Gowdra0e533642021-03-02 22:02:51 -08001400// nolint: gocyclo
Girish Gowdrae0140f02021-02-02 16:55:09 -08001401func (mm *onuMetricsManager) l2PmFsmDeletePM(ctx context.Context, e *fsm.Event) {
1402 // Copy the l2PmToDelete for which we want to collect the metrics since l2PmToDelete can change dynamically
1403 mm.onuMetricsManagerLock.RLock()
1404 copyOfL2PmToDelete := make([]string, len(mm.l2PmToDelete))
1405 _ = copy(copyOfL2PmToDelete, mm.l2PmToDelete)
1406 mm.onuMetricsManagerLock.RUnlock()
1407
1408 logger.Debugw(ctx, "state delete pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": mm.l2PmToDelete})
1409 for _, n := range copyOfL2PmToDelete {
1410 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001411 cnt := 0
1412 atLeastOneDeleteFailure := false
1413
1414 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1415 mm.onuMetricsManagerLock.RLock()
1416 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1417 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1418 mm.onuMetricsManagerLock.RUnlock()
1419
1420 if len(copyOfEntityIDs) == 0 {
1421 // if there are no enityIDs to remove for the PM ME just clear the PM name entry from cache and continue
1422 mm.onuMetricsManagerLock.Lock()
1423 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1424 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1425 logger.Debugw(ctx, "success-resp", log.Fields{"pm-name": n, "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1426 mm.onuMetricsManagerLock.Unlock()
1427 continue
1428 }
1429 logger.Debugw(ctx, "entities to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n, "entityIDs": copyOfEntityIDs})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001430 switch n {
1431 case EthernetBridgeHistoryName:
1432 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1433 boolForDirection = append(boolForDirection, true, false)
1434 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1435 for _, direction := range boolForDirection {
Girish Gowdra0e533642021-03-02 22:02:51 -08001436 for _, entityID := range copyOfEntityIDs {
1437 inner1:
1438 // retry L2PmDeleteAttempts times to delete the instance of PM
1439 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1440 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
1441 ctx, ConstDefaultOmciTimeout, true, direction, false, mm.pAdaptFsm.commChan, entityID)
1442 _ = mm.updatePmData(ctx, n, entityID, cPmRemove) // TODO: ignore error for now
1443 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1444 atLeastOneDeleteFailure = true
1445 } else {
1446 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1447 break inner1
1448 }
1449 }
1450 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1451 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001452 }
1453 }
1454 }
1455 case EthernetUniHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001456 for _, entityID := range copyOfEntityIDs {
1457 inner2:
1458 // retry L2PmDeleteAttempts times to delete the instance of PM
1459 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001460 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
1461 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001462 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
Girish Gowdra0e533642021-03-02 22:02:51 -08001463 atLeastOneDeleteFailure = true
1464 } else {
1465 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001466 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001467 }
1468 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001469 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1470 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1471 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001472 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001473 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001474 for _, entityID := range copyOfEntityIDs {
1475 inner3:
1476 // retry L2PmDeleteAttempts times to delete the instance of PM
1477 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1478 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
1479 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
1480 if resp := mm.waitForResponseOrTimeout(ctx, false, entityID, "FecPerformanceMonitoringHistoryData"); !resp {
1481 atLeastOneDeleteFailure = true
1482 } else {
1483 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1484 break inner3
1485 }
1486 }
1487 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1488 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001489 }
1490 }
1491 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001492 for _, entityID := range copyOfEntityIDs {
1493 inner4:
1494 // retry L2PmDeleteAttempts times to delete the instance of PM
1495 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1496 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
1497 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
1498 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1499 atLeastOneDeleteFailure = true
1500 } else {
1501 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1502 break inner4
1503 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001504 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001505 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1506 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1507 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001508 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001509 default:
1510 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1511 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001512 // If we could not completely clean up the PM ME then just give up.
1513 if atLeastOneDeleteFailure {
1514 logger.Warnw(ctx, "state delete pm - failed to delete at least one instance of the PM ME",
1515 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
1516 "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1517 mm.onuMetricsManagerLock.Lock()
1518 logger.Debugw(ctx, "exceeded-max-delete-retry-attempts--disabling-group", log.Fields{"groupName": n})
1519 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1520 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1521 mm.groupMetricMap[n].enabled = false
1522 mm.onuMetricsManagerLock.Unlock()
1523 } else { // success case
Girish Gowdrae0140f02021-02-02 16:55:09 -08001524 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001525 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1526 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1527 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 -08001528 mm.onuMetricsManagerLock.Unlock()
1529 }
1530 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001531 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 -08001532 // Does not matter we send success or failure here.
1533 // Those PMs that we failed to delete will be attempted to create again in the next PM collection cycle
1534 go func() {
1535 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1536 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1537 }
1538 }()
1539}
1540
1541// ** L2 PM FSM Handlers end **
1542
1543// syncTime synchronizes time with the ONU to establish a 15 min boundary for PM collection and reporting.
1544func (mm *onuMetricsManager) syncTime(ctx context.Context) error {
1545 if err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendSyncTime(ctx, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); err != nil {
1546 logger.Errorw(ctx, "cannot send sync time request", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1547 return err
1548 }
1549
1550 select {
1551 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1552 logger.Errorf(ctx, "timed out waiting for sync time response from onu", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1553 return fmt.Errorf("timed-out-waiting-for-sync-time-response-%v", mm.pDeviceHandler.deviceID)
1554 case syncTimeRes := <-mm.syncTimeResponseChan:
1555 if !syncTimeRes {
1556 return fmt.Errorf("failed-to-sync-time-%v", mm.pDeviceHandler.deviceID)
1557 }
1558 logger.Infow(ctx, "sync time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1559 return nil
1560 }
1561}
1562
1563func (mm *onuMetricsManager) collectEthernetFramePerformanceMonitoringHistoryData(ctx context.Context, upstream bool, entityID uint16) *voltha.MetricInformation {
1564 var mEnt *me.ManagedEntity
1565 var omciErr me.OmciErrors
1566 var classID me.ClassID
1567 var meAttributes me.AttributeValueMap
1568 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1569 meParam := me.ParamData{EntityID: entityID}
1570 if upstream {
1571 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataUpstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1572 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1573 return nil
1574 }
1575 classID = me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID
1576 } else {
1577 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataDownstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1578 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1579 return nil
1580 }
1581 classID = me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID
1582 }
1583
Girish Gowdrae0140f02021-02-02 16:55:09 -08001584 intervalEndTime := -1
1585 ethPMHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001586 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethPMHistData, &intervalEndTime); err != nil {
1587 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001588 }
1589
1590 // Populate some relevant context for the EthernetFramePerformanceMonitoringHistoryData PM
1591 ethPMHistData["class_id"] = float32(classID)
1592 ethPMHistData["interval_end_time"] = float32(intervalEndTime)
1593 ethPMHistData["parent_class_id"] = float32(me.MacBridgeConfigurationDataClassID) // EthernetFramePerformanceMonitoringHistoryData is attached to MBPCD ME
1594 ethPMHistData["parent_entity_id"] = float32(entityID)
1595 if upstream {
1596 ethPMHistData["upstream"] = float32(1)
1597 } else {
1598 ethPMHistData["upstream"] = float32(0)
1599 }
1600
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001601 metricInfo := mm.populateOnuMetricInfo(EthernetBridgeHistoryName, ethPMHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001602
Girish Gowdrae0140f02021-02-02 16:55:09 -08001603 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData successful",
1604 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream, "metricInfo": metricInfo})
1605 return &metricInfo
1606}
1607
1608func (mm *onuMetricsManager) collectEthernetUniHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1609 var mEnt *me.ManagedEntity
1610 var omciErr me.OmciErrors
1611 var classID me.ClassID
1612 var meAttributes me.AttributeValueMap
1613 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1614 meParam := me.ParamData{EntityID: entityID}
1615 if mEnt, omciErr = me.NewEthernetPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1616 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1617 return nil
1618 }
1619 classID = me.EthernetPerformanceMonitoringHistoryDataClassID
1620
Girish Gowdrae0140f02021-02-02 16:55:09 -08001621 intervalEndTime := -1
1622 ethUniHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001623 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethUniHistData, &intervalEndTime); err != nil {
1624 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001625 }
1626
1627 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1628 ethUniHistData["class_id"] = float32(classID)
1629 ethUniHistData["interval_end_time"] = float32(intervalEndTime)
1630
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001631 metricInfo := mm.populateOnuMetricInfo(EthernetUniHistoryName, ethUniHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001632
Girish Gowdrae0140f02021-02-02 16:55:09 -08001633 logger.Debugw(ctx, "collecting data for EthernetPerformanceMonitoringHistoryData successful",
1634 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1635 return &metricInfo
1636}
1637
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001638func (mm *onuMetricsManager) collectFecHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1639 var mEnt *me.ManagedEntity
1640 var omciErr me.OmciErrors
1641 var classID me.ClassID
1642 var meAttributes me.AttributeValueMap
1643 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1644 meParam := me.ParamData{EntityID: entityID}
1645 if mEnt, omciErr = me.NewFecPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1646 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1647 return nil
1648 }
1649 classID = me.FecPerformanceMonitoringHistoryDataClassID
1650
1651 intervalEndTime := -1
1652 fecHistData := make(map[string]float32)
1653 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, fecHistData, &intervalEndTime); err != nil {
1654 return nil
1655 }
1656
1657 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1658 fecHistData["class_id"] = float32(classID)
1659 fecHistData["interval_end_time"] = float32(intervalEndTime)
1660
1661 metricInfo := mm.populateOnuMetricInfo(FecHistoryName, fecHistData)
1662
1663 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData successful",
1664 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1665 return &metricInfo
1666}
1667
1668func (mm *onuMetricsManager) collectGemHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1669 var mEnt *me.ManagedEntity
1670 var omciErr me.OmciErrors
1671 var classID me.ClassID
1672 var meAttributes me.AttributeValueMap
1673 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1674 meParam := me.ParamData{EntityID: entityID}
1675 if mEnt, omciErr = me.NewGemPortNetworkCtpPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1676 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1677 return nil
1678 }
1679 classID = me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID
1680
1681 intervalEndTime := -1
1682 gemHistData := make(map[string]float32)
1683 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, gemHistData, &intervalEndTime); err != nil {
1684 return nil
1685 }
1686
1687 // Populate some relevant context for the GemPortNetworkCtpPerformanceMonitoringHistoryData PM
1688 gemHistData["class_id"] = float32(classID)
1689 gemHistData["interval_end_time"] = float32(intervalEndTime)
1690
1691 metricInfo := mm.populateOnuMetricInfo(GemPortHistoryName, gemHistData)
1692
1693 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData successful",
1694 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1695 return &metricInfo
1696}
1697
Girish Gowdrae0140f02021-02-02 16:55:09 -08001698// nolint: gocyclo
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001699func (mm *onuMetricsManager) populateEthernetBridgeHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
Girish Gowdrae0140f02021-02-02 16:55:09 -08001700 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001701 upstream := false
1702 if classID == me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID {
1703 upstream = true
1704 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001705 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1706 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1707 requestedAttributes["IntervalEndTime"] = 0
1708 }
1709 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1710 select {
1711 case meAttributes = <-mm.l2PmChan:
1712 logger.Debugw(ctx, "received ethernet pm history data metrics",
1713 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1714 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1715 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet pm history data",
1716 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1717 // The metrics will be empty in this case
1718 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-bridge-history-%v", mm.pDeviceHandler.deviceID)
1719 }
1720 // 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 -08001721 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1722 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 -08001723 }
1724 }
1725 for k := range EthernetBridgeHistory {
1726 // populate ethPMHistData only if metric key not already present (or populated), since it is possible that we populate
1727 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1728 if _, ok := ethPMHistData[k]; !ok {
1729 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001730 case "entity_id":
1731 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1732 ethPMHistData[k] = float32(val.(uint16))
1733 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001734 case "drop_events":
1735 if val, ok := meAttributes["DropEvents"]; ok && val != nil {
1736 ethPMHistData[k] = float32(val.(uint32))
1737 }
1738 case "octets":
1739 if val, ok := meAttributes["Octets"]; ok && val != nil {
1740 ethPMHistData[k] = float32(val.(uint32))
1741 }
1742 case "packets":
1743 if val, ok := meAttributes["Packets"]; ok && val != nil {
1744 ethPMHistData[k] = float32(val.(uint32))
1745 }
1746 case "broadcast_packets":
1747 if val, ok := meAttributes["BroadcastPackets"]; ok && val != nil {
1748 ethPMHistData[k] = float32(val.(uint32))
1749 }
1750 case "multicast_packets":
1751 if val, ok := meAttributes["MulticastPackets"]; ok && val != nil {
1752 ethPMHistData[k] = float32(val.(uint32))
1753 }
1754 case "crc_errored_packets":
1755 if val, ok := meAttributes["CrcErroredPackets"]; ok && val != nil {
1756 ethPMHistData[k] = float32(val.(uint32))
1757 }
1758 case "undersize_packets":
1759 if val, ok := meAttributes["UndersizePackets"]; ok && val != nil {
1760 ethPMHistData[k] = float32(val.(uint32))
1761 }
1762 case "oversize_packets":
1763 if val, ok := meAttributes["OversizePackets"]; ok && val != nil {
1764 ethPMHistData[k] = float32(val.(uint32))
1765 }
1766 case "64_octets":
1767 if val, ok := meAttributes["Packets64Octets"]; ok && val != nil {
1768 ethPMHistData[k] = float32(val.(uint32))
1769 }
1770 case "65_to_127_octets":
1771 if val, ok := meAttributes["Packets65To127Octets"]; ok && val != nil {
1772 ethPMHistData[k] = float32(val.(uint32))
1773 }
1774 case "128_to_255_octets":
1775 if val, ok := meAttributes["Packets128To255Octets"]; ok && val != nil {
1776 ethPMHistData[k] = float32(val.(uint32))
1777 }
1778 case "256_to_511_octets":
1779 if val, ok := meAttributes["Packets256To511Octets"]; ok && val != nil {
1780 ethPMHistData[k] = float32(val.(uint32))
1781 }
1782 case "512_to_1023_octets":
1783 if val, ok := meAttributes["Packets512To1023Octets"]; ok && val != nil {
1784 ethPMHistData[k] = float32(val.(uint32))
1785 }
1786 case "1024_to_1518_octets":
1787 if val, ok := meAttributes["Packets1024To1518Octets"]; ok && val != nil {
1788 ethPMHistData[k] = float32(val.(uint32))
1789 }
1790 default:
1791 // do nothing
1792 }
1793 }
1794 }
1795 return nil
1796}
1797
1798// nolint: gocyclo
1799func (mm *onuMetricsManager) populateEthernetUniHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1800 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMUniHistData map[string]float32, intervalEndTime *int) error {
1801 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1802 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1803 requestedAttributes["IntervalEndTime"] = 0
1804 }
1805 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1806 select {
1807 case meAttributes = <-mm.l2PmChan:
1808 logger.Debugw(ctx, "received ethernet uni history data metrics",
1809 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1810 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1811 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet uni history data",
1812 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1813 // The metrics will be empty in this case
1814 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-uni-history-%v", mm.pDeviceHandler.deviceID)
1815 }
1816 // 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 -08001817 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1818 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 -08001819 }
1820 }
1821 for k := range EthernetUniHistory {
1822 // populate ethPMUniHistData only if metric key not already present (or populated), since it is possible that we populate
1823 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1824 if _, ok := ethPMUniHistData[k]; !ok {
1825 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001826 case "entity_id":
1827 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1828 ethPMUniHistData[k] = float32(val.(uint16))
1829 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001830 case "fcs_errors":
1831 if val, ok := meAttributes["FcsErrors"]; ok && val != nil {
1832 ethPMUniHistData[k] = float32(val.(uint32))
1833 }
1834 case "excessive_collision_counter":
1835 if val, ok := meAttributes["ExcessiveCollisionCounter"]; ok && val != nil {
1836 ethPMUniHistData[k] = float32(val.(uint32))
1837 }
1838 case "late_collision_counter":
1839 if val, ok := meAttributes["LateCollisionCounter"]; ok && val != nil {
1840 ethPMUniHistData[k] = float32(val.(uint32))
1841 }
1842 case "frames_too_long":
1843 if val, ok := meAttributes["FramesTooLong"]; ok && val != nil {
1844 ethPMUniHistData[k] = float32(val.(uint32))
1845 }
1846 case "buffer_overflows_on_rx":
1847 if val, ok := meAttributes["BufferOverflowsOnReceive"]; ok && val != nil {
1848 ethPMUniHistData[k] = float32(val.(uint32))
1849 }
1850 case "buffer_overflows_on_tx":
1851 if val, ok := meAttributes["BufferOverflowsOnTransmit"]; ok && val != nil {
1852 ethPMUniHistData[k] = float32(val.(uint32))
1853 }
1854 case "single_collision_frame_counter":
1855 if val, ok := meAttributes["SingleCollisionFrameCounter"]; ok && val != nil {
1856 ethPMUniHistData[k] = float32(val.(uint32))
1857 }
1858 case "multiple_collisions_frame_counter":
1859 if val, ok := meAttributes["MultipleCollisionsFrameCounter"]; ok && val != nil {
1860 ethPMUniHistData[k] = float32(val.(uint32))
1861 }
1862 case "sqe_counter":
1863 if val, ok := meAttributes["SqeCounter"]; ok && val != nil {
1864 ethPMUniHistData[k] = float32(val.(uint32))
1865 }
1866 case "deferred_tx_counter":
1867 if val, ok := meAttributes["DeferredTransmissionCounter"]; ok && val != nil {
1868 ethPMUniHistData[k] = float32(val.(uint32))
1869 }
1870 case "internal_mac_tx_error_counter":
1871 if val, ok := meAttributes["InternalMacTransmitErrorCounter"]; ok && val != nil {
1872 ethPMUniHistData[k] = float32(val.(uint32))
1873 }
1874 case "carrier_sense_error_counter":
1875 if val, ok := meAttributes["CarrierSenseErrorCounter"]; ok && val != nil {
1876 ethPMUniHistData[k] = float32(val.(uint32))
1877 }
1878 case "alignment_error_counter":
1879 if val, ok := meAttributes["AlignmentErrorCounter"]; ok && val != nil {
1880 ethPMUniHistData[k] = float32(val.(uint32))
1881 }
1882 case "internal_mac_rx_error_counter":
1883 if val, ok := meAttributes["InternalMacReceiveErrorCounter"]; ok && val != nil {
1884 ethPMUniHistData[k] = float32(val.(uint32))
1885 }
1886 default:
1887 // do nothing
1888 }
1889 }
1890 }
1891 return nil
1892}
1893
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001894// nolint: gocyclo
1895func (mm *onuMetricsManager) populateFecHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1896 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, fecHistData map[string]float32, intervalEndTime *int) error {
1897 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1898 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1899 requestedAttributes["IntervalEndTime"] = 0
1900 }
1901 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1902 select {
1903 case meAttributes = <-mm.l2PmChan:
1904 logger.Debugw(ctx, "received fec history data metrics",
1905 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1906 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1907 logger.Errorw(ctx, "timeout waiting for omci-get response for fec history data",
1908 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1909 // The metrics will be empty in this case
1910 return fmt.Errorf("timeout-during-l2-pm-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1911 }
1912 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1913 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1914 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1915 }
1916 }
1917 for k := range FecHistory {
1918 // populate fecHistData only if metric key not already present (or populated), since it is possible that we populate
1919 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1920 if _, ok := fecHistData[k]; !ok {
1921 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001922 case "entity_id":
1923 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1924 fecHistData[k] = float32(val.(uint16))
1925 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001926 case "corrected_bytes":
1927 if val, ok := meAttributes["CorrectedBytes"]; ok && val != nil {
1928 fecHistData[k] = float32(val.(uint32))
1929 }
1930 case "corrected_code_words":
1931 if val, ok := meAttributes["CorrectedCodeWords"]; ok && val != nil {
1932 fecHistData[k] = float32(val.(uint32))
1933 }
1934 case "uncorrectable_code_words":
1935 if val, ok := meAttributes["UncorrectableCodeWords"]; ok && val != nil {
1936 fecHistData[k] = float32(val.(uint32))
1937 }
1938 case "total_code_words":
1939 if val, ok := meAttributes["TotalCodeWords"]; ok && val != nil {
1940 fecHistData[k] = float32(val.(uint32))
1941 }
1942 case "fec_seconds":
1943 if val, ok := meAttributes["FecSeconds"]; ok && val != nil {
1944 fecHistData[k] = float32(val.(uint16))
1945 }
1946 default:
1947 // do nothing
1948 }
1949 }
1950 }
1951 return nil
1952}
1953
1954// nolint: gocyclo
1955func (mm *onuMetricsManager) populateGemPortMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1956 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, gemPortHistData map[string]float32, intervalEndTime *int) error {
1957 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1958 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1959 requestedAttributes["IntervalEndTime"] = 0
1960 }
1961 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1962 select {
1963 case meAttributes = <-mm.l2PmChan:
1964 logger.Debugw(ctx, "received gem port history data metrics",
1965 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1966 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1967 logger.Errorw(ctx, "timeout waiting for omci-get response for gem port history data",
1968 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1969 // The metrics will be empty in this case
1970 return fmt.Errorf("timeout-during-l2-pm-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1971 }
1972 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1973 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1974 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1975 }
1976 }
1977 for k := range GemPortHistory {
1978 // populate gemPortHistData only if metric key not already present (or populated), since it is possible that we populate
1979 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1980 if _, ok := gemPortHistData[k]; !ok {
1981 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001982 case "entity_id":
1983 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1984 gemPortHistData[k] = float32(val.(uint16))
1985 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001986 case "transmitted_gem_frames":
1987 if val, ok := meAttributes["TransmittedGemFrames"]; ok && val != nil {
1988 gemPortHistData[k] = float32(val.(uint32))
1989 }
1990 case "received_gem_frames":
1991 if val, ok := meAttributes["ReceivedGemFrames"]; ok && val != nil {
1992 gemPortHistData[k] = float32(val.(uint32))
1993 }
1994 case "received_payload_bytes":
1995 if val, ok := meAttributes["ReceivedPayloadBytes"]; ok && val != nil {
1996 gemPortHistData[k] = float32(val.(uint64))
1997 }
1998 case "transmitted_payload_bytes":
1999 if val, ok := meAttributes["TransmittedPayloadBytes"]; ok && val != nil {
2000 gemPortHistData[k] = float32(val.(uint64))
2001 }
2002 case "encryption_key_errors":
2003 if val, ok := meAttributes["EncryptionKeyErrors"]; ok && val != nil {
2004 gemPortHistData[k] = float32(val.(uint32))
2005 }
2006 default:
2007 // do nothing
2008 }
2009 }
2010 }
2011 return nil
2012}
2013
Girish Gowdrae0140f02021-02-02 16:55:09 -08002014func (mm *onuMetricsManager) handleOmciCreateResponseMessage(ctx context.Context, msg OmciMessage) error {
2015 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
2016 if msgLayer == nil {
2017 logger.Errorw(ctx, "omci Msg layer could not be detected for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2018 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2019 }
2020 msgObj, msgOk := msgLayer.(*omci.CreateResponse)
2021 if !msgOk {
2022 logger.Errorw(ctx, "omci Msg layer could not be assigned for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2023 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2024 }
2025 logger.Debugw(ctx, "OMCI create response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2026 switch msgObj.EntityClass {
2027 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2028 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002029 me.EthernetPerformanceMonitoringHistoryDataClassID,
2030 me.FecPerformanceMonitoringHistoryDataClassID,
2031 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002032 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
2033 if msgObj.Result == me.Success || msgObj.Result == me.InstanceExists {
2034 mm.l2PmCreateOrDeleteResponseChan <- true
2035 } else {
2036 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2037 mm.l2PmCreateOrDeleteResponseChan <- false
2038 }
2039 return nil
2040 default:
2041 logger.Errorw(ctx, "unhandled omci create response message",
2042 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2043 }
2044 return fmt.Errorf("unhandled-omci-create-response-message-%v", mm.pDeviceHandler.deviceID)
2045}
2046
2047func (mm *onuMetricsManager) handleOmciDeleteResponseMessage(ctx context.Context, msg OmciMessage) error {
2048 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDeleteResponse)
2049 if msgLayer == nil {
2050 logger.Errorw(ctx, "omci Msg layer could not be detected for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2051 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2052 }
2053 msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
2054 if !msgOk {
2055 logger.Errorw(ctx, "omci Msg layer could not be assigned for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2056 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2057 }
2058 logger.Debugw(ctx, "OMCI delete response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2059 switch msgObj.EntityClass {
2060 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2061 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002062 me.EthernetPerformanceMonitoringHistoryDataClassID,
2063 me.FecPerformanceMonitoringHistoryDataClassID,
2064 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002065 // If the result is me.UnknownInstance it means the entity was already deleted. It is ok handled that as success
2066 if msgObj.Result == me.Success || msgObj.Result == me.UnknownInstance {
2067 mm.l2PmCreateOrDeleteResponseChan <- true
2068 } else {
2069 logger.Warnw(ctx, "failed to delete me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2070 mm.l2PmCreateOrDeleteResponseChan <- false
2071 }
2072 return nil
2073 default:
2074 logger.Errorw(ctx, "unhandled omci delete response message",
2075 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2076 }
2077 return fmt.Errorf("unhandled-omci-delete-response-message-%v", mm.pDeviceHandler.deviceID)
2078}
2079
2080func (mm *onuMetricsManager) generateTicks(ctx context.Context) {
2081 for {
2082 select {
2083 case <-time.After(L2PmCollectionInterval * time.Second):
2084 go func() {
2085 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
2086 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2087 }
2088 }()
2089 case <-mm.stopTicks:
2090 logger.Infow(ctx, "stopping ticks", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2091 return
2092 }
2093 }
2094}
2095
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002096func (mm *onuMetricsManager) handleMetricsPublish(ctx context.Context, metricName string, metricInfoSlice []*voltha.MetricInformation) {
2097 // Publish metrics if it is valid
2098 if metricInfoSlice != nil {
2099 mm.publishMetrics(ctx, metricInfoSlice)
2100 } else {
2101 // If collectAttempts exceeds L2PmCollectAttempts then remove it from activeL2Pms
2102 // slice so that we do not collect data from that PM ME anymore
2103 mm.onuMetricsManagerLock.Lock()
2104 mm.groupMetricMap[metricName].collectAttempts++
2105 if mm.groupMetricMap[metricName].collectAttempts > L2PmCollectAttempts {
2106 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, metricName)
2107 }
2108 logger.Warnw(ctx, "state collect data - no metrics collected",
2109 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName, "collectAttempts": mm.groupMetricMap[metricName].collectAttempts})
2110 mm.onuMetricsManagerLock.Unlock()
2111 }
2112}
2113
2114func (mm *onuMetricsManager) populateGroupSpecificMetrics(ctx context.Context, mEnt *me.ManagedEntity, classID me.ClassID, entityID uint16,
2115 meAttributes me.AttributeValueMap, data map[string]float32, intervalEndTime *int) error {
2116 var grpFunc groupMetricPopulateFunc
2117 switch classID {
2118 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID, me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID:
2119 grpFunc = mm.populateEthernetBridgeHistoryMetrics
2120 case me.EthernetPerformanceMonitoringHistoryDataClassID:
2121 grpFunc = mm.populateEthernetUniHistoryMetrics
2122 case me.FecPerformanceMonitoringHistoryDataClassID:
2123 grpFunc = mm.populateFecHistoryMetrics
2124 case me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
2125 grpFunc = mm.populateGemPortMetrics
2126 default:
2127 return fmt.Errorf("unknown-classid-%v", classID)
2128 }
2129
2130 size := 0
2131 requestedAttributes := make(me.AttributeValueMap)
2132 for _, v := range mEnt.GetAttributeDefinitions() {
2133 if (v.Size + size) <= MaxL2PMGetPayLoadSize {
2134 requestedAttributes[v.Name] = v.DefValue
2135 size = v.Size + size
2136 } else { // We exceeded the allow omci get size
2137 // Let's collect the attributes via get now and collect remaining in the next iteration
2138 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2139 logger.Errorw(ctx, "error during metric collection",
2140 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2141 return err
2142 }
2143 size = 0 // reset size
2144 requestedAttributes = make(me.AttributeValueMap) // reset map
2145 }
2146 }
2147 // Collect the omci get attributes for the last bunch of attributes.
2148 if len(requestedAttributes) > 0 {
2149 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2150 logger.Errorw(ctx, "error during metric collection",
2151 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2152 return err
2153 }
2154 }
2155 return nil
2156}
2157
2158func (mm *onuMetricsManager) populateOnuMetricInfo(title string, data map[string]float32) voltha.MetricInformation {
2159 metricsContext := make(map[string]string)
2160 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
2161 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
2162 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
2163
2164 raisedTs := time.Now().Unix()
2165 mmd := voltha.MetricMetaData{
2166 Title: title,
2167 Ts: float64(raisedTs),
2168 Context: metricsContext,
2169 DeviceId: mm.pDeviceHandler.deviceID,
2170 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
2171 SerialNo: mm.pDeviceHandler.device.SerialNumber,
2172 }
2173
2174 // create slice of metrics given that there could be more than one VEIP instance
2175 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: data}
2176 return metricInfo
2177}
2178
2179func (mm *onuMetricsManager) updateAndValidateIntervalEndTime(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap, intervalEndTime *int) bool {
2180 valid := false
2181 if *intervalEndTime == -1 { // first time
2182 // Update the interval end time
2183 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2184 *intervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2185 valid = true
2186 }
2187 } else {
2188 var currIntervalEndTime int
2189 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2190 currIntervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2191 }
2192 if currIntervalEndTime != *intervalEndTime { // interval end time changed during metric collection
2193 logger.Errorw(ctx, "interval end time changed during metrics collection for ethernet pm history data",
2194 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID,
2195 "currIntervalEndTime": *intervalEndTime, "newIntervalEndTime": currIntervalEndTime})
2196 } else {
2197 valid = true
2198 }
2199 }
2200 return valid
2201}
2202
2203func (mm *onuMetricsManager) waitForResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassName string) bool {
2204 logger.Debugw(ctx, "waitForResponseOrTimeout", log.Fields{"create": create, "instID": instID, "meClassName": meClassName})
2205 select {
2206 case resp := <-mm.l2PmCreateOrDeleteResponseChan:
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002207 logger.Debugw(ctx, "received l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002208 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassName": meClassName, "instID": instID})
2209 return resp
2210 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002211 logger.Errorw(ctx, "timeout waiting for l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002212 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassName": meClassName, "instID": instID})
2213 }
2214 return false
2215}
2216
2217func (mm *onuMetricsManager) initializeGroupMetric(grpMtrcs map[string]voltha.PmConfig_PmType, grpName string, grpEnabled bool, grpFreq uint32) {
2218 var pmConfigSlice []*voltha.PmConfig
2219 for k, v := range grpMtrcs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002220 pmConfigSlice = append(pmConfigSlice,
2221 &voltha.PmConfig{
2222 Name: k,
2223 Type: v,
2224 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2225 SampleFreq: grpFreq})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002226 }
2227 groupMetric := voltha.PmGroupConfig{
2228 GroupName: grpName,
2229 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2230 GroupFreq: grpFreq,
2231 Metrics: pmConfigSlice,
2232 }
2233 mm.pDeviceHandler.pmConfigs.Groups = append(mm.pDeviceHandler.pmConfigs.Groups, &groupMetric)
2234
2235}
2236
2237func (mm *onuMetricsManager) initializeL2PmFsm(ctx context.Context, aCommChannel chan Message) error {
2238 mm.pAdaptFsm = NewAdapterFsm("L2PmFSM", mm.pDeviceHandler.deviceID, aCommChannel)
2239 if mm.pAdaptFsm == nil {
2240 logger.Errorw(ctx, "L2PMFsm AdapterFsm could not be instantiated!!", log.Fields{
2241 "device-id": mm.pDeviceHandler.deviceID})
2242 return fmt.Errorf("nil-adapter-fsm")
2243 }
2244 // L2 PM FSM related state machine
2245 mm.pAdaptFsm.pFsm = fsm.NewFSM(
2246 l2PmStNull,
2247 fsm.Events{
2248 {Name: l2PmEventInit, Src: []string{l2PmStNull}, Dst: l2PmStStarting},
2249 {Name: l2PmEventTick, Src: []string{l2PmStStarting}, Dst: l2PmStSyncTime},
2250 {Name: l2PmEventTick, Src: []string{l2PmStIdle, l2PmEventDeleteMe, l2PmEventAddMe}, Dst: l2PmStCollectData},
2251 {Name: l2PmEventSuccess, Src: []string{l2PmStSyncTime, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2252 {Name: l2PmEventFailure, Src: []string{l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2253 {Name: l2PmEventFailure, Src: []string{l2PmStSyncTime}, Dst: l2PmStSyncTime},
2254 {Name: l2PmEventAddMe, Src: []string{l2PmStIdle}, Dst: l2PmStCreatePmMe},
2255 {Name: l2PmEventDeleteMe, Src: []string{l2PmStIdle}, Dst: l2PmStDeletePmMe},
2256 {Name: l2PmEventStop, Src: []string{l2PmStNull, l2PmStStarting, l2PmStSyncTime, l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStNull},
2257 },
2258 fsm.Callbacks{
2259 "enter_state": func(e *fsm.Event) { mm.pAdaptFsm.logFsmStateChange(ctx, e) },
2260 "enter_" + l2PmStNull: func(e *fsm.Event) { mm.l2PMFsmNull(ctx, e) },
2261 "enter_" + l2PmStIdle: func(e *fsm.Event) { mm.l2PMFsmIdle(ctx, e) },
2262 "enter_" + l2PmStStarting: func(e *fsm.Event) { mm.l2PMFsmStarting(ctx, e) },
2263 "enter_" + l2PmStSyncTime: func(e *fsm.Event) { mm.l2PMFsmSyncTime(ctx, e) },
2264 "enter_" + l2PmStCollectData: func(e *fsm.Event) { mm.l2PmFsmCollectData(ctx, e) },
2265 "enter_" + l2PmStCreatePmMe: func(e *fsm.Event) { mm.l2PmFsmCreatePM(ctx, e) },
2266 "enter_" + l2PmStDeletePmMe: func(e *fsm.Event) { mm.l2PmFsmDeletePM(ctx, e) },
2267 },
2268 )
2269 return nil
2270}
2271
2272func (mm *onuMetricsManager) initializeAllGroupMetrics() {
2273 mm.pDeviceHandler.pmConfigs = &voltha.PmConfigs{}
2274 mm.pDeviceHandler.pmConfigs.Id = mm.pDeviceHandler.deviceID
2275 mm.pDeviceHandler.pmConfigs.DefaultFreq = DefaultMetricCollectionFrequency
2276 mm.pDeviceHandler.pmConfigs.Grouped = GroupMetricEnabled
2277 mm.pDeviceHandler.pmConfigs.FreqOverride = DefaultFrequencyOverrideEnabled
2278
2279 // Populate group metrics.
2280 // Lets populate irrespective of GroupMetricEnabled is true or not.
2281 // The group metrics collection will decided on this flag later
2282
2283 mm.initializeGroupMetric(OpticalPowerGroupMetrics, OpticalPowerGroupMetricName,
2284 OpticalPowerGroupMetricEnabled, OpticalPowerMetricGroupCollectionFrequency)
2285
2286 mm.initializeGroupMetric(UniStatusGroupMetrics, UniStatusGroupMetricName,
2287 UniStatusGroupMetricEnabled, UniStatusMetricGroupCollectionFrequency)
2288
2289 // classical l2 pm counter start
2290
2291 mm.initializeGroupMetric(EthernetBridgeHistory, EthernetBridgeHistoryName,
2292 EthernetBridgeHistoryEnabled, EthernetBridgeHistoryFrequency)
2293
2294 mm.initializeGroupMetric(EthernetUniHistory, EthernetUniHistoryName,
2295 EthernetUniHistoryEnabled, EthernetUniHistoryFrequency)
2296
2297 mm.initializeGroupMetric(FecHistory, FecHistoryName,
2298 FecHistoryEnabled, FecHistoryFrequency)
2299
2300 mm.initializeGroupMetric(GemPortHistory, GemPortHistoryName,
2301 GemPortHistoryEnabled, GemPortHistoryFrequency)
2302
2303 // classical l2 pm counter end
2304
2305 // Add standalone metric (if present) after this (will be added to dh.pmConfigs.Metrics)
2306}
2307
2308func (mm *onuMetricsManager) populateLocalGroupMetricData(ctx context.Context) {
2309 // Populate local group metric structures
2310 for _, g := range mm.pDeviceHandler.pmConfigs.Groups {
2311 mm.groupMetricMap[g.GroupName] = &groupMetric{
2312 groupName: g.GroupName,
2313 enabled: g.Enabled,
2314 frequency: g.GroupFreq,
2315 }
2316 switch g.GroupName {
2317 case OpticalPowerGroupMetricName:
2318 mm.groupMetricMap[g.GroupName].metricMap = OpticalPowerGroupMetrics
2319 case UniStatusGroupMetricName:
2320 mm.groupMetricMap[g.GroupName].metricMap = UniStatusGroupMetrics
2321 case EthernetBridgeHistoryName:
2322 mm.groupMetricMap[g.GroupName].metricMap = EthernetBridgeHistory
2323 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2324 case EthernetUniHistoryName:
2325 mm.groupMetricMap[g.GroupName].metricMap = EthernetUniHistory
2326 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2327 case FecHistoryName:
2328 mm.groupMetricMap[g.GroupName].metricMap = FecHistory
2329 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2330 case GemPortHistoryName:
2331 mm.groupMetricMap[g.GroupName].metricMap = GemPortHistory
2332 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2333 default:
2334 logger.Errorw(ctx, "unhandled-group-name", log.Fields{"groupName": g.GroupName})
2335 }
2336 }
2337
2338 // Populate local standalone metric structures
2339 for _, m := range mm.pDeviceHandler.pmConfigs.Metrics {
2340 mm.standaloneMetricMap[m.Name] = &standaloneMetric{
2341 metricName: m.Name,
2342 enabled: m.Enabled,
2343 frequency: m.SampleFreq,
2344 }
2345 switch m.Name {
2346 // None exist as of now. Add when available.
2347 default:
2348 logger.Errorw(ctx, "unhandled-metric-name", log.Fields{"metricName": m.Name})
2349 }
2350 }
2351}
2352
2353func (mm *onuMetricsManager) AddGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2354 mm.onuMetricsManagerLock.Lock()
2355 defer mm.onuMetricsManagerLock.Unlock()
2356 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002357 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002358 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002359 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002360
2361 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, GemPortHistoryName)
2362 // We do not need to remove from l2PmToDelete slice as we could have Add and Delete of
2363 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2364 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2365 // gemPortNCTPPerfHistInstToAdd slice
2366}
2367
2368func (mm *onuMetricsManager) RemoveGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2369 mm.onuMetricsManagerLock.Lock()
2370 defer mm.onuMetricsManagerLock.Unlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08002371 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002372 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002373 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002374
2375 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, GemPortHistoryName)
2376 // We do not need to remove from l2PmToAdd slice as we could have Add and Delete of
2377 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2378 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2379 // gemPortNCTPPerfHistInstToAdd slice
2380}
2381
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002382func (mm *onuMetricsManager) updateGemPortNTPInstanceToAddForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002383 if mm.pDeviceHandler.pOnuTP != nil {
2384 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002385 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002386 for _, v := range gemPortInstIDs {
2387 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002388 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002389 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002390 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002391 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002392 logger.Debugw(ctx, "updateGemPortNTPInstanceToAddForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002393 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 -08002394 }
2395}
2396
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002397func (mm *onuMetricsManager) updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002398 if mm.pDeviceHandler.pOnuTP != nil {
2399 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002400 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002401 for _, v := range gemPortInstIDs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002402 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002403 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002404 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002405 }
2406 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002407 logger.Debugw(ctx, "updateGemPortNTPInstanceToDeleteForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002408 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, "gemToDel": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
2409}
2410
2411// restorePmData restores any PM data available on the KV store to local cache
2412func (mm *onuMetricsManager) restorePmData(ctx context.Context) error {
2413 logger.Debugw(ctx, "restorePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2414 if mm.pmKvStore == nil {
2415 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2416 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2417 }
2418 var errorsList []error
2419 for groupName, group := range mm.groupMetricMap {
2420 group.pmMEData = &pmMEData{}
2421 Value, err := mm.pmKvStore.Get(ctx, groupName)
2422 if err == nil {
2423 if Value != nil {
2424 logger.Debugw(ctx, "PM data read",
2425 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2426 tmpBytes, _ := kvstore.ToByte(Value.Value)
2427
2428 if err = json.Unmarshal(tmpBytes, &group.pmMEData); err != nil {
2429 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2430 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-unmarshal-PM-data-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2431 continue
2432 }
2433 logger.Debugw(ctx, "restorePmData - success", log.Fields{"pmData": group.pmMEData, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2434 } else {
2435 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2436 continue
2437 }
2438 } else {
2439 logger.Errorw(ctx, "restorePmData - fail", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "err": err})
2440 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-read-from-KVstore-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2441 continue
2442 }
2443 }
2444 if len(errorsList) > 0 {
2445 return fmt.Errorf("errors-restoring-pm-data-for-one-or-more-groups--errors:%v", errorsList)
2446 }
2447 logger.Debugw(ctx, "restorePmData - complete success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2448 return nil
2449}
2450
2451// getPmData gets pmMEData from cache. Since we have write through cache implementation for pmMEData,
2452// the data must be available in cache.
2453// Note, it is expected that caller of this function manages the required synchronization (like using locks etc.).
2454func (mm *onuMetricsManager) getPmData(ctx context.Context, groupName string) (*pmMEData, error) {
2455 if grp, ok := mm.groupMetricMap[groupName]; ok {
2456 return grp.pmMEData, nil
2457 }
2458 // Data not in cache, try to fetch from kv store.
2459 data := &pmMEData{}
2460 if mm.pmKvStore == nil {
2461 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2462 return data, fmt.Errorf("pmKvStore not set. device-id - %s", mm.pDeviceHandler.deviceID)
2463 }
2464 Value, err := mm.pmKvStore.Get(ctx, groupName)
2465 if err == nil {
2466 if Value != nil {
2467 logger.Debugw(ctx, "PM data read",
2468 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2469 tmpBytes, _ := kvstore.ToByte(Value.Value)
2470
2471 if err = json.Unmarshal(tmpBytes, data); err != nil {
2472 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2473 return data, err
2474 }
2475 logger.Debugw(ctx, "PM data", log.Fields{"pmData": data, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2476 } else {
2477 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2478 return data, err
2479 }
2480 } else {
2481 logger.Errorw(ctx, "unable to read from KVstore", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2482 return data, err
2483 }
2484
2485 return data, nil
2486}
2487
2488// updatePmData update pmMEData to store. It is write through cache, i.e., write to cache first and then update store
2489func (mm *onuMetricsManager) updatePmData(ctx context.Context, groupName string, meInstanceID uint16, pmAction string) error {
2490 logger.Debugw(ctx, "updatePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "entityID": meInstanceID, "pmAction": pmAction})
2491 mm.onuMetricsManagerLock.Lock()
2492 defer mm.onuMetricsManagerLock.Unlock()
2493
2494 if mm.pmKvStore == nil {
2495 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2496 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2497 }
2498
2499 pmMEData, err := mm.getPmData(ctx, groupName)
2500 if err != nil || pmMEData == nil {
2501 // error already logged in called function.
2502 return err
2503 }
2504 switch pmAction {
2505 case cPmAdd:
2506 pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(pmMEData.InstancesToAdd, meInstanceID)
2507 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2508 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2509 case cPmAdded:
2510 pmMEData.InstancesActive = mm.appendIfMissingUnt16(pmMEData.InstancesActive, meInstanceID)
2511 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2512 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2513 case cPmRemove:
2514 pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(pmMEData.InstancesToDelete, meInstanceID)
2515 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2516 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2517 case cPmRemoved:
2518 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2519 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2520 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2521 default:
2522 logger.Errorw(ctx, "unknown pm action", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pmAction": pmAction, "groupName": groupName})
2523 return fmt.Errorf(fmt.Sprintf("unknown-pm-action-deviceid-%s-groupName-%s-pmaction-%s", mm.pDeviceHandler.deviceID, groupName, pmAction))
2524 }
2525 // write through cache
2526 mm.groupMetricMap[groupName].pmMEData = pmMEData
2527
2528 Value, err := json.Marshal(*pmMEData)
2529 if err != nil {
2530 logger.Errorw(ctx, "unable to marshal PM data", log.Fields{"groupName": groupName, "pmAction": pmAction, "pmData": *pmMEData, "err": err})
2531 return err
2532 }
2533 // Update back to kv store
2534 if err = mm.pmKvStore.Put(ctx, groupName, Value); err != nil {
2535 logger.Errorw(ctx, "unable to put PM data to kv store", log.Fields{"groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction, "err": err})
2536 return err
2537 }
2538 logger.Debugw(ctx, "updatePmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction})
2539
2540 return nil
2541}
2542
2543// clearPmGroupData cleans PM Group data from store
2544func (mm *onuMetricsManager) clearPmGroupData(ctx context.Context) error {
2545 mm.onuMetricsManagerLock.Lock()
2546 defer mm.onuMetricsManagerLock.Unlock()
2547 logger.Debugw(ctx, "clearPmGroupData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2548 if mm.pmKvStore == nil {
2549 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2550 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2551 }
2552
2553 for n := range mm.groupMetricMap {
2554 if err := mm.pmKvStore.Delete(ctx, n); err != nil {
2555 logger.Errorw(ctx, "clearPmGroupData - fail", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "groupName": n, "err": err})
2556 // do not abort this procedure. continue to delete next group.
2557 } else {
2558 logger.Debugw(ctx, "clearPmGroupData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": n})
2559 }
2560 }
2561
2562 return nil
2563}
2564
2565// clearAllPmData clears all PM data associated with the device from KV store
2566func (mm *onuMetricsManager) clearAllPmData(ctx context.Context) error {
2567 mm.onuMetricsManagerLock.Lock()
2568 defer mm.onuMetricsManagerLock.Unlock()
2569 logger.Debugw(ctx, "clearAllPmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2570 if mm.pmKvStore == nil {
2571 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2572 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2573 }
2574
2575 if err := mm.pmKvStore.Delete(ctx, ""); err != nil {
2576 logger.Errorw(ctx, "unable to delete PM data from kv store", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "err": err})
2577 return err
2578 }
2579 logger.Debugw(ctx, "clearAllPmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2580 return nil
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002581}
2582
2583func (mm *onuMetricsManager) appendIfMissingString(slice []string, n string) []string {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002584 for _, ele := range slice {
2585 if ele == n {
2586 return slice
2587 }
2588 }
2589 return append(slice, n)
2590}
2591
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002592func (mm *onuMetricsManager) removeIfFoundString(slice []string, n string) []string {
2593 for i, ele := range slice {
2594 if ele == n {
2595 return append(slice[:i], slice[i+1:]...)
2596 }
2597 }
2598 return slice
2599}
2600
2601func (mm *onuMetricsManager) appendIfMissingUnt16(slice []uint16, n uint16) []uint16 {
2602 for _, ele := range slice {
2603 if ele == n {
2604 return slice
2605 }
2606 }
2607 return append(slice, n)
2608}
2609
2610func (mm *onuMetricsManager) removeIfFoundUint16(slice []uint16, n uint16) []uint16 {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002611 for i, ele := range slice {
2612 if ele == n {
2613 return append(slice[:i], slice[i+1:]...)
2614 }
2615 }
2616 return slice
Girish Gowdrae09a6202021-01-12 18:10:59 -08002617}