blob: cd8372519041a7a6fb54e6db999af61d68270a30 [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 Gowdrae09a6202021-01-12 18:10:59 -080022 "fmt"
Girish Gowdrae0140f02021-02-02 16:55:09 -080023 "github.com/looplab/fsm"
Girish Gowdrae09a6202021-01-12 18:10:59 -080024 "github.com/opencord/omci-lib-go"
25 me "github.com/opencord/omci-lib-go/generated"
26 "github.com/opencord/voltha-lib-go/v4/pkg/log"
27 "github.com/opencord/voltha-protos/v4/go/voltha"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080028 "sync"
Girish Gowdrae09a6202021-01-12 18:10:59 -080029 "time"
30)
31
Girish Gowdrae0140f02021-02-02 16:55:09 -080032const (
33 // events of L2 PM FSM
34 l2PmEventInit = "l2PmEventInit"
35 l2PmEventTick = "l2PmEventTick"
36 l2PmEventSuccess = "l2PmEventSuccess"
37 l2PmEventFailure = "l2PmEventFailure"
38 l2PmEventAddMe = "l2PmEventAddMe"
39 l2PmEventDeleteMe = "l2PmEventDeleteMe"
40 l2PmEventStop = "l2PmEventStop"
41)
42const (
43 // states of L2 PM FSM
44 l2PmStNull = "l2PmStNull"
45 l2PmStStarting = "l2PmStStarting"
46 l2PmStSyncTime = "l2PmStSyncTime"
47 l2PmStIdle = "l2PmStIdle"
48 l2PmStCreatePmMe = "l2PmStCreatePm"
49 l2PmStDeletePmMe = "l2PmStDeletePmMe"
50 l2PmStCollectData = "l2PmStCollectData"
51)
52
53const cL2PmFsmIdleState = l2PmStIdle
54
Girish Gowdra5a7c4922021-01-22 18:33:41 -080055// general constants used for overall Metric Collection management
56const (
57 DefaultMetricCollectionFrequency = 15 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
58 GroupMetricEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
59 DefaultFrequencyOverrideEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
60 FrequencyGranularity = 5 // The frequency (in seconds) has to be multiple of 5. This setting cannot changed later.
61)
62
63// OpticalPowerGroupMetrics are supported optical pm names
64var OpticalPowerGroupMetrics = map[string]voltha.PmConfig_PmType{
65 "ani_g_instance_id": voltha.PmConfig_CONTEXT,
66 "transmit_power": voltha.PmConfig_GAUGE,
67 "receive_power": voltha.PmConfig_GAUGE,
68}
69
70// OpticalPowerGroupMetrics specific constants
71const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080072 OpticalPowerGroupMetricName = "PON_Optical"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080073 OpticalPowerGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
74 OpticalPowerMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
75)
76
77// UniStatusGroupMetrics are supported UNI status names
78var UniStatusGroupMetrics = map[string]voltha.PmConfig_PmType{
79 "uni_port_no": voltha.PmConfig_CONTEXT,
80 "ethernet_type": voltha.PmConfig_GAUGE,
81 "oper_status": voltha.PmConfig_GAUGE,
82 "uni_admin_state": voltha.PmConfig_GAUGE,
83}
84
85// UniStatusGroupMetrics specific constants
86const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080087 UniStatusGroupMetricName = "UNI_Status"
Girish Gowdra5a7c4922021-01-22 18:33:41 -080088 UniStatusGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
89 UniStatusMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
90)
91
Girish Gowdrae0140f02021-02-02 16:55:09 -080092// *** Classical L2 PM Counters begin ***
93
94// EthernetBridgeHistory are supported ethernet bridge history counters fetched from
95// Ethernet Frame Performance Monitoring History Data Downstream and Ethernet Frame Performance Monitoring History Data Upstream MEs.
96var EthernetBridgeHistory = map[string]voltha.PmConfig_PmType{
97 "class_id": voltha.PmConfig_CONTEXT,
98 "entity_id": voltha.PmConfig_CONTEXT,
99 "interval_end_time": voltha.PmConfig_CONTEXT,
100 "parent_class_id": voltha.PmConfig_CONTEXT,
101 "parent_entity_id": voltha.PmConfig_CONTEXT,
102 "upstream": voltha.PmConfig_CONTEXT,
103
104 "drop_events": voltha.PmConfig_COUNTER,
105 "octets": voltha.PmConfig_COUNTER,
106 "packets": voltha.PmConfig_COUNTER,
107 "broadcast_packets": voltha.PmConfig_COUNTER,
108 "multicast_packets": voltha.PmConfig_COUNTER,
109 "crc_errored_packets": voltha.PmConfig_COUNTER,
110 "undersize_packets": voltha.PmConfig_COUNTER,
111 "oversize_packets": voltha.PmConfig_COUNTER,
112 "64_octets": voltha.PmConfig_COUNTER,
113 "65_to_127_octets": voltha.PmConfig_COUNTER,
114 "128_to_255_octets": voltha.PmConfig_COUNTER,
115 "256_to_511_octets": voltha.PmConfig_COUNTER,
116 "512_to_1023_octets": voltha.PmConfig_COUNTER,
117 "1024_to_1518_octets": voltha.PmConfig_COUNTER,
118}
119
120// EthernetUniHistory are supported ethernet uni history counters fetched from
121// Ethernet Performance Monitoring History Data ME.
122var EthernetUniHistory = map[string]voltha.PmConfig_PmType{
123 "class_id": voltha.PmConfig_CONTEXT,
124 "entity_id": voltha.PmConfig_CONTEXT,
125 "interval_end_time": voltha.PmConfig_CONTEXT,
126
127 "fcs_errors": voltha.PmConfig_COUNTER,
128 "excessive_collision_counter": voltha.PmConfig_COUNTER,
129 "late_collision_counter": voltha.PmConfig_COUNTER,
130 "frames_too_long": voltha.PmConfig_COUNTER,
131 "buffer_overflows_on_rx": voltha.PmConfig_COUNTER,
132 "buffer_overflows_on_tx": voltha.PmConfig_COUNTER,
133 "single_collision_frame_counter": voltha.PmConfig_COUNTER,
134 "multiple_collisions_frame_counter": voltha.PmConfig_COUNTER,
135 "sqe_counter": voltha.PmConfig_COUNTER,
136 "deferred_tx_counter": voltha.PmConfig_COUNTER,
137 "internal_mac_tx_error_counter": voltha.PmConfig_COUNTER,
138 "carrier_sense_error_counter": voltha.PmConfig_COUNTER,
139 "alignment_error_counter": voltha.PmConfig_COUNTER,
140 "internal_mac_rx_error_counter": voltha.PmConfig_COUNTER,
141}
142
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800143// FecHistory is supported FEC Performance Monitoring History Data related metrics
144var FecHistory = map[string]voltha.PmConfig_PmType{
145 "class_id": voltha.PmConfig_CONTEXT,
146 "entity_id": voltha.PmConfig_CONTEXT,
147 "interval_end_time": voltha.PmConfig_CONTEXT,
148
149 "corrected_bytes": voltha.PmConfig_COUNTER,
150 "corrected_code_words": voltha.PmConfig_COUNTER,
151 "uncorrectable_code_words": voltha.PmConfig_COUNTER,
152 "total_code_words": voltha.PmConfig_COUNTER,
153 "fec_seconds": voltha.PmConfig_COUNTER,
154}
155
156// GemPortHistory is supported GEM Port Network Ctp Performance Monitoring History Data
157// related metrics
158var GemPortHistory = map[string]voltha.PmConfig_PmType{
159 "class_id": voltha.PmConfig_CONTEXT,
160 "entity_id": voltha.PmConfig_CONTEXT,
161 "interval_end_time": voltha.PmConfig_CONTEXT,
162
163 "transmitted_gem_frames": voltha.PmConfig_COUNTER,
164 "received_gem_frames": voltha.PmConfig_COUNTER,
165 "received_payload_bytes": voltha.PmConfig_COUNTER,
166 "transmitted_payload_bytes": voltha.PmConfig_COUNTER,
167 "encryption_key_errors": voltha.PmConfig_COUNTER,
168}
169
Girish Gowdrae0140f02021-02-02 16:55:09 -0800170// Constants specific for L2 PM collection
171const (
172 L2PmCollectionInterval = 15 * 60 // Unit in seconds. Do not change this as this fixed by OMCI specification for L2 PM counters
173 SyncTimeRetryInterval = 15 // Unit seconds
174 L2PmCreateAttempts = 3
175 L2PmCollectAttempts = 3
Girish Gowdra453750f2021-02-16 16:36:46 -0800176 // Per Table 11.2.9-1 – OMCI baseline message limitations in G.988 spec, the max GET Response
177 // payload size is 25. We define 24 (one less) to allow for dynamic insertion of IntervalEndTime
178 // attribute (1 byte) in L2 PM GET Requests.
179 MaxL2PMGetPayLoadSize = 24
Girish Gowdrae0140f02021-02-02 16:55:09 -0800180)
181
182// EthernetUniHistoryName specific constants
183const (
184 EthernetBridgeHistoryName = "Ethernet_Bridge_Port_History"
185 EthernetBridgeHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
186 EthernetBridgeHistoryFrequency = L2PmCollectionInterval
187)
188
189// EthernetBridgeHistory specific constants
190const (
191 EthernetUniHistoryName = "Ethernet_UNI_History"
192 EthernetUniHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
193 EthernetUniHistoryFrequency = L2PmCollectionInterval
194)
195
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800196// FecHistory specific constants
197const (
198 FecHistoryName = "FEC_History"
199 FecHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
200 FecHistoryFrequency = L2PmCollectionInterval
201)
202
203// GemPortHistory specific constants
204const (
205 GemPortHistoryName = "GEM_Port_History"
206 GemPortHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
207 GemPortHistoryFrequency = L2PmCollectionInterval
208)
209
210// Defines the type for generic metric population function
211type groupMetricPopulateFunc func(context.Context, me.ClassID, uint16, me.AttributeValueMap, me.AttributeValueMap, map[string]float32, *int) error
212
Girish Gowdrae0140f02021-02-02 16:55:09 -0800213// *** Classical L2 PM Counters end ***
214
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800215type groupMetric struct {
216 groupName string
217 enabled bool
218 frequency uint32 // valid only if FrequencyOverride is enabled.
219 metricMap map[string]voltha.PmConfig_PmType
220 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
Girish Gowdrae0140f02021-02-02 16:55:09 -0800221 isL2PMCounter bool // true for only L2 PM counters
222 collectAttempts uint32 // number of attempts to collect L2 PM data
223 createRetryAttempts uint32 // number of attempts to try creating the L2 PM ME
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800224}
225
226type standaloneMetric struct {
227 metricName string
228 enabled bool
229 frequency uint32 // valid only if FrequencyOverride is enabled.
230 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
231}
232
Girish Gowdrae09a6202021-01-12 18:10:59 -0800233type onuMetricsManager struct {
234 pDeviceHandler *deviceHandler
Girish Gowdrae0140f02021-02-02 16:55:09 -0800235 pAdaptFsm *AdapterFsm
Girish Gowdrae09a6202021-01-12 18:10:59 -0800236
Girish Gowdrae0140f02021-02-02 16:55:09 -0800237 opticalMetricsChan chan me.AttributeValueMap
238 uniStatusMetricsChan chan me.AttributeValueMap
239 l2PmChan chan me.AttributeValueMap
240 syncTimeResponseChan chan bool // true is success, false is fail
241 l2PmCreateOrDeleteResponseChan chan bool // true is success, false is fail
242
243 activeL2Pms []string // list of active l2 pm MEs created on the ONU.
244 l2PmToDelete []string // list of L2 PMs to delete
245 l2PmToAdd []string // list of L2 PM to add
Girish Gowdrae09a6202021-01-12 18:10:59 -0800246
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800247 gemPortNCTPPerfHistInstToAdd []uint16
248 gemPortNCTPPerfHistInstToDelete []uint16
249 gemPortNCTPPerfHistInstActive []uint16
250
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800251 groupMetricMap map[string]*groupMetric
252 standaloneMetricMap map[string]*standaloneMetric
253
Girish Gowdrae09a6202021-01-12 18:10:59 -0800254 stopProcessingOmciResponses chan bool
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800255
Girish Gowdrae0140f02021-02-02 16:55:09 -0800256 stopTicks chan bool
257
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800258 nextGlobalMetricCollectionTime time.Time // valid only if pmConfig.FreqOverride is set to false.
259
260 onuMetricsManagerLock sync.RWMutex
Girish Gowdrae09a6202021-01-12 18:10:59 -0800261}
262
263// newonuMetricsManager returns a new instance of the newonuMetricsManager
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800264// Note that none of the context stored internally in onuMetricsManager is backed up on KV store for resiliency.
265// Metric collection is not a critical operation that needs support for resiliency. On adapter restart, some context
266// could be lost (except for Device.PmConfigs which is backed up the rw-core on KV store). An example of information
267// that is lost on adapter restart is nextCollectionInterval time.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800268func newonuMetricsManager(ctx context.Context, dh *deviceHandler) *onuMetricsManager {
269
270 var metricsManager onuMetricsManager
271 logger.Debugw(ctx, "init-onuMetricsManager", log.Fields{"device-id": dh.deviceID})
272 metricsManager.pDeviceHandler = dh
273
Girish Gowdrae0140f02021-02-02 16:55:09 -0800274 commMetricsChan := make(chan Message)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800275 metricsManager.opticalMetricsChan = make(chan me.AttributeValueMap)
276 metricsManager.uniStatusMetricsChan = make(chan me.AttributeValueMap)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800277 metricsManager.l2PmChan = make(chan me.AttributeValueMap)
278
279 metricsManager.syncTimeResponseChan = make(chan bool)
280 metricsManager.l2PmCreateOrDeleteResponseChan = make(chan bool)
281
Girish Gowdrae09a6202021-01-12 18:10:59 -0800282 metricsManager.stopProcessingOmciResponses = make(chan bool)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800283 metricsManager.stopTicks = make(chan bool)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800284
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800285 metricsManager.groupMetricMap = make(map[string]*groupMetric)
286 metricsManager.standaloneMetricMap = make(map[string]*standaloneMetric)
287
288 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 -0800289 metricsManager.initializeAllGroupMetrics()
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800290 }
291
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800292 metricsManager.populateLocalGroupMetricData(ctx)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800293
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800294 if err := metricsManager.initializeL2PmFsm(ctx, commMetricsChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800295 return nil
296 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800297
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800298 // initialize the next metric collection intervals.
299 metricsManager.initializeMetricCollectionTime(ctx)
300 logger.Info(ctx, "init-onuMetricsManager completed", log.Fields{"device-id": dh.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800301 return &metricsManager
302}
303
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800304func (mm *onuMetricsManager) initializeMetricCollectionTime(ctx context.Context) {
305 if mm.pDeviceHandler.pmConfigs.FreqOverride {
306 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to true, then group/standalone metric specific interval applies
307 mm.onuMetricsManagerLock.Lock()
308 defer mm.onuMetricsManagerLock.Unlock()
309 for _, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800310 if v.enabled && !v.isL2PMCounter { // L2 PM counter collection is managed in a L2PmFsm
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800311 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
312 }
313 }
314
315 for _, v := range mm.standaloneMetricMap {
316 if v.enabled {
317 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
318 }
319 }
320 } else {
321 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to false, then overall metric specific interval applies
322 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
323 }
324 logger.Infow(ctx, "initialized standalone group/metric collection time", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
325}
326
327func (mm *onuMetricsManager) updateDefaultFrequency(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
328 // Verify that the configured DefaultFrequency is > 0 and is a multiple of FrequencyGranularity
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800329 if pmConfigs.DefaultFreq == 0 || (pmConfigs.DefaultFreq > 0 && pmConfigs.DefaultFreq%FrequencyGranularity != 0) {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800330 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", pmConfigs.DefaultFreq, FrequencyGranularity)
331 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", pmConfigs.DefaultFreq, FrequencyGranularity)
332 }
333 mm.pDeviceHandler.pmConfigs.DefaultFreq = pmConfigs.DefaultFreq
334 // re-set the nextGlobalMetricCollectionTime based on the new DefaultFreq
335 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
336 logger.Debugw(ctx, "frequency-updated--new-frequency", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "frequency": mm.pDeviceHandler.pmConfigs.DefaultFreq})
337 return nil
338}
339
340func (mm *onuMetricsManager) updateGroupFreq(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
341 var newGroupFreq uint32
342 found := false
343 groupSliceIdx := 0
344 var group *voltha.PmGroupConfig
345 for groupSliceIdx, group = range pmConfigs.Groups {
346 if group.GroupName == aGroupName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800347 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
348 if group.GroupFreq == 0 || (group.GroupFreq > 0 && group.GroupFreq%FrequencyGranularity != 0) {
349 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", group.GroupFreq, FrequencyGranularity)
350 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", group.GroupFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800351 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800352 newGroupFreq = group.GroupFreq
353 found = true
354 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800355 }
356 }
357 // if not found update group freq and next collection interval for the group
358 if !found {
359 logger.Errorw(ctx, "group name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
360 return fmt.Errorf("group-name-not-found-%v", aGroupName)
361 }
362
363 updated := false
364 mm.onuMetricsManagerLock.Lock()
365 defer mm.onuMetricsManagerLock.Unlock()
366 for k, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800367 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 -0800368 v.frequency = newGroupFreq
369 // update internal pm config
370 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].GroupFreq = newGroupFreq
371 // Also updated the next group metric collection time from now
372 v.nextCollectionInterval = time.Now().Add(time.Duration(newGroupFreq) * time.Second)
373 updated = true
374 logger.Infow(ctx, "group frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
375 }
376 }
377 if !updated {
378 logger.Errorw(ctx, "group frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
379 return fmt.Errorf("internal-error-during-group-freq-update--groupname-%s-freq-%d", aGroupName, newGroupFreq)
380 }
381 return nil
382}
383
384func (mm *onuMetricsManager) updateMetricFreq(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
385 var newMetricFreq uint32
386 found := false
387 metricSliceIdx := 0
388 var metric *voltha.PmConfig
389 for metricSliceIdx, metric = range pmConfigs.Metrics {
390 if metric.Name == aMetricName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800391 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
392 if metric.SampleFreq == 0 || (metric.SampleFreq > 0 && metric.SampleFreq%FrequencyGranularity != 0) {
393 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", metric.SampleFreq, FrequencyGranularity)
394 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", metric.SampleFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800395 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800396 newMetricFreq = metric.SampleFreq
397 found = true
398 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800399 }
400 }
401 if !found {
402 logger.Errorw(ctx, "metric name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
403 return fmt.Errorf("metric-name-not-found-%v", aMetricName)
404 }
405
406 updated := false
407 mm.onuMetricsManagerLock.Lock()
408 defer mm.onuMetricsManagerLock.Unlock()
409 for k, v := range mm.groupMetricMap {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800410 if k == aMetricName {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800411 v.frequency = newMetricFreq
412 // update internal pm config
413 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].SampleFreq = newMetricFreq
414 // Also updated the next standalone metric collection time from now
415 v.nextCollectionInterval = time.Now().Add(time.Duration(newMetricFreq) * time.Second)
416 updated = true
417 logger.Infow(ctx, "metric frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
418 }
419 }
420 if !updated {
421 logger.Errorw(ctx, "metric frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
422 return fmt.Errorf("internal-error-during-standalone-metric-update--matricnane-%s-freq-%d", aMetricName, newMetricFreq)
423 }
424 return nil
425}
426
427func (mm *onuMetricsManager) updateGroupSupport(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
428 groupSliceIdx := 0
429 var group *voltha.PmGroupConfig
430
431 for groupSliceIdx, group = range pmConfigs.Groups {
432 if group.GroupName == aGroupName {
433 break
434 }
435 }
436 if group == nil {
437 logger.Errorw(ctx, "group metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
438 return fmt.Errorf("group-not-found--groupName-%s", aGroupName)
439 }
440
441 updated := false
442 mm.onuMetricsManagerLock.Lock()
443 defer mm.onuMetricsManagerLock.Unlock()
444 for k, v := range mm.groupMetricMap {
445 if k == aGroupName && v.enabled != group.Enabled {
446 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].Enabled = group.Enabled
447 v.enabled = group.Enabled
Girish Gowdrae0140f02021-02-02 16:55:09 -0800448 if group.Enabled {
449 if v.isL2PMCounter {
450 // If it is a L2 PM counter we need to mark the PM to be added
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800451 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800452 // 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 -0800453 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, v.groupName)
454
455 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
456 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
457 // take further action
458 if v.groupName == GemPortHistoryName {
459 mm.updateGemPortNTPInstanceToAddForPerfMonitoring()
460 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800461 } else if mm.pDeviceHandler.pmConfigs.FreqOverride { // otherwise just update the next collection interval
462 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
463 }
464 } else { // group counter is disabled
465 if v.isL2PMCounter {
466 // If it is a L2 PM counter we need to mark the PM to be deleted
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800467 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800468 // 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 -0800469 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, v.groupName)
470
471 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
472 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
473 // take further action
474 if v.groupName == GemPortHistoryName {
475 mm.updateGemPortNTPInstanceToDeleteForPerfMonitoring()
476 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800477 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800478 }
479 updated = true
Girish Gowdrae0140f02021-02-02 16:55:09 -0800480 if v.isL2PMCounter {
481 logger.Infow(ctx, "l2 pm group metric support updated",
482 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled, "l2PmToAdd": mm.l2PmToAdd, "l2PmToDelete": mm.l2PmToDelete})
483 } else {
484 logger.Infow(ctx, "group metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled})
485 }
486 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800487 }
488 }
489
490 if !updated {
491 logger.Errorw(ctx, "group metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
492 return fmt.Errorf("internal-error-during-group-support-update--groupName-%s", aGroupName)
493 }
494 return nil
495}
496
497func (mm *onuMetricsManager) updateMetricSupport(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
498 metricSliceIdx := 0
499 var metric *voltha.PmConfig
500
501 for metricSliceIdx, metric = range pmConfigs.Metrics {
502 if metric.Name == aMetricName {
503 break
504 }
505 }
506
507 if metric == nil {
508 logger.Errorw(ctx, "standalone metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
509 return fmt.Errorf("metric-not-found--metricname-%s", aMetricName)
510 }
511
512 updated := false
513 mm.onuMetricsManagerLock.Lock()
514 defer mm.onuMetricsManagerLock.Unlock()
515 for k, v := range mm.standaloneMetricMap {
516 if k == aMetricName && v.enabled != metric.Enabled {
517 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].Enabled = metric.Enabled
518 v.enabled = metric.Enabled
519 // If the standalone metric is now enabled and frequency override is enabled, set the next metric collection time
520 if metric.Enabled && mm.pDeviceHandler.pmConfigs.FreqOverride {
521 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
522 }
523 updated = true
524 logger.Infow(ctx, "standalone metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName, "enabled": metric.Enabled})
525 }
526 }
527 if !updated {
528 logger.Errorw(ctx, "standalone metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
529 return fmt.Errorf("internal-error-during-standalone-support-update--metricname-%s", aMetricName)
530 }
531 return nil
532}
533
534func (mm *onuMetricsManager) collectAllGroupAndStandaloneMetrics(ctx context.Context) {
535 if mm.pDeviceHandler.pmConfigs.Grouped { // metrics are managed as a group.
536 go mm.collectAllGroupMetrics(ctx)
537 } else {
538 go mm.collectAllStandaloneMetrics(ctx)
539 }
540}
541
542func (mm *onuMetricsManager) collectAllGroupMetrics(ctx context.Context) {
543 go func() {
544 logger.Debug(ctx, "startCollector before collecting optical metrics")
545 metricInfo := mm.collectOpticalMetrics(ctx)
546 if metricInfo != nil {
547 mm.publishMetrics(ctx, metricInfo)
548 }
549 }()
550
551 go func() {
552 logger.Debug(ctx, "startCollector before collecting uni metrics")
553 metricInfo := mm.collectUniStatusMetrics(ctx)
554 if metricInfo != nil {
555 mm.publishMetrics(ctx, metricInfo)
556 }
557 }()
558
559 // Add more here
560}
561
562func (mm *onuMetricsManager) collectAllStandaloneMetrics(ctx context.Context) {
563 // None exists as of now, add when available here
564}
565
566func (mm *onuMetricsManager) collectGroupMetric(ctx context.Context, groupName string) {
567 switch groupName {
568 case OpticalPowerGroupMetricName:
569 go func() {
570 if mi := mm.collectOpticalMetrics(ctx); mm != nil {
571 mm.publishMetrics(ctx, mi)
572 }
573 }()
574 case UniStatusGroupMetricName:
575 go func() {
576 if mi := mm.collectUniStatusMetrics(ctx); mm != nil {
577 mm.publishMetrics(ctx, mi)
578 }
579 }()
580 default:
581 logger.Errorw(ctx, "unhandled group metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName})
582 }
583}
584
585func (mm *onuMetricsManager) collectStandaloneMetric(ctx context.Context, metricName string) {
586 switch metricName {
587 // None exist as of now, add when available
588 default:
589 logger.Errorw(ctx, "unhandled standalone metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName})
590 }
591}
592
593// collectOpticalMetrics collects groups metrics related to optical power from ani-g ME.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800594func (mm *onuMetricsManager) collectOpticalMetrics(ctx context.Context) []*voltha.MetricInformation {
595 logger.Debugw(ctx, "collectOpticalMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800596
597 mm.onuMetricsManagerLock.RLock()
598 if !mm.groupMetricMap[OpticalPowerGroupMetricName].enabled {
599 mm.onuMetricsManagerLock.RUnlock()
600 logger.Debugw(ctx, "optical power group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
601 return nil
602 }
603 mm.onuMetricsManagerLock.RUnlock()
604
Girish Gowdrae09a6202021-01-12 18:10:59 -0800605 var metricInfoSlice []*voltha.MetricInformation
606 metricsContext := make(map[string]string)
607 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
608 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
609 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
610
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800611 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800612 mmd := voltha.MetricMetaData{
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800613 Title: OpticalPowerGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800614 Ts: float64(raisedTs),
615 Context: metricsContext,
616 DeviceId: mm.pDeviceHandler.deviceID,
617 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
618 SerialNo: mm.pDeviceHandler.device.SerialNumber,
619 }
620
Girish Gowdrae09a6202021-01-12 18:10:59 -0800621 // get the ANI-G instance IDs
622 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
623loop:
624 for _, anigInstID := range anigInstKeys {
625 var meAttributes me.AttributeValueMap
626 opticalMetrics := make(map[string]float32)
627 // Get the ANI-G instance optical power attributes
628 requestedAttributes := me.AttributeValueMap{"OpticalSignalLevel": 0, "TransmitOpticalLevel": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800629 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.AniGClassID, anigInstID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800630 select {
631 case meAttributes = <-mm.opticalMetricsChan:
632 logger.Debugw(ctx, "received optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
633 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
634 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
635 // The metrics will be empty in this case
636 break loop
637 }
638 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800639 for k := range OpticalPowerGroupMetrics {
640 switch k {
641 case "ani_g_instance_id":
642 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
643 opticalMetrics[k] = float32(val.(uint16))
644 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800645 case "transmit_power":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800646 if val, ok := meAttributes["TransmitOpticalLevel"]; ok && val != nil {
647 opticalMetrics[k] = float32(val.(uint16))
648 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800649 case "receive_power":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800650 if val, ok := meAttributes["OpticalSignalLevel"]; ok && val != nil {
651 opticalMetrics[k] = float32(val.(uint16))
652 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800653 default:
654 // do nothing
655 }
656 }
657 }
658 // create slice of metrics given that there could be more than one ANI-G instance and
659 // optical metrics are collected per ANI-G instance
660 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: opticalMetrics}
661 metricInfoSlice = append(metricInfoSlice, &metricInfo)
662 }
663
664 return metricInfoSlice
665}
666
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800667// collectUniStatusMetrics collects UNI status group metric from various MEs (uni-g, pptp and veip).
Girish Gowdrae09a6202021-01-12 18:10:59 -0800668// nolint: gocyclo
669func (mm *onuMetricsManager) collectUniStatusMetrics(ctx context.Context) []*voltha.MetricInformation {
670 logger.Debugw(ctx, "collectUniStatusMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800671 mm.onuMetricsManagerLock.RLock()
672 if !mm.groupMetricMap[UniStatusGroupMetricName].enabled {
673 mm.onuMetricsManagerLock.RUnlock()
674 logger.Debugw(ctx, "uni status group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
675 return nil
676 }
677 mm.onuMetricsManagerLock.RUnlock()
678
Girish Gowdrae09a6202021-01-12 18:10:59 -0800679 var metricInfoSlice []*voltha.MetricInformation
680 metricsContext := make(map[string]string)
681 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
682 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
683 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
684
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800685 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800686 mmd := voltha.MetricMetaData{
687 Title: "UniStatus", // Is this ok to hard code?
688 Ts: float64(raisedTs),
689 Context: metricsContext,
690 DeviceId: mm.pDeviceHandler.deviceID,
691 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
692 SerialNo: mm.pDeviceHandler.device.SerialNumber,
693 }
694
Girish Gowdrae09a6202021-01-12 18:10:59 -0800695 // get the UNI-G instance IDs
696 unigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.UniGClassID)
697loop1:
698 for _, unigInstID := range unigInstKeys {
699 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
700 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
701 unigMetrics := make(map[string]float32)
702 var meAttributes me.AttributeValueMap
703 // Get the UNI-G instance optical power attributes
704 requestedAttributes := me.AttributeValueMap{"AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800705 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.UniGClassID, unigInstID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800706 // Wait for metrics or timeout
707 select {
708 case meAttributes = <-mm.uniStatusMetricsChan:
709 logger.Debugw(ctx, "received uni-g metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
710 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
711 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
712 // The metrics could be empty in this case
713 break loop1
714 }
715 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800716 for k := range UniStatusGroupMetrics {
717 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800718 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800719 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
720 unigMetrics[k] = float32(val.(byte))
721 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800722 default:
723 // do nothing
724 }
725 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800726 var entityID uint32
727 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
728 entityID = uint32(val.(uint16))
729 }
730 // TODO: Rlock needed for reading uniEntityMap?
731 if uniPort, ok := mm.pDeviceHandler.uniEntityMap[entityID]; ok && uniPort != nil {
732 unigMetrics["uni_port_no"] = float32(uniPort.portNo)
733 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800734 // create slice of metrics given that there could be more than one UNI-G instance
735 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: unigMetrics}
736 metricInfoSlice = append(metricInfoSlice, &metricInfo)
737 }
738 }
739
740 // get the PPTP instance IDs
741 pptpInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.PhysicalPathTerminationPointEthernetUniClassID)
742loop2:
743 for _, pptpInstID := range pptpInstKeys {
744 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
745 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
746 var meAttributes me.AttributeValueMap
747 pptpMetrics := make(map[string]float32)
748
749 requestedAttributes := me.AttributeValueMap{"SensedType": 0, "OperationalState": 0, "AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800750 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.PhysicalPathTerminationPointEthernetUniClassID, pptpInstID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800751 // Wait for metrics or timeout
752 select {
753 case meAttributes = <-mm.uniStatusMetricsChan:
754 logger.Debugw(ctx, "received pptp metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
755 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
756 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
757 // The metrics could be empty in this case
758 break loop2
759 }
760
761 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800762 for k := range UniStatusGroupMetrics {
763 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800764 case "ethernet_type":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800765 if val, ok := meAttributes["SensedType"]; ok && val != nil {
766 pptpMetrics[k] = float32(val.(byte))
767 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800768 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800769 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
770 pptpMetrics[k] = float32(val.(byte))
771 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800772 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800773 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
774 pptpMetrics[k] = float32(val.(byte))
775 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800776 default:
777 // do nothing
778 }
779 }
780 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800781 var entityID uint32
782 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
783 entityID = uint32(val.(uint16))
784 }
785 // TODO: Rlock needed for reading uniEntityMap?
786 if uniPort, ok := mm.pDeviceHandler.uniEntityMap[entityID]; ok && uniPort != nil {
787 pptpMetrics["uni_port_no"] = float32(uniPort.portNo)
788 }
789
Girish Gowdrae09a6202021-01-12 18:10:59 -0800790 // create slice of metrics given that there could be more than one PPTP instance and
791 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: pptpMetrics}
792 metricInfoSlice = append(metricInfoSlice, &metricInfo)
793 }
794
795 // get the VEIP instance IDs
796 veipInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.VirtualEthernetInterfacePointClassID)
797loop3:
798 for _, veipInstID := range veipInstKeys {
799 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
800 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
801 var meAttributes me.AttributeValueMap
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800802 veipMetrics := make(map[string]float32)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800803
804 requestedAttributes := me.AttributeValueMap{"OperationalState": 0, "AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800805 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.VirtualEthernetInterfacePointClassID, veipInstID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800806 // Wait for metrics or timeout
807 select {
808 case meAttributes = <-mm.uniStatusMetricsChan:
809 logger.Debugw(ctx, "received veip metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
810 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
811 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
812 // The metrics could be empty in this case
813 break loop3
814 }
815
816 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800817 for k := range UniStatusGroupMetrics {
818 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800819 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800820 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
821 veipMetrics[k] = float32(val.(byte))
822 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800823 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800824 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
825 veipMetrics[k] = float32(val.(byte))
826 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800827 default:
828 // do nothing
829 }
830 }
831 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800832
833 var entityID uint32
834 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
835 entityID = uint32(meAttributes["ManagedEntityId"].(uint16))
836 }
837 // TODO: Rlock needed for reading uniEntityMap?
838 if uniPort, ok := mm.pDeviceHandler.uniEntityMap[entityID]; ok && uniPort != nil {
839 veipMetrics["uni_port_no"] = float32(uniPort.portNo)
840 }
841
Girish Gowdrae09a6202021-01-12 18:10:59 -0800842 // create slice of metrics given that there could be more than one VEIP instance
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800843 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: veipMetrics}
Girish Gowdrae09a6202021-01-12 18:10:59 -0800844 metricInfoSlice = append(metricInfoSlice, &metricInfo)
845 }
846
847 return metricInfoSlice
848}
849
850// publishMetrics publishes the metrics on kafka
851func (mm *onuMetricsManager) publishMetrics(ctx context.Context, metricInfo []*voltha.MetricInformation) {
852 var ke voltha.KpiEvent2
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800853 ts := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800854 ke.SliceData = metricInfo
855 ke.Type = voltha.KpiEventType_slice
856 ke.Ts = float64(ts)
857
858 if err := mm.pDeviceHandler.EventProxy.SendKpiEvent(ctx, "STATS_EVENT", &ke, voltha.EventCategory_EQUIPMENT, voltha.EventSubCategory_ONU, ts); err != nil {
859 logger.Errorw(ctx, "failed-to-send-pon-stats", log.Fields{"err": err})
860 }
861}
862
863func (mm *onuMetricsManager) processOmciMessages(ctx context.Context) {
864 logger.Infow(ctx, "Start routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
865 // Flush metric collection channels to be safe.
866 // It is possible that there is stale data on this channel if the processOmciMessages routine
867 // is stopped right after issuing a OMCI-GET request and started again.
868 // The processOmciMessages routine will get stopped if startCollector routine (in device_handler.go)
869 // is stopped - as a result of ONU going down.
870 mm.flushMetricCollectionChannels(ctx)
871
872 for {
873 select {
874 case <-mm.stopProcessingOmciResponses: // stop this routine
875 logger.Infow(ctx, "Stop routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
876 return
Girish Gowdrae0140f02021-02-02 16:55:09 -0800877 case message, ok := <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -0800878 if !ok {
879 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
880 continue
881 }
882 logger.Debugw(ctx, "Received message on ONU metrics channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
883
884 switch message.Type {
885 case OMCI:
886 msg, _ := message.Data.(OmciMessage)
887 mm.handleOmciMessage(ctx, msg)
888 default:
889 logger.Warn(ctx, "Unknown message type received", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "message.Type": message.Type})
890 }
891 }
892 }
893}
894
895func (mm *onuMetricsManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
896 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
897 "msgType": msg.OmciMsg.MessageType, "msg": msg})
898 switch msg.OmciMsg.MessageType {
899 case omci.GetResponseType:
900 //TODO: error handling
901 _ = mm.handleOmciGetResponseMessage(ctx, msg)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800902 case omci.SynchronizeTimeResponseType:
903 _ = mm.handleOmciSynchronizeTimeResponseMessage(ctx, msg)
904 case omci.CreateResponseType:
905 _ = mm.handleOmciCreateResponseMessage(ctx, msg)
906 case omci.DeleteResponseType:
907 _ = mm.handleOmciDeleteResponseMessage(ctx, msg)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800908 default:
909 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
910
911 }
912}
913
914func (mm *onuMetricsManager) handleOmciGetResponseMessage(ctx context.Context, msg OmciMessage) error {
915 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
916 if msgLayer == nil {
917 logger.Errorw(ctx, "omci Msg layer could not be detected for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
918 return fmt.Errorf("omci Msg layer could not be detected for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
919 }
920 msgObj, msgOk := msgLayer.(*omci.GetResponse)
921 if !msgOk {
922 logger.Errorw(ctx, "omci Msg layer could not be assigned for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
923 return fmt.Errorf("omci Msg layer could not be assigned for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
924 }
925 logger.Debugw(ctx, "OMCI GetResponse Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
926 if msgObj.Result == me.Success {
927 meAttributes := msgObj.Attributes
928 switch msgObj.EntityClass {
929 case me.AniGClassID:
930 mm.opticalMetricsChan <- meAttributes
931 return nil
932 case me.UniGClassID:
933 mm.uniStatusMetricsChan <- meAttributes
934 return nil
935 case me.PhysicalPathTerminationPointEthernetUniClassID:
936 mm.uniStatusMetricsChan <- meAttributes
937 return nil
938 case me.VirtualEthernetInterfacePointClassID:
939 mm.uniStatusMetricsChan <- meAttributes
940 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -0800941 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
942 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800943 me.EthernetPerformanceMonitoringHistoryDataClassID,
944 me.FecPerformanceMonitoringHistoryDataClassID,
945 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -0800946 mm.l2PmChan <- meAttributes
Girish Gowdrae09a6202021-01-12 18:10:59 -0800947 default:
948 logger.Errorw(ctx, "unhandled omci get response message",
949 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
950 }
951 }
952
Girish Gowdrae0140f02021-02-02 16:55:09 -0800953 return fmt.Errorf("unhandled-omci-get-response-message")
954}
955
956func (mm *onuMetricsManager) handleOmciSynchronizeTimeResponseMessage(ctx context.Context, msg OmciMessage) error {
957 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSynchronizeTimeResponse)
958 if msgLayer == nil {
959 logger.Errorw(ctx, "omci Msg layer could not be detected for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
960 return fmt.Errorf("omci Msg layer could not be detected for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
961 }
962 msgObj, msgOk := msgLayer.(*omci.SynchronizeTimeResponse)
963 if !msgOk {
964 logger.Errorw(ctx, "omci Msg layer could not be assigned for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
965 return fmt.Errorf("omci Msg layer could not be assigned for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
966 }
967 logger.Debugw(ctx, "OMCI synchronize time response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
968 if msgObj.Result == me.Success {
969 switch msgObj.EntityClass {
970 case me.OnuGClassID:
971 logger.Infow(ctx, "omci synchronize time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
972 mm.syncTimeResponseChan <- true
973 return nil
974 default:
975 logger.Errorw(ctx, "unhandled omci message",
976 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
977 }
978 }
979 mm.syncTimeResponseChan <- false
980 logger.Errorf(ctx, "unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
981 return fmt.Errorf("unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800982}
983
984// flushMetricCollectionChannels flushes all metric collection channels for any stale OMCI responses
985func (mm *onuMetricsManager) flushMetricCollectionChannels(ctx context.Context) {
986 // flush commMetricsChan
987 select {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800988 case <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -0800989 logger.Debug(ctx, "flushed common metrics channel")
990 default:
991 }
992
993 // flush opticalMetricsChan
994 select {
995 case <-mm.opticalMetricsChan:
996 logger.Debug(ctx, "flushed optical metrics channel")
997 default:
998 }
999
1000 // flush uniStatusMetricsChan
1001 select {
1002 case <-mm.uniStatusMetricsChan:
1003 logger.Debug(ctx, "flushed uni status metrics channel")
1004 default:
1005 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001006
1007 // flush syncTimeResponseChan
1008 select {
1009 case <-mm.syncTimeResponseChan:
1010 logger.Debug(ctx, "flushed sync time response channel")
1011 default:
1012 }
1013
1014 // flush l2PmChan
1015 select {
1016 case <-mm.l2PmChan:
1017 logger.Debug(ctx, "flushed L2 PM collection channel")
1018 default:
1019 }
1020
1021 // flush stopTicks
1022 select {
1023 case <-mm.stopTicks:
1024 logger.Debug(ctx, "flushed stopTicks channel")
1025 default:
1026 }
1027
1028}
1029
1030// ** L2 PM FSM Handlers start **
1031
1032func (mm *onuMetricsManager) l2PMFsmStarting(ctx context.Context, e *fsm.Event) {
1033 // Loop through all the group metrics
1034 // If it is a L2 PM Interval metric and it is enabled, then if it is not in the
1035 // list of active L2 PM list then mark it for creation
1036 // It it is a L2 PM Interval metric and it is disabled, then if it is in the
1037 // list of active L2 PM list then mark it for deletion
1038 mm.onuMetricsManagerLock.Lock()
1039 for n, g := range mm.groupMetricMap {
1040 if g.isL2PMCounter { // it is a l2 pm counter
1041 if g.enabled { // metric enabled.
1042 found := false
1043 inner1:
1044 for _, v := range mm.activeL2Pms {
1045 if v == n {
1046 found = true // metric already present in active l2 pm list
1047 break inner1
1048 }
1049 }
1050 if !found { // metric not in active l2 pm list. Mark this to be added later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001051 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001052 }
1053 } else { // metric not enabled.
1054 found := false
1055 inner2:
1056 for _, v := range mm.activeL2Pms {
1057 if v == n {
1058 found = true // metric is found in active l2 pm list
1059 break inner2
1060 }
1061 }
1062 if found { // metric is found in active l2 pm list. Mark this to be deleted later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001063 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001064 }
1065 }
1066 }
1067 }
1068 mm.onuMetricsManagerLock.Unlock()
1069 logger.Debugw(ctx, "pms to add and delete",
1070 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd, "pms-to-delete": mm.l2PmToDelete})
1071 go func() {
1072 // push a tick event to move to next state
1073 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1074 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1075 }
1076 }()
1077}
1078
1079func (mm *onuMetricsManager) l2PMFsmSyncTime(ctx context.Context, e *fsm.Event) {
1080 // Sync time with the ONU to establish 15min boundary for PM collection.
1081 if err := mm.syncTime(ctx); err != nil {
1082 go func() {
1083 time.Sleep(SyncTimeRetryInterval * time.Second) // retry to sync time after this timeout
1084 // This will result in FSM attempting to sync time again
1085 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventFailure); err != nil {
1086 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1087 }
1088 }()
1089 }
1090 // Initiate a tick generation routine every L2PmCollectionInterval
1091 go mm.generateTicks(ctx)
1092
1093 go func() {
1094 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1095 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1096 }
1097 }()
1098}
1099
1100func (mm *onuMetricsManager) l2PMFsmNull(ctx context.Context, e *fsm.Event) {
1101 // 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
1102 mm.onuMetricsManagerLock.Lock()
1103 mm.activeL2Pms = nil
1104 mm.l2PmToAdd = nil
1105 mm.l2PmToDelete = nil
1106 mm.onuMetricsManagerLock.Unlock()
1107}
1108func (mm *onuMetricsManager) l2PMFsmIdle(ctx context.Context, e *fsm.Event) {
1109 logger.Debugw(ctx, "Enter state idle", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1110
1111 mm.onuMetricsManagerLock.RLock()
1112 numOfPmToDelete := len(mm.l2PmToDelete)
1113 numOfPmToAdd := len(mm.l2PmToAdd)
1114 mm.onuMetricsManagerLock.RUnlock()
1115
1116 if numOfPmToDelete > 0 {
1117 logger.Debugw(ctx, "state idle - pms to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": numOfPmToDelete})
1118 go func() {
1119 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
1120 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1121 }
1122 }()
1123 } else if numOfPmToAdd > 0 {
1124 logger.Debugw(ctx, "state idle - pms to add", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": numOfPmToAdd})
1125 go func() {
1126 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
1127 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1128 }
1129 }()
1130 }
1131}
1132
1133func (mm *onuMetricsManager) l2PmFsmCollectData(ctx context.Context, e *fsm.Event) {
1134 logger.Debugw(ctx, "state collect data", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1135 // Copy the activeL2Pms for which we want to collect the metrics since activeL2Pms can change dynamically
1136 mm.onuMetricsManagerLock.RLock()
1137 copyOfActiveL2Pms := make([]string, len(mm.activeL2Pms))
1138 _ = copy(copyOfActiveL2Pms, mm.activeL2Pms)
1139 mm.onuMetricsManagerLock.RUnlock()
1140
1141 for _, n := range copyOfActiveL2Pms {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001142 var metricInfoSlice []*voltha.MetricInformation
Girish Gowdrae0140f02021-02-02 16:55:09 -08001143 switch n {
1144 case EthernetBridgeHistoryName:
1145 logger.Debugw(ctx, "state collect data - collecting data for EthernetFramePerformanceMonitoringHistoryData ME", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001146 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1147 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1148 entityID := macBridgePortAniEID + uniPort.entityID
1149 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, true, entityID); metricInfo != nil { // upstream
1150 metricInfoSlice = append(metricInfoSlice, metricInfo)
1151 }
1152 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, false, entityID); metricInfo != nil { // downstream
1153 metricInfoSlice = append(metricInfoSlice, metricInfo)
1154 }
1155 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001156 case EthernetUniHistoryName:
1157 logger.Debugw(ctx, "state collect data - collecting data for EthernetPerformanceMonitoringHistoryData ME", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001158 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1159 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
1160 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1161 entityID := uniPort.entityID
1162 if metricInfo := mm.collectEthernetUniHistoryData(ctx, entityID); metricInfo != nil { // upstream
1163 metricInfoSlice = append(metricInfoSlice, metricInfo)
1164 }
1165 }
1166 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001167 case FecHistoryName:
1168 // get the ANI-G instance IDs as FecHistory is tied to ANI-G instance id
1169 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
1170 for _, anigInstID := range anigInstKeys {
1171 if metricInfo := mm.collectFecHistoryData(ctx, anigInstID); metricInfo != nil { // upstream
1172 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001173 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001174 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001175 case GemPortHistoryName:
1176 mm.onuMetricsManagerLock.RLock()
1177 copyOfActiveGemPortInstIDs := make([]uint16, len(mm.gemPortNCTPPerfHistInstActive))
1178 _ = copy(copyOfActiveGemPortInstIDs, mm.gemPortNCTPPerfHistInstActive)
1179 mm.onuMetricsManagerLock.RUnlock()
1180 for _, v := range copyOfActiveGemPortInstIDs {
1181 if metricInfo := mm.collectGemHistoryData(ctx, v); metricInfo != nil { // upstream
1182 metricInfoSlice = append(metricInfoSlice, metricInfo)
1183 }
1184 }
1185
Girish Gowdrae0140f02021-02-02 16:55:09 -08001186 default:
1187 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1188 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001189 mm.handleMetricsPublish(ctx, n, metricInfoSlice)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001190 }
1191 // Does not matter we send success or failure here.
1192 // Those PMs that we failed to collect data will be attempted to collect again in the next PM collection cycle (assuming
1193 // we have not exceed max attempts to collect the PM data)
1194 go func() {
1195 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1196 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1197 }
1198 }()
1199}
1200
1201func (mm *onuMetricsManager) l2PmFsmCreatePM(ctx context.Context, e *fsm.Event) {
1202 // Copy the l2PmToAdd for which we want to collect the metrics since l2PmToAdd can change dynamically
1203 mm.onuMetricsManagerLock.RLock()
1204 copyOfL2PmToAdd := make([]string, len(mm.l2PmToAdd))
1205 _ = copy(copyOfL2PmToAdd, mm.l2PmToAdd)
1206 mm.onuMetricsManagerLock.RUnlock()
1207
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001208 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 -08001209 for _, n := range copyOfL2PmToAdd {
1210 resp := false
1211 switch n {
1212 case EthernetBridgeHistoryName:
1213 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1214 boolForDirection = append(boolForDirection, true, false)
1215 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1216 for _, direction := range boolForDirection {
1217 inner1:
1218 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1219 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1220 entityID := macBridgePortAniEID + uniPort.entityID
1221 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
1222 ctx, ConstDefaultOmciTimeout, true, direction, true, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001223 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1224 break inner1
Girish Gowdrae0140f02021-02-02 16:55:09 -08001225 }
1226 }
1227 }
1228 case EthernetUniHistoryName:
1229
1230 inner2:
1231 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1232 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
1233 // Attach the EthernetPerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1234 entityID := uniPort.entityID
1235 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
1236 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001237 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
1238 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001239 }
1240 }
1241 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001242 case FecHistoryName:
1243
1244 inner3:
1245 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
1246 // Attach the EthernetPerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1247 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
1248 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, anigInstID)
1249 if resp = mm.waitForResponseOrTimeout(ctx, true, anigInstID, "FecPerformanceMonitoringHistoryData"); !resp {
1250 break inner3
1251 }
1252 }
1253 case GemPortHistoryName:
1254
1255 mm.onuMetricsManagerLock.RLock()
1256 copyOfGemPortInstIDsToAdd := make([]uint16, len(mm.gemPortNCTPPerfHistInstToAdd))
1257 _ = copy(copyOfGemPortInstIDsToAdd, mm.gemPortNCTPPerfHistInstToAdd)
1258 mm.onuMetricsManagerLock.RUnlock()
1259 inner4:
1260 for _, v := range copyOfGemPortInstIDsToAdd {
1261 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
1262 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, v)
1263 if resp = mm.waitForResponseOrTimeout(ctx, true, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1264 break inner4
1265 }
1266 mm.onuMetricsManagerLock.Lock()
1267 mm.gemPortNCTPPerfHistInstActive = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstActive, v)
1268 mm.onuMetricsManagerLock.Unlock()
1269 }
1270
Girish Gowdrae0140f02021-02-02 16:55:09 -08001271 default:
1272 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1273 }
1274 // On success Update the local list maintained for active PMs and PMs to add
1275 if resp {
1276 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001277 mm.activeL2Pms = mm.appendIfMissingString(mm.activeL2Pms, n)
1278 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1279 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 -08001280 mm.onuMetricsManagerLock.Unlock()
1281 } else {
1282 // If createRetryAttempts exceeds L2PmCreateAttempts then locally disable the PM
1283 // and also remove it from l2PmToAdd slice so that we do not try to create the PM ME anymore
1284 mm.onuMetricsManagerLock.Lock()
1285 mm.groupMetricMap[n].createRetryAttempts++
1286 if mm.groupMetricMap[n].createRetryAttempts > L2PmCreateAttempts {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001287 logger.Debugw(ctx, "exceeded-max-add-retry-attempts--disabling-group", log.Fields{"groupName": n})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001288 mm.groupMetricMap[n].enabled = false
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001289 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1290
Girish Gowdrae0140f02021-02-02 16:55:09 -08001291 }
1292 logger.Warnw(ctx, "state create pm - failed to create pm",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001293 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
1294 "createRetryAttempts": mm.groupMetricMap[n].createRetryAttempts,
1295 "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001296 mm.onuMetricsManagerLock.Unlock()
1297 }
1298 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001299 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 -08001300 // Does not matter we send success or failure here.
1301 // Those PMs that we failed to create will be attempted to create again in the next PM creation cycle (assuming
1302 // we have not exceed max attempts to create the PM ME)
1303 go func() {
1304 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1305 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1306 }
1307 }()
1308}
1309
1310func (mm *onuMetricsManager) l2PmFsmDeletePM(ctx context.Context, e *fsm.Event) {
1311 // Copy the l2PmToDelete for which we want to collect the metrics since l2PmToDelete can change dynamically
1312 mm.onuMetricsManagerLock.RLock()
1313 copyOfL2PmToDelete := make([]string, len(mm.l2PmToDelete))
1314 _ = copy(copyOfL2PmToDelete, mm.l2PmToDelete)
1315 mm.onuMetricsManagerLock.RUnlock()
1316
1317 logger.Debugw(ctx, "state delete pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": mm.l2PmToDelete})
1318 for _, n := range copyOfL2PmToDelete {
1319 resp := false
1320 switch n {
1321 case EthernetBridgeHistoryName:
1322 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1323 boolForDirection = append(boolForDirection, true, false)
1324 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1325 for _, direction := range boolForDirection {
1326 inner1:
1327 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1328 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1329 entityID := macBridgePortAniEID + uniPort.entityID
1330 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
1331 ctx, ConstDefaultOmciTimeout, true, direction, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001332 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1333 break inner1
Girish Gowdrae0140f02021-02-02 16:55:09 -08001334 }
1335 }
1336 }
1337 case EthernetUniHistoryName:
1338
1339 inner2:
1340 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1341 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
1342 // Attach the EthernetPerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1343 entityID := uniPort.entityID
1344 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
1345 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001346 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
1347 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001348 }
1349 }
1350 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001351 case FecHistoryName:
1352
1353 inner3:
1354 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
1355 // Attach the EthernetPerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1356 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
1357 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, anigInstID)
1358 if resp := mm.waitForResponseOrTimeout(ctx, false, anigInstID, "FecPerformanceMonitoringHistoryData"); !resp {
1359 break inner3
1360 }
1361 }
1362 case GemPortHistoryName:
1363 mm.onuMetricsManagerLock.RLock()
1364 copyOfGemPortInstIDsToDelete := make([]uint16, len(mm.gemPortNCTPPerfHistInstToDelete))
1365 _ = copy(copyOfGemPortInstIDsToDelete, mm.gemPortNCTPPerfHistInstToDelete)
1366 mm.onuMetricsManagerLock.RUnlock()
1367 inner4:
1368 for _, v := range copyOfGemPortInstIDsToDelete {
1369 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
1370 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, v)
1371 if resp = mm.waitForResponseOrTimeout(ctx, false, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1372 break inner4
1373 }
1374 mm.onuMetricsManagerLock.Lock()
1375 mm.gemPortNCTPPerfHistInstActive = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstActive, v)
1376 mm.onuMetricsManagerLock.Unlock()
1377 }
1378
Girish Gowdrae0140f02021-02-02 16:55:09 -08001379 default:
1380 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1381 }
1382 // On success Update the local list maintained for active PMs and PMs to delete
1383 if resp {
1384 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001385 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1386 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1387 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 -08001388 mm.onuMetricsManagerLock.Unlock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001389 } else {
1390 logger.Warnw(ctx, "state delete pm - failed to delete pm",
1391 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n})
1392 // Nothing we can do about this.
Girish Gowdrae0140f02021-02-02 16:55:09 -08001393 }
1394 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001395 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 -08001396 // Does not matter we send success or failure here.
1397 // Those PMs that we failed to delete will be attempted to create again in the next PM collection cycle
1398 go func() {
1399 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1400 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1401 }
1402 }()
1403}
1404
1405// ** L2 PM FSM Handlers end **
1406
1407// syncTime synchronizes time with the ONU to establish a 15 min boundary for PM collection and reporting.
1408func (mm *onuMetricsManager) syncTime(ctx context.Context) error {
1409 if err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendSyncTime(ctx, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); err != nil {
1410 logger.Errorw(ctx, "cannot send sync time request", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1411 return err
1412 }
1413
1414 select {
1415 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1416 logger.Errorf(ctx, "timed out waiting for sync time response from onu", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1417 return fmt.Errorf("timed-out-waiting-for-sync-time-response-%v", mm.pDeviceHandler.deviceID)
1418 case syncTimeRes := <-mm.syncTimeResponseChan:
1419 if !syncTimeRes {
1420 return fmt.Errorf("failed-to-sync-time-%v", mm.pDeviceHandler.deviceID)
1421 }
1422 logger.Infow(ctx, "sync time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1423 return nil
1424 }
1425}
1426
1427func (mm *onuMetricsManager) collectEthernetFramePerformanceMonitoringHistoryData(ctx context.Context, upstream bool, entityID uint16) *voltha.MetricInformation {
1428 var mEnt *me.ManagedEntity
1429 var omciErr me.OmciErrors
1430 var classID me.ClassID
1431 var meAttributes me.AttributeValueMap
1432 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1433 meParam := me.ParamData{EntityID: entityID}
1434 if upstream {
1435 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataUpstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1436 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1437 return nil
1438 }
1439 classID = me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID
1440 } else {
1441 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataDownstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1442 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1443 return nil
1444 }
1445 classID = me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID
1446 }
1447
Girish Gowdrae0140f02021-02-02 16:55:09 -08001448 intervalEndTime := -1
1449 ethPMHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001450 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethPMHistData, &intervalEndTime); err != nil {
1451 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001452 }
1453
1454 // Populate some relevant context for the EthernetFramePerformanceMonitoringHistoryData PM
1455 ethPMHistData["class_id"] = float32(classID)
1456 ethPMHistData["interval_end_time"] = float32(intervalEndTime)
1457 ethPMHistData["parent_class_id"] = float32(me.MacBridgeConfigurationDataClassID) // EthernetFramePerformanceMonitoringHistoryData is attached to MBPCD ME
1458 ethPMHistData["parent_entity_id"] = float32(entityID)
1459 if upstream {
1460 ethPMHistData["upstream"] = float32(1)
1461 } else {
1462 ethPMHistData["upstream"] = float32(0)
1463 }
1464
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001465 metricInfo := mm.populateOnuMetricInfo(EthernetBridgeHistoryName, ethPMHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001466
Girish Gowdrae0140f02021-02-02 16:55:09 -08001467 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData successful",
1468 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream, "metricInfo": metricInfo})
1469 return &metricInfo
1470}
1471
1472func (mm *onuMetricsManager) collectEthernetUniHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1473 var mEnt *me.ManagedEntity
1474 var omciErr me.OmciErrors
1475 var classID me.ClassID
1476 var meAttributes me.AttributeValueMap
1477 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1478 meParam := me.ParamData{EntityID: entityID}
1479 if mEnt, omciErr = me.NewEthernetPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1480 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1481 return nil
1482 }
1483 classID = me.EthernetPerformanceMonitoringHistoryDataClassID
1484
Girish Gowdrae0140f02021-02-02 16:55:09 -08001485 intervalEndTime := -1
1486 ethUniHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001487 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethUniHistData, &intervalEndTime); err != nil {
1488 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001489 }
1490
1491 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1492 ethUniHistData["class_id"] = float32(classID)
1493 ethUniHistData["interval_end_time"] = float32(intervalEndTime)
1494
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001495 metricInfo := mm.populateOnuMetricInfo(EthernetUniHistoryName, ethUniHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001496
Girish Gowdrae0140f02021-02-02 16:55:09 -08001497 logger.Debugw(ctx, "collecting data for EthernetPerformanceMonitoringHistoryData successful",
1498 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1499 return &metricInfo
1500}
1501
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001502func (mm *onuMetricsManager) collectFecHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1503 var mEnt *me.ManagedEntity
1504 var omciErr me.OmciErrors
1505 var classID me.ClassID
1506 var meAttributes me.AttributeValueMap
1507 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1508 meParam := me.ParamData{EntityID: entityID}
1509 if mEnt, omciErr = me.NewFecPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1510 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1511 return nil
1512 }
1513 classID = me.FecPerformanceMonitoringHistoryDataClassID
1514
1515 intervalEndTime := -1
1516 fecHistData := make(map[string]float32)
1517 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, fecHistData, &intervalEndTime); err != nil {
1518 return nil
1519 }
1520
1521 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1522 fecHistData["class_id"] = float32(classID)
1523 fecHistData["interval_end_time"] = float32(intervalEndTime)
1524
1525 metricInfo := mm.populateOnuMetricInfo(FecHistoryName, fecHistData)
1526
1527 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData successful",
1528 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1529 return &metricInfo
1530}
1531
1532func (mm *onuMetricsManager) collectGemHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1533 var mEnt *me.ManagedEntity
1534 var omciErr me.OmciErrors
1535 var classID me.ClassID
1536 var meAttributes me.AttributeValueMap
1537 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1538 meParam := me.ParamData{EntityID: entityID}
1539 if mEnt, omciErr = me.NewGemPortNetworkCtpPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1540 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1541 return nil
1542 }
1543 classID = me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID
1544
1545 intervalEndTime := -1
1546 gemHistData := make(map[string]float32)
1547 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, gemHistData, &intervalEndTime); err != nil {
1548 return nil
1549 }
1550
1551 // Populate some relevant context for the GemPortNetworkCtpPerformanceMonitoringHistoryData PM
1552 gemHistData["class_id"] = float32(classID)
1553 gemHistData["interval_end_time"] = float32(intervalEndTime)
1554
1555 metricInfo := mm.populateOnuMetricInfo(GemPortHistoryName, gemHistData)
1556
1557 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData successful",
1558 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1559 return &metricInfo
1560}
1561
Girish Gowdrae0140f02021-02-02 16:55:09 -08001562// nolint: gocyclo
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001563func (mm *onuMetricsManager) populateEthernetBridgeHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
Girish Gowdrae0140f02021-02-02 16:55:09 -08001564 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001565 upstream := false
1566 if classID == me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID {
1567 upstream = true
1568 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001569 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1570 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1571 requestedAttributes["IntervalEndTime"] = 0
1572 }
1573 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1574 select {
1575 case meAttributes = <-mm.l2PmChan:
1576 logger.Debugw(ctx, "received ethernet pm history data metrics",
1577 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1578 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1579 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet pm history data",
1580 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1581 // The metrics will be empty in this case
1582 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-bridge-history-%v", mm.pDeviceHandler.deviceID)
1583 }
1584 // 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 -08001585 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1586 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 -08001587 }
1588 }
1589 for k := range EthernetBridgeHistory {
1590 // populate ethPMHistData only if metric key not already present (or populated), since it is possible that we populate
1591 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1592 if _, ok := ethPMHistData[k]; !ok {
1593 switch k {
1594 case "drop_events":
1595 if val, ok := meAttributes["DropEvents"]; ok && val != nil {
1596 ethPMHistData[k] = float32(val.(uint32))
1597 }
1598 case "octets":
1599 if val, ok := meAttributes["Octets"]; ok && val != nil {
1600 ethPMHistData[k] = float32(val.(uint32))
1601 }
1602 case "packets":
1603 if val, ok := meAttributes["Packets"]; ok && val != nil {
1604 ethPMHistData[k] = float32(val.(uint32))
1605 }
1606 case "broadcast_packets":
1607 if val, ok := meAttributes["BroadcastPackets"]; ok && val != nil {
1608 ethPMHistData[k] = float32(val.(uint32))
1609 }
1610 case "multicast_packets":
1611 if val, ok := meAttributes["MulticastPackets"]; ok && val != nil {
1612 ethPMHistData[k] = float32(val.(uint32))
1613 }
1614 case "crc_errored_packets":
1615 if val, ok := meAttributes["CrcErroredPackets"]; ok && val != nil {
1616 ethPMHistData[k] = float32(val.(uint32))
1617 }
1618 case "undersize_packets":
1619 if val, ok := meAttributes["UndersizePackets"]; ok && val != nil {
1620 ethPMHistData[k] = float32(val.(uint32))
1621 }
1622 case "oversize_packets":
1623 if val, ok := meAttributes["OversizePackets"]; ok && val != nil {
1624 ethPMHistData[k] = float32(val.(uint32))
1625 }
1626 case "64_octets":
1627 if val, ok := meAttributes["Packets64Octets"]; ok && val != nil {
1628 ethPMHistData[k] = float32(val.(uint32))
1629 }
1630 case "65_to_127_octets":
1631 if val, ok := meAttributes["Packets65To127Octets"]; ok && val != nil {
1632 ethPMHistData[k] = float32(val.(uint32))
1633 }
1634 case "128_to_255_octets":
1635 if val, ok := meAttributes["Packets128To255Octets"]; ok && val != nil {
1636 ethPMHistData[k] = float32(val.(uint32))
1637 }
1638 case "256_to_511_octets":
1639 if val, ok := meAttributes["Packets256To511Octets"]; ok && val != nil {
1640 ethPMHistData[k] = float32(val.(uint32))
1641 }
1642 case "512_to_1023_octets":
1643 if val, ok := meAttributes["Packets512To1023Octets"]; ok && val != nil {
1644 ethPMHistData[k] = float32(val.(uint32))
1645 }
1646 case "1024_to_1518_octets":
1647 if val, ok := meAttributes["Packets1024To1518Octets"]; ok && val != nil {
1648 ethPMHistData[k] = float32(val.(uint32))
1649 }
1650 default:
1651 // do nothing
1652 }
1653 }
1654 }
1655 return nil
1656}
1657
1658// nolint: gocyclo
1659func (mm *onuMetricsManager) populateEthernetUniHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1660 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMUniHistData map[string]float32, intervalEndTime *int) error {
1661 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1662 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1663 requestedAttributes["IntervalEndTime"] = 0
1664 }
1665 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1666 select {
1667 case meAttributes = <-mm.l2PmChan:
1668 logger.Debugw(ctx, "received ethernet uni history data metrics",
1669 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1670 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1671 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet uni history data",
1672 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1673 // The metrics will be empty in this case
1674 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-uni-history-%v", mm.pDeviceHandler.deviceID)
1675 }
1676 // 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 -08001677 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1678 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 -08001679 }
1680 }
1681 for k := range EthernetUniHistory {
1682 // populate ethPMUniHistData only if metric key not already present (or populated), since it is possible that we populate
1683 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1684 if _, ok := ethPMUniHistData[k]; !ok {
1685 switch k {
1686 case "fcs_errors":
1687 if val, ok := meAttributes["FcsErrors"]; ok && val != nil {
1688 ethPMUniHistData[k] = float32(val.(uint32))
1689 }
1690 case "excessive_collision_counter":
1691 if val, ok := meAttributes["ExcessiveCollisionCounter"]; ok && val != nil {
1692 ethPMUniHistData[k] = float32(val.(uint32))
1693 }
1694 case "late_collision_counter":
1695 if val, ok := meAttributes["LateCollisionCounter"]; ok && val != nil {
1696 ethPMUniHistData[k] = float32(val.(uint32))
1697 }
1698 case "frames_too_long":
1699 if val, ok := meAttributes["FramesTooLong"]; ok && val != nil {
1700 ethPMUniHistData[k] = float32(val.(uint32))
1701 }
1702 case "buffer_overflows_on_rx":
1703 if val, ok := meAttributes["BufferOverflowsOnReceive"]; ok && val != nil {
1704 ethPMUniHistData[k] = float32(val.(uint32))
1705 }
1706 case "buffer_overflows_on_tx":
1707 if val, ok := meAttributes["BufferOverflowsOnTransmit"]; ok && val != nil {
1708 ethPMUniHistData[k] = float32(val.(uint32))
1709 }
1710 case "single_collision_frame_counter":
1711 if val, ok := meAttributes["SingleCollisionFrameCounter"]; ok && val != nil {
1712 ethPMUniHistData[k] = float32(val.(uint32))
1713 }
1714 case "multiple_collisions_frame_counter":
1715 if val, ok := meAttributes["MultipleCollisionsFrameCounter"]; ok && val != nil {
1716 ethPMUniHistData[k] = float32(val.(uint32))
1717 }
1718 case "sqe_counter":
1719 if val, ok := meAttributes["SqeCounter"]; ok && val != nil {
1720 ethPMUniHistData[k] = float32(val.(uint32))
1721 }
1722 case "deferred_tx_counter":
1723 if val, ok := meAttributes["DeferredTransmissionCounter"]; ok && val != nil {
1724 ethPMUniHistData[k] = float32(val.(uint32))
1725 }
1726 case "internal_mac_tx_error_counter":
1727 if val, ok := meAttributes["InternalMacTransmitErrorCounter"]; ok && val != nil {
1728 ethPMUniHistData[k] = float32(val.(uint32))
1729 }
1730 case "carrier_sense_error_counter":
1731 if val, ok := meAttributes["CarrierSenseErrorCounter"]; ok && val != nil {
1732 ethPMUniHistData[k] = float32(val.(uint32))
1733 }
1734 case "alignment_error_counter":
1735 if val, ok := meAttributes["AlignmentErrorCounter"]; ok && val != nil {
1736 ethPMUniHistData[k] = float32(val.(uint32))
1737 }
1738 case "internal_mac_rx_error_counter":
1739 if val, ok := meAttributes["InternalMacReceiveErrorCounter"]; ok && val != nil {
1740 ethPMUniHistData[k] = float32(val.(uint32))
1741 }
1742 default:
1743 // do nothing
1744 }
1745 }
1746 }
1747 return nil
1748}
1749
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001750// nolint: gocyclo
1751func (mm *onuMetricsManager) populateFecHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1752 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, fecHistData map[string]float32, intervalEndTime *int) error {
1753 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1754 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1755 requestedAttributes["IntervalEndTime"] = 0
1756 }
1757 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1758 select {
1759 case meAttributes = <-mm.l2PmChan:
1760 logger.Debugw(ctx, "received fec history data metrics",
1761 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1762 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1763 logger.Errorw(ctx, "timeout waiting for omci-get response for fec history data",
1764 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1765 // The metrics will be empty in this case
1766 return fmt.Errorf("timeout-during-l2-pm-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1767 }
1768 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1769 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1770 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1771 }
1772 }
1773 for k := range FecHistory {
1774 // populate fecHistData only if metric key not already present (or populated), since it is possible that we populate
1775 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1776 if _, ok := fecHistData[k]; !ok {
1777 switch k {
1778 case "corrected_bytes":
1779 if val, ok := meAttributes["CorrectedBytes"]; ok && val != nil {
1780 fecHistData[k] = float32(val.(uint32))
1781 }
1782 case "corrected_code_words":
1783 if val, ok := meAttributes["CorrectedCodeWords"]; ok && val != nil {
1784 fecHistData[k] = float32(val.(uint32))
1785 }
1786 case "uncorrectable_code_words":
1787 if val, ok := meAttributes["UncorrectableCodeWords"]; ok && val != nil {
1788 fecHistData[k] = float32(val.(uint32))
1789 }
1790 case "total_code_words":
1791 if val, ok := meAttributes["TotalCodeWords"]; ok && val != nil {
1792 fecHistData[k] = float32(val.(uint32))
1793 }
1794 case "fec_seconds":
1795 if val, ok := meAttributes["FecSeconds"]; ok && val != nil {
1796 fecHistData[k] = float32(val.(uint16))
1797 }
1798 default:
1799 // do nothing
1800 }
1801 }
1802 }
1803 return nil
1804}
1805
1806// nolint: gocyclo
1807func (mm *onuMetricsManager) populateGemPortMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1808 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, gemPortHistData map[string]float32, intervalEndTime *int) error {
1809 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1810 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1811 requestedAttributes["IntervalEndTime"] = 0
1812 }
1813 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1814 select {
1815 case meAttributes = <-mm.l2PmChan:
1816 logger.Debugw(ctx, "received gem port history data metrics",
1817 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1818 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1819 logger.Errorw(ctx, "timeout waiting for omci-get response for gem port history data",
1820 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1821 // The metrics will be empty in this case
1822 return fmt.Errorf("timeout-during-l2-pm-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1823 }
1824 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1825 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1826 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1827 }
1828 }
1829 for k := range GemPortHistory {
1830 // populate gemPortHistData only if metric key not already present (or populated), since it is possible that we populate
1831 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1832 if _, ok := gemPortHistData[k]; !ok {
1833 switch k {
1834 case "transmitted_gem_frames":
1835 if val, ok := meAttributes["TransmittedGemFrames"]; ok && val != nil {
1836 gemPortHistData[k] = float32(val.(uint32))
1837 }
1838 case "received_gem_frames":
1839 if val, ok := meAttributes["ReceivedGemFrames"]; ok && val != nil {
1840 gemPortHistData[k] = float32(val.(uint32))
1841 }
1842 case "received_payload_bytes":
1843 if val, ok := meAttributes["ReceivedPayloadBytes"]; ok && val != nil {
1844 gemPortHistData[k] = float32(val.(uint64))
1845 }
1846 case "transmitted_payload_bytes":
1847 if val, ok := meAttributes["TransmittedPayloadBytes"]; ok && val != nil {
1848 gemPortHistData[k] = float32(val.(uint64))
1849 }
1850 case "encryption_key_errors":
1851 if val, ok := meAttributes["EncryptionKeyErrors"]; ok && val != nil {
1852 gemPortHistData[k] = float32(val.(uint32))
1853 }
1854 default:
1855 // do nothing
1856 }
1857 }
1858 }
1859 return nil
1860}
1861
Girish Gowdrae0140f02021-02-02 16:55:09 -08001862func (mm *onuMetricsManager) handleOmciCreateResponseMessage(ctx context.Context, msg OmciMessage) error {
1863 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
1864 if msgLayer == nil {
1865 logger.Errorw(ctx, "omci Msg layer could not be detected for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1866 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1867 }
1868 msgObj, msgOk := msgLayer.(*omci.CreateResponse)
1869 if !msgOk {
1870 logger.Errorw(ctx, "omci Msg layer could not be assigned for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1871 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1872 }
1873 logger.Debugw(ctx, "OMCI create response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1874 switch msgObj.EntityClass {
1875 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
1876 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001877 me.EthernetPerformanceMonitoringHistoryDataClassID,
1878 me.FecPerformanceMonitoringHistoryDataClassID,
1879 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001880 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
1881 if msgObj.Result == me.Success || msgObj.Result == me.InstanceExists {
1882 mm.l2PmCreateOrDeleteResponseChan <- true
1883 } else {
1884 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1885 mm.l2PmCreateOrDeleteResponseChan <- false
1886 }
1887 return nil
1888 default:
1889 logger.Errorw(ctx, "unhandled omci create response message",
1890 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1891 }
1892 return fmt.Errorf("unhandled-omci-create-response-message-%v", mm.pDeviceHandler.deviceID)
1893}
1894
1895func (mm *onuMetricsManager) handleOmciDeleteResponseMessage(ctx context.Context, msg OmciMessage) error {
1896 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDeleteResponse)
1897 if msgLayer == nil {
1898 logger.Errorw(ctx, "omci Msg layer could not be detected for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1899 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1900 }
1901 msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
1902 if !msgOk {
1903 logger.Errorw(ctx, "omci Msg layer could not be assigned for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1904 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1905 }
1906 logger.Debugw(ctx, "OMCI delete response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1907 switch msgObj.EntityClass {
1908 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
1909 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001910 me.EthernetPerformanceMonitoringHistoryDataClassID,
1911 me.FecPerformanceMonitoringHistoryDataClassID,
1912 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001913 // If the result is me.UnknownInstance it means the entity was already deleted. It is ok handled that as success
1914 if msgObj.Result == me.Success || msgObj.Result == me.UnknownInstance {
1915 mm.l2PmCreateOrDeleteResponseChan <- true
1916 } else {
1917 logger.Warnw(ctx, "failed to delete me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1918 mm.l2PmCreateOrDeleteResponseChan <- false
1919 }
1920 return nil
1921 default:
1922 logger.Errorw(ctx, "unhandled omci delete response message",
1923 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1924 }
1925 return fmt.Errorf("unhandled-omci-delete-response-message-%v", mm.pDeviceHandler.deviceID)
1926}
1927
1928func (mm *onuMetricsManager) generateTicks(ctx context.Context) {
1929 for {
1930 select {
1931 case <-time.After(L2PmCollectionInterval * time.Second):
1932 go func() {
1933 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1934 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1935 }
1936 }()
1937 case <-mm.stopTicks:
1938 logger.Infow(ctx, "stopping ticks", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1939 return
1940 }
1941 }
1942}
1943
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001944func (mm *onuMetricsManager) handleMetricsPublish(ctx context.Context, metricName string, metricInfoSlice []*voltha.MetricInformation) {
1945 // Publish metrics if it is valid
1946 if metricInfoSlice != nil {
1947 mm.publishMetrics(ctx, metricInfoSlice)
1948 } else {
1949 // If collectAttempts exceeds L2PmCollectAttempts then remove it from activeL2Pms
1950 // slice so that we do not collect data from that PM ME anymore
1951 mm.onuMetricsManagerLock.Lock()
1952 mm.groupMetricMap[metricName].collectAttempts++
1953 if mm.groupMetricMap[metricName].collectAttempts > L2PmCollectAttempts {
1954 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, metricName)
1955 }
1956 logger.Warnw(ctx, "state collect data - no metrics collected",
1957 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName, "collectAttempts": mm.groupMetricMap[metricName].collectAttempts})
1958 mm.onuMetricsManagerLock.Unlock()
1959 }
1960}
1961
1962func (mm *onuMetricsManager) populateGroupSpecificMetrics(ctx context.Context, mEnt *me.ManagedEntity, classID me.ClassID, entityID uint16,
1963 meAttributes me.AttributeValueMap, data map[string]float32, intervalEndTime *int) error {
1964 var grpFunc groupMetricPopulateFunc
1965 switch classID {
1966 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID, me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID:
1967 grpFunc = mm.populateEthernetBridgeHistoryMetrics
1968 case me.EthernetPerformanceMonitoringHistoryDataClassID:
1969 grpFunc = mm.populateEthernetUniHistoryMetrics
1970 case me.FecPerformanceMonitoringHistoryDataClassID:
1971 grpFunc = mm.populateFecHistoryMetrics
1972 case me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
1973 grpFunc = mm.populateGemPortMetrics
1974 default:
1975 return fmt.Errorf("unknown-classid-%v", classID)
1976 }
1977
1978 size := 0
1979 requestedAttributes := make(me.AttributeValueMap)
1980 for _, v := range mEnt.GetAttributeDefinitions() {
1981 if (v.Size + size) <= MaxL2PMGetPayLoadSize {
1982 requestedAttributes[v.Name] = v.DefValue
1983 size = v.Size + size
1984 } else { // We exceeded the allow omci get size
1985 // Let's collect the attributes via get now and collect remaining in the next iteration
1986 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
1987 logger.Errorw(ctx, "error during metric collection",
1988 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
1989 return err
1990 }
1991 size = 0 // reset size
1992 requestedAttributes = make(me.AttributeValueMap) // reset map
1993 }
1994 }
1995 // Collect the omci get attributes for the last bunch of attributes.
1996 if len(requestedAttributes) > 0 {
1997 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
1998 logger.Errorw(ctx, "error during metric collection",
1999 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2000 return err
2001 }
2002 }
2003 return nil
2004}
2005
2006func (mm *onuMetricsManager) populateOnuMetricInfo(title string, data map[string]float32) voltha.MetricInformation {
2007 metricsContext := make(map[string]string)
2008 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
2009 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
2010 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
2011
2012 raisedTs := time.Now().Unix()
2013 mmd := voltha.MetricMetaData{
2014 Title: title,
2015 Ts: float64(raisedTs),
2016 Context: metricsContext,
2017 DeviceId: mm.pDeviceHandler.deviceID,
2018 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
2019 SerialNo: mm.pDeviceHandler.device.SerialNumber,
2020 }
2021
2022 // create slice of metrics given that there could be more than one VEIP instance
2023 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: data}
2024 return metricInfo
2025}
2026
2027func (mm *onuMetricsManager) updateAndValidateIntervalEndTime(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap, intervalEndTime *int) bool {
2028 valid := false
2029 if *intervalEndTime == -1 { // first time
2030 // Update the interval end time
2031 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2032 *intervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2033 valid = true
2034 }
2035 } else {
2036 var currIntervalEndTime int
2037 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2038 currIntervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2039 }
2040 if currIntervalEndTime != *intervalEndTime { // interval end time changed during metric collection
2041 logger.Errorw(ctx, "interval end time changed during metrics collection for ethernet pm history data",
2042 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID,
2043 "currIntervalEndTime": *intervalEndTime, "newIntervalEndTime": currIntervalEndTime})
2044 } else {
2045 valid = true
2046 }
2047 }
2048 return valid
2049}
2050
2051func (mm *onuMetricsManager) waitForResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassName string) bool {
2052 logger.Debugw(ctx, "waitForResponseOrTimeout", log.Fields{"create": create, "instID": instID, "meClassName": meClassName})
2053 select {
2054 case resp := <-mm.l2PmCreateOrDeleteResponseChan:
2055 logger.Debugw(ctx, "received create l2 pm me response",
2056 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassName": meClassName, "instID": instID})
2057 return resp
2058 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
2059 logger.Errorw(ctx, "timeout waiting for create l2 pm me response",
2060 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassName": meClassName, "instID": instID})
2061 }
2062 return false
2063}
2064
2065func (mm *onuMetricsManager) initializeGroupMetric(grpMtrcs map[string]voltha.PmConfig_PmType, grpName string, grpEnabled bool, grpFreq uint32) {
2066 var pmConfigSlice []*voltha.PmConfig
2067 for k, v := range grpMtrcs {
2068 pmConfigSlice = append(pmConfigSlice, &voltha.PmConfig{Name: k, Type: v})
2069 }
2070 groupMetric := voltha.PmGroupConfig{
2071 GroupName: grpName,
2072 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2073 GroupFreq: grpFreq,
2074 Metrics: pmConfigSlice,
2075 }
2076 mm.pDeviceHandler.pmConfigs.Groups = append(mm.pDeviceHandler.pmConfigs.Groups, &groupMetric)
2077
2078}
2079
2080func (mm *onuMetricsManager) initializeL2PmFsm(ctx context.Context, aCommChannel chan Message) error {
2081 mm.pAdaptFsm = NewAdapterFsm("L2PmFSM", mm.pDeviceHandler.deviceID, aCommChannel)
2082 if mm.pAdaptFsm == nil {
2083 logger.Errorw(ctx, "L2PMFsm AdapterFsm could not be instantiated!!", log.Fields{
2084 "device-id": mm.pDeviceHandler.deviceID})
2085 return fmt.Errorf("nil-adapter-fsm")
2086 }
2087 // L2 PM FSM related state machine
2088 mm.pAdaptFsm.pFsm = fsm.NewFSM(
2089 l2PmStNull,
2090 fsm.Events{
2091 {Name: l2PmEventInit, Src: []string{l2PmStNull}, Dst: l2PmStStarting},
2092 {Name: l2PmEventTick, Src: []string{l2PmStStarting}, Dst: l2PmStSyncTime},
2093 {Name: l2PmEventTick, Src: []string{l2PmStIdle, l2PmEventDeleteMe, l2PmEventAddMe}, Dst: l2PmStCollectData},
2094 {Name: l2PmEventSuccess, Src: []string{l2PmStSyncTime, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2095 {Name: l2PmEventFailure, Src: []string{l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2096 {Name: l2PmEventFailure, Src: []string{l2PmStSyncTime}, Dst: l2PmStSyncTime},
2097 {Name: l2PmEventAddMe, Src: []string{l2PmStIdle}, Dst: l2PmStCreatePmMe},
2098 {Name: l2PmEventDeleteMe, Src: []string{l2PmStIdle}, Dst: l2PmStDeletePmMe},
2099 {Name: l2PmEventStop, Src: []string{l2PmStNull, l2PmStStarting, l2PmStSyncTime, l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStNull},
2100 },
2101 fsm.Callbacks{
2102 "enter_state": func(e *fsm.Event) { mm.pAdaptFsm.logFsmStateChange(ctx, e) },
2103 "enter_" + l2PmStNull: func(e *fsm.Event) { mm.l2PMFsmNull(ctx, e) },
2104 "enter_" + l2PmStIdle: func(e *fsm.Event) { mm.l2PMFsmIdle(ctx, e) },
2105 "enter_" + l2PmStStarting: func(e *fsm.Event) { mm.l2PMFsmStarting(ctx, e) },
2106 "enter_" + l2PmStSyncTime: func(e *fsm.Event) { mm.l2PMFsmSyncTime(ctx, e) },
2107 "enter_" + l2PmStCollectData: func(e *fsm.Event) { mm.l2PmFsmCollectData(ctx, e) },
2108 "enter_" + l2PmStCreatePmMe: func(e *fsm.Event) { mm.l2PmFsmCreatePM(ctx, e) },
2109 "enter_" + l2PmStDeletePmMe: func(e *fsm.Event) { mm.l2PmFsmDeletePM(ctx, e) },
2110 },
2111 )
2112 return nil
2113}
2114
2115func (mm *onuMetricsManager) initializeAllGroupMetrics() {
2116 mm.pDeviceHandler.pmConfigs = &voltha.PmConfigs{}
2117 mm.pDeviceHandler.pmConfigs.Id = mm.pDeviceHandler.deviceID
2118 mm.pDeviceHandler.pmConfigs.DefaultFreq = DefaultMetricCollectionFrequency
2119 mm.pDeviceHandler.pmConfigs.Grouped = GroupMetricEnabled
2120 mm.pDeviceHandler.pmConfigs.FreqOverride = DefaultFrequencyOverrideEnabled
2121
2122 // Populate group metrics.
2123 // Lets populate irrespective of GroupMetricEnabled is true or not.
2124 // The group metrics collection will decided on this flag later
2125
2126 mm.initializeGroupMetric(OpticalPowerGroupMetrics, OpticalPowerGroupMetricName,
2127 OpticalPowerGroupMetricEnabled, OpticalPowerMetricGroupCollectionFrequency)
2128
2129 mm.initializeGroupMetric(UniStatusGroupMetrics, UniStatusGroupMetricName,
2130 UniStatusGroupMetricEnabled, UniStatusMetricGroupCollectionFrequency)
2131
2132 // classical l2 pm counter start
2133
2134 mm.initializeGroupMetric(EthernetBridgeHistory, EthernetBridgeHistoryName,
2135 EthernetBridgeHistoryEnabled, EthernetBridgeHistoryFrequency)
2136
2137 mm.initializeGroupMetric(EthernetUniHistory, EthernetUniHistoryName,
2138 EthernetUniHistoryEnabled, EthernetUniHistoryFrequency)
2139
2140 mm.initializeGroupMetric(FecHistory, FecHistoryName,
2141 FecHistoryEnabled, FecHistoryFrequency)
2142
2143 mm.initializeGroupMetric(GemPortHistory, GemPortHistoryName,
2144 GemPortHistoryEnabled, GemPortHistoryFrequency)
2145
2146 // classical l2 pm counter end
2147
2148 // Add standalone metric (if present) after this (will be added to dh.pmConfigs.Metrics)
2149}
2150
2151func (mm *onuMetricsManager) populateLocalGroupMetricData(ctx context.Context) {
2152 // Populate local group metric structures
2153 for _, g := range mm.pDeviceHandler.pmConfigs.Groups {
2154 mm.groupMetricMap[g.GroupName] = &groupMetric{
2155 groupName: g.GroupName,
2156 enabled: g.Enabled,
2157 frequency: g.GroupFreq,
2158 }
2159 switch g.GroupName {
2160 case OpticalPowerGroupMetricName:
2161 mm.groupMetricMap[g.GroupName].metricMap = OpticalPowerGroupMetrics
2162 case UniStatusGroupMetricName:
2163 mm.groupMetricMap[g.GroupName].metricMap = UniStatusGroupMetrics
2164 case EthernetBridgeHistoryName:
2165 mm.groupMetricMap[g.GroupName].metricMap = EthernetBridgeHistory
2166 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2167 case EthernetUniHistoryName:
2168 mm.groupMetricMap[g.GroupName].metricMap = EthernetUniHistory
2169 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2170 case FecHistoryName:
2171 mm.groupMetricMap[g.GroupName].metricMap = FecHistory
2172 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2173 case GemPortHistoryName:
2174 mm.groupMetricMap[g.GroupName].metricMap = GemPortHistory
2175 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2176 default:
2177 logger.Errorw(ctx, "unhandled-group-name", log.Fields{"groupName": g.GroupName})
2178 }
2179 }
2180
2181 // Populate local standalone metric structures
2182 for _, m := range mm.pDeviceHandler.pmConfigs.Metrics {
2183 mm.standaloneMetricMap[m.Name] = &standaloneMetric{
2184 metricName: m.Name,
2185 enabled: m.Enabled,
2186 frequency: m.SampleFreq,
2187 }
2188 switch m.Name {
2189 // None exist as of now. Add when available.
2190 default:
2191 logger.Errorw(ctx, "unhandled-metric-name", log.Fields{"metricName": m.Name})
2192 }
2193 }
2194}
2195
2196func (mm *onuMetricsManager) AddGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2197 mm.onuMetricsManagerLock.Lock()
2198 defer mm.onuMetricsManagerLock.Unlock()
2199 // mark the instance for addition
2200 mm.gemPortNCTPPerfHistInstToAdd = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstToAdd, gemPortNTPInstID)
2201 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
2202 mm.gemPortNCTPPerfHistInstToDelete = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstToDelete, gemPortNTPInstID)
2203
2204 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, GemPortHistoryName)
2205 // We do not need to remove from l2PmToDelete slice as we could have Add and Delete of
2206 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2207 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2208 // gemPortNCTPPerfHistInstToAdd slice
2209}
2210
2211func (mm *onuMetricsManager) RemoveGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2212 mm.onuMetricsManagerLock.Lock()
2213 defer mm.onuMetricsManagerLock.Unlock()
2214 mm.gemPortNCTPPerfHistInstToDelete = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstToDelete, gemPortNTPInstID)
2215 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
2216 mm.gemPortNCTPPerfHistInstToAdd = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstToAdd, gemPortNTPInstID)
2217
2218 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, GemPortHistoryName)
2219 // We do not need to remove from l2PmToAdd slice as we could have Add and Delete of
2220 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2221 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2222 // gemPortNCTPPerfHistInstToAdd slice
2223}
2224
2225func (mm *onuMetricsManager) updateGemPortNTPInstanceToAddForPerfMonitoring() {
2226 if mm.pDeviceHandler.pOnuTP != nil {
2227 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
2228 mm.onuMetricsManagerLock.Lock()
2229 defer mm.onuMetricsManagerLock.Unlock()
2230 for _, v := range gemPortInstIDs {
2231 // mark the instance for addition
2232 mm.gemPortNCTPPerfHistInstToAdd = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstToAdd, v)
2233 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
2234 mm.gemPortNCTPPerfHistInstToDelete = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstToDelete, v)
2235 }
2236 }
2237}
2238
2239func (mm *onuMetricsManager) updateGemPortNTPInstanceToDeleteForPerfMonitoring() {
2240 if mm.pDeviceHandler.pOnuTP != nil {
2241 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
2242 mm.onuMetricsManagerLock.Lock()
2243 defer mm.onuMetricsManagerLock.Unlock()
2244 for _, v := range gemPortInstIDs {
2245 mm.gemPortNCTPPerfHistInstToDelete = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstToDelete, v)
2246 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
2247 mm.gemPortNCTPPerfHistInstToAdd = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstToAdd, v)
2248 }
2249 }
2250}
2251
2252func (mm *onuMetricsManager) appendIfMissingString(slice []string, n string) []string {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002253 for _, ele := range slice {
2254 if ele == n {
2255 return slice
2256 }
2257 }
2258 return append(slice, n)
2259}
2260
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002261func (mm *onuMetricsManager) removeIfFoundString(slice []string, n string) []string {
2262 for i, ele := range slice {
2263 if ele == n {
2264 return append(slice[:i], slice[i+1:]...)
2265 }
2266 }
2267 return slice
2268}
2269
2270func (mm *onuMetricsManager) appendIfMissingUnt16(slice []uint16, n uint16) []uint16 {
2271 for _, ele := range slice {
2272 if ele == n {
2273 return slice
2274 }
2275 }
2276 return append(slice, n)
2277}
2278
2279func (mm *onuMetricsManager) removeIfFoundUint16(slice []uint16, n uint16) []uint16 {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002280 for i, ele := range slice {
2281 if ele == n {
2282 return append(slice[:i], slice[i+1:]...)
2283 }
2284 }
2285 return slice
Girish Gowdrae09a6202021-01-12 18:10:59 -08002286}