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