blob: d94e1022731489c92831cad549ab9d462d7b3c25 [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 Gowdra0e533642021-03-02 22:02:51 -080085 "entity_id": voltha.PmConfig_CONTEXT,
Girish Gowdra5a7c4922021-01-22 18:33:41 -080086 "ethernet_type": voltha.PmConfig_GAUGE,
87 "oper_status": voltha.PmConfig_GAUGE,
88 "uni_admin_state": voltha.PmConfig_GAUGE,
89}
90
91// UniStatusGroupMetrics specific constants
92const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080093 UniStatusGroupMetricName = "UNI_Status"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080094 UniStatusGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
95 UniStatusMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
96)
97
Girish Gowdrae0140f02021-02-02 16:55:09 -080098// *** Classical L2 PM Counters begin ***
99
100// EthernetBridgeHistory are supported ethernet bridge history counters fetched from
101// Ethernet Frame Performance Monitoring History Data Downstream and Ethernet Frame Performance Monitoring History Data Upstream MEs.
102var EthernetBridgeHistory = map[string]voltha.PmConfig_PmType{
103 "class_id": voltha.PmConfig_CONTEXT,
104 "entity_id": voltha.PmConfig_CONTEXT,
105 "interval_end_time": voltha.PmConfig_CONTEXT,
106 "parent_class_id": voltha.PmConfig_CONTEXT,
107 "parent_entity_id": voltha.PmConfig_CONTEXT,
108 "upstream": voltha.PmConfig_CONTEXT,
109
110 "drop_events": voltha.PmConfig_COUNTER,
111 "octets": voltha.PmConfig_COUNTER,
112 "packets": voltha.PmConfig_COUNTER,
113 "broadcast_packets": voltha.PmConfig_COUNTER,
114 "multicast_packets": voltha.PmConfig_COUNTER,
115 "crc_errored_packets": voltha.PmConfig_COUNTER,
116 "undersize_packets": voltha.PmConfig_COUNTER,
117 "oversize_packets": voltha.PmConfig_COUNTER,
118 "64_octets": voltha.PmConfig_COUNTER,
119 "65_to_127_octets": voltha.PmConfig_COUNTER,
120 "128_to_255_octets": voltha.PmConfig_COUNTER,
121 "256_to_511_octets": voltha.PmConfig_COUNTER,
122 "512_to_1023_octets": voltha.PmConfig_COUNTER,
123 "1024_to_1518_octets": voltha.PmConfig_COUNTER,
124}
125
126// EthernetUniHistory are supported ethernet uni history counters fetched from
127// Ethernet Performance Monitoring History Data ME.
128var EthernetUniHistory = map[string]voltha.PmConfig_PmType{
129 "class_id": voltha.PmConfig_CONTEXT,
130 "entity_id": voltha.PmConfig_CONTEXT,
131 "interval_end_time": voltha.PmConfig_CONTEXT,
132
133 "fcs_errors": voltha.PmConfig_COUNTER,
134 "excessive_collision_counter": voltha.PmConfig_COUNTER,
135 "late_collision_counter": voltha.PmConfig_COUNTER,
136 "frames_too_long": voltha.PmConfig_COUNTER,
137 "buffer_overflows_on_rx": voltha.PmConfig_COUNTER,
138 "buffer_overflows_on_tx": voltha.PmConfig_COUNTER,
139 "single_collision_frame_counter": voltha.PmConfig_COUNTER,
140 "multiple_collisions_frame_counter": voltha.PmConfig_COUNTER,
141 "sqe_counter": voltha.PmConfig_COUNTER,
142 "deferred_tx_counter": voltha.PmConfig_COUNTER,
143 "internal_mac_tx_error_counter": voltha.PmConfig_COUNTER,
144 "carrier_sense_error_counter": voltha.PmConfig_COUNTER,
145 "alignment_error_counter": voltha.PmConfig_COUNTER,
146 "internal_mac_rx_error_counter": voltha.PmConfig_COUNTER,
147}
148
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800149// FecHistory is supported FEC Performance Monitoring History Data related metrics
150var FecHistory = map[string]voltha.PmConfig_PmType{
151 "class_id": voltha.PmConfig_CONTEXT,
152 "entity_id": voltha.PmConfig_CONTEXT,
153 "interval_end_time": voltha.PmConfig_CONTEXT,
154
155 "corrected_bytes": voltha.PmConfig_COUNTER,
156 "corrected_code_words": voltha.PmConfig_COUNTER,
157 "uncorrectable_code_words": voltha.PmConfig_COUNTER,
158 "total_code_words": voltha.PmConfig_COUNTER,
159 "fec_seconds": voltha.PmConfig_COUNTER,
160}
161
162// GemPortHistory is supported GEM Port Network Ctp Performance Monitoring History Data
163// related metrics
164var GemPortHistory = map[string]voltha.PmConfig_PmType{
165 "class_id": voltha.PmConfig_CONTEXT,
166 "entity_id": voltha.PmConfig_CONTEXT,
167 "interval_end_time": voltha.PmConfig_CONTEXT,
168
169 "transmitted_gem_frames": voltha.PmConfig_COUNTER,
170 "received_gem_frames": voltha.PmConfig_COUNTER,
171 "received_payload_bytes": voltha.PmConfig_COUNTER,
172 "transmitted_payload_bytes": voltha.PmConfig_COUNTER,
173 "encryption_key_errors": voltha.PmConfig_COUNTER,
174}
175
Girish Gowdrae0140f02021-02-02 16:55:09 -0800176// Constants specific for L2 PM collection
177const (
178 L2PmCollectionInterval = 15 * 60 // Unit in seconds. Do not change this as this fixed by OMCI specification for L2 PM counters
179 SyncTimeRetryInterval = 15 // Unit seconds
180 L2PmCreateAttempts = 3
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800181 L2PmDeleteAttempts = 3
Girish Gowdrae0140f02021-02-02 16:55:09 -0800182 L2PmCollectAttempts = 3
Girish Gowdra453750f2021-02-16 16:36:46 -0800183 // Per Table 11.2.9-1 – OMCI baseline message limitations in G.988 spec, the max GET Response
184 // payload size is 25. We define 24 (one less) to allow for dynamic insertion of IntervalEndTime
185 // attribute (1 byte) in L2 PM GET Requests.
186 MaxL2PMGetPayLoadSize = 24
Girish Gowdrae0140f02021-02-02 16:55:09 -0800187)
188
189// EthernetUniHistoryName specific constants
190const (
191 EthernetBridgeHistoryName = "Ethernet_Bridge_Port_History"
192 EthernetBridgeHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
193 EthernetBridgeHistoryFrequency = L2PmCollectionInterval
194)
195
196// EthernetBridgeHistory specific constants
197const (
198 EthernetUniHistoryName = "Ethernet_UNI_History"
199 EthernetUniHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
200 EthernetUniHistoryFrequency = L2PmCollectionInterval
201)
202
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800203// FecHistory specific constants
204const (
205 FecHistoryName = "FEC_History"
206 FecHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
207 FecHistoryFrequency = L2PmCollectionInterval
208)
209
210// GemPortHistory specific constants
211const (
212 GemPortHistoryName = "GEM_Port_History"
213 GemPortHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
214 GemPortHistoryFrequency = L2PmCollectionInterval
215)
216
Girish Gowdra0e533642021-03-02 22:02:51 -0800217// KV Store related constants
218const (
219 cPmKvStorePrefix = "%s/openonu/pm-data/%s" // <some-base-path>/openonu/pm-data/<onu-device-id>
220 cPmAdd = "add"
221 cPmAdded = "added"
222 cPmRemove = "remove"
223 cPmRemoved = "removed"
224)
225
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800226// Defines the type for generic metric population function
227type groupMetricPopulateFunc func(context.Context, me.ClassID, uint16, me.AttributeValueMap, me.AttributeValueMap, map[string]float32, *int) error
228
Girish Gowdrae0140f02021-02-02 16:55:09 -0800229// *** Classical L2 PM Counters end ***
230
Girish Gowdra0e533642021-03-02 22:02:51 -0800231type pmMEData struct {
232 InstancesActive []uint16 `json:"instances_active"` // list of active ME instance IDs for the group
233 InstancesToDelete []uint16 `json:"instances_to_delete"` // list of ME instance IDs marked for deletion for the group
234 InstancesToAdd []uint16 `json:"instances_to_add"` // list of ME instance IDs marked for addition for the group
235}
236
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800237type groupMetric struct {
238 groupName string
239 enabled bool
240 frequency uint32 // valid only if FrequencyOverride is enabled.
241 metricMap map[string]voltha.PmConfig_PmType
242 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
Girish Gowdrae0140f02021-02-02 16:55:09 -0800243 isL2PMCounter bool // true for only L2 PM counters
244 collectAttempts uint32 // number of attempts to collect L2 PM data
Girish Gowdra0e533642021-03-02 22:02:51 -0800245 pmMEData *pmMEData
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800246}
247
248type standaloneMetric struct {
249 metricName string
250 enabled bool
251 frequency uint32 // valid only if FrequencyOverride is enabled.
252 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
253}
254
Girish Gowdrae09a6202021-01-12 18:10:59 -0800255type onuMetricsManager struct {
256 pDeviceHandler *deviceHandler
Girish Gowdrae0140f02021-02-02 16:55:09 -0800257 pAdaptFsm *AdapterFsm
Girish Gowdrae09a6202021-01-12 18:10:59 -0800258
Girish Gowdrae0140f02021-02-02 16:55:09 -0800259 opticalMetricsChan chan me.AttributeValueMap
260 uniStatusMetricsChan chan me.AttributeValueMap
261 l2PmChan chan me.AttributeValueMap
262 syncTimeResponseChan chan bool // true is success, false is fail
263 l2PmCreateOrDeleteResponseChan chan bool // true is success, false is fail
264
265 activeL2Pms []string // list of active l2 pm MEs created on the ONU.
266 l2PmToDelete []string // list of L2 PMs to delete
267 l2PmToAdd []string // list of L2 PM to add
Girish Gowdrae09a6202021-01-12 18:10:59 -0800268
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800269 groupMetricMap map[string]*groupMetric
270 standaloneMetricMap map[string]*standaloneMetric
271
Girish Gowdrae09a6202021-01-12 18:10:59 -0800272 stopProcessingOmciResponses chan bool
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800273
Girish Gowdrae0140f02021-02-02 16:55:09 -0800274 stopTicks chan bool
275
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800276 nextGlobalMetricCollectionTime time.Time // valid only if pmConfig.FreqOverride is set to false.
277
278 onuMetricsManagerLock sync.RWMutex
Girish Gowdra0e533642021-03-02 22:02:51 -0800279
280 pmKvStore *db.Backend
Girish Gowdrae09a6202021-01-12 18:10:59 -0800281}
282
283// newonuMetricsManager returns a new instance of the newonuMetricsManager
Girish Gowdra0e533642021-03-02 22:02:51 -0800284// The metrics manager module is responsible for configuration and management of individual and group metrics.
285// Currently all the metrics are managed as a group which fall into two categories - L2 PM and "all others"
286// The L2 PM counters have a fixed 15min interval for PM collection while all other group counters have
287// the collection interval configurable.
288// The global PM config is part of the voltha.Device struct and is backed up on KV store (by rw-core).
289// This module also implements resiliency for L2 PM ME instances that are active/pending-delete/pending-add.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800290func newonuMetricsManager(ctx context.Context, dh *deviceHandler) *onuMetricsManager {
291
292 var metricsManager onuMetricsManager
293 logger.Debugw(ctx, "init-onuMetricsManager", log.Fields{"device-id": dh.deviceID})
294 metricsManager.pDeviceHandler = dh
295
Girish Gowdrae0140f02021-02-02 16:55:09 -0800296 commMetricsChan := make(chan Message)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800297 metricsManager.opticalMetricsChan = make(chan me.AttributeValueMap)
298 metricsManager.uniStatusMetricsChan = make(chan me.AttributeValueMap)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800299 metricsManager.l2PmChan = make(chan me.AttributeValueMap)
300
301 metricsManager.syncTimeResponseChan = make(chan bool)
302 metricsManager.l2PmCreateOrDeleteResponseChan = make(chan bool)
303
Girish Gowdrae09a6202021-01-12 18:10:59 -0800304 metricsManager.stopProcessingOmciResponses = make(chan bool)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800305 metricsManager.stopTicks = make(chan bool)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800306
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800307 metricsManager.groupMetricMap = make(map[string]*groupMetric)
308 metricsManager.standaloneMetricMap = make(map[string]*standaloneMetric)
309
310 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 -0800311 metricsManager.initializeAllGroupMetrics()
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800312 }
313
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800314 metricsManager.populateLocalGroupMetricData(ctx)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800315
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800316 if err := metricsManager.initializeL2PmFsm(ctx, commMetricsChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800317 return nil
318 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800319
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800320 // initialize the next metric collection intervals.
321 metricsManager.initializeMetricCollectionTime(ctx)
Girish Gowdra0e533642021-03-02 22:02:51 -0800322
323 baseKvStorePath := fmt.Sprintf(cPmKvStorePrefix, dh.pOpenOnuAc.cm.Backend.PathPrefix, dh.deviceID)
324 metricsManager.pmKvStore = dh.setBackend(ctx, baseKvStorePath)
325 if metricsManager.pmKvStore == nil {
326 logger.Errorw(ctx, "Can't initialize pmKvStore - no backend connection to PM module",
327 log.Fields{"device-id": dh.deviceID, "service": baseKvStorePath})
328 return nil
329 }
330
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800331 logger.Info(ctx, "init-onuMetricsManager completed", log.Fields{"device-id": dh.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800332 return &metricsManager
333}
334
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800335func (mm *onuMetricsManager) initializeMetricCollectionTime(ctx context.Context) {
336 if mm.pDeviceHandler.pmConfigs.FreqOverride {
337 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to true, then group/standalone metric specific interval applies
338 mm.onuMetricsManagerLock.Lock()
339 defer mm.onuMetricsManagerLock.Unlock()
340 for _, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800341 if v.enabled && !v.isL2PMCounter { // L2 PM counter collection is managed in a L2PmFsm
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800342 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
343 }
344 }
345
346 for _, v := range mm.standaloneMetricMap {
347 if v.enabled {
348 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
349 }
350 }
351 } else {
352 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to false, then overall metric specific interval applies
353 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
354 }
355 logger.Infow(ctx, "initialized standalone group/metric collection time", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
356}
357
358func (mm *onuMetricsManager) updateDefaultFrequency(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
359 // Verify that the configured DefaultFrequency is > 0 and is a multiple of FrequencyGranularity
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800360 if pmConfigs.DefaultFreq == 0 || (pmConfigs.DefaultFreq > 0 && pmConfigs.DefaultFreq%FrequencyGranularity != 0) {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800361 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", pmConfigs.DefaultFreq, FrequencyGranularity)
362 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", pmConfigs.DefaultFreq, FrequencyGranularity)
363 }
364 mm.pDeviceHandler.pmConfigs.DefaultFreq = pmConfigs.DefaultFreq
365 // re-set the nextGlobalMetricCollectionTime based on the new DefaultFreq
366 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
367 logger.Debugw(ctx, "frequency-updated--new-frequency", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "frequency": mm.pDeviceHandler.pmConfigs.DefaultFreq})
368 return nil
369}
370
371func (mm *onuMetricsManager) updateGroupFreq(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
372 var newGroupFreq uint32
373 found := false
374 groupSliceIdx := 0
375 var group *voltha.PmGroupConfig
376 for groupSliceIdx, group = range pmConfigs.Groups {
377 if group.GroupName == aGroupName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800378 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
379 if group.GroupFreq == 0 || (group.GroupFreq > 0 && group.GroupFreq%FrequencyGranularity != 0) {
380 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", group.GroupFreq, FrequencyGranularity)
381 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", group.GroupFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800382 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800383 newGroupFreq = group.GroupFreq
384 found = true
385 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800386 }
387 }
388 // if not found update group freq and next collection interval for the group
389 if !found {
390 logger.Errorw(ctx, "group name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
391 return fmt.Errorf("group-name-not-found-%v", aGroupName)
392 }
393
394 updated := false
395 mm.onuMetricsManagerLock.Lock()
396 defer mm.onuMetricsManagerLock.Unlock()
397 for k, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800398 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 -0800399 v.frequency = newGroupFreq
400 // update internal pm config
401 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].GroupFreq = newGroupFreq
402 // Also updated the next group metric collection time from now
403 v.nextCollectionInterval = time.Now().Add(time.Duration(newGroupFreq) * time.Second)
404 updated = true
405 logger.Infow(ctx, "group frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800406 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800407 }
408 }
409 if !updated {
410 logger.Errorw(ctx, "group frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
411 return fmt.Errorf("internal-error-during-group-freq-update--groupname-%s-freq-%d", aGroupName, newGroupFreq)
412 }
413 return nil
414}
415
416func (mm *onuMetricsManager) updateMetricFreq(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
417 var newMetricFreq uint32
418 found := false
419 metricSliceIdx := 0
420 var metric *voltha.PmConfig
421 for metricSliceIdx, metric = range pmConfigs.Metrics {
422 if metric.Name == aMetricName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800423 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
424 if metric.SampleFreq == 0 || (metric.SampleFreq > 0 && metric.SampleFreq%FrequencyGranularity != 0) {
425 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", metric.SampleFreq, FrequencyGranularity)
426 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", metric.SampleFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800427 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800428 newMetricFreq = metric.SampleFreq
429 found = true
430 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800431 }
432 }
433 if !found {
434 logger.Errorw(ctx, "metric name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
435 return fmt.Errorf("metric-name-not-found-%v", aMetricName)
436 }
437
438 updated := false
439 mm.onuMetricsManagerLock.Lock()
440 defer mm.onuMetricsManagerLock.Unlock()
441 for k, v := range mm.groupMetricMap {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800442 if k == aMetricName {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800443 v.frequency = newMetricFreq
444 // update internal pm config
445 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].SampleFreq = newMetricFreq
446 // Also updated the next standalone metric collection time from now
447 v.nextCollectionInterval = time.Now().Add(time.Duration(newMetricFreq) * time.Second)
448 updated = true
449 logger.Infow(ctx, "metric frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800450 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800451 }
452 }
453 if !updated {
454 logger.Errorw(ctx, "metric frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
455 return fmt.Errorf("internal-error-during-standalone-metric-update--matricnane-%s-freq-%d", aMetricName, newMetricFreq)
456 }
457 return nil
458}
459
460func (mm *onuMetricsManager) updateGroupSupport(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
461 groupSliceIdx := 0
462 var group *voltha.PmGroupConfig
463
464 for groupSliceIdx, group = range pmConfigs.Groups {
465 if group.GroupName == aGroupName {
466 break
467 }
468 }
469 if group == nil {
470 logger.Errorw(ctx, "group metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
471 return fmt.Errorf("group-not-found--groupName-%s", aGroupName)
472 }
473
474 updated := false
475 mm.onuMetricsManagerLock.Lock()
476 defer mm.onuMetricsManagerLock.Unlock()
477 for k, v := range mm.groupMetricMap {
478 if k == aGroupName && v.enabled != group.Enabled {
479 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].Enabled = group.Enabled
480 v.enabled = group.Enabled
Girish Gowdrae0140f02021-02-02 16:55:09 -0800481 if group.Enabled {
482 if v.isL2PMCounter {
483 // If it is a L2 PM counter we need to mark the PM to be added
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800484 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800485 // 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 -0800486 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, v.groupName)
487
488 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
489 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
490 // take further action
491 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800492 mm.updateGemPortNTPInstanceToAddForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800493 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800494 } else if mm.pDeviceHandler.pmConfigs.FreqOverride { // otherwise just update the next collection interval
495 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
496 }
497 } else { // group counter is disabled
498 if v.isL2PMCounter {
499 // If it is a L2 PM counter we need to mark the PM to be deleted
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800500 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800501 // 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 -0800502 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, v.groupName)
503
504 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
505 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
506 // take further action
507 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800508 mm.updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800509 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800510 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800511 }
512 updated = true
Girish Gowdrae0140f02021-02-02 16:55:09 -0800513 if v.isL2PMCounter {
514 logger.Infow(ctx, "l2 pm group metric support updated",
515 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled, "l2PmToAdd": mm.l2PmToAdd, "l2PmToDelete": mm.l2PmToDelete})
516 } else {
517 logger.Infow(ctx, "group metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled})
518 }
519 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800520 }
521 }
522
523 if !updated {
524 logger.Errorw(ctx, "group metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
525 return fmt.Errorf("internal-error-during-group-support-update--groupName-%s", aGroupName)
526 }
527 return nil
528}
529
530func (mm *onuMetricsManager) updateMetricSupport(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
531 metricSliceIdx := 0
532 var metric *voltha.PmConfig
533
534 for metricSliceIdx, metric = range pmConfigs.Metrics {
535 if metric.Name == aMetricName {
536 break
537 }
538 }
539
540 if metric == nil {
541 logger.Errorw(ctx, "standalone metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
542 return fmt.Errorf("metric-not-found--metricname-%s", aMetricName)
543 }
544
545 updated := false
546 mm.onuMetricsManagerLock.Lock()
547 defer mm.onuMetricsManagerLock.Unlock()
548 for k, v := range mm.standaloneMetricMap {
549 if k == aMetricName && v.enabled != metric.Enabled {
550 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].Enabled = metric.Enabled
551 v.enabled = metric.Enabled
552 // If the standalone metric is now enabled and frequency override is enabled, set the next metric collection time
553 if metric.Enabled && mm.pDeviceHandler.pmConfigs.FreqOverride {
554 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
555 }
556 updated = true
557 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 -0800558 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800559 }
560 }
561 if !updated {
562 logger.Errorw(ctx, "standalone metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
563 return fmt.Errorf("internal-error-during-standalone-support-update--metricname-%s", aMetricName)
564 }
565 return nil
566}
567
568func (mm *onuMetricsManager) collectAllGroupAndStandaloneMetrics(ctx context.Context) {
569 if mm.pDeviceHandler.pmConfigs.Grouped { // metrics are managed as a group.
570 go mm.collectAllGroupMetrics(ctx)
571 } else {
572 go mm.collectAllStandaloneMetrics(ctx)
573 }
574}
575
576func (mm *onuMetricsManager) collectAllGroupMetrics(ctx context.Context) {
577 go func() {
578 logger.Debug(ctx, "startCollector before collecting optical metrics")
579 metricInfo := mm.collectOpticalMetrics(ctx)
580 if metricInfo != nil {
581 mm.publishMetrics(ctx, metricInfo)
582 }
583 }()
584
585 go func() {
586 logger.Debug(ctx, "startCollector before collecting uni metrics")
587 metricInfo := mm.collectUniStatusMetrics(ctx)
588 if metricInfo != nil {
589 mm.publishMetrics(ctx, metricInfo)
590 }
591 }()
592
593 // Add more here
594}
595
596func (mm *onuMetricsManager) collectAllStandaloneMetrics(ctx context.Context) {
597 // None exists as of now, add when available here
598}
599
600func (mm *onuMetricsManager) collectGroupMetric(ctx context.Context, groupName string) {
601 switch groupName {
602 case OpticalPowerGroupMetricName:
603 go func() {
604 if mi := mm.collectOpticalMetrics(ctx); mm != nil {
605 mm.publishMetrics(ctx, mi)
606 }
607 }()
608 case UniStatusGroupMetricName:
609 go func() {
610 if mi := mm.collectUniStatusMetrics(ctx); mm != nil {
611 mm.publishMetrics(ctx, mi)
612 }
613 }()
614 default:
615 logger.Errorw(ctx, "unhandled group metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName})
616 }
617}
618
619func (mm *onuMetricsManager) collectStandaloneMetric(ctx context.Context, metricName string) {
620 switch metricName {
621 // None exist as of now, add when available
622 default:
623 logger.Errorw(ctx, "unhandled standalone metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName})
624 }
625}
626
627// collectOpticalMetrics collects groups metrics related to optical power from ani-g ME.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800628func (mm *onuMetricsManager) collectOpticalMetrics(ctx context.Context) []*voltha.MetricInformation {
629 logger.Debugw(ctx, "collectOpticalMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800630
631 mm.onuMetricsManagerLock.RLock()
632 if !mm.groupMetricMap[OpticalPowerGroupMetricName].enabled {
633 mm.onuMetricsManagerLock.RUnlock()
634 logger.Debugw(ctx, "optical power group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
635 return nil
636 }
637 mm.onuMetricsManagerLock.RUnlock()
638
Girish Gowdrae09a6202021-01-12 18:10:59 -0800639 var metricInfoSlice []*voltha.MetricInformation
640 metricsContext := make(map[string]string)
641 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
642 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
643 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
644
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800645 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800646 mmd := voltha.MetricMetaData{
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800647 Title: OpticalPowerGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800648 Ts: float64(raisedTs),
649 Context: metricsContext,
650 DeviceId: mm.pDeviceHandler.deviceID,
651 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
652 SerialNo: mm.pDeviceHandler.device.SerialNumber,
653 }
654
Girish Gowdrae09a6202021-01-12 18:10:59 -0800655 // get the ANI-G instance IDs
656 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
657loop:
658 for _, anigInstID := range anigInstKeys {
659 var meAttributes me.AttributeValueMap
660 opticalMetrics := make(map[string]float32)
661 // Get the ANI-G instance optical power attributes
662 requestedAttributes := me.AttributeValueMap{"OpticalSignalLevel": 0, "TransmitOpticalLevel": 0}
Girish Gowdra0b235842021-03-09 13:06:46 -0800663 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.AniGClassID, anigInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800664 select {
665 case meAttributes = <-mm.opticalMetricsChan:
666 logger.Debugw(ctx, "received optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0b235842021-03-09 13:06:46 -0800667 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800668 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 -0800669 // The metrics will be empty in this case
670 break loop
671 }
672 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800673 for k := range OpticalPowerGroupMetrics {
674 switch k {
675 case "ani_g_instance_id":
676 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
677 opticalMetrics[k] = float32(val.(uint16))
678 }
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800679 case "transmit_power_dBm":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800680 if val, ok := meAttributes["TransmitOpticalLevel"]; ok && val != nil {
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800681 opticalMetrics[k] = float32(math.Round((float64(mm.twosComplementToSignedInt16(val.(uint16)))/500.0)*10) / 10) // convert to dBm rounded of to single decimal place
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800682 }
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800683 case "receive_power_dBm":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800684 if val, ok := meAttributes["OpticalSignalLevel"]; ok && val != nil {
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800685 opticalMetrics[k] = float32(math.Round((float64(mm.twosComplementToSignedInt16(val.(uint16)))/500.0)*10) / 10) // convert to dBm rounded of to single decimal place
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800686 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800687 default:
688 // do nothing
689 }
690 }
691 }
692 // create slice of metrics given that there could be more than one ANI-G instance and
693 // optical metrics are collected per ANI-G instance
694 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: opticalMetrics}
695 metricInfoSlice = append(metricInfoSlice, &metricInfo)
696 }
697
698 return metricInfoSlice
699}
700
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800701// collectUniStatusMetrics collects UNI status group metric from various MEs (uni-g, pptp and veip).
Girish Gowdrae09a6202021-01-12 18:10:59 -0800702// nolint: gocyclo
703func (mm *onuMetricsManager) collectUniStatusMetrics(ctx context.Context) []*voltha.MetricInformation {
704 logger.Debugw(ctx, "collectUniStatusMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800705 mm.onuMetricsManagerLock.RLock()
706 if !mm.groupMetricMap[UniStatusGroupMetricName].enabled {
707 mm.onuMetricsManagerLock.RUnlock()
708 logger.Debugw(ctx, "uni status group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
709 return nil
710 }
711 mm.onuMetricsManagerLock.RUnlock()
712
Girish Gowdrae09a6202021-01-12 18:10:59 -0800713 var metricInfoSlice []*voltha.MetricInformation
714 metricsContext := make(map[string]string)
715 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
716 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
717 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
718
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800719 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800720 mmd := voltha.MetricMetaData{
721 Title: "UniStatus", // Is this ok to hard code?
722 Ts: float64(raisedTs),
723 Context: metricsContext,
724 DeviceId: mm.pDeviceHandler.deviceID,
725 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
726 SerialNo: mm.pDeviceHandler.device.SerialNumber,
727 }
728
Girish Gowdrae09a6202021-01-12 18:10:59 -0800729 // get the UNI-G instance IDs
730 unigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.UniGClassID)
731loop1:
732 for _, unigInstID := range unigInstKeys {
733 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
734 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
735 unigMetrics := make(map[string]float32)
736 var meAttributes me.AttributeValueMap
737 // Get the UNI-G instance optical power attributes
738 requestedAttributes := me.AttributeValueMap{"AdministrativeState": 0}
Girish Gowdra0b235842021-03-09 13:06:46 -0800739 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.UniGClassID, unigInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800740 // Wait for metrics or timeout
741 select {
742 case meAttributes = <-mm.uniStatusMetricsChan:
743 logger.Debugw(ctx, "received uni-g metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0b235842021-03-09 13:06:46 -0800744 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800745 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
746 // The metrics could be empty in this case
747 break loop1
748 }
749 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800750 for k := range UniStatusGroupMetrics {
751 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800752 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800753 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
754 unigMetrics[k] = float32(val.(byte))
755 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800756 default:
757 // do nothing
758 }
759 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800760 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800761 entityID := val.(uint16)
762 unigMetrics["entity_id"] = float32(entityID)
763 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
764 for _, uni := range mm.pDeviceHandler.uniEntityMap {
765 if uni.entityID == entityID {
766 unigMetrics["uni_port_no"] = float32(uni.portNo)
767 }
768 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800769 }
Girish Gowdra0e533642021-03-02 22:02:51 -0800770
Girish Gowdrae09a6202021-01-12 18:10:59 -0800771 // create slice of metrics given that there could be more than one UNI-G instance
772 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: unigMetrics}
773 metricInfoSlice = append(metricInfoSlice, &metricInfo)
774 }
775 }
776
777 // get the PPTP instance IDs
778 pptpInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.PhysicalPathTerminationPointEthernetUniClassID)
779loop2:
780 for _, pptpInstID := range pptpInstKeys {
781 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
782 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
783 var meAttributes me.AttributeValueMap
784 pptpMetrics := make(map[string]float32)
785
786 requestedAttributes := me.AttributeValueMap{"SensedType": 0, "OperationalState": 0, "AdministrativeState": 0}
Girish Gowdra0b235842021-03-09 13:06:46 -0800787 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.PhysicalPathTerminationPointEthernetUniClassID, pptpInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800788 // Wait for metrics or timeout
789 select {
790 case meAttributes = <-mm.uniStatusMetricsChan:
791 logger.Debugw(ctx, "received pptp metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0b235842021-03-09 13:06:46 -0800792 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800793 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
794 // The metrics could be empty in this case
795 break loop2
796 }
797
798 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800799 for k := range UniStatusGroupMetrics {
800 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800801 case "ethernet_type":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800802 if val, ok := meAttributes["SensedType"]; ok && val != nil {
803 pptpMetrics[k] = float32(val.(byte))
804 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800805 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800806 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
807 pptpMetrics[k] = float32(val.(byte))
808 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800809 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800810 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
811 pptpMetrics[k] = float32(val.(byte))
812 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800813 default:
814 // do nothing
815 }
816 }
817 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800818 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800819 entityID := val.(uint16)
820 pptpMetrics["entity_id"] = float32(entityID)
821 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
822 for _, uni := range mm.pDeviceHandler.uniEntityMap {
823 if uni.entityID == entityID {
824 pptpMetrics["uni_port_no"] = float32(uni.portNo)
825 }
826 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800827 }
828
Girish Gowdrae09a6202021-01-12 18:10:59 -0800829 // create slice of metrics given that there could be more than one PPTP instance and
830 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: pptpMetrics}
831 metricInfoSlice = append(metricInfoSlice, &metricInfo)
832 }
833
834 // get the VEIP instance IDs
835 veipInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.VirtualEthernetInterfacePointClassID)
836loop3:
837 for _, veipInstID := range veipInstKeys {
838 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
839 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
840 var meAttributes me.AttributeValueMap
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800841 veipMetrics := make(map[string]float32)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800842
843 requestedAttributes := me.AttributeValueMap{"OperationalState": 0, "AdministrativeState": 0}
Girish Gowdra0b235842021-03-09 13:06:46 -0800844 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.VirtualEthernetInterfacePointClassID, veipInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800845 // Wait for metrics or timeout
846 select {
847 case meAttributes = <-mm.uniStatusMetricsChan:
848 logger.Debugw(ctx, "received veip metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0b235842021-03-09 13:06:46 -0800849 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800850 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
851 // The metrics could be empty in this case
852 break loop3
853 }
854
855 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800856 for k := range UniStatusGroupMetrics {
857 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800858 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800859 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
860 veipMetrics[k] = float32(val.(byte))
861 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800862 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800863 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
864 veipMetrics[k] = float32(val.(byte))
865 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800866 default:
867 // do nothing
868 }
869 }
870 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800871
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800872 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800873 entityID := val.(uint16)
874 veipMetrics["entity_id"] = float32(entityID)
875 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
876 for _, uni := range mm.pDeviceHandler.uniEntityMap {
877 if uni.entityID == entityID {
878 veipMetrics["uni_port_no"] = float32(uni.portNo)
879 }
880 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800881 }
882
Girish Gowdrae09a6202021-01-12 18:10:59 -0800883 // create slice of metrics given that there could be more than one VEIP instance
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800884 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: veipMetrics}
Girish Gowdrae09a6202021-01-12 18:10:59 -0800885 metricInfoSlice = append(metricInfoSlice, &metricInfo)
886 }
887
888 return metricInfoSlice
889}
890
891// publishMetrics publishes the metrics on kafka
892func (mm *onuMetricsManager) publishMetrics(ctx context.Context, metricInfo []*voltha.MetricInformation) {
893 var ke voltha.KpiEvent2
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800894 ts := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800895 ke.SliceData = metricInfo
896 ke.Type = voltha.KpiEventType_slice
897 ke.Ts = float64(ts)
898
899 if err := mm.pDeviceHandler.EventProxy.SendKpiEvent(ctx, "STATS_EVENT", &ke, voltha.EventCategory_EQUIPMENT, voltha.EventSubCategory_ONU, ts); err != nil {
900 logger.Errorw(ctx, "failed-to-send-pon-stats", log.Fields{"err": err})
901 }
902}
903
904func (mm *onuMetricsManager) processOmciMessages(ctx context.Context) {
905 logger.Infow(ctx, "Start routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
906 // Flush metric collection channels to be safe.
907 // It is possible that there is stale data on this channel if the processOmciMessages routine
908 // is stopped right after issuing a OMCI-GET request and started again.
909 // The processOmciMessages routine will get stopped if startCollector routine (in device_handler.go)
910 // is stopped - as a result of ONU going down.
911 mm.flushMetricCollectionChannels(ctx)
912
913 for {
914 select {
915 case <-mm.stopProcessingOmciResponses: // stop this routine
916 logger.Infow(ctx, "Stop routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
917 return
Girish Gowdrae0140f02021-02-02 16:55:09 -0800918 case message, ok := <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -0800919 if !ok {
920 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
921 continue
922 }
923 logger.Debugw(ctx, "Received message on ONU metrics channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
924
925 switch message.Type {
926 case OMCI:
927 msg, _ := message.Data.(OmciMessage)
928 mm.handleOmciMessage(ctx, msg)
929 default:
930 logger.Warn(ctx, "Unknown message type received", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "message.Type": message.Type})
931 }
932 }
933 }
934}
935
936func (mm *onuMetricsManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
937 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
938 "msgType": msg.OmciMsg.MessageType, "msg": msg})
939 switch msg.OmciMsg.MessageType {
940 case omci.GetResponseType:
941 //TODO: error handling
942 _ = mm.handleOmciGetResponseMessage(ctx, msg)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800943 case omci.SynchronizeTimeResponseType:
944 _ = mm.handleOmciSynchronizeTimeResponseMessage(ctx, msg)
945 case omci.CreateResponseType:
946 _ = mm.handleOmciCreateResponseMessage(ctx, msg)
947 case omci.DeleteResponseType:
948 _ = mm.handleOmciDeleteResponseMessage(ctx, msg)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800949 default:
950 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
951
952 }
953}
954
955func (mm *onuMetricsManager) handleOmciGetResponseMessage(ctx context.Context, msg OmciMessage) error {
956 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
957 if msgLayer == nil {
958 logger.Errorw(ctx, "omci Msg layer could not be detected for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
959 return fmt.Errorf("omci Msg layer could not be detected for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
960 }
961 msgObj, msgOk := msgLayer.(*omci.GetResponse)
962 if !msgOk {
963 logger.Errorw(ctx, "omci Msg layer could not be assigned for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
964 return fmt.Errorf("omci Msg layer could not be assigned for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
965 }
966 logger.Debugw(ctx, "OMCI GetResponse Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
967 if msgObj.Result == me.Success {
968 meAttributes := msgObj.Attributes
969 switch msgObj.EntityClass {
970 case me.AniGClassID:
971 mm.opticalMetricsChan <- meAttributes
972 return nil
973 case me.UniGClassID:
974 mm.uniStatusMetricsChan <- meAttributes
975 return nil
976 case me.PhysicalPathTerminationPointEthernetUniClassID:
977 mm.uniStatusMetricsChan <- meAttributes
978 return nil
979 case me.VirtualEthernetInterfacePointClassID:
980 mm.uniStatusMetricsChan <- meAttributes
981 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -0800982 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
983 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800984 me.EthernetPerformanceMonitoringHistoryDataClassID,
985 me.FecPerformanceMonitoringHistoryDataClassID,
986 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -0800987 mm.l2PmChan <- meAttributes
Girish Gowdrae09a6202021-01-12 18:10:59 -0800988 default:
989 logger.Errorw(ctx, "unhandled omci get response message",
990 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
991 }
992 }
993
Girish Gowdrae0140f02021-02-02 16:55:09 -0800994 return fmt.Errorf("unhandled-omci-get-response-message")
995}
996
997func (mm *onuMetricsManager) handleOmciSynchronizeTimeResponseMessage(ctx context.Context, msg OmciMessage) error {
998 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSynchronizeTimeResponse)
999 if msgLayer == nil {
1000 logger.Errorw(ctx, "omci Msg layer could not be detected for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1001 return fmt.Errorf("omci Msg layer could not be detected for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1002 }
1003 msgObj, msgOk := msgLayer.(*omci.SynchronizeTimeResponse)
1004 if !msgOk {
1005 logger.Errorw(ctx, "omci Msg layer could not be assigned for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1006 return fmt.Errorf("omci Msg layer could not be assigned for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1007 }
1008 logger.Debugw(ctx, "OMCI synchronize time response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1009 if msgObj.Result == me.Success {
1010 switch msgObj.EntityClass {
1011 case me.OnuGClassID:
1012 logger.Infow(ctx, "omci synchronize time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1013 mm.syncTimeResponseChan <- true
1014 return nil
1015 default:
1016 logger.Errorw(ctx, "unhandled omci message",
1017 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1018 }
1019 }
1020 mm.syncTimeResponseChan <- false
1021 logger.Errorf(ctx, "unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
1022 return fmt.Errorf("unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001023}
1024
1025// flushMetricCollectionChannels flushes all metric collection channels for any stale OMCI responses
1026func (mm *onuMetricsManager) flushMetricCollectionChannels(ctx context.Context) {
1027 // flush commMetricsChan
1028 select {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001029 case <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -08001030 logger.Debug(ctx, "flushed common metrics channel")
1031 default:
1032 }
1033
1034 // flush opticalMetricsChan
1035 select {
1036 case <-mm.opticalMetricsChan:
1037 logger.Debug(ctx, "flushed optical metrics channel")
1038 default:
1039 }
1040
1041 // flush uniStatusMetricsChan
1042 select {
1043 case <-mm.uniStatusMetricsChan:
1044 logger.Debug(ctx, "flushed uni status metrics channel")
1045 default:
1046 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001047
1048 // flush syncTimeResponseChan
1049 select {
1050 case <-mm.syncTimeResponseChan:
1051 logger.Debug(ctx, "flushed sync time response channel")
1052 default:
1053 }
1054
1055 // flush l2PmChan
1056 select {
1057 case <-mm.l2PmChan:
1058 logger.Debug(ctx, "flushed L2 PM collection channel")
1059 default:
1060 }
1061
1062 // flush stopTicks
1063 select {
1064 case <-mm.stopTicks:
1065 logger.Debug(ctx, "flushed stopTicks channel")
1066 default:
1067 }
1068
1069}
1070
1071// ** L2 PM FSM Handlers start **
1072
1073func (mm *onuMetricsManager) l2PMFsmStarting(ctx context.Context, e *fsm.Event) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001074 // restore data from KV store
1075 if err := mm.restorePmData(ctx); err != nil {
1076 logger.Errorw(ctx, "error restoring pm data", log.Fields{"err": err})
1077 // we continue given that it does not effect the actual services for the ONU,
1078 // but there may be some negative effect on PM collection (there may be some mismatch in
1079 // the actual PM config and what is present on the device).
1080 }
1081
Girish Gowdrae0140f02021-02-02 16:55:09 -08001082 // Loop through all the group metrics
1083 // If it is a L2 PM Interval metric and it is enabled, then if it is not in the
1084 // list of active L2 PM list then mark it for creation
1085 // It it is a L2 PM Interval metric and it is disabled, then if it is in the
1086 // list of active L2 PM list then mark it for deletion
1087 mm.onuMetricsManagerLock.Lock()
1088 for n, g := range mm.groupMetricMap {
1089 if g.isL2PMCounter { // it is a l2 pm counter
1090 if g.enabled { // metric enabled.
1091 found := false
1092 inner1:
1093 for _, v := range mm.activeL2Pms {
1094 if v == n {
1095 found = true // metric already present in active l2 pm list
1096 break inner1
1097 }
1098 }
1099 if !found { // metric not in active l2 pm list. Mark this to be added later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001100 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001101 }
1102 } else { // metric not enabled.
1103 found := false
1104 inner2:
1105 for _, v := range mm.activeL2Pms {
1106 if v == n {
1107 found = true // metric is found in active l2 pm list
1108 break inner2
1109 }
1110 }
1111 if found { // metric is found in active l2 pm list. Mark this to be deleted later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001112 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001113 }
1114 }
1115 }
1116 }
1117 mm.onuMetricsManagerLock.Unlock()
1118 logger.Debugw(ctx, "pms to add and delete",
1119 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd, "pms-to-delete": mm.l2PmToDelete})
1120 go func() {
1121 // push a tick event to move to next state
1122 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1123 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1124 }
1125 }()
1126}
1127
1128func (mm *onuMetricsManager) l2PMFsmSyncTime(ctx context.Context, e *fsm.Event) {
1129 // Sync time with the ONU to establish 15min boundary for PM collection.
1130 if err := mm.syncTime(ctx); err != nil {
1131 go func() {
1132 time.Sleep(SyncTimeRetryInterval * time.Second) // retry to sync time after this timeout
1133 // This will result in FSM attempting to sync time again
1134 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventFailure); err != nil {
1135 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1136 }
1137 }()
1138 }
1139 // Initiate a tick generation routine every L2PmCollectionInterval
1140 go mm.generateTicks(ctx)
1141
1142 go func() {
1143 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1144 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1145 }
1146 }()
1147}
1148
1149func (mm *onuMetricsManager) l2PMFsmNull(ctx context.Context, e *fsm.Event) {
1150 // 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
1151 mm.onuMetricsManagerLock.Lock()
1152 mm.activeL2Pms = nil
1153 mm.l2PmToAdd = nil
1154 mm.l2PmToDelete = nil
1155 mm.onuMetricsManagerLock.Unlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001156 // If the FSM was stopped, then clear PM data from KV store
1157 // The FSM is stopped when ONU goes down. It is time to clear its data from store
1158 if e.Event == l2PmEventStop {
1159 _ = mm.clearPmGroupData(ctx) // ignore error
1160 }
1161
Girish Gowdrae0140f02021-02-02 16:55:09 -08001162}
1163func (mm *onuMetricsManager) l2PMFsmIdle(ctx context.Context, e *fsm.Event) {
1164 logger.Debugw(ctx, "Enter state idle", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1165
1166 mm.onuMetricsManagerLock.RLock()
1167 numOfPmToDelete := len(mm.l2PmToDelete)
1168 numOfPmToAdd := len(mm.l2PmToAdd)
1169 mm.onuMetricsManagerLock.RUnlock()
1170
1171 if numOfPmToDelete > 0 {
1172 logger.Debugw(ctx, "state idle - pms to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": numOfPmToDelete})
1173 go func() {
1174 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
1175 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1176 }
1177 }()
1178 } else if numOfPmToAdd > 0 {
1179 logger.Debugw(ctx, "state idle - pms to add", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": numOfPmToAdd})
1180 go func() {
1181 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
1182 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1183 }
1184 }()
1185 }
1186}
1187
1188func (mm *onuMetricsManager) l2PmFsmCollectData(ctx context.Context, e *fsm.Event) {
1189 logger.Debugw(ctx, "state collect data", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1190 // Copy the activeL2Pms for which we want to collect the metrics since activeL2Pms can change dynamically
1191 mm.onuMetricsManagerLock.RLock()
1192 copyOfActiveL2Pms := make([]string, len(mm.activeL2Pms))
1193 _ = copy(copyOfActiveL2Pms, mm.activeL2Pms)
1194 mm.onuMetricsManagerLock.RUnlock()
1195
1196 for _, n := range copyOfActiveL2Pms {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001197 var metricInfoSlice []*voltha.MetricInformation
Girish Gowdra0e533642021-03-02 22:02:51 -08001198
1199 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1200 mm.onuMetricsManagerLock.RLock()
1201 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1202 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1203 mm.onuMetricsManagerLock.RUnlock()
1204
Girish Gowdrae0140f02021-02-02 16:55:09 -08001205 switch n {
1206 case EthernetBridgeHistoryName:
1207 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 -08001208 for _, entityID := range copyOfEntityIDs {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001209 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, true, entityID); metricInfo != nil { // upstream
1210 metricInfoSlice = append(metricInfoSlice, metricInfo)
1211 }
1212 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, false, entityID); metricInfo != nil { // downstream
1213 metricInfoSlice = append(metricInfoSlice, metricInfo)
1214 }
1215 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001216 case EthernetUniHistoryName:
1217 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 -08001218 for _, entityID := range copyOfEntityIDs {
1219 if metricInfo := mm.collectEthernetUniHistoryData(ctx, entityID); metricInfo != nil { // upstream
1220 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001221 }
1222 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001223
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001224 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001225 for _, entityID := range copyOfEntityIDs {
1226 if metricInfo := mm.collectFecHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001227 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001228 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001229 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001230 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001231 for _, entityID := range copyOfEntityIDs {
1232 if metricInfo := mm.collectGemHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001233 metricInfoSlice = append(metricInfoSlice, metricInfo)
1234 }
1235 }
1236
Girish Gowdrae0140f02021-02-02 16:55:09 -08001237 default:
1238 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1239 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001240 mm.handleMetricsPublish(ctx, n, metricInfoSlice)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001241 }
1242 // Does not matter we send success or failure here.
1243 // Those PMs that we failed to collect data will be attempted to collect again in the next PM collection cycle (assuming
1244 // we have not exceed max attempts to collect the PM data)
1245 go func() {
1246 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1247 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1248 }
1249 }()
1250}
1251
Girish Gowdra0e533642021-03-02 22:02:51 -08001252// nolint: gocyclo
Girish Gowdrae0140f02021-02-02 16:55:09 -08001253func (mm *onuMetricsManager) l2PmFsmCreatePM(ctx context.Context, e *fsm.Event) {
1254 // Copy the l2PmToAdd for which we want to collect the metrics since l2PmToAdd can change dynamically
1255 mm.onuMetricsManagerLock.RLock()
1256 copyOfL2PmToAdd := make([]string, len(mm.l2PmToAdd))
1257 _ = copy(copyOfL2PmToAdd, mm.l2PmToAdd)
1258 mm.onuMetricsManagerLock.RUnlock()
1259
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001260 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 -08001261 for _, n := range copyOfL2PmToAdd {
1262 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001263 atLeastOneSuccess := false // flag indicates if at least one ME instance of the PM was successfully created.
1264 cnt := 0
Girish Gowdrae0140f02021-02-02 16:55:09 -08001265 switch n {
1266 case EthernetBridgeHistoryName:
1267 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1268 boolForDirection = append(boolForDirection, true, false)
1269 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1270 for _, direction := range boolForDirection {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001271 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1272 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1273 entityID := macBridgePortAniEID + uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001274 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1275 inner1:
1276 // retry L2PmCreateAttempts times to create the instance of PM
1277 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1278 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001279 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, true, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001280 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetFramePerformanceMonitoringHistoryData"); resp {
1281 atLeastOneSuccess = true
1282 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1283 break inner1
1284 }
1285 }
1286 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1287 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001288 }
1289 }
1290 }
1291 case EthernetUniHistoryName:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001292 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1293 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
Girish Gowdra0e533642021-03-02 22:02:51 -08001294 // Attach the EthernetPerformanceMonitoringHistoryData ME to PPTP port instance
Girish Gowdrae0140f02021-02-02 16:55:09 -08001295 entityID := uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001296 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1297 inner2:
1298 // retry L2PmCreateAttempts times to create the instance of PM
1299 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1300 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001301 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001302 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetPerformanceMonitoringHistoryData"); resp {
1303 atLeastOneSuccess = true
1304 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1305 break inner2
1306 }
1307 }
1308 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1309 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001310 }
1311 }
1312 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001313 case FecHistoryName:
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001314 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001315 // Attach the FecPerformanceMonitoringHistoryData ME to the ANI-G ME instance
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001316 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001317 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, anigInstID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001318 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdd) // TODO: ignore error for now
1319 inner3:
1320 // retry L2PmCreateAttempts times to create the instance of PM
1321 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1322 if resp = mm.waitForResponseOrTimeout(ctx, true, anigInstID, "FecPerformanceMonitoringHistoryData"); resp {
1323 atLeastOneSuccess = true
1324 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdded) // TODO: ignore error for now
1325 break inner3
1326 }
1327 }
1328 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1329 _ = mm.updatePmData(ctx, n, anigInstID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001330 }
1331 }
1332 case GemPortHistoryName:
1333
1334 mm.onuMetricsManagerLock.RLock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001335 copyOfGemPortInstIDsToAdd := make([]uint16, len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd))
1336 _ = copy(copyOfGemPortInstIDsToAdd, mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001337 mm.onuMetricsManagerLock.RUnlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001338
1339 if len(copyOfGemPortInstIDsToAdd) == 0 {
1340 // If there are no gemport history MEs to be created, just skip further processing
1341 // Otherwise down below (after 'switch' case handling) we assume the ME creation failed because resp and atLeastOneSuccess flag are false.
1342 // Normally there are no GemPortHistory MEs to create at start up. They come in only after provisioning service on the ONU.
1343 mm.onuMetricsManagerLock.Lock()
1344 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1345 mm.onuMetricsManagerLock.Unlock()
1346 continue
1347 }
1348
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001349 for _, v := range copyOfGemPortInstIDsToAdd {
1350 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001351 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, v)
Girish Gowdra0e533642021-03-02 22:02:51 -08001352 _ = mm.updatePmData(ctx, n, v, cPmAdd) // TODO: ignore error for now
1353 inner4:
1354 // retry L2PmCreateAttempts times to create the instance of PM
1355 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1356 if resp = mm.waitForResponseOrTimeout(ctx, true, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); resp {
1357 atLeastOneSuccess = true
1358 _ = mm.updatePmData(ctx, n, v, cPmAdded) // TODO: ignore error for now
1359 break inner4
1360 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001361 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001362 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1363 _ = mm.updatePmData(ctx, n, v, cPmRemoved) // TODO: ignore error for now
1364 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001365 }
1366
Girish Gowdrae0140f02021-02-02 16:55:09 -08001367 default:
1368 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1369 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001370 // 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
1371 if atLeastOneSuccess {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001372 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001373 mm.activeL2Pms = mm.appendIfMissingString(mm.activeL2Pms, n)
1374 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1375 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 -08001376 mm.onuMetricsManagerLock.Unlock()
1377 } else {
Girish Gowdra0e533642021-03-02 22:02:51 -08001378 // 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 -08001379 // and also remove it from l2PmToAdd slice so that we do not try to create the PM ME anymore
1380 mm.onuMetricsManagerLock.Lock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001381 logger.Debugw(ctx, "exceeded-max-add-retry-attempts--disabling-group", log.Fields{"groupName": n})
1382 mm.groupMetricMap[n].enabled = false
1383 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001384
Girish Gowdrae0140f02021-02-02 16:55:09 -08001385 logger.Warnw(ctx, "state create pm - failed to create pm",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001386 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
Girish Gowdra0e533642021-03-02 22:02:51 -08001387 "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001388 mm.onuMetricsManagerLock.Unlock()
1389 }
1390 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001391 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 -08001392 // Does not matter we send success or failure here.
1393 // Those PMs that we failed to create will be attempted to create again in the next PM creation cycle (assuming
1394 // we have not exceed max attempts to create the PM ME)
1395 go func() {
1396 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1397 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1398 }
1399 }()
1400}
1401
Girish Gowdra0e533642021-03-02 22:02:51 -08001402// nolint: gocyclo
Girish Gowdrae0140f02021-02-02 16:55:09 -08001403func (mm *onuMetricsManager) l2PmFsmDeletePM(ctx context.Context, e *fsm.Event) {
1404 // Copy the l2PmToDelete for which we want to collect the metrics since l2PmToDelete can change dynamically
1405 mm.onuMetricsManagerLock.RLock()
1406 copyOfL2PmToDelete := make([]string, len(mm.l2PmToDelete))
1407 _ = copy(copyOfL2PmToDelete, mm.l2PmToDelete)
1408 mm.onuMetricsManagerLock.RUnlock()
1409
1410 logger.Debugw(ctx, "state delete pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": mm.l2PmToDelete})
1411 for _, n := range copyOfL2PmToDelete {
1412 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001413 cnt := 0
1414 atLeastOneDeleteFailure := false
1415
1416 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1417 mm.onuMetricsManagerLock.RLock()
1418 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1419 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1420 mm.onuMetricsManagerLock.RUnlock()
1421
1422 if len(copyOfEntityIDs) == 0 {
1423 // if there are no enityIDs to remove for the PM ME just clear the PM name entry from cache and continue
1424 mm.onuMetricsManagerLock.Lock()
1425 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1426 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1427 logger.Debugw(ctx, "success-resp", log.Fields{"pm-name": n, "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1428 mm.onuMetricsManagerLock.Unlock()
1429 continue
1430 }
1431 logger.Debugw(ctx, "entities to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n, "entityIDs": copyOfEntityIDs})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001432 switch n {
1433 case EthernetBridgeHistoryName:
1434 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1435 boolForDirection = append(boolForDirection, true, false)
1436 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1437 for _, direction := range boolForDirection {
Girish Gowdra0e533642021-03-02 22:02:51 -08001438 for _, entityID := range copyOfEntityIDs {
1439 inner1:
1440 // retry L2PmDeleteAttempts times to delete the instance of PM
1441 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1442 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001443 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001444 _ = mm.updatePmData(ctx, n, entityID, cPmRemove) // TODO: ignore error for now
1445 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1446 atLeastOneDeleteFailure = true
1447 } else {
1448 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1449 break inner1
1450 }
1451 }
1452 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1453 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001454 }
1455 }
1456 }
1457 case EthernetUniHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001458 for _, entityID := range copyOfEntityIDs {
1459 inner2:
1460 // retry L2PmDeleteAttempts times to delete the instance of PM
1461 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001462 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001463 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001464 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
Girish Gowdra0e533642021-03-02 22:02:51 -08001465 atLeastOneDeleteFailure = true
1466 } else {
1467 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001468 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001469 }
1470 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001471 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1472 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1473 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001474 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001475 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001476 for _, entityID := range copyOfEntityIDs {
1477 inner3:
1478 // retry L2PmDeleteAttempts times to delete the instance of PM
1479 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1480 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001481 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001482 if resp := mm.waitForResponseOrTimeout(ctx, false, entityID, "FecPerformanceMonitoringHistoryData"); !resp {
1483 atLeastOneDeleteFailure = true
1484 } else {
1485 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1486 break inner3
1487 }
1488 }
1489 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1490 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001491 }
1492 }
1493 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001494 for _, entityID := range copyOfEntityIDs {
1495 inner4:
1496 // retry L2PmDeleteAttempts times to delete the instance of PM
1497 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1498 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001499 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001500 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1501 atLeastOneDeleteFailure = true
1502 } else {
1503 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1504 break inner4
1505 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001506 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001507 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1508 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1509 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001510 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001511 default:
1512 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1513 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001514 // If we could not completely clean up the PM ME then just give up.
1515 if atLeastOneDeleteFailure {
1516 logger.Warnw(ctx, "state delete pm - failed to delete at least one instance of the PM ME",
1517 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
1518 "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1519 mm.onuMetricsManagerLock.Lock()
1520 logger.Debugw(ctx, "exceeded-max-delete-retry-attempts--disabling-group", log.Fields{"groupName": n})
1521 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1522 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1523 mm.groupMetricMap[n].enabled = false
1524 mm.onuMetricsManagerLock.Unlock()
1525 } else { // success case
Girish Gowdrae0140f02021-02-02 16:55:09 -08001526 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001527 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1528 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1529 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 -08001530 mm.onuMetricsManagerLock.Unlock()
1531 }
1532 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001533 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 -08001534 // Does not matter we send success or failure here.
1535 // Those PMs that we failed to delete will be attempted to create again in the next PM collection cycle
1536 go func() {
1537 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1538 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1539 }
1540 }()
1541}
1542
1543// ** L2 PM FSM Handlers end **
1544
1545// syncTime synchronizes time with the ONU to establish a 15 min boundary for PM collection and reporting.
1546func (mm *onuMetricsManager) syncTime(ctx context.Context) error {
Girish Gowdra0b235842021-03-09 13:06:46 -08001547 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 -08001548 logger.Errorw(ctx, "cannot send sync time request", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1549 return err
1550 }
1551
1552 select {
Girish Gowdra0b235842021-03-09 13:06:46 -08001553 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001554 logger.Errorf(ctx, "timed out waiting for sync time response from onu", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1555 return fmt.Errorf("timed-out-waiting-for-sync-time-response-%v", mm.pDeviceHandler.deviceID)
1556 case syncTimeRes := <-mm.syncTimeResponseChan:
1557 if !syncTimeRes {
1558 return fmt.Errorf("failed-to-sync-time-%v", mm.pDeviceHandler.deviceID)
1559 }
1560 logger.Infow(ctx, "sync time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1561 return nil
1562 }
1563}
1564
1565func (mm *onuMetricsManager) collectEthernetFramePerformanceMonitoringHistoryData(ctx context.Context, upstream bool, entityID uint16) *voltha.MetricInformation {
1566 var mEnt *me.ManagedEntity
1567 var omciErr me.OmciErrors
1568 var classID me.ClassID
1569 var meAttributes me.AttributeValueMap
1570 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1571 meParam := me.ParamData{EntityID: entityID}
1572 if upstream {
1573 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataUpstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1574 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1575 return nil
1576 }
1577 classID = me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID
1578 } else {
1579 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataDownstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1580 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1581 return nil
1582 }
1583 classID = me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID
1584 }
1585
Girish Gowdrae0140f02021-02-02 16:55:09 -08001586 intervalEndTime := -1
1587 ethPMHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001588 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethPMHistData, &intervalEndTime); err != nil {
1589 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001590 }
1591
1592 // Populate some relevant context for the EthernetFramePerformanceMonitoringHistoryData PM
1593 ethPMHistData["class_id"] = float32(classID)
1594 ethPMHistData["interval_end_time"] = float32(intervalEndTime)
1595 ethPMHistData["parent_class_id"] = float32(me.MacBridgeConfigurationDataClassID) // EthernetFramePerformanceMonitoringHistoryData is attached to MBPCD ME
1596 ethPMHistData["parent_entity_id"] = float32(entityID)
1597 if upstream {
1598 ethPMHistData["upstream"] = float32(1)
1599 } else {
1600 ethPMHistData["upstream"] = float32(0)
1601 }
1602
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001603 metricInfo := mm.populateOnuMetricInfo(EthernetBridgeHistoryName, ethPMHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001604
Girish Gowdrae0140f02021-02-02 16:55:09 -08001605 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData successful",
1606 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream, "metricInfo": metricInfo})
1607 return &metricInfo
1608}
1609
1610func (mm *onuMetricsManager) collectEthernetUniHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1611 var mEnt *me.ManagedEntity
1612 var omciErr me.OmciErrors
1613 var classID me.ClassID
1614 var meAttributes me.AttributeValueMap
1615 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1616 meParam := me.ParamData{EntityID: entityID}
1617 if mEnt, omciErr = me.NewEthernetPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1618 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1619 return nil
1620 }
1621 classID = me.EthernetPerformanceMonitoringHistoryDataClassID
1622
Girish Gowdrae0140f02021-02-02 16:55:09 -08001623 intervalEndTime := -1
1624 ethUniHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001625 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethUniHistData, &intervalEndTime); err != nil {
1626 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001627 }
1628
1629 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1630 ethUniHistData["class_id"] = float32(classID)
1631 ethUniHistData["interval_end_time"] = float32(intervalEndTime)
1632
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001633 metricInfo := mm.populateOnuMetricInfo(EthernetUniHistoryName, ethUniHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001634
Girish Gowdrae0140f02021-02-02 16:55:09 -08001635 logger.Debugw(ctx, "collecting data for EthernetPerformanceMonitoringHistoryData successful",
1636 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1637 return &metricInfo
1638}
1639
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001640func (mm *onuMetricsManager) collectFecHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1641 var mEnt *me.ManagedEntity
1642 var omciErr me.OmciErrors
1643 var classID me.ClassID
1644 var meAttributes me.AttributeValueMap
1645 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1646 meParam := me.ParamData{EntityID: entityID}
1647 if mEnt, omciErr = me.NewFecPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1648 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1649 return nil
1650 }
1651 classID = me.FecPerformanceMonitoringHistoryDataClassID
1652
1653 intervalEndTime := -1
1654 fecHistData := make(map[string]float32)
1655 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, fecHistData, &intervalEndTime); err != nil {
1656 return nil
1657 }
1658
1659 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1660 fecHistData["class_id"] = float32(classID)
1661 fecHistData["interval_end_time"] = float32(intervalEndTime)
1662
1663 metricInfo := mm.populateOnuMetricInfo(FecHistoryName, fecHistData)
1664
1665 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData successful",
1666 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1667 return &metricInfo
1668}
1669
1670func (mm *onuMetricsManager) collectGemHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1671 var mEnt *me.ManagedEntity
1672 var omciErr me.OmciErrors
1673 var classID me.ClassID
1674 var meAttributes me.AttributeValueMap
1675 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1676 meParam := me.ParamData{EntityID: entityID}
1677 if mEnt, omciErr = me.NewGemPortNetworkCtpPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1678 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1679 return nil
1680 }
1681 classID = me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID
1682
1683 intervalEndTime := -1
1684 gemHistData := make(map[string]float32)
1685 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, gemHistData, &intervalEndTime); err != nil {
1686 return nil
1687 }
1688
1689 // Populate some relevant context for the GemPortNetworkCtpPerformanceMonitoringHistoryData PM
1690 gemHistData["class_id"] = float32(classID)
1691 gemHistData["interval_end_time"] = float32(intervalEndTime)
1692
1693 metricInfo := mm.populateOnuMetricInfo(GemPortHistoryName, gemHistData)
1694
1695 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData successful",
1696 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1697 return &metricInfo
1698}
1699
Girish Gowdrae0140f02021-02-02 16:55:09 -08001700// nolint: gocyclo
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001701func (mm *onuMetricsManager) populateEthernetBridgeHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
Girish Gowdrae0140f02021-02-02 16:55:09 -08001702 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001703 upstream := false
1704 if classID == me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID {
1705 upstream = true
1706 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001707 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1708 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1709 requestedAttributes["IntervalEndTime"] = 0
1710 }
Girish Gowdra0b235842021-03-09 13:06:46 -08001711 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001712 select {
1713 case meAttributes = <-mm.l2PmChan:
1714 logger.Debugw(ctx, "received ethernet pm history data metrics",
1715 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
Girish Gowdra0b235842021-03-09 13:06:46 -08001716 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001717 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet pm history data",
1718 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1719 // The metrics will be empty in this case
1720 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-bridge-history-%v", mm.pDeviceHandler.deviceID)
1721 }
1722 // 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 -08001723 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1724 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 -08001725 }
1726 }
1727 for k := range EthernetBridgeHistory {
1728 // populate ethPMHistData only if metric key not already present (or populated), since it is possible that we populate
1729 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1730 if _, ok := ethPMHistData[k]; !ok {
1731 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001732 case "entity_id":
1733 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1734 ethPMHistData[k] = float32(val.(uint16))
1735 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001736 case "drop_events":
1737 if val, ok := meAttributes["DropEvents"]; ok && val != nil {
1738 ethPMHistData[k] = float32(val.(uint32))
1739 }
1740 case "octets":
1741 if val, ok := meAttributes["Octets"]; ok && val != nil {
1742 ethPMHistData[k] = float32(val.(uint32))
1743 }
1744 case "packets":
1745 if val, ok := meAttributes["Packets"]; ok && val != nil {
1746 ethPMHistData[k] = float32(val.(uint32))
1747 }
1748 case "broadcast_packets":
1749 if val, ok := meAttributes["BroadcastPackets"]; ok && val != nil {
1750 ethPMHistData[k] = float32(val.(uint32))
1751 }
1752 case "multicast_packets":
1753 if val, ok := meAttributes["MulticastPackets"]; ok && val != nil {
1754 ethPMHistData[k] = float32(val.(uint32))
1755 }
1756 case "crc_errored_packets":
1757 if val, ok := meAttributes["CrcErroredPackets"]; ok && val != nil {
1758 ethPMHistData[k] = float32(val.(uint32))
1759 }
1760 case "undersize_packets":
1761 if val, ok := meAttributes["UndersizePackets"]; ok && val != nil {
1762 ethPMHistData[k] = float32(val.(uint32))
1763 }
1764 case "oversize_packets":
1765 if val, ok := meAttributes["OversizePackets"]; ok && val != nil {
1766 ethPMHistData[k] = float32(val.(uint32))
1767 }
1768 case "64_octets":
1769 if val, ok := meAttributes["Packets64Octets"]; ok && val != nil {
1770 ethPMHistData[k] = float32(val.(uint32))
1771 }
1772 case "65_to_127_octets":
1773 if val, ok := meAttributes["Packets65To127Octets"]; ok && val != nil {
1774 ethPMHistData[k] = float32(val.(uint32))
1775 }
1776 case "128_to_255_octets":
1777 if val, ok := meAttributes["Packets128To255Octets"]; ok && val != nil {
1778 ethPMHistData[k] = float32(val.(uint32))
1779 }
1780 case "256_to_511_octets":
1781 if val, ok := meAttributes["Packets256To511Octets"]; ok && val != nil {
1782 ethPMHistData[k] = float32(val.(uint32))
1783 }
1784 case "512_to_1023_octets":
1785 if val, ok := meAttributes["Packets512To1023Octets"]; ok && val != nil {
1786 ethPMHistData[k] = float32(val.(uint32))
1787 }
1788 case "1024_to_1518_octets":
1789 if val, ok := meAttributes["Packets1024To1518Octets"]; ok && val != nil {
1790 ethPMHistData[k] = float32(val.(uint32))
1791 }
1792 default:
1793 // do nothing
1794 }
1795 }
1796 }
1797 return nil
1798}
1799
1800// nolint: gocyclo
1801func (mm *onuMetricsManager) populateEthernetUniHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1802 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMUniHistData map[string]float32, intervalEndTime *int) error {
1803 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1804 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1805 requestedAttributes["IntervalEndTime"] = 0
1806 }
Girish Gowdra0b235842021-03-09 13:06:46 -08001807 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001808 select {
1809 case meAttributes = <-mm.l2PmChan:
1810 logger.Debugw(ctx, "received ethernet uni history data metrics",
1811 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Girish Gowdra0b235842021-03-09 13:06:46 -08001812 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001813 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet uni history data",
1814 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1815 // The metrics will be empty in this case
1816 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-uni-history-%v", mm.pDeviceHandler.deviceID)
1817 }
1818 // 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 -08001819 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1820 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 -08001821 }
1822 }
1823 for k := range EthernetUniHistory {
1824 // populate ethPMUniHistData only if metric key not already present (or populated), since it is possible that we populate
1825 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1826 if _, ok := ethPMUniHistData[k]; !ok {
1827 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001828 case "entity_id":
1829 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1830 ethPMUniHistData[k] = float32(val.(uint16))
1831 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001832 case "fcs_errors":
1833 if val, ok := meAttributes["FcsErrors"]; ok && val != nil {
1834 ethPMUniHistData[k] = float32(val.(uint32))
1835 }
1836 case "excessive_collision_counter":
1837 if val, ok := meAttributes["ExcessiveCollisionCounter"]; ok && val != nil {
1838 ethPMUniHistData[k] = float32(val.(uint32))
1839 }
1840 case "late_collision_counter":
1841 if val, ok := meAttributes["LateCollisionCounter"]; ok && val != nil {
1842 ethPMUniHistData[k] = float32(val.(uint32))
1843 }
1844 case "frames_too_long":
1845 if val, ok := meAttributes["FramesTooLong"]; ok && val != nil {
1846 ethPMUniHistData[k] = float32(val.(uint32))
1847 }
1848 case "buffer_overflows_on_rx":
1849 if val, ok := meAttributes["BufferOverflowsOnReceive"]; ok && val != nil {
1850 ethPMUniHistData[k] = float32(val.(uint32))
1851 }
1852 case "buffer_overflows_on_tx":
1853 if val, ok := meAttributes["BufferOverflowsOnTransmit"]; ok && val != nil {
1854 ethPMUniHistData[k] = float32(val.(uint32))
1855 }
1856 case "single_collision_frame_counter":
1857 if val, ok := meAttributes["SingleCollisionFrameCounter"]; ok && val != nil {
1858 ethPMUniHistData[k] = float32(val.(uint32))
1859 }
1860 case "multiple_collisions_frame_counter":
1861 if val, ok := meAttributes["MultipleCollisionsFrameCounter"]; ok && val != nil {
1862 ethPMUniHistData[k] = float32(val.(uint32))
1863 }
1864 case "sqe_counter":
1865 if val, ok := meAttributes["SqeCounter"]; ok && val != nil {
1866 ethPMUniHistData[k] = float32(val.(uint32))
1867 }
1868 case "deferred_tx_counter":
1869 if val, ok := meAttributes["DeferredTransmissionCounter"]; ok && val != nil {
1870 ethPMUniHistData[k] = float32(val.(uint32))
1871 }
1872 case "internal_mac_tx_error_counter":
1873 if val, ok := meAttributes["InternalMacTransmitErrorCounter"]; ok && val != nil {
1874 ethPMUniHistData[k] = float32(val.(uint32))
1875 }
1876 case "carrier_sense_error_counter":
1877 if val, ok := meAttributes["CarrierSenseErrorCounter"]; ok && val != nil {
1878 ethPMUniHistData[k] = float32(val.(uint32))
1879 }
1880 case "alignment_error_counter":
1881 if val, ok := meAttributes["AlignmentErrorCounter"]; ok && val != nil {
1882 ethPMUniHistData[k] = float32(val.(uint32))
1883 }
1884 case "internal_mac_rx_error_counter":
1885 if val, ok := meAttributes["InternalMacReceiveErrorCounter"]; ok && val != nil {
1886 ethPMUniHistData[k] = float32(val.(uint32))
1887 }
1888 default:
1889 // do nothing
1890 }
1891 }
1892 }
1893 return nil
1894}
1895
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001896// nolint: gocyclo
1897func (mm *onuMetricsManager) populateFecHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1898 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, fecHistData map[string]float32, intervalEndTime *int) error {
1899 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1900 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1901 requestedAttributes["IntervalEndTime"] = 0
1902 }
Girish Gowdra0b235842021-03-09 13:06:46 -08001903 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001904 select {
1905 case meAttributes = <-mm.l2PmChan:
1906 logger.Debugw(ctx, "received fec history data metrics",
1907 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Girish Gowdra0b235842021-03-09 13:06:46 -08001908 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001909 logger.Errorw(ctx, "timeout waiting for omci-get response for fec history data",
1910 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1911 // The metrics will be empty in this case
1912 return fmt.Errorf("timeout-during-l2-pm-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1913 }
1914 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1915 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1916 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1917 }
1918 }
1919 for k := range FecHistory {
1920 // populate fecHistData only if metric key not already present (or populated), since it is possible that we populate
1921 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1922 if _, ok := fecHistData[k]; !ok {
1923 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001924 case "entity_id":
1925 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1926 fecHistData[k] = float32(val.(uint16))
1927 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001928 case "corrected_bytes":
1929 if val, ok := meAttributes["CorrectedBytes"]; ok && val != nil {
1930 fecHistData[k] = float32(val.(uint32))
1931 }
1932 case "corrected_code_words":
1933 if val, ok := meAttributes["CorrectedCodeWords"]; ok && val != nil {
1934 fecHistData[k] = float32(val.(uint32))
1935 }
1936 case "uncorrectable_code_words":
1937 if val, ok := meAttributes["UncorrectableCodeWords"]; ok && val != nil {
1938 fecHistData[k] = float32(val.(uint32))
1939 }
1940 case "total_code_words":
1941 if val, ok := meAttributes["TotalCodeWords"]; ok && val != nil {
1942 fecHistData[k] = float32(val.(uint32))
1943 }
1944 case "fec_seconds":
1945 if val, ok := meAttributes["FecSeconds"]; ok && val != nil {
1946 fecHistData[k] = float32(val.(uint16))
1947 }
1948 default:
1949 // do nothing
1950 }
1951 }
1952 }
1953 return nil
1954}
1955
1956// nolint: gocyclo
1957func (mm *onuMetricsManager) populateGemPortMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1958 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, gemPortHistData map[string]float32, intervalEndTime *int) error {
1959 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1960 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1961 requestedAttributes["IntervalEndTime"] = 0
1962 }
Girish Gowdra0b235842021-03-09 13:06:46 -08001963 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001964 select {
1965 case meAttributes = <-mm.l2PmChan:
1966 logger.Debugw(ctx, "received gem port history data metrics",
1967 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Girish Gowdra0b235842021-03-09 13:06:46 -08001968 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001969 logger.Errorw(ctx, "timeout waiting for omci-get response for gem port history data",
1970 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1971 // The metrics will be empty in this case
1972 return fmt.Errorf("timeout-during-l2-pm-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1973 }
1974 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1975 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1976 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1977 }
1978 }
1979 for k := range GemPortHistory {
1980 // populate gemPortHistData only if metric key not already present (or populated), since it is possible that we populate
1981 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1982 if _, ok := gemPortHistData[k]; !ok {
1983 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001984 case "entity_id":
1985 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1986 gemPortHistData[k] = float32(val.(uint16))
1987 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001988 case "transmitted_gem_frames":
1989 if val, ok := meAttributes["TransmittedGemFrames"]; ok && val != nil {
1990 gemPortHistData[k] = float32(val.(uint32))
1991 }
1992 case "received_gem_frames":
1993 if val, ok := meAttributes["ReceivedGemFrames"]; ok && val != nil {
1994 gemPortHistData[k] = float32(val.(uint32))
1995 }
1996 case "received_payload_bytes":
1997 if val, ok := meAttributes["ReceivedPayloadBytes"]; ok && val != nil {
1998 gemPortHistData[k] = float32(val.(uint64))
1999 }
2000 case "transmitted_payload_bytes":
2001 if val, ok := meAttributes["TransmittedPayloadBytes"]; ok && val != nil {
2002 gemPortHistData[k] = float32(val.(uint64))
2003 }
2004 case "encryption_key_errors":
2005 if val, ok := meAttributes["EncryptionKeyErrors"]; ok && val != nil {
2006 gemPortHistData[k] = float32(val.(uint32))
2007 }
2008 default:
2009 // do nothing
2010 }
2011 }
2012 }
2013 return nil
2014}
2015
Girish Gowdrae0140f02021-02-02 16:55:09 -08002016func (mm *onuMetricsManager) handleOmciCreateResponseMessage(ctx context.Context, msg OmciMessage) error {
2017 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
2018 if msgLayer == nil {
2019 logger.Errorw(ctx, "omci Msg layer could not be detected for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2020 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2021 }
2022 msgObj, msgOk := msgLayer.(*omci.CreateResponse)
2023 if !msgOk {
2024 logger.Errorw(ctx, "omci Msg layer could not be assigned for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2025 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2026 }
2027 logger.Debugw(ctx, "OMCI create response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2028 switch msgObj.EntityClass {
2029 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2030 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002031 me.EthernetPerformanceMonitoringHistoryDataClassID,
2032 me.FecPerformanceMonitoringHistoryDataClassID,
2033 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002034 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
2035 if msgObj.Result == me.Success || msgObj.Result == me.InstanceExists {
2036 mm.l2PmCreateOrDeleteResponseChan <- true
2037 } else {
2038 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2039 mm.l2PmCreateOrDeleteResponseChan <- false
2040 }
2041 return nil
2042 default:
2043 logger.Errorw(ctx, "unhandled omci create response message",
2044 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2045 }
2046 return fmt.Errorf("unhandled-omci-create-response-message-%v", mm.pDeviceHandler.deviceID)
2047}
2048
2049func (mm *onuMetricsManager) handleOmciDeleteResponseMessage(ctx context.Context, msg OmciMessage) error {
2050 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDeleteResponse)
2051 if msgLayer == nil {
2052 logger.Errorw(ctx, "omci Msg layer could not be detected for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2053 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2054 }
2055 msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
2056 if !msgOk {
2057 logger.Errorw(ctx, "omci Msg layer could not be assigned for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2058 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2059 }
2060 logger.Debugw(ctx, "OMCI delete response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2061 switch msgObj.EntityClass {
2062 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2063 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002064 me.EthernetPerformanceMonitoringHistoryDataClassID,
2065 me.FecPerformanceMonitoringHistoryDataClassID,
2066 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002067 // If the result is me.UnknownInstance it means the entity was already deleted. It is ok handled that as success
2068 if msgObj.Result == me.Success || msgObj.Result == me.UnknownInstance {
2069 mm.l2PmCreateOrDeleteResponseChan <- true
2070 } else {
2071 logger.Warnw(ctx, "failed to delete me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2072 mm.l2PmCreateOrDeleteResponseChan <- false
2073 }
2074 return nil
2075 default:
2076 logger.Errorw(ctx, "unhandled omci delete response message",
2077 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2078 }
2079 return fmt.Errorf("unhandled-omci-delete-response-message-%v", mm.pDeviceHandler.deviceID)
2080}
2081
2082func (mm *onuMetricsManager) generateTicks(ctx context.Context) {
2083 for {
2084 select {
2085 case <-time.After(L2PmCollectionInterval * time.Second):
2086 go func() {
2087 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
2088 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2089 }
2090 }()
2091 case <-mm.stopTicks:
2092 logger.Infow(ctx, "stopping ticks", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2093 return
2094 }
2095 }
2096}
2097
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002098func (mm *onuMetricsManager) handleMetricsPublish(ctx context.Context, metricName string, metricInfoSlice []*voltha.MetricInformation) {
2099 // Publish metrics if it is valid
2100 if metricInfoSlice != nil {
2101 mm.publishMetrics(ctx, metricInfoSlice)
2102 } else {
2103 // If collectAttempts exceeds L2PmCollectAttempts then remove it from activeL2Pms
2104 // slice so that we do not collect data from that PM ME anymore
2105 mm.onuMetricsManagerLock.Lock()
2106 mm.groupMetricMap[metricName].collectAttempts++
2107 if mm.groupMetricMap[metricName].collectAttempts > L2PmCollectAttempts {
2108 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, metricName)
2109 }
2110 logger.Warnw(ctx, "state collect data - no metrics collected",
2111 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName, "collectAttempts": mm.groupMetricMap[metricName].collectAttempts})
2112 mm.onuMetricsManagerLock.Unlock()
2113 }
2114}
2115
2116func (mm *onuMetricsManager) populateGroupSpecificMetrics(ctx context.Context, mEnt *me.ManagedEntity, classID me.ClassID, entityID uint16,
2117 meAttributes me.AttributeValueMap, data map[string]float32, intervalEndTime *int) error {
2118 var grpFunc groupMetricPopulateFunc
2119 switch classID {
2120 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID, me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID:
2121 grpFunc = mm.populateEthernetBridgeHistoryMetrics
2122 case me.EthernetPerformanceMonitoringHistoryDataClassID:
2123 grpFunc = mm.populateEthernetUniHistoryMetrics
2124 case me.FecPerformanceMonitoringHistoryDataClassID:
2125 grpFunc = mm.populateFecHistoryMetrics
2126 case me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
2127 grpFunc = mm.populateGemPortMetrics
2128 default:
2129 return fmt.Errorf("unknown-classid-%v", classID)
2130 }
2131
2132 size := 0
2133 requestedAttributes := make(me.AttributeValueMap)
2134 for _, v := range mEnt.GetAttributeDefinitions() {
2135 if (v.Size + size) <= MaxL2PMGetPayLoadSize {
2136 requestedAttributes[v.Name] = v.DefValue
2137 size = v.Size + size
2138 } else { // We exceeded the allow omci get size
2139 // Let's collect the attributes via get now and collect remaining in the next iteration
2140 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2141 logger.Errorw(ctx, "error during metric collection",
2142 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2143 return err
2144 }
2145 size = 0 // reset size
2146 requestedAttributes = make(me.AttributeValueMap) // reset map
2147 }
2148 }
2149 // Collect the omci get attributes for the last bunch of attributes.
2150 if len(requestedAttributes) > 0 {
2151 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2152 logger.Errorw(ctx, "error during metric collection",
2153 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2154 return err
2155 }
2156 }
2157 return nil
2158}
2159
2160func (mm *onuMetricsManager) populateOnuMetricInfo(title string, data map[string]float32) voltha.MetricInformation {
2161 metricsContext := make(map[string]string)
2162 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
2163 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
2164 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
2165
2166 raisedTs := time.Now().Unix()
2167 mmd := voltha.MetricMetaData{
2168 Title: title,
2169 Ts: float64(raisedTs),
2170 Context: metricsContext,
2171 DeviceId: mm.pDeviceHandler.deviceID,
2172 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
2173 SerialNo: mm.pDeviceHandler.device.SerialNumber,
2174 }
2175
2176 // create slice of metrics given that there could be more than one VEIP instance
2177 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: data}
2178 return metricInfo
2179}
2180
2181func (mm *onuMetricsManager) updateAndValidateIntervalEndTime(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap, intervalEndTime *int) bool {
2182 valid := false
2183 if *intervalEndTime == -1 { // first time
2184 // Update the interval end time
2185 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2186 *intervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2187 valid = true
2188 }
2189 } else {
2190 var currIntervalEndTime int
2191 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2192 currIntervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2193 }
2194 if currIntervalEndTime != *intervalEndTime { // interval end time changed during metric collection
2195 logger.Errorw(ctx, "interval end time changed during metrics collection for ethernet pm history data",
2196 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID,
2197 "currIntervalEndTime": *intervalEndTime, "newIntervalEndTime": currIntervalEndTime})
2198 } else {
2199 valid = true
2200 }
2201 }
2202 return valid
2203}
2204
2205func (mm *onuMetricsManager) waitForResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassName string) bool {
2206 logger.Debugw(ctx, "waitForResponseOrTimeout", log.Fields{"create": create, "instID": instID, "meClassName": meClassName})
2207 select {
2208 case resp := <-mm.l2PmCreateOrDeleteResponseChan:
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002209 logger.Debugw(ctx, "received l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002210 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassName": meClassName, "instID": instID})
2211 return resp
Girish Gowdra0b235842021-03-09 13:06:46 -08002212 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002213 logger.Errorw(ctx, "timeout waiting for l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002214 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassName": meClassName, "instID": instID})
2215 }
2216 return false
2217}
2218
2219func (mm *onuMetricsManager) initializeGroupMetric(grpMtrcs map[string]voltha.PmConfig_PmType, grpName string, grpEnabled bool, grpFreq uint32) {
2220 var pmConfigSlice []*voltha.PmConfig
2221 for k, v := range grpMtrcs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002222 pmConfigSlice = append(pmConfigSlice,
2223 &voltha.PmConfig{
2224 Name: k,
2225 Type: v,
2226 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2227 SampleFreq: grpFreq})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002228 }
2229 groupMetric := voltha.PmGroupConfig{
2230 GroupName: grpName,
2231 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2232 GroupFreq: grpFreq,
2233 Metrics: pmConfigSlice,
2234 }
2235 mm.pDeviceHandler.pmConfigs.Groups = append(mm.pDeviceHandler.pmConfigs.Groups, &groupMetric)
2236
2237}
2238
2239func (mm *onuMetricsManager) initializeL2PmFsm(ctx context.Context, aCommChannel chan Message) error {
2240 mm.pAdaptFsm = NewAdapterFsm("L2PmFSM", mm.pDeviceHandler.deviceID, aCommChannel)
2241 if mm.pAdaptFsm == nil {
2242 logger.Errorw(ctx, "L2PMFsm AdapterFsm could not be instantiated!!", log.Fields{
2243 "device-id": mm.pDeviceHandler.deviceID})
2244 return fmt.Errorf("nil-adapter-fsm")
2245 }
2246 // L2 PM FSM related state machine
2247 mm.pAdaptFsm.pFsm = fsm.NewFSM(
2248 l2PmStNull,
2249 fsm.Events{
2250 {Name: l2PmEventInit, Src: []string{l2PmStNull}, Dst: l2PmStStarting},
2251 {Name: l2PmEventTick, Src: []string{l2PmStStarting}, Dst: l2PmStSyncTime},
2252 {Name: l2PmEventTick, Src: []string{l2PmStIdle, l2PmEventDeleteMe, l2PmEventAddMe}, Dst: l2PmStCollectData},
2253 {Name: l2PmEventSuccess, Src: []string{l2PmStSyncTime, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2254 {Name: l2PmEventFailure, Src: []string{l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2255 {Name: l2PmEventFailure, Src: []string{l2PmStSyncTime}, Dst: l2PmStSyncTime},
2256 {Name: l2PmEventAddMe, Src: []string{l2PmStIdle}, Dst: l2PmStCreatePmMe},
2257 {Name: l2PmEventDeleteMe, Src: []string{l2PmStIdle}, Dst: l2PmStDeletePmMe},
2258 {Name: l2PmEventStop, Src: []string{l2PmStNull, l2PmStStarting, l2PmStSyncTime, l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStNull},
2259 },
2260 fsm.Callbacks{
2261 "enter_state": func(e *fsm.Event) { mm.pAdaptFsm.logFsmStateChange(ctx, e) },
2262 "enter_" + l2PmStNull: func(e *fsm.Event) { mm.l2PMFsmNull(ctx, e) },
2263 "enter_" + l2PmStIdle: func(e *fsm.Event) { mm.l2PMFsmIdle(ctx, e) },
2264 "enter_" + l2PmStStarting: func(e *fsm.Event) { mm.l2PMFsmStarting(ctx, e) },
2265 "enter_" + l2PmStSyncTime: func(e *fsm.Event) { mm.l2PMFsmSyncTime(ctx, e) },
2266 "enter_" + l2PmStCollectData: func(e *fsm.Event) { mm.l2PmFsmCollectData(ctx, e) },
2267 "enter_" + l2PmStCreatePmMe: func(e *fsm.Event) { mm.l2PmFsmCreatePM(ctx, e) },
2268 "enter_" + l2PmStDeletePmMe: func(e *fsm.Event) { mm.l2PmFsmDeletePM(ctx, e) },
2269 },
2270 )
2271 return nil
2272}
2273
2274func (mm *onuMetricsManager) initializeAllGroupMetrics() {
2275 mm.pDeviceHandler.pmConfigs = &voltha.PmConfigs{}
2276 mm.pDeviceHandler.pmConfigs.Id = mm.pDeviceHandler.deviceID
2277 mm.pDeviceHandler.pmConfigs.DefaultFreq = DefaultMetricCollectionFrequency
2278 mm.pDeviceHandler.pmConfigs.Grouped = GroupMetricEnabled
2279 mm.pDeviceHandler.pmConfigs.FreqOverride = DefaultFrequencyOverrideEnabled
2280
2281 // Populate group metrics.
2282 // Lets populate irrespective of GroupMetricEnabled is true or not.
2283 // The group metrics collection will decided on this flag later
2284
2285 mm.initializeGroupMetric(OpticalPowerGroupMetrics, OpticalPowerGroupMetricName,
2286 OpticalPowerGroupMetricEnabled, OpticalPowerMetricGroupCollectionFrequency)
2287
2288 mm.initializeGroupMetric(UniStatusGroupMetrics, UniStatusGroupMetricName,
2289 UniStatusGroupMetricEnabled, UniStatusMetricGroupCollectionFrequency)
2290
2291 // classical l2 pm counter start
2292
2293 mm.initializeGroupMetric(EthernetBridgeHistory, EthernetBridgeHistoryName,
2294 EthernetBridgeHistoryEnabled, EthernetBridgeHistoryFrequency)
2295
2296 mm.initializeGroupMetric(EthernetUniHistory, EthernetUniHistoryName,
2297 EthernetUniHistoryEnabled, EthernetUniHistoryFrequency)
2298
2299 mm.initializeGroupMetric(FecHistory, FecHistoryName,
2300 FecHistoryEnabled, FecHistoryFrequency)
2301
2302 mm.initializeGroupMetric(GemPortHistory, GemPortHistoryName,
2303 GemPortHistoryEnabled, GemPortHistoryFrequency)
2304
2305 // classical l2 pm counter end
2306
2307 // Add standalone metric (if present) after this (will be added to dh.pmConfigs.Metrics)
2308}
2309
2310func (mm *onuMetricsManager) populateLocalGroupMetricData(ctx context.Context) {
2311 // Populate local group metric structures
2312 for _, g := range mm.pDeviceHandler.pmConfigs.Groups {
2313 mm.groupMetricMap[g.GroupName] = &groupMetric{
2314 groupName: g.GroupName,
2315 enabled: g.Enabled,
2316 frequency: g.GroupFreq,
2317 }
2318 switch g.GroupName {
2319 case OpticalPowerGroupMetricName:
2320 mm.groupMetricMap[g.GroupName].metricMap = OpticalPowerGroupMetrics
2321 case UniStatusGroupMetricName:
2322 mm.groupMetricMap[g.GroupName].metricMap = UniStatusGroupMetrics
2323 case EthernetBridgeHistoryName:
2324 mm.groupMetricMap[g.GroupName].metricMap = EthernetBridgeHistory
2325 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2326 case EthernetUniHistoryName:
2327 mm.groupMetricMap[g.GroupName].metricMap = EthernetUniHistory
2328 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2329 case FecHistoryName:
2330 mm.groupMetricMap[g.GroupName].metricMap = FecHistory
2331 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2332 case GemPortHistoryName:
2333 mm.groupMetricMap[g.GroupName].metricMap = GemPortHistory
2334 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2335 default:
2336 logger.Errorw(ctx, "unhandled-group-name", log.Fields{"groupName": g.GroupName})
2337 }
2338 }
2339
2340 // Populate local standalone metric structures
2341 for _, m := range mm.pDeviceHandler.pmConfigs.Metrics {
2342 mm.standaloneMetricMap[m.Name] = &standaloneMetric{
2343 metricName: m.Name,
2344 enabled: m.Enabled,
2345 frequency: m.SampleFreq,
2346 }
2347 switch m.Name {
2348 // None exist as of now. Add when available.
2349 default:
2350 logger.Errorw(ctx, "unhandled-metric-name", log.Fields{"metricName": m.Name})
2351 }
2352 }
2353}
2354
2355func (mm *onuMetricsManager) AddGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2356 mm.onuMetricsManagerLock.Lock()
2357 defer mm.onuMetricsManagerLock.Unlock()
2358 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002359 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002360 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002361 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002362
2363 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, GemPortHistoryName)
2364 // We do not need to remove from l2PmToDelete slice as we could have Add and Delete of
2365 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2366 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2367 // gemPortNCTPPerfHistInstToAdd slice
2368}
2369
2370func (mm *onuMetricsManager) RemoveGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2371 mm.onuMetricsManagerLock.Lock()
2372 defer mm.onuMetricsManagerLock.Unlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08002373 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002374 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002375 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002376
2377 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, GemPortHistoryName)
2378 // We do not need to remove from l2PmToAdd slice as we could have Add and Delete of
2379 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2380 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2381 // gemPortNCTPPerfHistInstToAdd slice
2382}
2383
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002384func (mm *onuMetricsManager) updateGemPortNTPInstanceToAddForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002385 if mm.pDeviceHandler.pOnuTP != nil {
2386 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002387 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002388 for _, v := range gemPortInstIDs {
2389 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002390 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002391 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002392 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002393 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002394 logger.Debugw(ctx, "updateGemPortNTPInstanceToAddForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002395 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, "gemToDel": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002396 }
2397}
2398
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002399func (mm *onuMetricsManager) updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002400 if mm.pDeviceHandler.pOnuTP != nil {
2401 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002402 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002403 for _, v := range gemPortInstIDs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002404 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002405 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002406 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002407 }
2408 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002409 logger.Debugw(ctx, "updateGemPortNTPInstanceToDeleteForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002410 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, "gemToDel": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
2411}
2412
2413// restorePmData restores any PM data available on the KV store to local cache
2414func (mm *onuMetricsManager) restorePmData(ctx context.Context) error {
2415 logger.Debugw(ctx, "restorePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2416 if mm.pmKvStore == nil {
2417 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2418 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2419 }
2420 var errorsList []error
2421 for groupName, group := range mm.groupMetricMap {
2422 group.pmMEData = &pmMEData{}
2423 Value, err := mm.pmKvStore.Get(ctx, groupName)
2424 if err == nil {
2425 if Value != nil {
2426 logger.Debugw(ctx, "PM data read",
2427 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2428 tmpBytes, _ := kvstore.ToByte(Value.Value)
2429
2430 if err = json.Unmarshal(tmpBytes, &group.pmMEData); err != nil {
2431 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2432 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-unmarshal-PM-data-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2433 continue
2434 }
2435 logger.Debugw(ctx, "restorePmData - success", log.Fields{"pmData": group.pmMEData, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2436 } else {
2437 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2438 continue
2439 }
2440 } else {
2441 logger.Errorw(ctx, "restorePmData - fail", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "err": err})
2442 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-read-from-KVstore-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2443 continue
2444 }
2445 }
2446 if len(errorsList) > 0 {
2447 return fmt.Errorf("errors-restoring-pm-data-for-one-or-more-groups--errors:%v", errorsList)
2448 }
2449 logger.Debugw(ctx, "restorePmData - complete success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2450 return nil
2451}
2452
2453// getPmData gets pmMEData from cache. Since we have write through cache implementation for pmMEData,
2454// the data must be available in cache.
2455// Note, it is expected that caller of this function manages the required synchronization (like using locks etc.).
2456func (mm *onuMetricsManager) getPmData(ctx context.Context, groupName string) (*pmMEData, error) {
2457 if grp, ok := mm.groupMetricMap[groupName]; ok {
2458 return grp.pmMEData, nil
2459 }
2460 // Data not in cache, try to fetch from kv store.
2461 data := &pmMEData{}
2462 if mm.pmKvStore == nil {
2463 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2464 return data, fmt.Errorf("pmKvStore not set. device-id - %s", mm.pDeviceHandler.deviceID)
2465 }
2466 Value, err := mm.pmKvStore.Get(ctx, groupName)
2467 if err == nil {
2468 if Value != nil {
2469 logger.Debugw(ctx, "PM data read",
2470 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2471 tmpBytes, _ := kvstore.ToByte(Value.Value)
2472
2473 if err = json.Unmarshal(tmpBytes, data); err != nil {
2474 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2475 return data, err
2476 }
2477 logger.Debugw(ctx, "PM data", log.Fields{"pmData": data, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2478 } else {
2479 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2480 return data, err
2481 }
2482 } else {
2483 logger.Errorw(ctx, "unable to read from KVstore", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2484 return data, err
2485 }
2486
2487 return data, nil
2488}
2489
2490// updatePmData update pmMEData to store. It is write through cache, i.e., write to cache first and then update store
2491func (mm *onuMetricsManager) updatePmData(ctx context.Context, groupName string, meInstanceID uint16, pmAction string) error {
2492 logger.Debugw(ctx, "updatePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "entityID": meInstanceID, "pmAction": pmAction})
2493 mm.onuMetricsManagerLock.Lock()
2494 defer mm.onuMetricsManagerLock.Unlock()
2495
2496 if mm.pmKvStore == nil {
2497 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2498 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2499 }
2500
2501 pmMEData, err := mm.getPmData(ctx, groupName)
2502 if err != nil || pmMEData == nil {
2503 // error already logged in called function.
2504 return err
2505 }
2506 switch pmAction {
2507 case cPmAdd:
2508 pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(pmMEData.InstancesToAdd, meInstanceID)
2509 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2510 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2511 case cPmAdded:
2512 pmMEData.InstancesActive = mm.appendIfMissingUnt16(pmMEData.InstancesActive, meInstanceID)
2513 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2514 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2515 case cPmRemove:
2516 pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(pmMEData.InstancesToDelete, meInstanceID)
2517 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2518 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2519 case cPmRemoved:
2520 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2521 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2522 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2523 default:
2524 logger.Errorw(ctx, "unknown pm action", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pmAction": pmAction, "groupName": groupName})
2525 return fmt.Errorf(fmt.Sprintf("unknown-pm-action-deviceid-%s-groupName-%s-pmaction-%s", mm.pDeviceHandler.deviceID, groupName, pmAction))
2526 }
2527 // write through cache
2528 mm.groupMetricMap[groupName].pmMEData = pmMEData
2529
2530 Value, err := json.Marshal(*pmMEData)
2531 if err != nil {
2532 logger.Errorw(ctx, "unable to marshal PM data", log.Fields{"groupName": groupName, "pmAction": pmAction, "pmData": *pmMEData, "err": err})
2533 return err
2534 }
2535 // Update back to kv store
2536 if err = mm.pmKvStore.Put(ctx, groupName, Value); err != nil {
2537 logger.Errorw(ctx, "unable to put PM data to kv store", log.Fields{"groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction, "err": err})
2538 return err
2539 }
2540 logger.Debugw(ctx, "updatePmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction})
2541
2542 return nil
2543}
2544
2545// clearPmGroupData cleans PM Group data from store
2546func (mm *onuMetricsManager) clearPmGroupData(ctx context.Context) error {
2547 mm.onuMetricsManagerLock.Lock()
2548 defer mm.onuMetricsManagerLock.Unlock()
2549 logger.Debugw(ctx, "clearPmGroupData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2550 if mm.pmKvStore == nil {
2551 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2552 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2553 }
2554
2555 for n := range mm.groupMetricMap {
2556 if err := mm.pmKvStore.Delete(ctx, n); err != nil {
2557 logger.Errorw(ctx, "clearPmGroupData - fail", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "groupName": n, "err": err})
2558 // do not abort this procedure. continue to delete next group.
2559 } else {
2560 logger.Debugw(ctx, "clearPmGroupData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": n})
2561 }
2562 }
2563
2564 return nil
2565}
2566
2567// clearAllPmData clears all PM data associated with the device from KV store
2568func (mm *onuMetricsManager) clearAllPmData(ctx context.Context) error {
2569 mm.onuMetricsManagerLock.Lock()
2570 defer mm.onuMetricsManagerLock.Unlock()
2571 logger.Debugw(ctx, "clearAllPmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2572 if mm.pmKvStore == nil {
2573 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2574 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2575 }
Holger Hildebrandt44a0d4f2021-03-18 14:00:54 +00002576 var value error
2577 for n := range mm.groupMetricMap {
2578 if err := mm.pmKvStore.Delete(ctx, n); err != nil {
2579 logger.Errorw(ctx, "clearPmGroupData - fail", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "groupName": n, "err": err})
2580 value = err
2581 // do not abort this procedure - continue to delete next group.
2582 } else {
2583 logger.Debugw(ctx, "clearPmGroupData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": n})
2584 }
Girish Gowdra0e533642021-03-02 22:02:51 -08002585 }
Holger Hildebrandt44a0d4f2021-03-18 14:00:54 +00002586 if value == nil {
2587 logger.Debugw(ctx, "clearAllPmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2588 }
2589 return value
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002590}
2591
2592func (mm *onuMetricsManager) appendIfMissingString(slice []string, n string) []string {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002593 for _, ele := range slice {
2594 if ele == n {
2595 return slice
2596 }
2597 }
2598 return append(slice, n)
2599}
2600
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002601func (mm *onuMetricsManager) removeIfFoundString(slice []string, n string) []string {
2602 for i, ele := range slice {
2603 if ele == n {
2604 return append(slice[:i], slice[i+1:]...)
2605 }
2606 }
2607 return slice
2608}
2609
2610func (mm *onuMetricsManager) appendIfMissingUnt16(slice []uint16, n uint16) []uint16 {
2611 for _, ele := range slice {
2612 if ele == n {
2613 return slice
2614 }
2615 }
2616 return append(slice, n)
2617}
2618
2619func (mm *onuMetricsManager) removeIfFoundUint16(slice []uint16, n uint16) []uint16 {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002620 for i, ele := range slice {
2621 if ele == n {
2622 return append(slice[:i], slice[i+1:]...)
2623 }
2624 }
2625 return slice
Girish Gowdrae09a6202021-01-12 18:10:59 -08002626}
Girish Gowdrae20a4f62021-03-09 16:06:23 -08002627
2628func (mm *onuMetricsManager) twosComplementToSignedInt16(val uint16) int16 {
2629 var uint16MsbMask uint16 = 0x8000
2630 if val&uint16MsbMask == uint16MsbMask {
2631 return int16(^val+1) * -1
2632 }
2633
2634 return int16(val)
2635}
2636
2637/* // These are need in the future
2638
2639func (mm *onuMetricsManager) twosComplementToSignedInt32(val uint32) int32 {
2640 var uint32MsbMask uint32 = 0x80000000
2641 if val & uint32MsbMask == uint32MsbMask {
2642 return int32(^val + 1) * -1
2643 }
2644
2645 return int32(val)
2646}
2647
2648func (mm *onuMetricsManager) twosComplementToSignedInt64(val uint64) int64 {
2649 var uint64MsbMask uint64 = 0x8000000000000000
2650 if val & uint64MsbMask == uint64MsbMask {
2651 return int64(^val + 1) * -1
2652 }
2653
2654 return int64(val)
2655}
2656
2657*/