blob: 41efe82a29707a5752eed34649b32fe0c91406fa [file] [log] [blame]
Girish Gowdrae09a6202021-01-12 18:10:59 -08001/*
2 * Copyright 2021-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
19
20import (
21 "context"
Girish Gowdra0e533642021-03-02 22:02:51 -080022 "encoding/json"
Girish Gowdrae09a6202021-01-12 18:10:59 -080023 "fmt"
Girish Gowdrae0140f02021-02-02 16:55:09 -080024 "github.com/looplab/fsm"
Girish Gowdrae09a6202021-01-12 18:10:59 -080025 "github.com/opencord/omci-lib-go"
26 me "github.com/opencord/omci-lib-go/generated"
Girish Gowdra0e533642021-03-02 22:02:51 -080027 "github.com/opencord/voltha-lib-go/v4/pkg/db"
28 "github.com/opencord/voltha-lib-go/v4/pkg/db/kvstore"
Girish Gowdrae09a6202021-01-12 18:10:59 -080029 "github.com/opencord/voltha-lib-go/v4/pkg/log"
30 "github.com/opencord/voltha-protos/v4/go/voltha"
Girish Gowdrae20a4f62021-03-09 16:06:23 -080031 "math"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080032 "sync"
Girish Gowdrae09a6202021-01-12 18:10:59 -080033 "time"
34)
35
Girish Gowdrae0140f02021-02-02 16:55:09 -080036const (
37 // events of L2 PM FSM
38 l2PmEventInit = "l2PmEventInit"
39 l2PmEventTick = "l2PmEventTick"
40 l2PmEventSuccess = "l2PmEventSuccess"
41 l2PmEventFailure = "l2PmEventFailure"
42 l2PmEventAddMe = "l2PmEventAddMe"
43 l2PmEventDeleteMe = "l2PmEventDeleteMe"
44 l2PmEventStop = "l2PmEventStop"
45)
46const (
47 // states of L2 PM FSM
48 l2PmStNull = "l2PmStNull"
49 l2PmStStarting = "l2PmStStarting"
50 l2PmStSyncTime = "l2PmStSyncTime"
51 l2PmStIdle = "l2PmStIdle"
52 l2PmStCreatePmMe = "l2PmStCreatePm"
53 l2PmStDeletePmMe = "l2PmStDeletePmMe"
54 l2PmStCollectData = "l2PmStCollectData"
55)
56
57const cL2PmFsmIdleState = l2PmStIdle
58
Girish Gowdra5a7c4922021-01-22 18:33:41 -080059// general constants used for overall Metric Collection management
60const (
61 DefaultMetricCollectionFrequency = 15 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
62 GroupMetricEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
63 DefaultFrequencyOverrideEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
64 FrequencyGranularity = 5 // The frequency (in seconds) has to be multiple of 5. This setting cannot changed later.
65)
66
67// OpticalPowerGroupMetrics are supported optical pm names
68var OpticalPowerGroupMetrics = map[string]voltha.PmConfig_PmType{
Girish Gowdrae20a4f62021-03-09 16:06:23 -080069 "ani_g_instance_id": voltha.PmConfig_CONTEXT,
70 "transmit_power_dBm": voltha.PmConfig_GAUGE,
71 "receive_power_dBm": voltha.PmConfig_GAUGE,
Girish Gowdra5a7c4922021-01-22 18:33:41 -080072}
73
74// OpticalPowerGroupMetrics specific constants
75const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080076 OpticalPowerGroupMetricName = "PON_Optical"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080077 OpticalPowerGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
78 OpticalPowerMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
79)
80
81// UniStatusGroupMetrics are supported UNI status names
82var UniStatusGroupMetrics = map[string]voltha.PmConfig_PmType{
83 "uni_port_no": voltha.PmConfig_CONTEXT,
Girish Gowdra0e533642021-03-02 22:02:51 -080084 "entity_id": voltha.PmConfig_CONTEXT,
Girish Gowdra5a7c4922021-01-22 18:33:41 -080085 "ethernet_type": voltha.PmConfig_GAUGE,
86 "oper_status": voltha.PmConfig_GAUGE,
87 "uni_admin_state": voltha.PmConfig_GAUGE,
88}
89
90// UniStatusGroupMetrics specific constants
91const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080092 UniStatusGroupMetricName = "UNI_Status"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080093 UniStatusGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
94 UniStatusMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
95)
96
Girish Gowdrae0140f02021-02-02 16:55:09 -080097// *** Classical L2 PM Counters begin ***
98
99// EthernetBridgeHistory are supported ethernet bridge history counters fetched from
100// Ethernet Frame Performance Monitoring History Data Downstream and Ethernet Frame Performance Monitoring History Data Upstream MEs.
101var EthernetBridgeHistory = map[string]voltha.PmConfig_PmType{
102 "class_id": voltha.PmConfig_CONTEXT,
103 "entity_id": voltha.PmConfig_CONTEXT,
104 "interval_end_time": voltha.PmConfig_CONTEXT,
105 "parent_class_id": voltha.PmConfig_CONTEXT,
106 "parent_entity_id": voltha.PmConfig_CONTEXT,
107 "upstream": voltha.PmConfig_CONTEXT,
108
109 "drop_events": voltha.PmConfig_COUNTER,
110 "octets": voltha.PmConfig_COUNTER,
111 "packets": voltha.PmConfig_COUNTER,
112 "broadcast_packets": voltha.PmConfig_COUNTER,
113 "multicast_packets": voltha.PmConfig_COUNTER,
114 "crc_errored_packets": voltha.PmConfig_COUNTER,
115 "undersize_packets": voltha.PmConfig_COUNTER,
116 "oversize_packets": voltha.PmConfig_COUNTER,
117 "64_octets": voltha.PmConfig_COUNTER,
118 "65_to_127_octets": voltha.PmConfig_COUNTER,
119 "128_to_255_octets": voltha.PmConfig_COUNTER,
120 "256_to_511_octets": voltha.PmConfig_COUNTER,
121 "512_to_1023_octets": voltha.PmConfig_COUNTER,
122 "1024_to_1518_octets": voltha.PmConfig_COUNTER,
123}
124
125// EthernetUniHistory are supported ethernet uni history counters fetched from
126// Ethernet Performance Monitoring History Data ME.
127var EthernetUniHistory = map[string]voltha.PmConfig_PmType{
128 "class_id": voltha.PmConfig_CONTEXT,
129 "entity_id": voltha.PmConfig_CONTEXT,
130 "interval_end_time": voltha.PmConfig_CONTEXT,
131
132 "fcs_errors": voltha.PmConfig_COUNTER,
133 "excessive_collision_counter": voltha.PmConfig_COUNTER,
134 "late_collision_counter": voltha.PmConfig_COUNTER,
135 "frames_too_long": voltha.PmConfig_COUNTER,
136 "buffer_overflows_on_rx": voltha.PmConfig_COUNTER,
137 "buffer_overflows_on_tx": voltha.PmConfig_COUNTER,
138 "single_collision_frame_counter": voltha.PmConfig_COUNTER,
139 "multiple_collisions_frame_counter": voltha.PmConfig_COUNTER,
140 "sqe_counter": voltha.PmConfig_COUNTER,
141 "deferred_tx_counter": voltha.PmConfig_COUNTER,
142 "internal_mac_tx_error_counter": voltha.PmConfig_COUNTER,
143 "carrier_sense_error_counter": voltha.PmConfig_COUNTER,
144 "alignment_error_counter": voltha.PmConfig_COUNTER,
145 "internal_mac_rx_error_counter": voltha.PmConfig_COUNTER,
146}
147
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800148// FecHistory is supported FEC Performance Monitoring History Data related metrics
149var FecHistory = map[string]voltha.PmConfig_PmType{
150 "class_id": voltha.PmConfig_CONTEXT,
151 "entity_id": voltha.PmConfig_CONTEXT,
152 "interval_end_time": voltha.PmConfig_CONTEXT,
153
154 "corrected_bytes": voltha.PmConfig_COUNTER,
155 "corrected_code_words": voltha.PmConfig_COUNTER,
156 "uncorrectable_code_words": voltha.PmConfig_COUNTER,
157 "total_code_words": voltha.PmConfig_COUNTER,
158 "fec_seconds": voltha.PmConfig_COUNTER,
159}
160
161// GemPortHistory is supported GEM Port Network Ctp Performance Monitoring History Data
162// related metrics
163var GemPortHistory = map[string]voltha.PmConfig_PmType{
164 "class_id": voltha.PmConfig_CONTEXT,
165 "entity_id": voltha.PmConfig_CONTEXT,
166 "interval_end_time": voltha.PmConfig_CONTEXT,
167
168 "transmitted_gem_frames": voltha.PmConfig_COUNTER,
169 "received_gem_frames": voltha.PmConfig_COUNTER,
170 "received_payload_bytes": voltha.PmConfig_COUNTER,
171 "transmitted_payload_bytes": voltha.PmConfig_COUNTER,
172 "encryption_key_errors": voltha.PmConfig_COUNTER,
173}
174
Girish Gowdrae0140f02021-02-02 16:55:09 -0800175// Constants specific for L2 PM collection
176const (
177 L2PmCollectionInterval = 15 * 60 // Unit in seconds. Do not change this as this fixed by OMCI specification for L2 PM counters
178 SyncTimeRetryInterval = 15 // Unit seconds
179 L2PmCreateAttempts = 3
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800180 L2PmDeleteAttempts = 3
Girish Gowdrae0140f02021-02-02 16:55:09 -0800181 L2PmCollectAttempts = 3
Girish Gowdra453750f2021-02-16 16:36:46 -0800182 // Per Table 11.2.9-1 – OMCI baseline message limitations in G.988 spec, the max GET Response
183 // payload size is 25. We define 24 (one less) to allow for dynamic insertion of IntervalEndTime
184 // attribute (1 byte) in L2 PM GET Requests.
185 MaxL2PMGetPayLoadSize = 24
Girish Gowdrae0140f02021-02-02 16:55:09 -0800186)
187
188// EthernetUniHistoryName specific constants
189const (
190 EthernetBridgeHistoryName = "Ethernet_Bridge_Port_History"
191 EthernetBridgeHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
192 EthernetBridgeHistoryFrequency = L2PmCollectionInterval
193)
194
195// EthernetBridgeHistory specific constants
196const (
197 EthernetUniHistoryName = "Ethernet_UNI_History"
198 EthernetUniHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
199 EthernetUniHistoryFrequency = L2PmCollectionInterval
200)
201
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800202// FecHistory specific constants
203const (
204 FecHistoryName = "FEC_History"
205 FecHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
206 FecHistoryFrequency = L2PmCollectionInterval
207)
208
209// GemPortHistory specific constants
210const (
211 GemPortHistoryName = "GEM_Port_History"
212 GemPortHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
213 GemPortHistoryFrequency = L2PmCollectionInterval
214)
215
Girish Gowdra0e533642021-03-02 22:02:51 -0800216// KV Store related constants
217const (
218 cPmKvStorePrefix = "%s/openonu/pm-data/%s" // <some-base-path>/openonu/pm-data/<onu-device-id>
219 cPmAdd = "add"
220 cPmAdded = "added"
221 cPmRemove = "remove"
222 cPmRemoved = "removed"
223)
224
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800225// Defines the type for generic metric population function
226type groupMetricPopulateFunc func(context.Context, me.ClassID, uint16, me.AttributeValueMap, me.AttributeValueMap, map[string]float32, *int) error
227
Girish Gowdrae0140f02021-02-02 16:55:09 -0800228// *** Classical L2 PM Counters end ***
229
Girish Gowdra0e533642021-03-02 22:02:51 -0800230type pmMEData struct {
231 InstancesActive []uint16 `json:"instances_active"` // list of active ME instance IDs for the group
232 InstancesToDelete []uint16 `json:"instances_to_delete"` // list of ME instance IDs marked for deletion for the group
233 InstancesToAdd []uint16 `json:"instances_to_add"` // list of ME instance IDs marked for addition for the group
234}
235
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800236type groupMetric struct {
237 groupName string
238 enabled bool
239 frequency uint32 // valid only if FrequencyOverride is enabled.
240 metricMap map[string]voltha.PmConfig_PmType
241 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
Girish Gowdrae0140f02021-02-02 16:55:09 -0800242 isL2PMCounter bool // true for only L2 PM counters
243 collectAttempts uint32 // number of attempts to collect L2 PM data
Girish Gowdra0e533642021-03-02 22:02:51 -0800244 pmMEData *pmMEData
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800245}
246
247type standaloneMetric struct {
248 metricName string
249 enabled bool
250 frequency uint32 // valid only if FrequencyOverride is enabled.
251 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
252}
253
Girish Gowdrae09a6202021-01-12 18:10:59 -0800254type onuMetricsManager struct {
255 pDeviceHandler *deviceHandler
Girish Gowdrae0140f02021-02-02 16:55:09 -0800256 pAdaptFsm *AdapterFsm
Girish Gowdrae09a6202021-01-12 18:10:59 -0800257
Girish Gowdrae0140f02021-02-02 16:55:09 -0800258 opticalMetricsChan chan me.AttributeValueMap
259 uniStatusMetricsChan chan me.AttributeValueMap
260 l2PmChan chan me.AttributeValueMap
261 syncTimeResponseChan chan bool // true is success, false is fail
262 l2PmCreateOrDeleteResponseChan chan bool // true is success, false is fail
263
264 activeL2Pms []string // list of active l2 pm MEs created on the ONU.
265 l2PmToDelete []string // list of L2 PMs to delete
266 l2PmToAdd []string // list of L2 PM to add
Girish Gowdrae09a6202021-01-12 18:10:59 -0800267
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800268 groupMetricMap map[string]*groupMetric
269 standaloneMetricMap map[string]*standaloneMetric
270
Girish Gowdrae09a6202021-01-12 18:10:59 -0800271 stopProcessingOmciResponses chan bool
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800272
Girish Gowdrae0140f02021-02-02 16:55:09 -0800273 stopTicks chan bool
274
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800275 nextGlobalMetricCollectionTime time.Time // valid only if pmConfig.FreqOverride is set to false.
276
277 onuMetricsManagerLock sync.RWMutex
Girish Gowdra0e533642021-03-02 22:02:51 -0800278
279 pmKvStore *db.Backend
Girish Gowdrae09a6202021-01-12 18:10:59 -0800280}
281
282// newonuMetricsManager returns a new instance of the newonuMetricsManager
Girish Gowdra0e533642021-03-02 22:02:51 -0800283// The metrics manager module is responsible for configuration and management of individual and group metrics.
284// Currently all the metrics are managed as a group which fall into two categories - L2 PM and "all others"
285// The L2 PM counters have a fixed 15min interval for PM collection while all other group counters have
286// the collection interval configurable.
287// The global PM config is part of the voltha.Device struct and is backed up on KV store (by rw-core).
288// This module also implements resiliency for L2 PM ME instances that are active/pending-delete/pending-add.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800289func newonuMetricsManager(ctx context.Context, dh *deviceHandler) *onuMetricsManager {
290
291 var metricsManager onuMetricsManager
292 logger.Debugw(ctx, "init-onuMetricsManager", log.Fields{"device-id": dh.deviceID})
293 metricsManager.pDeviceHandler = dh
294
Girish Gowdrae0140f02021-02-02 16:55:09 -0800295 commMetricsChan := make(chan Message)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800296 metricsManager.opticalMetricsChan = make(chan me.AttributeValueMap)
297 metricsManager.uniStatusMetricsChan = make(chan me.AttributeValueMap)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800298 metricsManager.l2PmChan = make(chan me.AttributeValueMap)
299
300 metricsManager.syncTimeResponseChan = make(chan bool)
301 metricsManager.l2PmCreateOrDeleteResponseChan = make(chan bool)
302
Girish Gowdrae09a6202021-01-12 18:10:59 -0800303 metricsManager.stopProcessingOmciResponses = make(chan bool)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800304 metricsManager.stopTicks = make(chan bool)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800305
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800306 metricsManager.groupMetricMap = make(map[string]*groupMetric)
307 metricsManager.standaloneMetricMap = make(map[string]*standaloneMetric)
308
309 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 -0800310 metricsManager.initializeAllGroupMetrics()
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800311 }
312
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800313 metricsManager.populateLocalGroupMetricData(ctx)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800314
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800315 if err := metricsManager.initializeL2PmFsm(ctx, commMetricsChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800316 return nil
317 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800318
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800319 // initialize the next metric collection intervals.
320 metricsManager.initializeMetricCollectionTime(ctx)
Girish Gowdra0e533642021-03-02 22:02:51 -0800321
322 baseKvStorePath := fmt.Sprintf(cPmKvStorePrefix, dh.pOpenOnuAc.cm.Backend.PathPrefix, dh.deviceID)
323 metricsManager.pmKvStore = dh.setBackend(ctx, baseKvStorePath)
324 if metricsManager.pmKvStore == nil {
325 logger.Errorw(ctx, "Can't initialize pmKvStore - no backend connection to PM module",
326 log.Fields{"device-id": dh.deviceID, "service": baseKvStorePath})
327 return nil
328 }
329
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800330 logger.Info(ctx, "init-onuMetricsManager completed", log.Fields{"device-id": dh.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800331 return &metricsManager
332}
333
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800334func (mm *onuMetricsManager) initializeMetricCollectionTime(ctx context.Context) {
335 if mm.pDeviceHandler.pmConfigs.FreqOverride {
336 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to true, then group/standalone metric specific interval applies
337 mm.onuMetricsManagerLock.Lock()
338 defer mm.onuMetricsManagerLock.Unlock()
339 for _, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800340 if v.enabled && !v.isL2PMCounter { // L2 PM counter collection is managed in a L2PmFsm
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800341 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
342 }
343 }
344
345 for _, v := range mm.standaloneMetricMap {
346 if v.enabled {
347 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
348 }
349 }
350 } else {
351 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to false, then overall metric specific interval applies
352 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
353 }
354 logger.Infow(ctx, "initialized standalone group/metric collection time", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
355}
356
357func (mm *onuMetricsManager) updateDefaultFrequency(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
358 // Verify that the configured DefaultFrequency is > 0 and is a multiple of FrequencyGranularity
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800359 if pmConfigs.DefaultFreq == 0 || (pmConfigs.DefaultFreq > 0 && pmConfigs.DefaultFreq%FrequencyGranularity != 0) {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800360 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", pmConfigs.DefaultFreq, FrequencyGranularity)
361 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", pmConfigs.DefaultFreq, FrequencyGranularity)
362 }
363 mm.pDeviceHandler.pmConfigs.DefaultFreq = pmConfigs.DefaultFreq
364 // re-set the nextGlobalMetricCollectionTime based on the new DefaultFreq
365 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
366 logger.Debugw(ctx, "frequency-updated--new-frequency", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "frequency": mm.pDeviceHandler.pmConfigs.DefaultFreq})
367 return nil
368}
369
370func (mm *onuMetricsManager) updateGroupFreq(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
371 var newGroupFreq uint32
372 found := false
373 groupSliceIdx := 0
374 var group *voltha.PmGroupConfig
375 for groupSliceIdx, group = range pmConfigs.Groups {
376 if group.GroupName == aGroupName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800377 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
378 if group.GroupFreq == 0 || (group.GroupFreq > 0 && group.GroupFreq%FrequencyGranularity != 0) {
379 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", group.GroupFreq, FrequencyGranularity)
380 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", group.GroupFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800381 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800382 newGroupFreq = group.GroupFreq
383 found = true
384 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800385 }
386 }
387 // if not found update group freq and next collection interval for the group
388 if !found {
389 logger.Errorw(ctx, "group name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
390 return fmt.Errorf("group-name-not-found-%v", aGroupName)
391 }
392
393 updated := false
394 mm.onuMetricsManagerLock.Lock()
395 defer mm.onuMetricsManagerLock.Unlock()
396 for k, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800397 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 -0800398 v.frequency = newGroupFreq
399 // update internal pm config
400 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].GroupFreq = newGroupFreq
401 // Also updated the next group metric collection time from now
402 v.nextCollectionInterval = time.Now().Add(time.Duration(newGroupFreq) * time.Second)
403 updated = true
404 logger.Infow(ctx, "group frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800405 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800406 }
407 }
408 if !updated {
409 logger.Errorw(ctx, "group frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
410 return fmt.Errorf("internal-error-during-group-freq-update--groupname-%s-freq-%d", aGroupName, newGroupFreq)
411 }
412 return nil
413}
414
415func (mm *onuMetricsManager) updateMetricFreq(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
416 var newMetricFreq uint32
417 found := false
418 metricSliceIdx := 0
419 var metric *voltha.PmConfig
420 for metricSliceIdx, metric = range pmConfigs.Metrics {
421 if metric.Name == aMetricName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800422 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
423 if metric.SampleFreq == 0 || (metric.SampleFreq > 0 && metric.SampleFreq%FrequencyGranularity != 0) {
424 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", metric.SampleFreq, FrequencyGranularity)
425 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", metric.SampleFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800426 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800427 newMetricFreq = metric.SampleFreq
428 found = true
429 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800430 }
431 }
432 if !found {
433 logger.Errorw(ctx, "metric name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
434 return fmt.Errorf("metric-name-not-found-%v", aMetricName)
435 }
436
437 updated := false
438 mm.onuMetricsManagerLock.Lock()
439 defer mm.onuMetricsManagerLock.Unlock()
440 for k, v := range mm.groupMetricMap {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800441 if k == aMetricName {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800442 v.frequency = newMetricFreq
443 // update internal pm config
444 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].SampleFreq = newMetricFreq
445 // Also updated the next standalone metric collection time from now
446 v.nextCollectionInterval = time.Now().Add(time.Duration(newMetricFreq) * time.Second)
447 updated = true
448 logger.Infow(ctx, "metric frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800449 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800450 }
451 }
452 if !updated {
453 logger.Errorw(ctx, "metric frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
454 return fmt.Errorf("internal-error-during-standalone-metric-update--matricnane-%s-freq-%d", aMetricName, newMetricFreq)
455 }
456 return nil
457}
458
459func (mm *onuMetricsManager) updateGroupSupport(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
460 groupSliceIdx := 0
461 var group *voltha.PmGroupConfig
462
463 for groupSliceIdx, group = range pmConfigs.Groups {
464 if group.GroupName == aGroupName {
465 break
466 }
467 }
468 if group == nil {
469 logger.Errorw(ctx, "group metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
470 return fmt.Errorf("group-not-found--groupName-%s", aGroupName)
471 }
472
473 updated := false
474 mm.onuMetricsManagerLock.Lock()
475 defer mm.onuMetricsManagerLock.Unlock()
476 for k, v := range mm.groupMetricMap {
477 if k == aGroupName && v.enabled != group.Enabled {
478 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].Enabled = group.Enabled
479 v.enabled = group.Enabled
Girish Gowdrae0140f02021-02-02 16:55:09 -0800480 if group.Enabled {
481 if v.isL2PMCounter {
482 // If it is a L2 PM counter we need to mark the PM to be added
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800483 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800484 // 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 -0800485 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, v.groupName)
486
487 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
488 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
489 // take further action
490 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800491 mm.updateGemPortNTPInstanceToAddForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800492 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800493 } else if mm.pDeviceHandler.pmConfigs.FreqOverride { // otherwise just update the next collection interval
494 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
495 }
496 } else { // group counter is disabled
497 if v.isL2PMCounter {
498 // If it is a L2 PM counter we need to mark the PM to be deleted
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800499 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800500 // 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 -0800501 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, v.groupName)
502
503 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
504 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
505 // take further action
506 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800507 mm.updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800508 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800509 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800510 }
511 updated = true
Girish Gowdrae0140f02021-02-02 16:55:09 -0800512 if v.isL2PMCounter {
513 logger.Infow(ctx, "l2 pm group metric support updated",
514 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled, "l2PmToAdd": mm.l2PmToAdd, "l2PmToDelete": mm.l2PmToDelete})
515 } else {
516 logger.Infow(ctx, "group metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled})
517 }
518 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800519 }
520 }
521
522 if !updated {
523 logger.Errorw(ctx, "group metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
524 return fmt.Errorf("internal-error-during-group-support-update--groupName-%s", aGroupName)
525 }
526 return nil
527}
528
529func (mm *onuMetricsManager) updateMetricSupport(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
530 metricSliceIdx := 0
531 var metric *voltha.PmConfig
532
533 for metricSliceIdx, metric = range pmConfigs.Metrics {
534 if metric.Name == aMetricName {
535 break
536 }
537 }
538
539 if metric == nil {
540 logger.Errorw(ctx, "standalone metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
541 return fmt.Errorf("metric-not-found--metricname-%s", aMetricName)
542 }
543
544 updated := false
545 mm.onuMetricsManagerLock.Lock()
546 defer mm.onuMetricsManagerLock.Unlock()
547 for k, v := range mm.standaloneMetricMap {
548 if k == aMetricName && v.enabled != metric.Enabled {
549 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].Enabled = metric.Enabled
550 v.enabled = metric.Enabled
551 // If the standalone metric is now enabled and frequency override is enabled, set the next metric collection time
552 if metric.Enabled && mm.pDeviceHandler.pmConfigs.FreqOverride {
553 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
554 }
555 updated = true
556 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 -0800557 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800558 }
559 }
560 if !updated {
561 logger.Errorw(ctx, "standalone metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
562 return fmt.Errorf("internal-error-during-standalone-support-update--metricname-%s", aMetricName)
563 }
564 return nil
565}
566
567func (mm *onuMetricsManager) collectAllGroupAndStandaloneMetrics(ctx context.Context) {
568 if mm.pDeviceHandler.pmConfigs.Grouped { // metrics are managed as a group.
569 go mm.collectAllGroupMetrics(ctx)
570 } else {
571 go mm.collectAllStandaloneMetrics(ctx)
572 }
573}
574
575func (mm *onuMetricsManager) collectAllGroupMetrics(ctx context.Context) {
576 go func() {
577 logger.Debug(ctx, "startCollector before collecting optical metrics")
578 metricInfo := mm.collectOpticalMetrics(ctx)
579 if metricInfo != nil {
580 mm.publishMetrics(ctx, metricInfo)
581 }
582 }()
583
584 go func() {
585 logger.Debug(ctx, "startCollector before collecting uni metrics")
586 metricInfo := mm.collectUniStatusMetrics(ctx)
587 if metricInfo != nil {
588 mm.publishMetrics(ctx, metricInfo)
589 }
590 }()
591
592 // Add more here
593}
594
595func (mm *onuMetricsManager) collectAllStandaloneMetrics(ctx context.Context) {
596 // None exists as of now, add when available here
597}
598
599func (mm *onuMetricsManager) collectGroupMetric(ctx context.Context, groupName string) {
600 switch groupName {
601 case OpticalPowerGroupMetricName:
602 go func() {
603 if mi := mm.collectOpticalMetrics(ctx); mm != nil {
604 mm.publishMetrics(ctx, mi)
605 }
606 }()
607 case UniStatusGroupMetricName:
608 go func() {
609 if mi := mm.collectUniStatusMetrics(ctx); mm != nil {
610 mm.publishMetrics(ctx, mi)
611 }
612 }()
613 default:
614 logger.Errorw(ctx, "unhandled group metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName})
615 }
616}
617
618func (mm *onuMetricsManager) collectStandaloneMetric(ctx context.Context, metricName string) {
619 switch metricName {
620 // None exist as of now, add when available
621 default:
622 logger.Errorw(ctx, "unhandled standalone metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName})
623 }
624}
625
626// collectOpticalMetrics collects groups metrics related to optical power from ani-g ME.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800627func (mm *onuMetricsManager) collectOpticalMetrics(ctx context.Context) []*voltha.MetricInformation {
628 logger.Debugw(ctx, "collectOpticalMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800629
630 mm.onuMetricsManagerLock.RLock()
631 if !mm.groupMetricMap[OpticalPowerGroupMetricName].enabled {
632 mm.onuMetricsManagerLock.RUnlock()
633 logger.Debugw(ctx, "optical power group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
634 return nil
635 }
636 mm.onuMetricsManagerLock.RUnlock()
637
Girish Gowdrae09a6202021-01-12 18:10:59 -0800638 var metricInfoSlice []*voltha.MetricInformation
639 metricsContext := make(map[string]string)
640 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
641 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
642 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
643
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800644 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800645 mmd := voltha.MetricMetaData{
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800646 Title: OpticalPowerGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800647 Ts: float64(raisedTs),
648 Context: metricsContext,
649 DeviceId: mm.pDeviceHandler.deviceID,
650 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
651 SerialNo: mm.pDeviceHandler.device.SerialNumber,
652 }
653
Girish Gowdrae09a6202021-01-12 18:10:59 -0800654 // get the ANI-G instance IDs
655 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
656loop:
657 for _, anigInstID := range anigInstKeys {
658 var meAttributes me.AttributeValueMap
659 opticalMetrics := make(map[string]float32)
660 // Get the ANI-G instance optical power attributes
661 requestedAttributes := me.AttributeValueMap{"OpticalSignalLevel": 0, "TransmitOpticalLevel": 0}
Girish Gowdra0b235842021-03-09 13:06:46 -0800662 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 -0800663 select {
664 case meAttributes = <-mm.opticalMetricsChan:
665 logger.Debugw(ctx, "received optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0b235842021-03-09 13:06:46 -0800666 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800667 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 -0800668 // The metrics will be empty in this case
669 break loop
670 }
671 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800672 for k := range OpticalPowerGroupMetrics {
673 switch k {
674 case "ani_g_instance_id":
675 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
676 opticalMetrics[k] = float32(val.(uint16))
677 }
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800678 case "transmit_power_dBm":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800679 if val, ok := meAttributes["TransmitOpticalLevel"]; ok && val != nil {
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800680 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 -0800681 }
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800682 case "receive_power_dBm":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800683 if val, ok := meAttributes["OpticalSignalLevel"]; ok && val != nil {
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800684 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 -0800685 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800686 default:
687 // do nothing
688 }
689 }
690 }
691 // create slice of metrics given that there could be more than one ANI-G instance and
692 // optical metrics are collected per ANI-G instance
693 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: opticalMetrics}
694 metricInfoSlice = append(metricInfoSlice, &metricInfo)
695 }
696
697 return metricInfoSlice
698}
699
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800700// collectUniStatusMetrics collects UNI status group metric from various MEs (uni-g, pptp and veip).
Girish Gowdrae09a6202021-01-12 18:10:59 -0800701// nolint: gocyclo
702func (mm *onuMetricsManager) collectUniStatusMetrics(ctx context.Context) []*voltha.MetricInformation {
703 logger.Debugw(ctx, "collectUniStatusMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800704 mm.onuMetricsManagerLock.RLock()
705 if !mm.groupMetricMap[UniStatusGroupMetricName].enabled {
706 mm.onuMetricsManagerLock.RUnlock()
707 logger.Debugw(ctx, "uni status group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
708 return nil
709 }
710 mm.onuMetricsManagerLock.RUnlock()
711
Girish Gowdrae09a6202021-01-12 18:10:59 -0800712 var metricInfoSlice []*voltha.MetricInformation
713 metricsContext := make(map[string]string)
714 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
715 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
716 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
717
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800718 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800719 mmd := voltha.MetricMetaData{
720 Title: "UniStatus", // Is this ok to hard code?
721 Ts: float64(raisedTs),
722 Context: metricsContext,
723 DeviceId: mm.pDeviceHandler.deviceID,
724 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
725 SerialNo: mm.pDeviceHandler.device.SerialNumber,
726 }
727
Girish Gowdrae09a6202021-01-12 18:10:59 -0800728 // get the UNI-G instance IDs
729 unigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.UniGClassID)
730loop1:
731 for _, unigInstID := range unigInstKeys {
732 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
733 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
734 unigMetrics := make(map[string]float32)
735 var meAttributes me.AttributeValueMap
736 // Get the UNI-G instance optical power attributes
737 requestedAttributes := me.AttributeValueMap{"AdministrativeState": 0}
Girish Gowdra0b235842021-03-09 13:06:46 -0800738 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 -0800739 // Wait for metrics or timeout
740 select {
741 case meAttributes = <-mm.uniStatusMetricsChan:
742 logger.Debugw(ctx, "received uni-g metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0b235842021-03-09 13:06:46 -0800743 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800744 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
745 // The metrics could be empty in this case
746 break loop1
747 }
748 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800749 for k := range UniStatusGroupMetrics {
750 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800751 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800752 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
753 unigMetrics[k] = float32(val.(byte))
754 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800755 default:
756 // do nothing
757 }
758 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800759 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800760 entityID := val.(uint16)
761 unigMetrics["entity_id"] = float32(entityID)
762 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
763 for _, uni := range mm.pDeviceHandler.uniEntityMap {
764 if uni.entityID == entityID {
765 unigMetrics["uni_port_no"] = float32(uni.portNo)
766 }
767 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800768 }
Girish Gowdra0e533642021-03-02 22:02:51 -0800769
Girish Gowdrae09a6202021-01-12 18:10:59 -0800770 // create slice of metrics given that there could be more than one UNI-G instance
771 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: unigMetrics}
772 metricInfoSlice = append(metricInfoSlice, &metricInfo)
773 }
774 }
775
776 // get the PPTP instance IDs
777 pptpInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.PhysicalPathTerminationPointEthernetUniClassID)
778loop2:
779 for _, pptpInstID := range pptpInstKeys {
780 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
781 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
782 var meAttributes me.AttributeValueMap
783 pptpMetrics := make(map[string]float32)
784
785 requestedAttributes := me.AttributeValueMap{"SensedType": 0, "OperationalState": 0, "AdministrativeState": 0}
Girish Gowdra0b235842021-03-09 13:06:46 -0800786 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 -0800787 // Wait for metrics or timeout
788 select {
789 case meAttributes = <-mm.uniStatusMetricsChan:
790 logger.Debugw(ctx, "received pptp metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0b235842021-03-09 13:06:46 -0800791 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800792 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
793 // The metrics could be empty in this case
794 break loop2
795 }
796
797 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800798 for k := range UniStatusGroupMetrics {
799 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800800 case "ethernet_type":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800801 if val, ok := meAttributes["SensedType"]; ok && val != nil {
802 pptpMetrics[k] = float32(val.(byte))
803 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800804 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800805 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
806 pptpMetrics[k] = float32(val.(byte))
807 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800808 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800809 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
810 pptpMetrics[k] = float32(val.(byte))
811 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800812 default:
813 // do nothing
814 }
815 }
816 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800817 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800818 entityID := val.(uint16)
819 pptpMetrics["entity_id"] = float32(entityID)
820 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
821 for _, uni := range mm.pDeviceHandler.uniEntityMap {
822 if uni.entityID == entityID {
823 pptpMetrics["uni_port_no"] = float32(uni.portNo)
824 }
825 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800826 }
827
Girish Gowdrae09a6202021-01-12 18:10:59 -0800828 // create slice of metrics given that there could be more than one PPTP instance and
829 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: pptpMetrics}
830 metricInfoSlice = append(metricInfoSlice, &metricInfo)
831 }
832
833 // get the VEIP instance IDs
834 veipInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.VirtualEthernetInterfacePointClassID)
835loop3:
836 for _, veipInstID := range veipInstKeys {
837 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
838 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
839 var meAttributes me.AttributeValueMap
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800840 veipMetrics := make(map[string]float32)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800841
842 requestedAttributes := me.AttributeValueMap{"OperationalState": 0, "AdministrativeState": 0}
Girish Gowdra0b235842021-03-09 13:06:46 -0800843 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 -0800844 // Wait for metrics or timeout
845 select {
846 case meAttributes = <-mm.uniStatusMetricsChan:
847 logger.Debugw(ctx, "received veip metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0b235842021-03-09 13:06:46 -0800848 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800849 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
850 // The metrics could be empty in this case
851 break loop3
852 }
853
854 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800855 for k := range UniStatusGroupMetrics {
856 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800857 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800858 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
859 veipMetrics[k] = float32(val.(byte))
860 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800861 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800862 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
863 veipMetrics[k] = float32(val.(byte))
864 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800865 default:
866 // do nothing
867 }
868 }
869 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800870
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800871 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800872 entityID := val.(uint16)
873 veipMetrics["entity_id"] = float32(entityID)
874 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
875 for _, uni := range mm.pDeviceHandler.uniEntityMap {
876 if uni.entityID == entityID {
877 veipMetrics["uni_port_no"] = float32(uni.portNo)
878 }
879 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800880 }
881
Girish Gowdrae09a6202021-01-12 18:10:59 -0800882 // create slice of metrics given that there could be more than one VEIP instance
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800883 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: veipMetrics}
Girish Gowdrae09a6202021-01-12 18:10:59 -0800884 metricInfoSlice = append(metricInfoSlice, &metricInfo)
885 }
886
887 return metricInfoSlice
888}
889
890// publishMetrics publishes the metrics on kafka
891func (mm *onuMetricsManager) publishMetrics(ctx context.Context, metricInfo []*voltha.MetricInformation) {
892 var ke voltha.KpiEvent2
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800893 ts := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800894 ke.SliceData = metricInfo
895 ke.Type = voltha.KpiEventType_slice
896 ke.Ts = float64(ts)
897
898 if err := mm.pDeviceHandler.EventProxy.SendKpiEvent(ctx, "STATS_EVENT", &ke, voltha.EventCategory_EQUIPMENT, voltha.EventSubCategory_ONU, ts); err != nil {
899 logger.Errorw(ctx, "failed-to-send-pon-stats", log.Fields{"err": err})
900 }
901}
902
903func (mm *onuMetricsManager) processOmciMessages(ctx context.Context) {
904 logger.Infow(ctx, "Start routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
905 // Flush metric collection channels to be safe.
906 // It is possible that there is stale data on this channel if the processOmciMessages routine
907 // is stopped right after issuing a OMCI-GET request and started again.
908 // The processOmciMessages routine will get stopped if startCollector routine (in device_handler.go)
909 // is stopped - as a result of ONU going down.
910 mm.flushMetricCollectionChannels(ctx)
911
912 for {
913 select {
914 case <-mm.stopProcessingOmciResponses: // stop this routine
915 logger.Infow(ctx, "Stop routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
916 return
Girish Gowdrae0140f02021-02-02 16:55:09 -0800917 case message, ok := <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -0800918 if !ok {
919 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
920 continue
921 }
922 logger.Debugw(ctx, "Received message on ONU metrics channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
923
924 switch message.Type {
925 case OMCI:
926 msg, _ := message.Data.(OmciMessage)
927 mm.handleOmciMessage(ctx, msg)
928 default:
929 logger.Warn(ctx, "Unknown message type received", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "message.Type": message.Type})
930 }
931 }
932 }
933}
934
935func (mm *onuMetricsManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
936 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
937 "msgType": msg.OmciMsg.MessageType, "msg": msg})
938 switch msg.OmciMsg.MessageType {
939 case omci.GetResponseType:
940 //TODO: error handling
941 _ = mm.handleOmciGetResponseMessage(ctx, msg)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800942 case omci.SynchronizeTimeResponseType:
943 _ = mm.handleOmciSynchronizeTimeResponseMessage(ctx, msg)
944 case omci.CreateResponseType:
945 _ = mm.handleOmciCreateResponseMessage(ctx, msg)
946 case omci.DeleteResponseType:
947 _ = mm.handleOmciDeleteResponseMessage(ctx, msg)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800948 default:
949 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
950
951 }
952}
953
954func (mm *onuMetricsManager) handleOmciGetResponseMessage(ctx context.Context, msg OmciMessage) error {
955 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
956 if msgLayer == nil {
957 logger.Errorw(ctx, "omci Msg layer could not be detected for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
958 return fmt.Errorf("omci Msg layer could not be detected for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
959 }
960 msgObj, msgOk := msgLayer.(*omci.GetResponse)
961 if !msgOk {
962 logger.Errorw(ctx, "omci Msg layer could not be assigned for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
963 return fmt.Errorf("omci Msg layer could not be assigned for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
964 }
965 logger.Debugw(ctx, "OMCI GetResponse Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
966 if msgObj.Result == me.Success {
967 meAttributes := msgObj.Attributes
968 switch msgObj.EntityClass {
969 case me.AniGClassID:
970 mm.opticalMetricsChan <- meAttributes
971 return nil
972 case me.UniGClassID:
973 mm.uniStatusMetricsChan <- meAttributes
974 return nil
975 case me.PhysicalPathTerminationPointEthernetUniClassID:
976 mm.uniStatusMetricsChan <- meAttributes
977 return nil
978 case me.VirtualEthernetInterfacePointClassID:
979 mm.uniStatusMetricsChan <- meAttributes
980 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -0800981 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
982 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800983 me.EthernetPerformanceMonitoringHistoryDataClassID,
984 me.FecPerformanceMonitoringHistoryDataClassID,
985 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -0800986 mm.l2PmChan <- meAttributes
Girish Gowdrae09a6202021-01-12 18:10:59 -0800987 default:
988 logger.Errorw(ctx, "unhandled omci get response message",
989 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
990 }
991 }
992
Girish Gowdrae0140f02021-02-02 16:55:09 -0800993 return fmt.Errorf("unhandled-omci-get-response-message")
994}
995
996func (mm *onuMetricsManager) handleOmciSynchronizeTimeResponseMessage(ctx context.Context, msg OmciMessage) error {
997 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSynchronizeTimeResponse)
998 if msgLayer == nil {
999 logger.Errorw(ctx, "omci Msg layer could not be detected for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1000 return fmt.Errorf("omci Msg layer could not be detected for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1001 }
1002 msgObj, msgOk := msgLayer.(*omci.SynchronizeTimeResponse)
1003 if !msgOk {
1004 logger.Errorw(ctx, "omci Msg layer could not be assigned for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1005 return fmt.Errorf("omci Msg layer could not be assigned for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1006 }
1007 logger.Debugw(ctx, "OMCI synchronize time response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1008 if msgObj.Result == me.Success {
1009 switch msgObj.EntityClass {
1010 case me.OnuGClassID:
1011 logger.Infow(ctx, "omci synchronize time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1012 mm.syncTimeResponseChan <- true
1013 return nil
1014 default:
1015 logger.Errorw(ctx, "unhandled omci message",
1016 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1017 }
1018 }
1019 mm.syncTimeResponseChan <- false
1020 logger.Errorf(ctx, "unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
1021 return fmt.Errorf("unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001022}
1023
1024// flushMetricCollectionChannels flushes all metric collection channels for any stale OMCI responses
1025func (mm *onuMetricsManager) flushMetricCollectionChannels(ctx context.Context) {
1026 // flush commMetricsChan
1027 select {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001028 case <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -08001029 logger.Debug(ctx, "flushed common metrics channel")
1030 default:
1031 }
1032
1033 // flush opticalMetricsChan
1034 select {
1035 case <-mm.opticalMetricsChan:
1036 logger.Debug(ctx, "flushed optical metrics channel")
1037 default:
1038 }
1039
1040 // flush uniStatusMetricsChan
1041 select {
1042 case <-mm.uniStatusMetricsChan:
1043 logger.Debug(ctx, "flushed uni status metrics channel")
1044 default:
1045 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001046
1047 // flush syncTimeResponseChan
1048 select {
1049 case <-mm.syncTimeResponseChan:
1050 logger.Debug(ctx, "flushed sync time response channel")
1051 default:
1052 }
1053
1054 // flush l2PmChan
1055 select {
1056 case <-mm.l2PmChan:
1057 logger.Debug(ctx, "flushed L2 PM collection channel")
1058 default:
1059 }
1060
1061 // flush stopTicks
1062 select {
1063 case <-mm.stopTicks:
1064 logger.Debug(ctx, "flushed stopTicks channel")
1065 default:
1066 }
1067
1068}
1069
1070// ** L2 PM FSM Handlers start **
1071
1072func (mm *onuMetricsManager) l2PMFsmStarting(ctx context.Context, e *fsm.Event) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001073 // restore data from KV store
1074 if err := mm.restorePmData(ctx); err != nil {
1075 logger.Errorw(ctx, "error restoring pm data", log.Fields{"err": err})
1076 // we continue given that it does not effect the actual services for the ONU,
1077 // but there may be some negative effect on PM collection (there may be some mismatch in
1078 // the actual PM config and what is present on the device).
1079 }
1080
Girish Gowdrae0140f02021-02-02 16:55:09 -08001081 // Loop through all the group metrics
1082 // If it is a L2 PM Interval metric and it is enabled, then if it is not in the
1083 // list of active L2 PM list then mark it for creation
1084 // It it is a L2 PM Interval metric and it is disabled, then if it is in the
1085 // list of active L2 PM list then mark it for deletion
1086 mm.onuMetricsManagerLock.Lock()
1087 for n, g := range mm.groupMetricMap {
1088 if g.isL2PMCounter { // it is a l2 pm counter
1089 if g.enabled { // metric enabled.
1090 found := false
1091 inner1:
1092 for _, v := range mm.activeL2Pms {
1093 if v == n {
1094 found = true // metric already present in active l2 pm list
1095 break inner1
1096 }
1097 }
1098 if !found { // metric not in active l2 pm list. Mark this to be added later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001099 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001100 }
1101 } else { // metric not enabled.
1102 found := false
1103 inner2:
1104 for _, v := range mm.activeL2Pms {
1105 if v == n {
1106 found = true // metric is found in active l2 pm list
1107 break inner2
1108 }
1109 }
1110 if found { // metric is found in active l2 pm list. Mark this to be deleted later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001111 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001112 }
1113 }
1114 }
1115 }
1116 mm.onuMetricsManagerLock.Unlock()
1117 logger.Debugw(ctx, "pms to add and delete",
1118 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd, "pms-to-delete": mm.l2PmToDelete})
1119 go func() {
1120 // push a tick event to move to next state
1121 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1122 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1123 }
1124 }()
1125}
1126
1127func (mm *onuMetricsManager) l2PMFsmSyncTime(ctx context.Context, e *fsm.Event) {
1128 // Sync time with the ONU to establish 15min boundary for PM collection.
1129 if err := mm.syncTime(ctx); err != nil {
1130 go func() {
1131 time.Sleep(SyncTimeRetryInterval * time.Second) // retry to sync time after this timeout
1132 // This will result in FSM attempting to sync time again
1133 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventFailure); err != nil {
1134 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1135 }
1136 }()
1137 }
1138 // Initiate a tick generation routine every L2PmCollectionInterval
1139 go mm.generateTicks(ctx)
1140
1141 go func() {
1142 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1143 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1144 }
1145 }()
1146}
1147
1148func (mm *onuMetricsManager) l2PMFsmNull(ctx context.Context, e *fsm.Event) {
1149 // 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
1150 mm.onuMetricsManagerLock.Lock()
1151 mm.activeL2Pms = nil
1152 mm.l2PmToAdd = nil
1153 mm.l2PmToDelete = nil
1154 mm.onuMetricsManagerLock.Unlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001155 // If the FSM was stopped, then clear PM data from KV store
1156 // The FSM is stopped when ONU goes down. It is time to clear its data from store
1157 if e.Event == l2PmEventStop {
1158 _ = mm.clearPmGroupData(ctx) // ignore error
1159 }
1160
Girish Gowdrae0140f02021-02-02 16:55:09 -08001161}
1162func (mm *onuMetricsManager) l2PMFsmIdle(ctx context.Context, e *fsm.Event) {
1163 logger.Debugw(ctx, "Enter state idle", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1164
1165 mm.onuMetricsManagerLock.RLock()
1166 numOfPmToDelete := len(mm.l2PmToDelete)
1167 numOfPmToAdd := len(mm.l2PmToAdd)
1168 mm.onuMetricsManagerLock.RUnlock()
1169
1170 if numOfPmToDelete > 0 {
1171 logger.Debugw(ctx, "state idle - pms to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": numOfPmToDelete})
1172 go func() {
1173 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
1174 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1175 }
1176 }()
1177 } else if numOfPmToAdd > 0 {
1178 logger.Debugw(ctx, "state idle - pms to add", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": numOfPmToAdd})
1179 go func() {
1180 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
1181 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1182 }
1183 }()
1184 }
1185}
1186
1187func (mm *onuMetricsManager) l2PmFsmCollectData(ctx context.Context, e *fsm.Event) {
1188 logger.Debugw(ctx, "state collect data", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1189 // Copy the activeL2Pms for which we want to collect the metrics since activeL2Pms can change dynamically
1190 mm.onuMetricsManagerLock.RLock()
1191 copyOfActiveL2Pms := make([]string, len(mm.activeL2Pms))
1192 _ = copy(copyOfActiveL2Pms, mm.activeL2Pms)
1193 mm.onuMetricsManagerLock.RUnlock()
1194
1195 for _, n := range copyOfActiveL2Pms {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001196 var metricInfoSlice []*voltha.MetricInformation
Girish Gowdra0e533642021-03-02 22:02:51 -08001197
1198 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1199 mm.onuMetricsManagerLock.RLock()
1200 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1201 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1202 mm.onuMetricsManagerLock.RUnlock()
1203
Girish Gowdrae0140f02021-02-02 16:55:09 -08001204 switch n {
1205 case EthernetBridgeHistoryName:
1206 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 -08001207 for _, entityID := range copyOfEntityIDs {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001208 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, true, entityID); metricInfo != nil { // upstream
1209 metricInfoSlice = append(metricInfoSlice, metricInfo)
1210 }
1211 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, false, entityID); metricInfo != nil { // downstream
1212 metricInfoSlice = append(metricInfoSlice, metricInfo)
1213 }
1214 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001215 case EthernetUniHistoryName:
1216 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 -08001217 for _, entityID := range copyOfEntityIDs {
1218 if metricInfo := mm.collectEthernetUniHistoryData(ctx, entityID); metricInfo != nil { // upstream
1219 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001220 }
1221 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001222
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001223 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001224 for _, entityID := range copyOfEntityIDs {
1225 if metricInfo := mm.collectFecHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001226 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001227 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001228 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001229 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001230 for _, entityID := range copyOfEntityIDs {
1231 if metricInfo := mm.collectGemHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001232 metricInfoSlice = append(metricInfoSlice, metricInfo)
1233 }
1234 }
1235
Girish Gowdrae0140f02021-02-02 16:55:09 -08001236 default:
1237 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1238 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001239 mm.handleMetricsPublish(ctx, n, metricInfoSlice)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001240 }
1241 // Does not matter we send success or failure here.
1242 // Those PMs that we failed to collect data will be attempted to collect again in the next PM collection cycle (assuming
1243 // we have not exceed max attempts to collect the PM data)
1244 go func() {
1245 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1246 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1247 }
1248 }()
1249}
1250
Girish Gowdra0e533642021-03-02 22:02:51 -08001251// nolint: gocyclo
Girish Gowdrae0140f02021-02-02 16:55:09 -08001252func (mm *onuMetricsManager) l2PmFsmCreatePM(ctx context.Context, e *fsm.Event) {
1253 // Copy the l2PmToAdd for which we want to collect the metrics since l2PmToAdd can change dynamically
1254 mm.onuMetricsManagerLock.RLock()
1255 copyOfL2PmToAdd := make([]string, len(mm.l2PmToAdd))
1256 _ = copy(copyOfL2PmToAdd, mm.l2PmToAdd)
1257 mm.onuMetricsManagerLock.RUnlock()
1258
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001259 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 -08001260 for _, n := range copyOfL2PmToAdd {
1261 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001262 atLeastOneSuccess := false // flag indicates if at least one ME instance of the PM was successfully created.
1263 cnt := 0
Girish Gowdrae0140f02021-02-02 16:55:09 -08001264 switch n {
1265 case EthernetBridgeHistoryName:
1266 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1267 boolForDirection = append(boolForDirection, true, false)
1268 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1269 for _, direction := range boolForDirection {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001270 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1271 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1272 entityID := macBridgePortAniEID + uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001273 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1274 inner1:
1275 // retry L2PmCreateAttempts times to create the instance of PM
1276 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1277 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001278 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, true, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001279 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetFramePerformanceMonitoringHistoryData"); resp {
1280 atLeastOneSuccess = true
1281 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1282 break inner1
1283 }
1284 }
1285 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1286 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001287 }
1288 }
1289 }
1290 case EthernetUniHistoryName:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001291 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1292 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
Girish Gowdra0e533642021-03-02 22:02:51 -08001293 // Attach the EthernetPerformanceMonitoringHistoryData ME to PPTP port instance
Girish Gowdrae0140f02021-02-02 16:55:09 -08001294 entityID := uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001295 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1296 inner2:
1297 // retry L2PmCreateAttempts times to create the instance of PM
1298 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1299 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001300 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001301 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetPerformanceMonitoringHistoryData"); resp {
1302 atLeastOneSuccess = true
1303 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1304 break inner2
1305 }
1306 }
1307 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1308 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001309 }
1310 }
1311 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001312 case FecHistoryName:
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001313 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001314 // Attach the FecPerformanceMonitoringHistoryData ME to the ANI-G ME instance
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001315 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001316 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, anigInstID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001317 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdd) // TODO: ignore error for now
1318 inner3:
1319 // retry L2PmCreateAttempts times to create the instance of PM
1320 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1321 if resp = mm.waitForResponseOrTimeout(ctx, true, anigInstID, "FecPerformanceMonitoringHistoryData"); resp {
1322 atLeastOneSuccess = true
1323 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdded) // TODO: ignore error for now
1324 break inner3
1325 }
1326 }
1327 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1328 _ = mm.updatePmData(ctx, n, anigInstID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001329 }
1330 }
1331 case GemPortHistoryName:
1332
1333 mm.onuMetricsManagerLock.RLock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001334 copyOfGemPortInstIDsToAdd := make([]uint16, len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd))
1335 _ = copy(copyOfGemPortInstIDsToAdd, mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001336 mm.onuMetricsManagerLock.RUnlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001337
1338 if len(copyOfGemPortInstIDsToAdd) == 0 {
1339 // If there are no gemport history MEs to be created, just skip further processing
1340 // Otherwise down below (after 'switch' case handling) we assume the ME creation failed because resp and atLeastOneSuccess flag are false.
1341 // Normally there are no GemPortHistory MEs to create at start up. They come in only after provisioning service on the ONU.
1342 mm.onuMetricsManagerLock.Lock()
1343 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1344 mm.onuMetricsManagerLock.Unlock()
1345 continue
1346 }
1347
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001348 for _, v := range copyOfGemPortInstIDsToAdd {
1349 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001350 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, v)
Girish Gowdra0e533642021-03-02 22:02:51 -08001351 _ = mm.updatePmData(ctx, n, v, cPmAdd) // TODO: ignore error for now
1352 inner4:
1353 // retry L2PmCreateAttempts times to create the instance of PM
1354 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1355 if resp = mm.waitForResponseOrTimeout(ctx, true, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); resp {
1356 atLeastOneSuccess = true
1357 _ = mm.updatePmData(ctx, n, v, cPmAdded) // TODO: ignore error for now
1358 break inner4
1359 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001360 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001361 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1362 _ = mm.updatePmData(ctx, n, v, cPmRemoved) // TODO: ignore error for now
1363 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001364 }
1365
Girish Gowdrae0140f02021-02-02 16:55:09 -08001366 default:
1367 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1368 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001369 // 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
1370 if atLeastOneSuccess {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001371 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001372 mm.activeL2Pms = mm.appendIfMissingString(mm.activeL2Pms, n)
1373 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1374 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 -08001375 mm.onuMetricsManagerLock.Unlock()
1376 } else {
Girish Gowdra0e533642021-03-02 22:02:51 -08001377 // 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 -08001378 // and also remove it from l2PmToAdd slice so that we do not try to create the PM ME anymore
1379 mm.onuMetricsManagerLock.Lock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001380 logger.Debugw(ctx, "exceeded-max-add-retry-attempts--disabling-group", log.Fields{"groupName": n})
1381 mm.groupMetricMap[n].enabled = false
1382 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001383
Girish Gowdrae0140f02021-02-02 16:55:09 -08001384 logger.Warnw(ctx, "state create pm - failed to create pm",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001385 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
Girish Gowdra0e533642021-03-02 22:02:51 -08001386 "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001387 mm.onuMetricsManagerLock.Unlock()
1388 }
1389 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001390 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 -08001391 // Does not matter we send success or failure here.
1392 // Those PMs that we failed to create will be attempted to create again in the next PM creation cycle (assuming
1393 // we have not exceed max attempts to create the PM ME)
1394 go func() {
1395 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1396 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1397 }
1398 }()
1399}
1400
Girish Gowdra0e533642021-03-02 22:02:51 -08001401// nolint: gocyclo
Girish Gowdrae0140f02021-02-02 16:55:09 -08001402func (mm *onuMetricsManager) l2PmFsmDeletePM(ctx context.Context, e *fsm.Event) {
1403 // Copy the l2PmToDelete for which we want to collect the metrics since l2PmToDelete can change dynamically
1404 mm.onuMetricsManagerLock.RLock()
1405 copyOfL2PmToDelete := make([]string, len(mm.l2PmToDelete))
1406 _ = copy(copyOfL2PmToDelete, mm.l2PmToDelete)
1407 mm.onuMetricsManagerLock.RUnlock()
1408
1409 logger.Debugw(ctx, "state delete pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": mm.l2PmToDelete})
1410 for _, n := range copyOfL2PmToDelete {
1411 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001412 cnt := 0
1413 atLeastOneDeleteFailure := false
1414
1415 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1416 mm.onuMetricsManagerLock.RLock()
1417 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1418 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1419 mm.onuMetricsManagerLock.RUnlock()
1420
1421 if len(copyOfEntityIDs) == 0 {
1422 // if there are no enityIDs to remove for the PM ME just clear the PM name entry from cache and continue
1423 mm.onuMetricsManagerLock.Lock()
1424 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1425 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1426 logger.Debugw(ctx, "success-resp", log.Fields{"pm-name": n, "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1427 mm.onuMetricsManagerLock.Unlock()
1428 continue
1429 }
1430 logger.Debugw(ctx, "entities to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n, "entityIDs": copyOfEntityIDs})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001431 switch n {
1432 case EthernetBridgeHistoryName:
1433 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1434 boolForDirection = append(boolForDirection, true, false)
1435 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1436 for _, direction := range boolForDirection {
Girish Gowdra0e533642021-03-02 22:02:51 -08001437 for _, entityID := range copyOfEntityIDs {
1438 inner1:
1439 // retry L2PmDeleteAttempts times to delete the instance of PM
1440 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1441 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001442 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001443 _ = mm.updatePmData(ctx, n, entityID, cPmRemove) // TODO: ignore error for now
1444 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1445 atLeastOneDeleteFailure = true
1446 } else {
1447 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1448 break inner1
1449 }
1450 }
1451 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1452 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001453 }
1454 }
1455 }
1456 case EthernetUniHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001457 for _, entityID := range copyOfEntityIDs {
1458 inner2:
1459 // retry L2PmDeleteAttempts times to delete the instance of PM
1460 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001461 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001462 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001463 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
Girish Gowdra0e533642021-03-02 22:02:51 -08001464 atLeastOneDeleteFailure = true
1465 } else {
1466 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001467 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001468 }
1469 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001470 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1471 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1472 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001473 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001474 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001475 for _, entityID := range copyOfEntityIDs {
1476 inner3:
1477 // retry L2PmDeleteAttempts times to delete the instance of PM
1478 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1479 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001480 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001481 if resp := mm.waitForResponseOrTimeout(ctx, false, entityID, "FecPerformanceMonitoringHistoryData"); !resp {
1482 atLeastOneDeleteFailure = true
1483 } else {
1484 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1485 break inner3
1486 }
1487 }
1488 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1489 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001490 }
1491 }
1492 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001493 for _, entityID := range copyOfEntityIDs {
1494 inner4:
1495 // retry L2PmDeleteAttempts times to delete the instance of PM
1496 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
1497 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001498 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra0e533642021-03-02 22:02:51 -08001499 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1500 atLeastOneDeleteFailure = true
1501 } else {
1502 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1503 break inner4
1504 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001505 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001506 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1507 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1508 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001509 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001510 default:
1511 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1512 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001513 // If we could not completely clean up the PM ME then just give up.
1514 if atLeastOneDeleteFailure {
1515 logger.Warnw(ctx, "state delete pm - failed to delete at least one instance of the PM ME",
1516 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
1517 "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1518 mm.onuMetricsManagerLock.Lock()
1519 logger.Debugw(ctx, "exceeded-max-delete-retry-attempts--disabling-group", log.Fields{"groupName": n})
1520 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1521 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1522 mm.groupMetricMap[n].enabled = false
1523 mm.onuMetricsManagerLock.Unlock()
1524 } else { // success case
Girish Gowdrae0140f02021-02-02 16:55:09 -08001525 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001526 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1527 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1528 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 -08001529 mm.onuMetricsManagerLock.Unlock()
1530 }
1531 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001532 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 -08001533 // Does not matter we send success or failure here.
1534 // Those PMs that we failed to delete will be attempted to create again in the next PM collection cycle
1535 go func() {
1536 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1537 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1538 }
1539 }()
1540}
1541
1542// ** L2 PM FSM Handlers end **
1543
1544// syncTime synchronizes time with the ONU to establish a 15 min boundary for PM collection and reporting.
1545func (mm *onuMetricsManager) syncTime(ctx context.Context) error {
Girish Gowdra0b235842021-03-09 13:06:46 -08001546 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 -08001547 logger.Errorw(ctx, "cannot send sync time request", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1548 return err
1549 }
1550
1551 select {
Girish Gowdra0b235842021-03-09 13:06:46 -08001552 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001553 logger.Errorf(ctx, "timed out waiting for sync time response from onu", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1554 return fmt.Errorf("timed-out-waiting-for-sync-time-response-%v", mm.pDeviceHandler.deviceID)
1555 case syncTimeRes := <-mm.syncTimeResponseChan:
1556 if !syncTimeRes {
1557 return fmt.Errorf("failed-to-sync-time-%v", mm.pDeviceHandler.deviceID)
1558 }
1559 logger.Infow(ctx, "sync time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1560 return nil
1561 }
1562}
1563
1564func (mm *onuMetricsManager) collectEthernetFramePerformanceMonitoringHistoryData(ctx context.Context, upstream bool, entityID uint16) *voltha.MetricInformation {
1565 var mEnt *me.ManagedEntity
1566 var omciErr me.OmciErrors
1567 var classID me.ClassID
1568 var meAttributes me.AttributeValueMap
1569 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1570 meParam := me.ParamData{EntityID: entityID}
1571 if upstream {
1572 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataUpstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1573 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1574 return nil
1575 }
1576 classID = me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID
1577 } else {
1578 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataDownstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1579 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1580 return nil
1581 }
1582 classID = me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID
1583 }
1584
Girish Gowdrae0140f02021-02-02 16:55:09 -08001585 intervalEndTime := -1
1586 ethPMHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001587 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethPMHistData, &intervalEndTime); err != nil {
1588 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001589 }
1590
1591 // Populate some relevant context for the EthernetFramePerformanceMonitoringHistoryData PM
1592 ethPMHistData["class_id"] = float32(classID)
1593 ethPMHistData["interval_end_time"] = float32(intervalEndTime)
1594 ethPMHistData["parent_class_id"] = float32(me.MacBridgeConfigurationDataClassID) // EthernetFramePerformanceMonitoringHistoryData is attached to MBPCD ME
1595 ethPMHistData["parent_entity_id"] = float32(entityID)
1596 if upstream {
1597 ethPMHistData["upstream"] = float32(1)
1598 } else {
1599 ethPMHistData["upstream"] = float32(0)
1600 }
1601
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001602 metricInfo := mm.populateOnuMetricInfo(EthernetBridgeHistoryName, ethPMHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001603
Girish Gowdrae0140f02021-02-02 16:55:09 -08001604 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData successful",
1605 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream, "metricInfo": metricInfo})
1606 return &metricInfo
1607}
1608
1609func (mm *onuMetricsManager) collectEthernetUniHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1610 var mEnt *me.ManagedEntity
1611 var omciErr me.OmciErrors
1612 var classID me.ClassID
1613 var meAttributes me.AttributeValueMap
1614 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1615 meParam := me.ParamData{EntityID: entityID}
1616 if mEnt, omciErr = me.NewEthernetPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1617 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1618 return nil
1619 }
1620 classID = me.EthernetPerformanceMonitoringHistoryDataClassID
1621
Girish Gowdrae0140f02021-02-02 16:55:09 -08001622 intervalEndTime := -1
1623 ethUniHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001624 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethUniHistData, &intervalEndTime); err != nil {
1625 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001626 }
1627
1628 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1629 ethUniHistData["class_id"] = float32(classID)
1630 ethUniHistData["interval_end_time"] = float32(intervalEndTime)
1631
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001632 metricInfo := mm.populateOnuMetricInfo(EthernetUniHistoryName, ethUniHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001633
Girish Gowdrae0140f02021-02-02 16:55:09 -08001634 logger.Debugw(ctx, "collecting data for EthernetPerformanceMonitoringHistoryData successful",
1635 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1636 return &metricInfo
1637}
1638
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001639func (mm *onuMetricsManager) collectFecHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1640 var mEnt *me.ManagedEntity
1641 var omciErr me.OmciErrors
1642 var classID me.ClassID
1643 var meAttributes me.AttributeValueMap
1644 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1645 meParam := me.ParamData{EntityID: entityID}
1646 if mEnt, omciErr = me.NewFecPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1647 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1648 return nil
1649 }
1650 classID = me.FecPerformanceMonitoringHistoryDataClassID
1651
1652 intervalEndTime := -1
1653 fecHistData := make(map[string]float32)
1654 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, fecHistData, &intervalEndTime); err != nil {
1655 return nil
1656 }
1657
1658 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1659 fecHistData["class_id"] = float32(classID)
1660 fecHistData["interval_end_time"] = float32(intervalEndTime)
1661
1662 metricInfo := mm.populateOnuMetricInfo(FecHistoryName, fecHistData)
1663
1664 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData successful",
1665 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1666 return &metricInfo
1667}
1668
1669func (mm *onuMetricsManager) collectGemHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1670 var mEnt *me.ManagedEntity
1671 var omciErr me.OmciErrors
1672 var classID me.ClassID
1673 var meAttributes me.AttributeValueMap
1674 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1675 meParam := me.ParamData{EntityID: entityID}
1676 if mEnt, omciErr = me.NewGemPortNetworkCtpPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1677 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1678 return nil
1679 }
1680 classID = me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID
1681
1682 intervalEndTime := -1
1683 gemHistData := make(map[string]float32)
1684 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, gemHistData, &intervalEndTime); err != nil {
1685 return nil
1686 }
1687
1688 // Populate some relevant context for the GemPortNetworkCtpPerformanceMonitoringHistoryData PM
1689 gemHistData["class_id"] = float32(classID)
1690 gemHistData["interval_end_time"] = float32(intervalEndTime)
1691
1692 metricInfo := mm.populateOnuMetricInfo(GemPortHistoryName, gemHistData)
1693
1694 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData successful",
1695 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1696 return &metricInfo
1697}
1698
Girish Gowdrae0140f02021-02-02 16:55:09 -08001699// nolint: gocyclo
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001700func (mm *onuMetricsManager) populateEthernetBridgeHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
Girish Gowdrae0140f02021-02-02 16:55:09 -08001701 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001702 upstream := false
1703 if classID == me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID {
1704 upstream = true
1705 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001706 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1707 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1708 requestedAttributes["IntervalEndTime"] = 0
1709 }
Girish Gowdra0b235842021-03-09 13:06:46 -08001710 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 -08001711 select {
1712 case meAttributes = <-mm.l2PmChan:
1713 logger.Debugw(ctx, "received ethernet pm history data metrics",
1714 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
Girish Gowdra0b235842021-03-09 13:06:46 -08001715 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001716 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet pm history data",
1717 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1718 // The metrics will be empty in this case
1719 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-bridge-history-%v", mm.pDeviceHandler.deviceID)
1720 }
1721 // 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 -08001722 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1723 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 -08001724 }
1725 }
1726 for k := range EthernetBridgeHistory {
1727 // populate ethPMHistData only if metric key not already present (or populated), since it is possible that we populate
1728 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1729 if _, ok := ethPMHistData[k]; !ok {
1730 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001731 case "entity_id":
1732 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1733 ethPMHistData[k] = float32(val.(uint16))
1734 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001735 case "drop_events":
1736 if val, ok := meAttributes["DropEvents"]; ok && val != nil {
1737 ethPMHistData[k] = float32(val.(uint32))
1738 }
1739 case "octets":
1740 if val, ok := meAttributes["Octets"]; ok && val != nil {
1741 ethPMHistData[k] = float32(val.(uint32))
1742 }
1743 case "packets":
1744 if val, ok := meAttributes["Packets"]; ok && val != nil {
1745 ethPMHistData[k] = float32(val.(uint32))
1746 }
1747 case "broadcast_packets":
1748 if val, ok := meAttributes["BroadcastPackets"]; ok && val != nil {
1749 ethPMHistData[k] = float32(val.(uint32))
1750 }
1751 case "multicast_packets":
1752 if val, ok := meAttributes["MulticastPackets"]; ok && val != nil {
1753 ethPMHistData[k] = float32(val.(uint32))
1754 }
1755 case "crc_errored_packets":
1756 if val, ok := meAttributes["CrcErroredPackets"]; ok && val != nil {
1757 ethPMHistData[k] = float32(val.(uint32))
1758 }
1759 case "undersize_packets":
1760 if val, ok := meAttributes["UndersizePackets"]; ok && val != nil {
1761 ethPMHistData[k] = float32(val.(uint32))
1762 }
1763 case "oversize_packets":
1764 if val, ok := meAttributes["OversizePackets"]; ok && val != nil {
1765 ethPMHistData[k] = float32(val.(uint32))
1766 }
1767 case "64_octets":
1768 if val, ok := meAttributes["Packets64Octets"]; ok && val != nil {
1769 ethPMHistData[k] = float32(val.(uint32))
1770 }
1771 case "65_to_127_octets":
1772 if val, ok := meAttributes["Packets65To127Octets"]; ok && val != nil {
1773 ethPMHistData[k] = float32(val.(uint32))
1774 }
1775 case "128_to_255_octets":
1776 if val, ok := meAttributes["Packets128To255Octets"]; ok && val != nil {
1777 ethPMHistData[k] = float32(val.(uint32))
1778 }
1779 case "256_to_511_octets":
1780 if val, ok := meAttributes["Packets256To511Octets"]; ok && val != nil {
1781 ethPMHistData[k] = float32(val.(uint32))
1782 }
1783 case "512_to_1023_octets":
1784 if val, ok := meAttributes["Packets512To1023Octets"]; ok && val != nil {
1785 ethPMHistData[k] = float32(val.(uint32))
1786 }
1787 case "1024_to_1518_octets":
1788 if val, ok := meAttributes["Packets1024To1518Octets"]; ok && val != nil {
1789 ethPMHistData[k] = float32(val.(uint32))
1790 }
1791 default:
1792 // do nothing
1793 }
1794 }
1795 }
1796 return nil
1797}
1798
1799// nolint: gocyclo
1800func (mm *onuMetricsManager) populateEthernetUniHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1801 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMUniHistData map[string]float32, intervalEndTime *int) error {
1802 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1803 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1804 requestedAttributes["IntervalEndTime"] = 0
1805 }
Girish Gowdra0b235842021-03-09 13:06:46 -08001806 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 -08001807 select {
1808 case meAttributes = <-mm.l2PmChan:
1809 logger.Debugw(ctx, "received ethernet uni history data metrics",
1810 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Girish Gowdra0b235842021-03-09 13:06:46 -08001811 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001812 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet uni history data",
1813 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1814 // The metrics will be empty in this case
1815 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-uni-history-%v", mm.pDeviceHandler.deviceID)
1816 }
1817 // 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 -08001818 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1819 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 -08001820 }
1821 }
1822 for k := range EthernetUniHistory {
1823 // populate ethPMUniHistData only if metric key not already present (or populated), since it is possible that we populate
1824 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1825 if _, ok := ethPMUniHistData[k]; !ok {
1826 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001827 case "entity_id":
1828 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1829 ethPMUniHistData[k] = float32(val.(uint16))
1830 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001831 case "fcs_errors":
1832 if val, ok := meAttributes["FcsErrors"]; ok && val != nil {
1833 ethPMUniHistData[k] = float32(val.(uint32))
1834 }
1835 case "excessive_collision_counter":
1836 if val, ok := meAttributes["ExcessiveCollisionCounter"]; ok && val != nil {
1837 ethPMUniHistData[k] = float32(val.(uint32))
1838 }
1839 case "late_collision_counter":
1840 if val, ok := meAttributes["LateCollisionCounter"]; ok && val != nil {
1841 ethPMUniHistData[k] = float32(val.(uint32))
1842 }
1843 case "frames_too_long":
1844 if val, ok := meAttributes["FramesTooLong"]; ok && val != nil {
1845 ethPMUniHistData[k] = float32(val.(uint32))
1846 }
1847 case "buffer_overflows_on_rx":
1848 if val, ok := meAttributes["BufferOverflowsOnReceive"]; ok && val != nil {
1849 ethPMUniHistData[k] = float32(val.(uint32))
1850 }
1851 case "buffer_overflows_on_tx":
1852 if val, ok := meAttributes["BufferOverflowsOnTransmit"]; ok && val != nil {
1853 ethPMUniHistData[k] = float32(val.(uint32))
1854 }
1855 case "single_collision_frame_counter":
1856 if val, ok := meAttributes["SingleCollisionFrameCounter"]; ok && val != nil {
1857 ethPMUniHistData[k] = float32(val.(uint32))
1858 }
1859 case "multiple_collisions_frame_counter":
1860 if val, ok := meAttributes["MultipleCollisionsFrameCounter"]; ok && val != nil {
1861 ethPMUniHistData[k] = float32(val.(uint32))
1862 }
1863 case "sqe_counter":
1864 if val, ok := meAttributes["SqeCounter"]; ok && val != nil {
1865 ethPMUniHistData[k] = float32(val.(uint32))
1866 }
1867 case "deferred_tx_counter":
1868 if val, ok := meAttributes["DeferredTransmissionCounter"]; ok && val != nil {
1869 ethPMUniHistData[k] = float32(val.(uint32))
1870 }
1871 case "internal_mac_tx_error_counter":
1872 if val, ok := meAttributes["InternalMacTransmitErrorCounter"]; ok && val != nil {
1873 ethPMUniHistData[k] = float32(val.(uint32))
1874 }
1875 case "carrier_sense_error_counter":
1876 if val, ok := meAttributes["CarrierSenseErrorCounter"]; ok && val != nil {
1877 ethPMUniHistData[k] = float32(val.(uint32))
1878 }
1879 case "alignment_error_counter":
1880 if val, ok := meAttributes["AlignmentErrorCounter"]; ok && val != nil {
1881 ethPMUniHistData[k] = float32(val.(uint32))
1882 }
1883 case "internal_mac_rx_error_counter":
1884 if val, ok := meAttributes["InternalMacReceiveErrorCounter"]; ok && val != nil {
1885 ethPMUniHistData[k] = float32(val.(uint32))
1886 }
1887 default:
1888 // do nothing
1889 }
1890 }
1891 }
1892 return nil
1893}
1894
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001895// nolint: gocyclo
1896func (mm *onuMetricsManager) populateFecHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1897 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, fecHistData map[string]float32, intervalEndTime *int) error {
1898 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1899 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1900 requestedAttributes["IntervalEndTime"] = 0
1901 }
Girish Gowdra0b235842021-03-09 13:06:46 -08001902 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 -08001903 select {
1904 case meAttributes = <-mm.l2PmChan:
1905 logger.Debugw(ctx, "received fec history data metrics",
1906 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Girish Gowdra0b235842021-03-09 13:06:46 -08001907 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001908 logger.Errorw(ctx, "timeout waiting for omci-get response for fec history data",
1909 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1910 // The metrics will be empty in this case
1911 return fmt.Errorf("timeout-during-l2-pm-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1912 }
1913 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1914 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1915 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1916 }
1917 }
1918 for k := range FecHistory {
1919 // populate fecHistData only if metric key not already present (or populated), since it is possible that we populate
1920 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1921 if _, ok := fecHistData[k]; !ok {
1922 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001923 case "entity_id":
1924 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1925 fecHistData[k] = float32(val.(uint16))
1926 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001927 case "corrected_bytes":
1928 if val, ok := meAttributes["CorrectedBytes"]; ok && val != nil {
1929 fecHistData[k] = float32(val.(uint32))
1930 }
1931 case "corrected_code_words":
1932 if val, ok := meAttributes["CorrectedCodeWords"]; ok && val != nil {
1933 fecHistData[k] = float32(val.(uint32))
1934 }
1935 case "uncorrectable_code_words":
1936 if val, ok := meAttributes["UncorrectableCodeWords"]; ok && val != nil {
1937 fecHistData[k] = float32(val.(uint32))
1938 }
1939 case "total_code_words":
1940 if val, ok := meAttributes["TotalCodeWords"]; ok && val != nil {
1941 fecHistData[k] = float32(val.(uint32))
1942 }
1943 case "fec_seconds":
1944 if val, ok := meAttributes["FecSeconds"]; ok && val != nil {
1945 fecHistData[k] = float32(val.(uint16))
1946 }
1947 default:
1948 // do nothing
1949 }
1950 }
1951 }
1952 return nil
1953}
1954
1955// nolint: gocyclo
1956func (mm *onuMetricsManager) populateGemPortMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1957 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, gemPortHistData map[string]float32, intervalEndTime *int) error {
1958 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1959 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1960 requestedAttributes["IntervalEndTime"] = 0
1961 }
Girish Gowdra0b235842021-03-09 13:06:46 -08001962 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 -08001963 select {
1964 case meAttributes = <-mm.l2PmChan:
1965 logger.Debugw(ctx, "received gem port history data metrics",
1966 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Girish Gowdra0b235842021-03-09 13:06:46 -08001967 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001968 logger.Errorw(ctx, "timeout waiting for omci-get response for gem port history data",
1969 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1970 // The metrics will be empty in this case
1971 return fmt.Errorf("timeout-during-l2-pm-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1972 }
1973 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1974 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1975 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1976 }
1977 }
1978 for k := range GemPortHistory {
1979 // populate gemPortHistData only if metric key not already present (or populated), since it is possible that we populate
1980 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1981 if _, ok := gemPortHistData[k]; !ok {
1982 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001983 case "entity_id":
1984 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1985 gemPortHistData[k] = float32(val.(uint16))
1986 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001987 case "transmitted_gem_frames":
1988 if val, ok := meAttributes["TransmittedGemFrames"]; ok && val != nil {
1989 gemPortHistData[k] = float32(val.(uint32))
1990 }
1991 case "received_gem_frames":
1992 if val, ok := meAttributes["ReceivedGemFrames"]; ok && val != nil {
1993 gemPortHistData[k] = float32(val.(uint32))
1994 }
1995 case "received_payload_bytes":
1996 if val, ok := meAttributes["ReceivedPayloadBytes"]; ok && val != nil {
1997 gemPortHistData[k] = float32(val.(uint64))
1998 }
1999 case "transmitted_payload_bytes":
2000 if val, ok := meAttributes["TransmittedPayloadBytes"]; ok && val != nil {
2001 gemPortHistData[k] = float32(val.(uint64))
2002 }
2003 case "encryption_key_errors":
2004 if val, ok := meAttributes["EncryptionKeyErrors"]; ok && val != nil {
2005 gemPortHistData[k] = float32(val.(uint32))
2006 }
2007 default:
2008 // do nothing
2009 }
2010 }
2011 }
2012 return nil
2013}
2014
Girish Gowdrae0140f02021-02-02 16:55:09 -08002015func (mm *onuMetricsManager) handleOmciCreateResponseMessage(ctx context.Context, msg OmciMessage) error {
2016 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
2017 if msgLayer == nil {
2018 logger.Errorw(ctx, "omci Msg layer could not be detected for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2019 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2020 }
2021 msgObj, msgOk := msgLayer.(*omci.CreateResponse)
2022 if !msgOk {
2023 logger.Errorw(ctx, "omci Msg layer could not be assigned for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2024 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2025 }
2026 logger.Debugw(ctx, "OMCI create response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2027 switch msgObj.EntityClass {
2028 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2029 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002030 me.EthernetPerformanceMonitoringHistoryDataClassID,
2031 me.FecPerformanceMonitoringHistoryDataClassID,
2032 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002033 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
2034 if msgObj.Result == me.Success || msgObj.Result == me.InstanceExists {
2035 mm.l2PmCreateOrDeleteResponseChan <- true
2036 } else {
2037 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2038 mm.l2PmCreateOrDeleteResponseChan <- false
2039 }
2040 return nil
2041 default:
2042 logger.Errorw(ctx, "unhandled omci create response message",
2043 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2044 }
2045 return fmt.Errorf("unhandled-omci-create-response-message-%v", mm.pDeviceHandler.deviceID)
2046}
2047
2048func (mm *onuMetricsManager) handleOmciDeleteResponseMessage(ctx context.Context, msg OmciMessage) error {
2049 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDeleteResponse)
2050 if msgLayer == nil {
2051 logger.Errorw(ctx, "omci Msg layer could not be detected for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2052 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2053 }
2054 msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
2055 if !msgOk {
2056 logger.Errorw(ctx, "omci Msg layer could not be assigned for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2057 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2058 }
2059 logger.Debugw(ctx, "OMCI delete response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2060 switch msgObj.EntityClass {
2061 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2062 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002063 me.EthernetPerformanceMonitoringHistoryDataClassID,
2064 me.FecPerformanceMonitoringHistoryDataClassID,
2065 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002066 // If the result is me.UnknownInstance it means the entity was already deleted. It is ok handled that as success
2067 if msgObj.Result == me.Success || msgObj.Result == me.UnknownInstance {
2068 mm.l2PmCreateOrDeleteResponseChan <- true
2069 } else {
2070 logger.Warnw(ctx, "failed to delete me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2071 mm.l2PmCreateOrDeleteResponseChan <- false
2072 }
2073 return nil
2074 default:
2075 logger.Errorw(ctx, "unhandled omci delete response message",
2076 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2077 }
2078 return fmt.Errorf("unhandled-omci-delete-response-message-%v", mm.pDeviceHandler.deviceID)
2079}
2080
2081func (mm *onuMetricsManager) generateTicks(ctx context.Context) {
2082 for {
2083 select {
2084 case <-time.After(L2PmCollectionInterval * time.Second):
2085 go func() {
2086 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
2087 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2088 }
2089 }()
2090 case <-mm.stopTicks:
2091 logger.Infow(ctx, "stopping ticks", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2092 return
2093 }
2094 }
2095}
2096
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002097func (mm *onuMetricsManager) handleMetricsPublish(ctx context.Context, metricName string, metricInfoSlice []*voltha.MetricInformation) {
2098 // Publish metrics if it is valid
2099 if metricInfoSlice != nil {
2100 mm.publishMetrics(ctx, metricInfoSlice)
2101 } else {
2102 // If collectAttempts exceeds L2PmCollectAttempts then remove it from activeL2Pms
2103 // slice so that we do not collect data from that PM ME anymore
2104 mm.onuMetricsManagerLock.Lock()
2105 mm.groupMetricMap[metricName].collectAttempts++
2106 if mm.groupMetricMap[metricName].collectAttempts > L2PmCollectAttempts {
2107 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, metricName)
2108 }
2109 logger.Warnw(ctx, "state collect data - no metrics collected",
2110 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName, "collectAttempts": mm.groupMetricMap[metricName].collectAttempts})
2111 mm.onuMetricsManagerLock.Unlock()
2112 }
2113}
2114
2115func (mm *onuMetricsManager) populateGroupSpecificMetrics(ctx context.Context, mEnt *me.ManagedEntity, classID me.ClassID, entityID uint16,
2116 meAttributes me.AttributeValueMap, data map[string]float32, intervalEndTime *int) error {
2117 var grpFunc groupMetricPopulateFunc
2118 switch classID {
2119 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID, me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID:
2120 grpFunc = mm.populateEthernetBridgeHistoryMetrics
2121 case me.EthernetPerformanceMonitoringHistoryDataClassID:
2122 grpFunc = mm.populateEthernetUniHistoryMetrics
2123 case me.FecPerformanceMonitoringHistoryDataClassID:
2124 grpFunc = mm.populateFecHistoryMetrics
2125 case me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
2126 grpFunc = mm.populateGemPortMetrics
2127 default:
2128 return fmt.Errorf("unknown-classid-%v", classID)
2129 }
2130
2131 size := 0
2132 requestedAttributes := make(me.AttributeValueMap)
2133 for _, v := range mEnt.GetAttributeDefinitions() {
2134 if (v.Size + size) <= MaxL2PMGetPayLoadSize {
2135 requestedAttributes[v.Name] = v.DefValue
2136 size = v.Size + size
2137 } else { // We exceeded the allow omci get size
2138 // Let's collect the attributes via get now and collect remaining in the next iteration
2139 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2140 logger.Errorw(ctx, "error during metric collection",
2141 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2142 return err
2143 }
2144 size = 0 // reset size
2145 requestedAttributes = make(me.AttributeValueMap) // reset map
2146 }
2147 }
2148 // Collect the omci get attributes for the last bunch of attributes.
2149 if len(requestedAttributes) > 0 {
2150 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2151 logger.Errorw(ctx, "error during metric collection",
2152 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2153 return err
2154 }
2155 }
2156 return nil
2157}
2158
2159func (mm *onuMetricsManager) populateOnuMetricInfo(title string, data map[string]float32) voltha.MetricInformation {
2160 metricsContext := make(map[string]string)
2161 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
2162 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
2163 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
2164
2165 raisedTs := time.Now().Unix()
2166 mmd := voltha.MetricMetaData{
2167 Title: title,
2168 Ts: float64(raisedTs),
2169 Context: metricsContext,
2170 DeviceId: mm.pDeviceHandler.deviceID,
2171 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
2172 SerialNo: mm.pDeviceHandler.device.SerialNumber,
2173 }
2174
2175 // create slice of metrics given that there could be more than one VEIP instance
2176 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: data}
2177 return metricInfo
2178}
2179
2180func (mm *onuMetricsManager) updateAndValidateIntervalEndTime(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap, intervalEndTime *int) bool {
2181 valid := false
2182 if *intervalEndTime == -1 { // first time
2183 // Update the interval end time
2184 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2185 *intervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2186 valid = true
2187 }
2188 } else {
2189 var currIntervalEndTime int
2190 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2191 currIntervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2192 }
2193 if currIntervalEndTime != *intervalEndTime { // interval end time changed during metric collection
2194 logger.Errorw(ctx, "interval end time changed during metrics collection for ethernet pm history data",
2195 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID,
2196 "currIntervalEndTime": *intervalEndTime, "newIntervalEndTime": currIntervalEndTime})
2197 } else {
2198 valid = true
2199 }
2200 }
2201 return valid
2202}
2203
2204func (mm *onuMetricsManager) waitForResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassName string) bool {
2205 logger.Debugw(ctx, "waitForResponseOrTimeout", log.Fields{"create": create, "instID": instID, "meClassName": meClassName})
2206 select {
2207 case resp := <-mm.l2PmCreateOrDeleteResponseChan:
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002208 logger.Debugw(ctx, "received l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002209 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassName": meClassName, "instID": instID})
2210 return resp
Girish Gowdra0b235842021-03-09 13:06:46 -08002211 case <-time.After(time.Duration(mm.pDeviceHandler.pOpenOnuAc.omciTimeout) * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002212 logger.Errorw(ctx, "timeout waiting for l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002213 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassName": meClassName, "instID": instID})
2214 }
2215 return false
2216}
2217
2218func (mm *onuMetricsManager) initializeGroupMetric(grpMtrcs map[string]voltha.PmConfig_PmType, grpName string, grpEnabled bool, grpFreq uint32) {
2219 var pmConfigSlice []*voltha.PmConfig
2220 for k, v := range grpMtrcs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002221 pmConfigSlice = append(pmConfigSlice,
2222 &voltha.PmConfig{
2223 Name: k,
2224 Type: v,
2225 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2226 SampleFreq: grpFreq})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002227 }
2228 groupMetric := voltha.PmGroupConfig{
2229 GroupName: grpName,
2230 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2231 GroupFreq: grpFreq,
2232 Metrics: pmConfigSlice,
2233 }
2234 mm.pDeviceHandler.pmConfigs.Groups = append(mm.pDeviceHandler.pmConfigs.Groups, &groupMetric)
2235
2236}
2237
2238func (mm *onuMetricsManager) initializeL2PmFsm(ctx context.Context, aCommChannel chan Message) error {
2239 mm.pAdaptFsm = NewAdapterFsm("L2PmFSM", mm.pDeviceHandler.deviceID, aCommChannel)
2240 if mm.pAdaptFsm == nil {
2241 logger.Errorw(ctx, "L2PMFsm AdapterFsm could not be instantiated!!", log.Fields{
2242 "device-id": mm.pDeviceHandler.deviceID})
2243 return fmt.Errorf("nil-adapter-fsm")
2244 }
2245 // L2 PM FSM related state machine
2246 mm.pAdaptFsm.pFsm = fsm.NewFSM(
2247 l2PmStNull,
2248 fsm.Events{
2249 {Name: l2PmEventInit, Src: []string{l2PmStNull}, Dst: l2PmStStarting},
2250 {Name: l2PmEventTick, Src: []string{l2PmStStarting}, Dst: l2PmStSyncTime},
2251 {Name: l2PmEventTick, Src: []string{l2PmStIdle, l2PmEventDeleteMe, l2PmEventAddMe}, Dst: l2PmStCollectData},
2252 {Name: l2PmEventSuccess, Src: []string{l2PmStSyncTime, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2253 {Name: l2PmEventFailure, Src: []string{l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2254 {Name: l2PmEventFailure, Src: []string{l2PmStSyncTime}, Dst: l2PmStSyncTime},
2255 {Name: l2PmEventAddMe, Src: []string{l2PmStIdle}, Dst: l2PmStCreatePmMe},
2256 {Name: l2PmEventDeleteMe, Src: []string{l2PmStIdle}, Dst: l2PmStDeletePmMe},
2257 {Name: l2PmEventStop, Src: []string{l2PmStNull, l2PmStStarting, l2PmStSyncTime, l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStNull},
2258 },
2259 fsm.Callbacks{
2260 "enter_state": func(e *fsm.Event) { mm.pAdaptFsm.logFsmStateChange(ctx, e) },
2261 "enter_" + l2PmStNull: func(e *fsm.Event) { mm.l2PMFsmNull(ctx, e) },
2262 "enter_" + l2PmStIdle: func(e *fsm.Event) { mm.l2PMFsmIdle(ctx, e) },
2263 "enter_" + l2PmStStarting: func(e *fsm.Event) { mm.l2PMFsmStarting(ctx, e) },
2264 "enter_" + l2PmStSyncTime: func(e *fsm.Event) { mm.l2PMFsmSyncTime(ctx, e) },
2265 "enter_" + l2PmStCollectData: func(e *fsm.Event) { mm.l2PmFsmCollectData(ctx, e) },
2266 "enter_" + l2PmStCreatePmMe: func(e *fsm.Event) { mm.l2PmFsmCreatePM(ctx, e) },
2267 "enter_" + l2PmStDeletePmMe: func(e *fsm.Event) { mm.l2PmFsmDeletePM(ctx, e) },
2268 },
2269 )
2270 return nil
2271}
2272
2273func (mm *onuMetricsManager) initializeAllGroupMetrics() {
2274 mm.pDeviceHandler.pmConfigs = &voltha.PmConfigs{}
2275 mm.pDeviceHandler.pmConfigs.Id = mm.pDeviceHandler.deviceID
2276 mm.pDeviceHandler.pmConfigs.DefaultFreq = DefaultMetricCollectionFrequency
2277 mm.pDeviceHandler.pmConfigs.Grouped = GroupMetricEnabled
2278 mm.pDeviceHandler.pmConfigs.FreqOverride = DefaultFrequencyOverrideEnabled
2279
2280 // Populate group metrics.
2281 // Lets populate irrespective of GroupMetricEnabled is true or not.
2282 // The group metrics collection will decided on this flag later
2283
2284 mm.initializeGroupMetric(OpticalPowerGroupMetrics, OpticalPowerGroupMetricName,
2285 OpticalPowerGroupMetricEnabled, OpticalPowerMetricGroupCollectionFrequency)
2286
2287 mm.initializeGroupMetric(UniStatusGroupMetrics, UniStatusGroupMetricName,
2288 UniStatusGroupMetricEnabled, UniStatusMetricGroupCollectionFrequency)
2289
2290 // classical l2 pm counter start
2291
2292 mm.initializeGroupMetric(EthernetBridgeHistory, EthernetBridgeHistoryName,
2293 EthernetBridgeHistoryEnabled, EthernetBridgeHistoryFrequency)
2294
2295 mm.initializeGroupMetric(EthernetUniHistory, EthernetUniHistoryName,
2296 EthernetUniHistoryEnabled, EthernetUniHistoryFrequency)
2297
2298 mm.initializeGroupMetric(FecHistory, FecHistoryName,
2299 FecHistoryEnabled, FecHistoryFrequency)
2300
2301 mm.initializeGroupMetric(GemPortHistory, GemPortHistoryName,
2302 GemPortHistoryEnabled, GemPortHistoryFrequency)
2303
2304 // classical l2 pm counter end
2305
2306 // Add standalone metric (if present) after this (will be added to dh.pmConfigs.Metrics)
2307}
2308
2309func (mm *onuMetricsManager) populateLocalGroupMetricData(ctx context.Context) {
2310 // Populate local group metric structures
2311 for _, g := range mm.pDeviceHandler.pmConfigs.Groups {
2312 mm.groupMetricMap[g.GroupName] = &groupMetric{
2313 groupName: g.GroupName,
2314 enabled: g.Enabled,
2315 frequency: g.GroupFreq,
2316 }
2317 switch g.GroupName {
2318 case OpticalPowerGroupMetricName:
2319 mm.groupMetricMap[g.GroupName].metricMap = OpticalPowerGroupMetrics
2320 case UniStatusGroupMetricName:
2321 mm.groupMetricMap[g.GroupName].metricMap = UniStatusGroupMetrics
2322 case EthernetBridgeHistoryName:
2323 mm.groupMetricMap[g.GroupName].metricMap = EthernetBridgeHistory
2324 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2325 case EthernetUniHistoryName:
2326 mm.groupMetricMap[g.GroupName].metricMap = EthernetUniHistory
2327 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2328 case FecHistoryName:
2329 mm.groupMetricMap[g.GroupName].metricMap = FecHistory
2330 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2331 case GemPortHistoryName:
2332 mm.groupMetricMap[g.GroupName].metricMap = GemPortHistory
2333 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2334 default:
2335 logger.Errorw(ctx, "unhandled-group-name", log.Fields{"groupName": g.GroupName})
2336 }
2337 }
2338
2339 // Populate local standalone metric structures
2340 for _, m := range mm.pDeviceHandler.pmConfigs.Metrics {
2341 mm.standaloneMetricMap[m.Name] = &standaloneMetric{
2342 metricName: m.Name,
2343 enabled: m.Enabled,
2344 frequency: m.SampleFreq,
2345 }
2346 switch m.Name {
2347 // None exist as of now. Add when available.
2348 default:
2349 logger.Errorw(ctx, "unhandled-metric-name", log.Fields{"metricName": m.Name})
2350 }
2351 }
2352}
2353
2354func (mm *onuMetricsManager) AddGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2355 mm.onuMetricsManagerLock.Lock()
2356 defer mm.onuMetricsManagerLock.Unlock()
2357 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002358 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002359 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002360 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002361
2362 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, GemPortHistoryName)
2363 // We do not need to remove from l2PmToDelete slice as we could have Add and Delete of
2364 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2365 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2366 // gemPortNCTPPerfHistInstToAdd slice
2367}
2368
2369func (mm *onuMetricsManager) RemoveGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2370 mm.onuMetricsManagerLock.Lock()
2371 defer mm.onuMetricsManagerLock.Unlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08002372 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002373 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002374 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002375
2376 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, GemPortHistoryName)
2377 // We do not need to remove from l2PmToAdd slice as we could have Add and Delete of
2378 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2379 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2380 // gemPortNCTPPerfHistInstToAdd slice
2381}
2382
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002383func (mm *onuMetricsManager) updateGemPortNTPInstanceToAddForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002384 if mm.pDeviceHandler.pOnuTP != nil {
2385 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002386 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002387 for _, v := range gemPortInstIDs {
2388 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002389 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002390 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002391 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002392 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002393 logger.Debugw(ctx, "updateGemPortNTPInstanceToAddForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002394 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 -08002395 }
2396}
2397
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002398func (mm *onuMetricsManager) updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002399 if mm.pDeviceHandler.pOnuTP != nil {
2400 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002401 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002402 for _, v := range gemPortInstIDs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002403 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002404 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002405 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002406 }
2407 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002408 logger.Debugw(ctx, "updateGemPortNTPInstanceToDeleteForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002409 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, "gemToDel": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
2410}
2411
2412// restorePmData restores any PM data available on the KV store to local cache
2413func (mm *onuMetricsManager) restorePmData(ctx context.Context) error {
2414 logger.Debugw(ctx, "restorePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2415 if mm.pmKvStore == nil {
2416 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2417 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2418 }
2419 var errorsList []error
2420 for groupName, group := range mm.groupMetricMap {
2421 group.pmMEData = &pmMEData{}
2422 Value, err := mm.pmKvStore.Get(ctx, groupName)
2423 if err == nil {
2424 if Value != nil {
2425 logger.Debugw(ctx, "PM data read",
2426 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2427 tmpBytes, _ := kvstore.ToByte(Value.Value)
2428
2429 if err = json.Unmarshal(tmpBytes, &group.pmMEData); err != nil {
2430 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2431 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-unmarshal-PM-data-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2432 continue
2433 }
2434 logger.Debugw(ctx, "restorePmData - success", log.Fields{"pmData": group.pmMEData, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2435 } else {
2436 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2437 continue
2438 }
2439 } else {
2440 logger.Errorw(ctx, "restorePmData - fail", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "err": err})
2441 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-read-from-KVstore-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2442 continue
2443 }
2444 }
2445 if len(errorsList) > 0 {
2446 return fmt.Errorf("errors-restoring-pm-data-for-one-or-more-groups--errors:%v", errorsList)
2447 }
2448 logger.Debugw(ctx, "restorePmData - complete success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2449 return nil
2450}
2451
2452// getPmData gets pmMEData from cache. Since we have write through cache implementation for pmMEData,
2453// the data must be available in cache.
2454// Note, it is expected that caller of this function manages the required synchronization (like using locks etc.).
2455func (mm *onuMetricsManager) getPmData(ctx context.Context, groupName string) (*pmMEData, error) {
2456 if grp, ok := mm.groupMetricMap[groupName]; ok {
2457 return grp.pmMEData, nil
2458 }
2459 // Data not in cache, try to fetch from kv store.
2460 data := &pmMEData{}
2461 if mm.pmKvStore == nil {
2462 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2463 return data, fmt.Errorf("pmKvStore not set. device-id - %s", mm.pDeviceHandler.deviceID)
2464 }
2465 Value, err := mm.pmKvStore.Get(ctx, groupName)
2466 if err == nil {
2467 if Value != nil {
2468 logger.Debugw(ctx, "PM data read",
2469 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2470 tmpBytes, _ := kvstore.ToByte(Value.Value)
2471
2472 if err = json.Unmarshal(tmpBytes, data); err != nil {
2473 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2474 return data, err
2475 }
2476 logger.Debugw(ctx, "PM data", log.Fields{"pmData": data, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2477 } else {
2478 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2479 return data, err
2480 }
2481 } else {
2482 logger.Errorw(ctx, "unable to read from KVstore", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2483 return data, err
2484 }
2485
2486 return data, nil
2487}
2488
2489// updatePmData update pmMEData to store. It is write through cache, i.e., write to cache first and then update store
2490func (mm *onuMetricsManager) updatePmData(ctx context.Context, groupName string, meInstanceID uint16, pmAction string) error {
2491 logger.Debugw(ctx, "updatePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "entityID": meInstanceID, "pmAction": pmAction})
2492 mm.onuMetricsManagerLock.Lock()
2493 defer mm.onuMetricsManagerLock.Unlock()
2494
2495 if mm.pmKvStore == nil {
2496 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2497 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2498 }
2499
2500 pmMEData, err := mm.getPmData(ctx, groupName)
2501 if err != nil || pmMEData == nil {
2502 // error already logged in called function.
2503 return err
2504 }
2505 switch pmAction {
2506 case cPmAdd:
2507 pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(pmMEData.InstancesToAdd, meInstanceID)
2508 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2509 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2510 case cPmAdded:
2511 pmMEData.InstancesActive = mm.appendIfMissingUnt16(pmMEData.InstancesActive, meInstanceID)
2512 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2513 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2514 case cPmRemove:
2515 pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(pmMEData.InstancesToDelete, meInstanceID)
2516 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2517 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2518 case cPmRemoved:
2519 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2520 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2521 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2522 default:
2523 logger.Errorw(ctx, "unknown pm action", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pmAction": pmAction, "groupName": groupName})
2524 return fmt.Errorf(fmt.Sprintf("unknown-pm-action-deviceid-%s-groupName-%s-pmaction-%s", mm.pDeviceHandler.deviceID, groupName, pmAction))
2525 }
2526 // write through cache
2527 mm.groupMetricMap[groupName].pmMEData = pmMEData
2528
2529 Value, err := json.Marshal(*pmMEData)
2530 if err != nil {
2531 logger.Errorw(ctx, "unable to marshal PM data", log.Fields{"groupName": groupName, "pmAction": pmAction, "pmData": *pmMEData, "err": err})
2532 return err
2533 }
2534 // Update back to kv store
2535 if err = mm.pmKvStore.Put(ctx, groupName, Value); err != nil {
2536 logger.Errorw(ctx, "unable to put PM data to kv store", log.Fields{"groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction, "err": err})
2537 return err
2538 }
2539 logger.Debugw(ctx, "updatePmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction})
2540
2541 return nil
2542}
2543
2544// clearPmGroupData cleans PM Group data from store
2545func (mm *onuMetricsManager) clearPmGroupData(ctx context.Context) error {
2546 mm.onuMetricsManagerLock.Lock()
2547 defer mm.onuMetricsManagerLock.Unlock()
2548 logger.Debugw(ctx, "clearPmGroupData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2549 if mm.pmKvStore == nil {
2550 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2551 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2552 }
2553
2554 for n := range mm.groupMetricMap {
2555 if err := mm.pmKvStore.Delete(ctx, n); err != nil {
2556 logger.Errorw(ctx, "clearPmGroupData - fail", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "groupName": n, "err": err})
2557 // do not abort this procedure. continue to delete next group.
2558 } else {
2559 logger.Debugw(ctx, "clearPmGroupData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": n})
2560 }
2561 }
2562
2563 return nil
2564}
2565
2566// clearAllPmData clears all PM data associated with the device from KV store
2567func (mm *onuMetricsManager) clearAllPmData(ctx context.Context) error {
2568 mm.onuMetricsManagerLock.Lock()
2569 defer mm.onuMetricsManagerLock.Unlock()
2570 logger.Debugw(ctx, "clearAllPmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2571 if mm.pmKvStore == nil {
2572 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2573 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2574 }
2575
2576 if err := mm.pmKvStore.Delete(ctx, ""); err != nil {
2577 logger.Errorw(ctx, "unable to delete PM data from kv store", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "err": err})
2578 return err
2579 }
2580 logger.Debugw(ctx, "clearAllPmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2581 return nil
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002582}
2583
2584func (mm *onuMetricsManager) appendIfMissingString(slice []string, n string) []string {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002585 for _, ele := range slice {
2586 if ele == n {
2587 return slice
2588 }
2589 }
2590 return append(slice, n)
2591}
2592
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002593func (mm *onuMetricsManager) removeIfFoundString(slice []string, n string) []string {
2594 for i, ele := range slice {
2595 if ele == n {
2596 return append(slice[:i], slice[i+1:]...)
2597 }
2598 }
2599 return slice
2600}
2601
2602func (mm *onuMetricsManager) appendIfMissingUnt16(slice []uint16, n uint16) []uint16 {
2603 for _, ele := range slice {
2604 if ele == n {
2605 return slice
2606 }
2607 }
2608 return append(slice, n)
2609}
2610
2611func (mm *onuMetricsManager) removeIfFoundUint16(slice []uint16, n uint16) []uint16 {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002612 for i, ele := range slice {
2613 if ele == n {
2614 return append(slice[:i], slice[i+1:]...)
2615 }
2616 }
2617 return slice
Girish Gowdrae09a6202021-01-12 18:10:59 -08002618}
Girish Gowdrae20a4f62021-03-09 16:06:23 -08002619
2620func (mm *onuMetricsManager) twosComplementToSignedInt16(val uint16) int16 {
2621 var uint16MsbMask uint16 = 0x8000
2622 if val&uint16MsbMask == uint16MsbMask {
2623 return int16(^val+1) * -1
2624 }
2625
2626 return int16(val)
2627}
2628
2629/* // These are need in the future
2630
2631func (mm *onuMetricsManager) twosComplementToSignedInt32(val uint32) int32 {
2632 var uint32MsbMask uint32 = 0x80000000
2633 if val & uint32MsbMask == uint32MsbMask {
2634 return int32(^val + 1) * -1
2635 }
2636
2637 return int32(val)
2638}
2639
2640func (mm *onuMetricsManager) twosComplementToSignedInt64(val uint64) int64 {
2641 var uint64MsbMask uint64 = 0x8000000000000000
2642 if val & uint64MsbMask == uint64MsbMask {
2643 return int64(^val + 1) * -1
2644 }
2645
2646 return int64(val)
2647}
2648
2649*/