blob: 747ba8ab02afb8e2bc9f4d763a07253e5119adcb [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
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800175 L2PmDeleteAttempts = 3
Girish Gowdrae0140f02021-02-02 16:55:09 -0800176 L2PmCollectAttempts = 3
Girish Gowdra453750f2021-02-16 16:36:46 -0800177 // Per Table 11.2.9-1 – OMCI baseline message limitations in G.988 spec, the max GET Response
178 // payload size is 25. We define 24 (one less) to allow for dynamic insertion of IntervalEndTime
179 // attribute (1 byte) in L2 PM GET Requests.
180 MaxL2PMGetPayLoadSize = 24
Girish Gowdrae0140f02021-02-02 16:55:09 -0800181)
182
183// EthernetUniHistoryName specific constants
184const (
185 EthernetBridgeHistoryName = "Ethernet_Bridge_Port_History"
186 EthernetBridgeHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
187 EthernetBridgeHistoryFrequency = L2PmCollectionInterval
188)
189
190// EthernetBridgeHistory specific constants
191const (
192 EthernetUniHistoryName = "Ethernet_UNI_History"
193 EthernetUniHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
194 EthernetUniHistoryFrequency = L2PmCollectionInterval
195)
196
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800197// FecHistory specific constants
198const (
199 FecHistoryName = "FEC_History"
200 FecHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
201 FecHistoryFrequency = L2PmCollectionInterval
202)
203
204// GemPortHistory specific constants
205const (
206 GemPortHistoryName = "GEM_Port_History"
207 GemPortHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
208 GemPortHistoryFrequency = L2PmCollectionInterval
209)
210
211// Defines the type for generic metric population function
212type groupMetricPopulateFunc func(context.Context, me.ClassID, uint16, me.AttributeValueMap, me.AttributeValueMap, map[string]float32, *int) error
213
Girish Gowdrae0140f02021-02-02 16:55:09 -0800214// *** Classical L2 PM Counters end ***
215
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800216type groupMetric struct {
217 groupName string
218 enabled bool
219 frequency uint32 // valid only if FrequencyOverride is enabled.
220 metricMap map[string]voltha.PmConfig_PmType
221 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
Girish Gowdrae0140f02021-02-02 16:55:09 -0800222 isL2PMCounter bool // true for only L2 PM counters
223 collectAttempts uint32 // number of attempts to collect L2 PM data
224 createRetryAttempts uint32 // number of attempts to try creating the L2 PM ME
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800225 deleteRetryAttempts uint32 // number of attempts to try deleting the L2 PM ME
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800226}
227
228type standaloneMetric struct {
229 metricName string
230 enabled bool
231 frequency uint32 // valid only if FrequencyOverride is enabled.
232 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
233}
234
Girish Gowdrae09a6202021-01-12 18:10:59 -0800235type onuMetricsManager struct {
236 pDeviceHandler *deviceHandler
Girish Gowdrae0140f02021-02-02 16:55:09 -0800237 pAdaptFsm *AdapterFsm
Girish Gowdrae09a6202021-01-12 18:10:59 -0800238
Girish Gowdrae0140f02021-02-02 16:55:09 -0800239 opticalMetricsChan chan me.AttributeValueMap
240 uniStatusMetricsChan chan me.AttributeValueMap
241 l2PmChan chan me.AttributeValueMap
242 syncTimeResponseChan chan bool // true is success, false is fail
243 l2PmCreateOrDeleteResponseChan chan bool // true is success, false is fail
244
245 activeL2Pms []string // list of active l2 pm MEs created on the ONU.
246 l2PmToDelete []string // list of L2 PMs to delete
247 l2PmToAdd []string // list of L2 PM to add
Girish Gowdrae09a6202021-01-12 18:10:59 -0800248
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800249 gemPortNCTPPerfHistInstToAdd []uint16
250 gemPortNCTPPerfHistInstToDelete []uint16
251 gemPortNCTPPerfHistInstActive []uint16
252
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800253 groupMetricMap map[string]*groupMetric
254 standaloneMetricMap map[string]*standaloneMetric
255
Girish Gowdrae09a6202021-01-12 18:10:59 -0800256 stopProcessingOmciResponses chan bool
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800257
Girish Gowdrae0140f02021-02-02 16:55:09 -0800258 stopTicks chan bool
259
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800260 nextGlobalMetricCollectionTime time.Time // valid only if pmConfig.FreqOverride is set to false.
261
262 onuMetricsManagerLock sync.RWMutex
Girish Gowdrae09a6202021-01-12 18:10:59 -0800263}
264
265// newonuMetricsManager returns a new instance of the newonuMetricsManager
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800266// Note that none of the context stored internally in onuMetricsManager is backed up on KV store for resiliency.
267// Metric collection is not a critical operation that needs support for resiliency. On adapter restart, some context
268// could be lost (except for Device.PmConfigs which is backed up the rw-core on KV store). An example of information
269// that is lost on adapter restart is nextCollectionInterval time.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800270func newonuMetricsManager(ctx context.Context, dh *deviceHandler) *onuMetricsManager {
271
272 var metricsManager onuMetricsManager
273 logger.Debugw(ctx, "init-onuMetricsManager", log.Fields{"device-id": dh.deviceID})
274 metricsManager.pDeviceHandler = dh
275
Girish Gowdrae0140f02021-02-02 16:55:09 -0800276 commMetricsChan := make(chan Message)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800277 metricsManager.opticalMetricsChan = make(chan me.AttributeValueMap)
278 metricsManager.uniStatusMetricsChan = make(chan me.AttributeValueMap)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800279 metricsManager.l2PmChan = make(chan me.AttributeValueMap)
280
281 metricsManager.syncTimeResponseChan = make(chan bool)
282 metricsManager.l2PmCreateOrDeleteResponseChan = make(chan bool)
283
Girish Gowdrae09a6202021-01-12 18:10:59 -0800284 metricsManager.stopProcessingOmciResponses = make(chan bool)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800285 metricsManager.stopTicks = make(chan bool)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800286
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800287 metricsManager.groupMetricMap = make(map[string]*groupMetric)
288 metricsManager.standaloneMetricMap = make(map[string]*standaloneMetric)
289
290 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 -0800291 metricsManager.initializeAllGroupMetrics()
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800292 }
293
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800294 metricsManager.populateLocalGroupMetricData(ctx)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800295
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800296 if err := metricsManager.initializeL2PmFsm(ctx, commMetricsChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800297 return nil
298 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800299
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800300 // initialize the next metric collection intervals.
301 metricsManager.initializeMetricCollectionTime(ctx)
302 logger.Info(ctx, "init-onuMetricsManager completed", log.Fields{"device-id": dh.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800303 return &metricsManager
304}
305
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800306func (mm *onuMetricsManager) initializeMetricCollectionTime(ctx context.Context) {
307 if mm.pDeviceHandler.pmConfigs.FreqOverride {
308 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to true, then group/standalone metric specific interval applies
309 mm.onuMetricsManagerLock.Lock()
310 defer mm.onuMetricsManagerLock.Unlock()
311 for _, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800312 if v.enabled && !v.isL2PMCounter { // L2 PM counter collection is managed in a L2PmFsm
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800313 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
314 }
315 }
316
317 for _, v := range mm.standaloneMetricMap {
318 if v.enabled {
319 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
320 }
321 }
322 } else {
323 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to false, then overall metric specific interval applies
324 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
325 }
326 logger.Infow(ctx, "initialized standalone group/metric collection time", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
327}
328
329func (mm *onuMetricsManager) updateDefaultFrequency(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
330 // Verify that the configured DefaultFrequency is > 0 and is a multiple of FrequencyGranularity
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800331 if pmConfigs.DefaultFreq == 0 || (pmConfigs.DefaultFreq > 0 && pmConfigs.DefaultFreq%FrequencyGranularity != 0) {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800332 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", pmConfigs.DefaultFreq, FrequencyGranularity)
333 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", pmConfigs.DefaultFreq, FrequencyGranularity)
334 }
335 mm.pDeviceHandler.pmConfigs.DefaultFreq = pmConfigs.DefaultFreq
336 // re-set the nextGlobalMetricCollectionTime based on the new DefaultFreq
337 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
338 logger.Debugw(ctx, "frequency-updated--new-frequency", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "frequency": mm.pDeviceHandler.pmConfigs.DefaultFreq})
339 return nil
340}
341
342func (mm *onuMetricsManager) updateGroupFreq(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
343 var newGroupFreq uint32
344 found := false
345 groupSliceIdx := 0
346 var group *voltha.PmGroupConfig
347 for groupSliceIdx, group = range pmConfigs.Groups {
348 if group.GroupName == aGroupName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800349 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
350 if group.GroupFreq == 0 || (group.GroupFreq > 0 && group.GroupFreq%FrequencyGranularity != 0) {
351 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", group.GroupFreq, FrequencyGranularity)
352 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", group.GroupFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800353 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800354 newGroupFreq = group.GroupFreq
355 found = true
356 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800357 }
358 }
359 // if not found update group freq and next collection interval for the group
360 if !found {
361 logger.Errorw(ctx, "group name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
362 return fmt.Errorf("group-name-not-found-%v", aGroupName)
363 }
364
365 updated := false
366 mm.onuMetricsManagerLock.Lock()
367 defer mm.onuMetricsManagerLock.Unlock()
368 for k, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800369 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 -0800370 v.frequency = newGroupFreq
371 // update internal pm config
372 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].GroupFreq = newGroupFreq
373 // Also updated the next group metric collection time from now
374 v.nextCollectionInterval = time.Now().Add(time.Duration(newGroupFreq) * time.Second)
375 updated = true
376 logger.Infow(ctx, "group frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800377 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800378 }
379 }
380 if !updated {
381 logger.Errorw(ctx, "group frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
382 return fmt.Errorf("internal-error-during-group-freq-update--groupname-%s-freq-%d", aGroupName, newGroupFreq)
383 }
384 return nil
385}
386
387func (mm *onuMetricsManager) updateMetricFreq(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
388 var newMetricFreq uint32
389 found := false
390 metricSliceIdx := 0
391 var metric *voltha.PmConfig
392 for metricSliceIdx, metric = range pmConfigs.Metrics {
393 if metric.Name == aMetricName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800394 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
395 if metric.SampleFreq == 0 || (metric.SampleFreq > 0 && metric.SampleFreq%FrequencyGranularity != 0) {
396 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", metric.SampleFreq, FrequencyGranularity)
397 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", metric.SampleFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800398 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800399 newMetricFreq = metric.SampleFreq
400 found = true
401 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800402 }
403 }
404 if !found {
405 logger.Errorw(ctx, "metric name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
406 return fmt.Errorf("metric-name-not-found-%v", aMetricName)
407 }
408
409 updated := false
410 mm.onuMetricsManagerLock.Lock()
411 defer mm.onuMetricsManagerLock.Unlock()
412 for k, v := range mm.groupMetricMap {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800413 if k == aMetricName {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800414 v.frequency = newMetricFreq
415 // update internal pm config
416 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].SampleFreq = newMetricFreq
417 // Also updated the next standalone metric collection time from now
418 v.nextCollectionInterval = time.Now().Add(time.Duration(newMetricFreq) * time.Second)
419 updated = true
420 logger.Infow(ctx, "metric frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800421 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800422 }
423 }
424 if !updated {
425 logger.Errorw(ctx, "metric frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
426 return fmt.Errorf("internal-error-during-standalone-metric-update--matricnane-%s-freq-%d", aMetricName, newMetricFreq)
427 }
428 return nil
429}
430
431func (mm *onuMetricsManager) updateGroupSupport(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
432 groupSliceIdx := 0
433 var group *voltha.PmGroupConfig
434
435 for groupSliceIdx, group = range pmConfigs.Groups {
436 if group.GroupName == aGroupName {
437 break
438 }
439 }
440 if group == nil {
441 logger.Errorw(ctx, "group metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
442 return fmt.Errorf("group-not-found--groupName-%s", aGroupName)
443 }
444
445 updated := false
446 mm.onuMetricsManagerLock.Lock()
447 defer mm.onuMetricsManagerLock.Unlock()
448 for k, v := range mm.groupMetricMap {
449 if k == aGroupName && v.enabled != group.Enabled {
450 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].Enabled = group.Enabled
451 v.enabled = group.Enabled
Girish Gowdrae0140f02021-02-02 16:55:09 -0800452 if group.Enabled {
453 if v.isL2PMCounter {
454 // If it is a L2 PM counter we need to mark the PM to be added
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800455 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800456 // 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 -0800457 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, v.groupName)
458
459 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
460 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
461 // take further action
462 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800463 mm.updateGemPortNTPInstanceToAddForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800464 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800465 } else if mm.pDeviceHandler.pmConfigs.FreqOverride { // otherwise just update the next collection interval
466 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
467 }
468 } else { // group counter is disabled
469 if v.isL2PMCounter {
470 // If it is a L2 PM counter we need to mark the PM to be deleted
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800471 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800472 // 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 -0800473 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, v.groupName)
474
475 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
476 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
477 // take further action
478 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800479 mm.updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800480 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800481 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800482 }
483 updated = true
Girish Gowdrae0140f02021-02-02 16:55:09 -0800484 if v.isL2PMCounter {
485 logger.Infow(ctx, "l2 pm group metric support updated",
486 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled, "l2PmToAdd": mm.l2PmToAdd, "l2PmToDelete": mm.l2PmToDelete})
487 } else {
488 logger.Infow(ctx, "group metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled})
489 }
490 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800491 }
492 }
493
494 if !updated {
495 logger.Errorw(ctx, "group metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
496 return fmt.Errorf("internal-error-during-group-support-update--groupName-%s", aGroupName)
497 }
498 return nil
499}
500
501func (mm *onuMetricsManager) updateMetricSupport(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
502 metricSliceIdx := 0
503 var metric *voltha.PmConfig
504
505 for metricSliceIdx, metric = range pmConfigs.Metrics {
506 if metric.Name == aMetricName {
507 break
508 }
509 }
510
511 if metric == nil {
512 logger.Errorw(ctx, "standalone metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
513 return fmt.Errorf("metric-not-found--metricname-%s", aMetricName)
514 }
515
516 updated := false
517 mm.onuMetricsManagerLock.Lock()
518 defer mm.onuMetricsManagerLock.Unlock()
519 for k, v := range mm.standaloneMetricMap {
520 if k == aMetricName && v.enabled != metric.Enabled {
521 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].Enabled = metric.Enabled
522 v.enabled = metric.Enabled
523 // If the standalone metric is now enabled and frequency override is enabled, set the next metric collection time
524 if metric.Enabled && mm.pDeviceHandler.pmConfigs.FreqOverride {
525 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
526 }
527 updated = true
528 logger.Infow(ctx, "standalone metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName, "enabled": metric.Enabled})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800529 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800530 }
531 }
532 if !updated {
533 logger.Errorw(ctx, "standalone metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
534 return fmt.Errorf("internal-error-during-standalone-support-update--metricname-%s", aMetricName)
535 }
536 return nil
537}
538
539func (mm *onuMetricsManager) collectAllGroupAndStandaloneMetrics(ctx context.Context) {
540 if mm.pDeviceHandler.pmConfigs.Grouped { // metrics are managed as a group.
541 go mm.collectAllGroupMetrics(ctx)
542 } else {
543 go mm.collectAllStandaloneMetrics(ctx)
544 }
545}
546
547func (mm *onuMetricsManager) collectAllGroupMetrics(ctx context.Context) {
548 go func() {
549 logger.Debug(ctx, "startCollector before collecting optical metrics")
550 metricInfo := mm.collectOpticalMetrics(ctx)
551 if metricInfo != nil {
552 mm.publishMetrics(ctx, metricInfo)
553 }
554 }()
555
556 go func() {
557 logger.Debug(ctx, "startCollector before collecting uni metrics")
558 metricInfo := mm.collectUniStatusMetrics(ctx)
559 if metricInfo != nil {
560 mm.publishMetrics(ctx, metricInfo)
561 }
562 }()
563
564 // Add more here
565}
566
567func (mm *onuMetricsManager) collectAllStandaloneMetrics(ctx context.Context) {
568 // None exists as of now, add when available here
569}
570
571func (mm *onuMetricsManager) collectGroupMetric(ctx context.Context, groupName string) {
572 switch groupName {
573 case OpticalPowerGroupMetricName:
574 go func() {
575 if mi := mm.collectOpticalMetrics(ctx); mm != nil {
576 mm.publishMetrics(ctx, mi)
577 }
578 }()
579 case UniStatusGroupMetricName:
580 go func() {
581 if mi := mm.collectUniStatusMetrics(ctx); mm != nil {
582 mm.publishMetrics(ctx, mi)
583 }
584 }()
585 default:
586 logger.Errorw(ctx, "unhandled group metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName})
587 }
588}
589
590func (mm *onuMetricsManager) collectStandaloneMetric(ctx context.Context, metricName string) {
591 switch metricName {
592 // None exist as of now, add when available
593 default:
594 logger.Errorw(ctx, "unhandled standalone metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName})
595 }
596}
597
598// collectOpticalMetrics collects groups metrics related to optical power from ani-g ME.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800599func (mm *onuMetricsManager) collectOpticalMetrics(ctx context.Context) []*voltha.MetricInformation {
600 logger.Debugw(ctx, "collectOpticalMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800601
602 mm.onuMetricsManagerLock.RLock()
603 if !mm.groupMetricMap[OpticalPowerGroupMetricName].enabled {
604 mm.onuMetricsManagerLock.RUnlock()
605 logger.Debugw(ctx, "optical power group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
606 return nil
607 }
608 mm.onuMetricsManagerLock.RUnlock()
609
Girish Gowdrae09a6202021-01-12 18:10:59 -0800610 var metricInfoSlice []*voltha.MetricInformation
611 metricsContext := make(map[string]string)
612 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
613 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
614 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
615
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800616 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800617 mmd := voltha.MetricMetaData{
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800618 Title: OpticalPowerGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800619 Ts: float64(raisedTs),
620 Context: metricsContext,
621 DeviceId: mm.pDeviceHandler.deviceID,
622 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
623 SerialNo: mm.pDeviceHandler.device.SerialNumber,
624 }
625
Girish Gowdrae09a6202021-01-12 18:10:59 -0800626 // get the ANI-G instance IDs
627 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
628loop:
629 for _, anigInstID := range anigInstKeys {
630 var meAttributes me.AttributeValueMap
631 opticalMetrics := make(map[string]float32)
632 // Get the ANI-G instance optical power attributes
633 requestedAttributes := me.AttributeValueMap{"OpticalSignalLevel": 0, "TransmitOpticalLevel": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800634 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 -0800635 select {
636 case meAttributes = <-mm.opticalMetricsChan:
637 logger.Debugw(ctx, "received optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
638 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800639 logger.Errorw(ctx, "timeout waiting for omci-get response for optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800640 // The metrics will be empty in this case
641 break loop
642 }
643 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800644 for k := range OpticalPowerGroupMetrics {
645 switch k {
646 case "ani_g_instance_id":
647 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
648 opticalMetrics[k] = float32(val.(uint16))
649 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800650 case "transmit_power":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800651 if val, ok := meAttributes["TransmitOpticalLevel"]; ok && val != nil {
652 opticalMetrics[k] = float32(val.(uint16))
653 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800654 case "receive_power":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800655 if val, ok := meAttributes["OpticalSignalLevel"]; ok && val != nil {
656 opticalMetrics[k] = float32(val.(uint16))
657 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800658 default:
659 // do nothing
660 }
661 }
662 }
663 // create slice of metrics given that there could be more than one ANI-G instance and
664 // optical metrics are collected per ANI-G instance
665 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: opticalMetrics}
666 metricInfoSlice = append(metricInfoSlice, &metricInfo)
667 }
668
669 return metricInfoSlice
670}
671
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800672// collectUniStatusMetrics collects UNI status group metric from various MEs (uni-g, pptp and veip).
Girish Gowdrae09a6202021-01-12 18:10:59 -0800673// nolint: gocyclo
674func (mm *onuMetricsManager) collectUniStatusMetrics(ctx context.Context) []*voltha.MetricInformation {
675 logger.Debugw(ctx, "collectUniStatusMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800676 mm.onuMetricsManagerLock.RLock()
677 if !mm.groupMetricMap[UniStatusGroupMetricName].enabled {
678 mm.onuMetricsManagerLock.RUnlock()
679 logger.Debugw(ctx, "uni status group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
680 return nil
681 }
682 mm.onuMetricsManagerLock.RUnlock()
683
Girish Gowdrae09a6202021-01-12 18:10:59 -0800684 var metricInfoSlice []*voltha.MetricInformation
685 metricsContext := make(map[string]string)
686 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
687 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
688 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
689
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800690 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800691 mmd := voltha.MetricMetaData{
692 Title: "UniStatus", // Is this ok to hard code?
693 Ts: float64(raisedTs),
694 Context: metricsContext,
695 DeviceId: mm.pDeviceHandler.deviceID,
696 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
697 SerialNo: mm.pDeviceHandler.device.SerialNumber,
698 }
699
Girish Gowdrae09a6202021-01-12 18:10:59 -0800700 // get the UNI-G instance IDs
701 unigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.UniGClassID)
702loop1:
703 for _, unigInstID := range unigInstKeys {
704 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
705 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
706 unigMetrics := make(map[string]float32)
707 var meAttributes me.AttributeValueMap
708 // Get the UNI-G instance optical power attributes
709 requestedAttributes := me.AttributeValueMap{"AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800710 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 -0800711 // Wait for metrics or timeout
712 select {
713 case meAttributes = <-mm.uniStatusMetricsChan:
714 logger.Debugw(ctx, "received uni-g metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
715 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
716 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
717 // The metrics could be empty in this case
718 break loop1
719 }
720 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800721 for k := range UniStatusGroupMetrics {
722 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800723 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800724 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
725 unigMetrics[k] = float32(val.(byte))
726 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800727 default:
728 // do nothing
729 }
730 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800731 var entityID uint32
732 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
733 entityID = uint32(val.(uint16))
734 }
735 // TODO: Rlock needed for reading uniEntityMap?
736 if uniPort, ok := mm.pDeviceHandler.uniEntityMap[entityID]; ok && uniPort != nil {
737 unigMetrics["uni_port_no"] = float32(uniPort.portNo)
738 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800739 // create slice of metrics given that there could be more than one UNI-G instance
740 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: unigMetrics}
741 metricInfoSlice = append(metricInfoSlice, &metricInfo)
742 }
743 }
744
745 // get the PPTP instance IDs
746 pptpInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.PhysicalPathTerminationPointEthernetUniClassID)
747loop2:
748 for _, pptpInstID := range pptpInstKeys {
749 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
750 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
751 var meAttributes me.AttributeValueMap
752 pptpMetrics := make(map[string]float32)
753
754 requestedAttributes := me.AttributeValueMap{"SensedType": 0, "OperationalState": 0, "AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800755 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 -0800756 // Wait for metrics or timeout
757 select {
758 case meAttributes = <-mm.uniStatusMetricsChan:
759 logger.Debugw(ctx, "received pptp metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
760 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
761 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
762 // The metrics could be empty in this case
763 break loop2
764 }
765
766 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800767 for k := range UniStatusGroupMetrics {
768 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800769 case "ethernet_type":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800770 if val, ok := meAttributes["SensedType"]; ok && val != nil {
771 pptpMetrics[k] = float32(val.(byte))
772 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800773 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800774 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
775 pptpMetrics[k] = float32(val.(byte))
776 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800777 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800778 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
779 pptpMetrics[k] = float32(val.(byte))
780 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800781 default:
782 // do nothing
783 }
784 }
785 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800786 var entityID uint32
787 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
788 entityID = uint32(val.(uint16))
789 }
790 // TODO: Rlock needed for reading uniEntityMap?
791 if uniPort, ok := mm.pDeviceHandler.uniEntityMap[entityID]; ok && uniPort != nil {
792 pptpMetrics["uni_port_no"] = float32(uniPort.portNo)
793 }
794
Girish Gowdrae09a6202021-01-12 18:10:59 -0800795 // create slice of metrics given that there could be more than one PPTP instance and
796 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: pptpMetrics}
797 metricInfoSlice = append(metricInfoSlice, &metricInfo)
798 }
799
800 // get the VEIP instance IDs
801 veipInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.VirtualEthernetInterfacePointClassID)
802loop3:
803 for _, veipInstID := range veipInstKeys {
804 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
805 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
806 var meAttributes me.AttributeValueMap
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800807 veipMetrics := make(map[string]float32)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800808
809 requestedAttributes := me.AttributeValueMap{"OperationalState": 0, "AdministrativeState": 0}
Girish Gowdrae0140f02021-02-02 16:55:09 -0800810 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 -0800811 // Wait for metrics or timeout
812 select {
813 case meAttributes = <-mm.uniStatusMetricsChan:
814 logger.Debugw(ctx, "received veip metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
815 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
816 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
817 // The metrics could be empty in this case
818 break loop3
819 }
820
821 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800822 for k := range UniStatusGroupMetrics {
823 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800824 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800825 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
826 veipMetrics[k] = float32(val.(byte))
827 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800828 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800829 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
830 veipMetrics[k] = float32(val.(byte))
831 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800832 default:
833 // do nothing
834 }
835 }
836 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800837
838 var entityID uint32
839 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
840 entityID = uint32(meAttributes["ManagedEntityId"].(uint16))
841 }
842 // TODO: Rlock needed for reading uniEntityMap?
843 if uniPort, ok := mm.pDeviceHandler.uniEntityMap[entityID]; ok && uniPort != nil {
844 veipMetrics["uni_port_no"] = float32(uniPort.portNo)
845 }
846
Girish Gowdrae09a6202021-01-12 18:10:59 -0800847 // create slice of metrics given that there could be more than one VEIP instance
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800848 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: veipMetrics}
Girish Gowdrae09a6202021-01-12 18:10:59 -0800849 metricInfoSlice = append(metricInfoSlice, &metricInfo)
850 }
851
852 return metricInfoSlice
853}
854
855// publishMetrics publishes the metrics on kafka
856func (mm *onuMetricsManager) publishMetrics(ctx context.Context, metricInfo []*voltha.MetricInformation) {
857 var ke voltha.KpiEvent2
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800858 ts := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800859 ke.SliceData = metricInfo
860 ke.Type = voltha.KpiEventType_slice
861 ke.Ts = float64(ts)
862
863 if err := mm.pDeviceHandler.EventProxy.SendKpiEvent(ctx, "STATS_EVENT", &ke, voltha.EventCategory_EQUIPMENT, voltha.EventSubCategory_ONU, ts); err != nil {
864 logger.Errorw(ctx, "failed-to-send-pon-stats", log.Fields{"err": err})
865 }
866}
867
868func (mm *onuMetricsManager) processOmciMessages(ctx context.Context) {
869 logger.Infow(ctx, "Start routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
870 // Flush metric collection channels to be safe.
871 // It is possible that there is stale data on this channel if the processOmciMessages routine
872 // is stopped right after issuing a OMCI-GET request and started again.
873 // The processOmciMessages routine will get stopped if startCollector routine (in device_handler.go)
874 // is stopped - as a result of ONU going down.
875 mm.flushMetricCollectionChannels(ctx)
876
877 for {
878 select {
879 case <-mm.stopProcessingOmciResponses: // stop this routine
880 logger.Infow(ctx, "Stop routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
881 return
Girish Gowdrae0140f02021-02-02 16:55:09 -0800882 case message, ok := <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -0800883 if !ok {
884 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
885 continue
886 }
887 logger.Debugw(ctx, "Received message on ONU metrics channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
888
889 switch message.Type {
890 case OMCI:
891 msg, _ := message.Data.(OmciMessage)
892 mm.handleOmciMessage(ctx, msg)
893 default:
894 logger.Warn(ctx, "Unknown message type received", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "message.Type": message.Type})
895 }
896 }
897 }
898}
899
900func (mm *onuMetricsManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
901 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
902 "msgType": msg.OmciMsg.MessageType, "msg": msg})
903 switch msg.OmciMsg.MessageType {
904 case omci.GetResponseType:
905 //TODO: error handling
906 _ = mm.handleOmciGetResponseMessage(ctx, msg)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800907 case omci.SynchronizeTimeResponseType:
908 _ = mm.handleOmciSynchronizeTimeResponseMessage(ctx, msg)
909 case omci.CreateResponseType:
910 _ = mm.handleOmciCreateResponseMessage(ctx, msg)
911 case omci.DeleteResponseType:
912 _ = mm.handleOmciDeleteResponseMessage(ctx, msg)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800913 default:
914 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
915
916 }
917}
918
919func (mm *onuMetricsManager) handleOmciGetResponseMessage(ctx context.Context, msg OmciMessage) error {
920 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
921 if msgLayer == nil {
922 logger.Errorw(ctx, "omci Msg layer could not be detected for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
923 return fmt.Errorf("omci Msg layer could not be detected for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
924 }
925 msgObj, msgOk := msgLayer.(*omci.GetResponse)
926 if !msgOk {
927 logger.Errorw(ctx, "omci Msg layer could not be assigned for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
928 return fmt.Errorf("omci Msg layer could not be assigned for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
929 }
930 logger.Debugw(ctx, "OMCI GetResponse Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
931 if msgObj.Result == me.Success {
932 meAttributes := msgObj.Attributes
933 switch msgObj.EntityClass {
934 case me.AniGClassID:
935 mm.opticalMetricsChan <- meAttributes
936 return nil
937 case me.UniGClassID:
938 mm.uniStatusMetricsChan <- meAttributes
939 return nil
940 case me.PhysicalPathTerminationPointEthernetUniClassID:
941 mm.uniStatusMetricsChan <- meAttributes
942 return nil
943 case me.VirtualEthernetInterfacePointClassID:
944 mm.uniStatusMetricsChan <- meAttributes
945 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -0800946 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
947 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800948 me.EthernetPerformanceMonitoringHistoryDataClassID,
949 me.FecPerformanceMonitoringHistoryDataClassID,
950 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -0800951 mm.l2PmChan <- meAttributes
Girish Gowdrae09a6202021-01-12 18:10:59 -0800952 default:
953 logger.Errorw(ctx, "unhandled omci get response message",
954 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
955 }
956 }
957
Girish Gowdrae0140f02021-02-02 16:55:09 -0800958 return fmt.Errorf("unhandled-omci-get-response-message")
959}
960
961func (mm *onuMetricsManager) handleOmciSynchronizeTimeResponseMessage(ctx context.Context, msg OmciMessage) error {
962 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSynchronizeTimeResponse)
963 if msgLayer == nil {
964 logger.Errorw(ctx, "omci Msg layer could not be detected for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
965 return fmt.Errorf("omci Msg layer could not be detected for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
966 }
967 msgObj, msgOk := msgLayer.(*omci.SynchronizeTimeResponse)
968 if !msgOk {
969 logger.Errorw(ctx, "omci Msg layer could not be assigned for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
970 return fmt.Errorf("omci Msg layer could not be assigned for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
971 }
972 logger.Debugw(ctx, "OMCI synchronize time response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
973 if msgObj.Result == me.Success {
974 switch msgObj.EntityClass {
975 case me.OnuGClassID:
976 logger.Infow(ctx, "omci synchronize time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
977 mm.syncTimeResponseChan <- true
978 return nil
979 default:
980 logger.Errorw(ctx, "unhandled omci message",
981 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
982 }
983 }
984 mm.syncTimeResponseChan <- false
985 logger.Errorf(ctx, "unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
986 return fmt.Errorf("unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800987}
988
989// flushMetricCollectionChannels flushes all metric collection channels for any stale OMCI responses
990func (mm *onuMetricsManager) flushMetricCollectionChannels(ctx context.Context) {
991 // flush commMetricsChan
992 select {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800993 case <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -0800994 logger.Debug(ctx, "flushed common metrics channel")
995 default:
996 }
997
998 // flush opticalMetricsChan
999 select {
1000 case <-mm.opticalMetricsChan:
1001 logger.Debug(ctx, "flushed optical metrics channel")
1002 default:
1003 }
1004
1005 // flush uniStatusMetricsChan
1006 select {
1007 case <-mm.uniStatusMetricsChan:
1008 logger.Debug(ctx, "flushed uni status metrics channel")
1009 default:
1010 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001011
1012 // flush syncTimeResponseChan
1013 select {
1014 case <-mm.syncTimeResponseChan:
1015 logger.Debug(ctx, "flushed sync time response channel")
1016 default:
1017 }
1018
1019 // flush l2PmChan
1020 select {
1021 case <-mm.l2PmChan:
1022 logger.Debug(ctx, "flushed L2 PM collection channel")
1023 default:
1024 }
1025
1026 // flush stopTicks
1027 select {
1028 case <-mm.stopTicks:
1029 logger.Debug(ctx, "flushed stopTicks channel")
1030 default:
1031 }
1032
1033}
1034
1035// ** L2 PM FSM Handlers start **
1036
1037func (mm *onuMetricsManager) l2PMFsmStarting(ctx context.Context, e *fsm.Event) {
1038 // Loop through all the group metrics
1039 // If it is a L2 PM Interval metric and it is enabled, then if it is not in the
1040 // list of active L2 PM list then mark it for creation
1041 // It it is a L2 PM Interval metric and it is disabled, then if it is in the
1042 // list of active L2 PM list then mark it for deletion
1043 mm.onuMetricsManagerLock.Lock()
1044 for n, g := range mm.groupMetricMap {
1045 if g.isL2PMCounter { // it is a l2 pm counter
1046 if g.enabled { // metric enabled.
1047 found := false
1048 inner1:
1049 for _, v := range mm.activeL2Pms {
1050 if v == n {
1051 found = true // metric already present in active l2 pm list
1052 break inner1
1053 }
1054 }
1055 if !found { // metric not in active l2 pm list. Mark this to be added later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001056 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001057 }
1058 } else { // metric not enabled.
1059 found := false
1060 inner2:
1061 for _, v := range mm.activeL2Pms {
1062 if v == n {
1063 found = true // metric is found in active l2 pm list
1064 break inner2
1065 }
1066 }
1067 if found { // metric is found in active l2 pm list. Mark this to be deleted later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001068 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001069 }
1070 }
1071 }
1072 }
1073 mm.onuMetricsManagerLock.Unlock()
1074 logger.Debugw(ctx, "pms to add and delete",
1075 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd, "pms-to-delete": mm.l2PmToDelete})
1076 go func() {
1077 // push a tick event to move to next state
1078 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1079 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1080 }
1081 }()
1082}
1083
1084func (mm *onuMetricsManager) l2PMFsmSyncTime(ctx context.Context, e *fsm.Event) {
1085 // Sync time with the ONU to establish 15min boundary for PM collection.
1086 if err := mm.syncTime(ctx); err != nil {
1087 go func() {
1088 time.Sleep(SyncTimeRetryInterval * time.Second) // retry to sync time after this timeout
1089 // This will result in FSM attempting to sync time again
1090 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventFailure); err != nil {
1091 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1092 }
1093 }()
1094 }
1095 // Initiate a tick generation routine every L2PmCollectionInterval
1096 go mm.generateTicks(ctx)
1097
1098 go func() {
1099 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1100 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1101 }
1102 }()
1103}
1104
1105func (mm *onuMetricsManager) l2PMFsmNull(ctx context.Context, e *fsm.Event) {
1106 // 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
1107 mm.onuMetricsManagerLock.Lock()
1108 mm.activeL2Pms = nil
1109 mm.l2PmToAdd = nil
1110 mm.l2PmToDelete = nil
1111 mm.onuMetricsManagerLock.Unlock()
1112}
1113func (mm *onuMetricsManager) l2PMFsmIdle(ctx context.Context, e *fsm.Event) {
1114 logger.Debugw(ctx, "Enter state idle", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1115
1116 mm.onuMetricsManagerLock.RLock()
1117 numOfPmToDelete := len(mm.l2PmToDelete)
1118 numOfPmToAdd := len(mm.l2PmToAdd)
1119 mm.onuMetricsManagerLock.RUnlock()
1120
1121 if numOfPmToDelete > 0 {
1122 logger.Debugw(ctx, "state idle - pms to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": numOfPmToDelete})
1123 go func() {
1124 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
1125 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1126 }
1127 }()
1128 } else if numOfPmToAdd > 0 {
1129 logger.Debugw(ctx, "state idle - pms to add", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": numOfPmToAdd})
1130 go func() {
1131 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
1132 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1133 }
1134 }()
1135 }
1136}
1137
1138func (mm *onuMetricsManager) l2PmFsmCollectData(ctx context.Context, e *fsm.Event) {
1139 logger.Debugw(ctx, "state collect data", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1140 // Copy the activeL2Pms for which we want to collect the metrics since activeL2Pms can change dynamically
1141 mm.onuMetricsManagerLock.RLock()
1142 copyOfActiveL2Pms := make([]string, len(mm.activeL2Pms))
1143 _ = copy(copyOfActiveL2Pms, mm.activeL2Pms)
1144 mm.onuMetricsManagerLock.RUnlock()
1145
1146 for _, n := range copyOfActiveL2Pms {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001147 var metricInfoSlice []*voltha.MetricInformation
Girish Gowdrae0140f02021-02-02 16:55:09 -08001148 switch n {
1149 case EthernetBridgeHistoryName:
1150 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 -08001151 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1152 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1153 entityID := macBridgePortAniEID + uniPort.entityID
1154 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, true, entityID); metricInfo != nil { // upstream
1155 metricInfoSlice = append(metricInfoSlice, metricInfo)
1156 }
1157 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, false, entityID); metricInfo != nil { // downstream
1158 metricInfoSlice = append(metricInfoSlice, metricInfo)
1159 }
1160 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001161 case EthernetUniHistoryName:
1162 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 -08001163 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1164 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
1165 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1166 entityID := uniPort.entityID
1167 if metricInfo := mm.collectEthernetUniHistoryData(ctx, entityID); metricInfo != nil { // upstream
1168 metricInfoSlice = append(metricInfoSlice, metricInfo)
1169 }
1170 }
1171 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001172 case FecHistoryName:
1173 // get the ANI-G instance IDs as FecHistory is tied to ANI-G instance id
1174 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
1175 for _, anigInstID := range anigInstKeys {
1176 if metricInfo := mm.collectFecHistoryData(ctx, anigInstID); metricInfo != nil { // upstream
1177 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001178 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001179 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001180 case GemPortHistoryName:
1181 mm.onuMetricsManagerLock.RLock()
1182 copyOfActiveGemPortInstIDs := make([]uint16, len(mm.gemPortNCTPPerfHistInstActive))
1183 _ = copy(copyOfActiveGemPortInstIDs, mm.gemPortNCTPPerfHistInstActive)
1184 mm.onuMetricsManagerLock.RUnlock()
1185 for _, v := range copyOfActiveGemPortInstIDs {
1186 if metricInfo := mm.collectGemHistoryData(ctx, v); metricInfo != nil { // upstream
1187 metricInfoSlice = append(metricInfoSlice, metricInfo)
1188 }
1189 }
1190
Girish Gowdrae0140f02021-02-02 16:55:09 -08001191 default:
1192 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1193 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001194 mm.handleMetricsPublish(ctx, n, metricInfoSlice)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001195 }
1196 // Does not matter we send success or failure here.
1197 // Those PMs that we failed to collect data will be attempted to collect again in the next PM collection cycle (assuming
1198 // we have not exceed max attempts to collect the PM data)
1199 go func() {
1200 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1201 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1202 }
1203 }()
1204}
1205
1206func (mm *onuMetricsManager) l2PmFsmCreatePM(ctx context.Context, e *fsm.Event) {
1207 // Copy the l2PmToAdd for which we want to collect the metrics since l2PmToAdd can change dynamically
1208 mm.onuMetricsManagerLock.RLock()
1209 copyOfL2PmToAdd := make([]string, len(mm.l2PmToAdd))
1210 _ = copy(copyOfL2PmToAdd, mm.l2PmToAdd)
1211 mm.onuMetricsManagerLock.RUnlock()
1212
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001213 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 -08001214 for _, n := range copyOfL2PmToAdd {
1215 resp := false
1216 switch n {
1217 case EthernetBridgeHistoryName:
1218 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1219 boolForDirection = append(boolForDirection, true, false)
1220 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1221 for _, direction := range boolForDirection {
1222 inner1:
1223 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1224 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1225 entityID := macBridgePortAniEID + uniPort.entityID
1226 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
1227 ctx, ConstDefaultOmciTimeout, true, direction, true, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001228 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1229 break inner1
Girish Gowdrae0140f02021-02-02 16:55:09 -08001230 }
1231 }
1232 }
1233 case EthernetUniHistoryName:
1234
1235 inner2:
1236 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1237 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
1238 // Attach the EthernetPerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1239 entityID := uniPort.entityID
1240 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
1241 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001242 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
1243 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001244 }
1245 }
1246 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001247 case FecHistoryName:
1248
1249 inner3:
1250 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
1251 // Attach the EthernetPerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1252 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
1253 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, anigInstID)
1254 if resp = mm.waitForResponseOrTimeout(ctx, true, anigInstID, "FecPerformanceMonitoringHistoryData"); !resp {
1255 break inner3
1256 }
1257 }
1258 case GemPortHistoryName:
1259
1260 mm.onuMetricsManagerLock.RLock()
1261 copyOfGemPortInstIDsToAdd := make([]uint16, len(mm.gemPortNCTPPerfHistInstToAdd))
1262 _ = copy(copyOfGemPortInstIDsToAdd, mm.gemPortNCTPPerfHistInstToAdd)
1263 mm.onuMetricsManagerLock.RUnlock()
1264 inner4:
1265 for _, v := range copyOfGemPortInstIDsToAdd {
1266 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
1267 ctx, ConstDefaultOmciTimeout, true, true, mm.pAdaptFsm.commChan, v)
1268 if resp = mm.waitForResponseOrTimeout(ctx, true, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1269 break inner4
1270 }
1271 mm.onuMetricsManagerLock.Lock()
1272 mm.gemPortNCTPPerfHistInstActive = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstActive, v)
1273 mm.onuMetricsManagerLock.Unlock()
1274 }
1275
Girish Gowdrae0140f02021-02-02 16:55:09 -08001276 default:
1277 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1278 }
1279 // On success Update the local list maintained for active PMs and PMs to add
1280 if resp {
1281 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001282 mm.activeL2Pms = mm.appendIfMissingString(mm.activeL2Pms, n)
1283 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1284 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 -08001285 mm.onuMetricsManagerLock.Unlock()
1286 } else {
1287 // If createRetryAttempts exceeds L2PmCreateAttempts then locally disable the PM
1288 // and also remove it from l2PmToAdd slice so that we do not try to create the PM ME anymore
1289 mm.onuMetricsManagerLock.Lock()
1290 mm.groupMetricMap[n].createRetryAttempts++
1291 if mm.groupMetricMap[n].createRetryAttempts > L2PmCreateAttempts {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001292 logger.Debugw(ctx, "exceeded-max-add-retry-attempts--disabling-group", log.Fields{"groupName": n})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001293 mm.groupMetricMap[n].enabled = false
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08001294 mm.groupMetricMap[n].createRetryAttempts = 0 // reset counter
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001295 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1296
Girish Gowdrae0140f02021-02-02 16:55:09 -08001297 }
1298 logger.Warnw(ctx, "state create pm - failed to create pm",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001299 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
1300 "createRetryAttempts": mm.groupMetricMap[n].createRetryAttempts,
1301 "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001302 mm.onuMetricsManagerLock.Unlock()
1303 }
1304 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001305 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 -08001306 // Does not matter we send success or failure here.
1307 // Those PMs that we failed to create will be attempted to create again in the next PM creation cycle (assuming
1308 // we have not exceed max attempts to create the PM ME)
1309 go func() {
1310 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1311 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1312 }
1313 }()
1314}
1315
1316func (mm *onuMetricsManager) l2PmFsmDeletePM(ctx context.Context, e *fsm.Event) {
1317 // Copy the l2PmToDelete for which we want to collect the metrics since l2PmToDelete can change dynamically
1318 mm.onuMetricsManagerLock.RLock()
1319 copyOfL2PmToDelete := make([]string, len(mm.l2PmToDelete))
1320 _ = copy(copyOfL2PmToDelete, mm.l2PmToDelete)
1321 mm.onuMetricsManagerLock.RUnlock()
1322
1323 logger.Debugw(ctx, "state delete pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": mm.l2PmToDelete})
1324 for _, n := range copyOfL2PmToDelete {
1325 resp := false
1326 switch n {
1327 case EthernetBridgeHistoryName:
1328 boolForDirection := make([]bool, 2) // stores true and false to indicate upstream and downstream directions.
1329 boolForDirection = append(boolForDirection, true, false)
1330 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
1331 for _, direction := range boolForDirection {
1332 inner1:
1333 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1334 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1335 entityID := macBridgePortAniEID + uniPort.entityID
1336 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
1337 ctx, ConstDefaultOmciTimeout, true, direction, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001338 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1339 break inner1
Girish Gowdrae0140f02021-02-02 16:55:09 -08001340 }
1341 }
1342 }
1343 case EthernetUniHistoryName:
1344
1345 inner2:
1346 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1347 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
1348 // Attach the EthernetPerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1349 entityID := uniPort.entityID
1350 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
1351 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001352 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
1353 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001354 }
1355 }
1356 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001357 case FecHistoryName:
1358
1359 inner3:
1360 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
1361 // Attach the EthernetPerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
1362 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
1363 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, anigInstID)
1364 if resp := mm.waitForResponseOrTimeout(ctx, false, anigInstID, "FecPerformanceMonitoringHistoryData"); !resp {
1365 break inner3
1366 }
1367 }
1368 case GemPortHistoryName:
1369 mm.onuMetricsManagerLock.RLock()
1370 copyOfGemPortInstIDsToDelete := make([]uint16, len(mm.gemPortNCTPPerfHistInstToDelete))
1371 _ = copy(copyOfGemPortInstIDsToDelete, mm.gemPortNCTPPerfHistInstToDelete)
1372 mm.onuMetricsManagerLock.RUnlock()
1373 inner4:
1374 for _, v := range copyOfGemPortInstIDsToDelete {
1375 mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
1376 ctx, ConstDefaultOmciTimeout, true, false, mm.pAdaptFsm.commChan, v)
1377 if resp = mm.waitForResponseOrTimeout(ctx, false, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1378 break inner4
1379 }
1380 mm.onuMetricsManagerLock.Lock()
1381 mm.gemPortNCTPPerfHistInstActive = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstActive, v)
1382 mm.onuMetricsManagerLock.Unlock()
1383 }
1384
Girish Gowdrae0140f02021-02-02 16:55:09 -08001385 default:
1386 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1387 }
1388 // On success Update the local list maintained for active PMs and PMs to delete
1389 if resp {
1390 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001391 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1392 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1393 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 -08001394 mm.onuMetricsManagerLock.Unlock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001395 } else {
1396 logger.Warnw(ctx, "state delete pm - failed to delete pm",
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08001397 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
1398 "deleteRetryAttempts": mm.groupMetricMap[n].deleteRetryAttempts,
1399 "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1400 // If deleteRetryAttempts exceeds L2PmDeleteAttempts then just give up
1401 mm.onuMetricsManagerLock.Lock()
1402 mm.groupMetricMap[n].deleteRetryAttempts++
1403 if mm.groupMetricMap[n].deleteRetryAttempts > L2PmDeleteAttempts {
1404 logger.Debugw(ctx, "exceeded-max-delete-retry-attempts--disabling-group", log.Fields{"groupName": n})
1405 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1406 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1407 mm.groupMetricMap[n].deleteRetryAttempts = 0 // reset counter
1408 }
1409 mm.onuMetricsManagerLock.Unlock()
Girish Gowdrae0140f02021-02-02 16:55:09 -08001410 }
1411 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001412 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 -08001413 // Does not matter we send success or failure here.
1414 // Those PMs that we failed to delete will be attempted to create again in the next PM collection cycle
1415 go func() {
1416 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1417 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1418 }
1419 }()
1420}
1421
1422// ** L2 PM FSM Handlers end **
1423
1424// syncTime synchronizes time with the ONU to establish a 15 min boundary for PM collection and reporting.
1425func (mm *onuMetricsManager) syncTime(ctx context.Context) error {
1426 if err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendSyncTime(ctx, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); err != nil {
1427 logger.Errorw(ctx, "cannot send sync time request", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1428 return err
1429 }
1430
1431 select {
1432 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1433 logger.Errorf(ctx, "timed out waiting for sync time response from onu", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1434 return fmt.Errorf("timed-out-waiting-for-sync-time-response-%v", mm.pDeviceHandler.deviceID)
1435 case syncTimeRes := <-mm.syncTimeResponseChan:
1436 if !syncTimeRes {
1437 return fmt.Errorf("failed-to-sync-time-%v", mm.pDeviceHandler.deviceID)
1438 }
1439 logger.Infow(ctx, "sync time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1440 return nil
1441 }
1442}
1443
1444func (mm *onuMetricsManager) collectEthernetFramePerformanceMonitoringHistoryData(ctx context.Context, upstream bool, entityID uint16) *voltha.MetricInformation {
1445 var mEnt *me.ManagedEntity
1446 var omciErr me.OmciErrors
1447 var classID me.ClassID
1448 var meAttributes me.AttributeValueMap
1449 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1450 meParam := me.ParamData{EntityID: entityID}
1451 if upstream {
1452 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataUpstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1453 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1454 return nil
1455 }
1456 classID = me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID
1457 } else {
1458 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataDownstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1459 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1460 return nil
1461 }
1462 classID = me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID
1463 }
1464
Girish Gowdrae0140f02021-02-02 16:55:09 -08001465 intervalEndTime := -1
1466 ethPMHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001467 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethPMHistData, &intervalEndTime); err != nil {
1468 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001469 }
1470
1471 // Populate some relevant context for the EthernetFramePerformanceMonitoringHistoryData PM
1472 ethPMHistData["class_id"] = float32(classID)
1473 ethPMHistData["interval_end_time"] = float32(intervalEndTime)
1474 ethPMHistData["parent_class_id"] = float32(me.MacBridgeConfigurationDataClassID) // EthernetFramePerformanceMonitoringHistoryData is attached to MBPCD ME
1475 ethPMHistData["parent_entity_id"] = float32(entityID)
1476 if upstream {
1477 ethPMHistData["upstream"] = float32(1)
1478 } else {
1479 ethPMHistData["upstream"] = float32(0)
1480 }
1481
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001482 metricInfo := mm.populateOnuMetricInfo(EthernetBridgeHistoryName, ethPMHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001483
Girish Gowdrae0140f02021-02-02 16:55:09 -08001484 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData successful",
1485 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream, "metricInfo": metricInfo})
1486 return &metricInfo
1487}
1488
1489func (mm *onuMetricsManager) collectEthernetUniHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1490 var mEnt *me.ManagedEntity
1491 var omciErr me.OmciErrors
1492 var classID me.ClassID
1493 var meAttributes me.AttributeValueMap
1494 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1495 meParam := me.ParamData{EntityID: entityID}
1496 if mEnt, omciErr = me.NewEthernetPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1497 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1498 return nil
1499 }
1500 classID = me.EthernetPerformanceMonitoringHistoryDataClassID
1501
Girish Gowdrae0140f02021-02-02 16:55:09 -08001502 intervalEndTime := -1
1503 ethUniHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001504 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethUniHistData, &intervalEndTime); err != nil {
1505 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001506 }
1507
1508 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1509 ethUniHistData["class_id"] = float32(classID)
1510 ethUniHistData["interval_end_time"] = float32(intervalEndTime)
1511
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001512 metricInfo := mm.populateOnuMetricInfo(EthernetUniHistoryName, ethUniHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001513
Girish Gowdrae0140f02021-02-02 16:55:09 -08001514 logger.Debugw(ctx, "collecting data for EthernetPerformanceMonitoringHistoryData successful",
1515 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1516 return &metricInfo
1517}
1518
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001519func (mm *onuMetricsManager) collectFecHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1520 var mEnt *me.ManagedEntity
1521 var omciErr me.OmciErrors
1522 var classID me.ClassID
1523 var meAttributes me.AttributeValueMap
1524 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1525 meParam := me.ParamData{EntityID: entityID}
1526 if mEnt, omciErr = me.NewFecPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1527 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1528 return nil
1529 }
1530 classID = me.FecPerformanceMonitoringHistoryDataClassID
1531
1532 intervalEndTime := -1
1533 fecHistData := make(map[string]float32)
1534 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, fecHistData, &intervalEndTime); err != nil {
1535 return nil
1536 }
1537
1538 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1539 fecHistData["class_id"] = float32(classID)
1540 fecHistData["interval_end_time"] = float32(intervalEndTime)
1541
1542 metricInfo := mm.populateOnuMetricInfo(FecHistoryName, fecHistData)
1543
1544 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData successful",
1545 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1546 return &metricInfo
1547}
1548
1549func (mm *onuMetricsManager) collectGemHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1550 var mEnt *me.ManagedEntity
1551 var omciErr me.OmciErrors
1552 var classID me.ClassID
1553 var meAttributes me.AttributeValueMap
1554 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1555 meParam := me.ParamData{EntityID: entityID}
1556 if mEnt, omciErr = me.NewGemPortNetworkCtpPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1557 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1558 return nil
1559 }
1560 classID = me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID
1561
1562 intervalEndTime := -1
1563 gemHistData := make(map[string]float32)
1564 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, gemHistData, &intervalEndTime); err != nil {
1565 return nil
1566 }
1567
1568 // Populate some relevant context for the GemPortNetworkCtpPerformanceMonitoringHistoryData PM
1569 gemHistData["class_id"] = float32(classID)
1570 gemHistData["interval_end_time"] = float32(intervalEndTime)
1571
1572 metricInfo := mm.populateOnuMetricInfo(GemPortHistoryName, gemHistData)
1573
1574 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData successful",
1575 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1576 return &metricInfo
1577}
1578
Girish Gowdrae0140f02021-02-02 16:55:09 -08001579// nolint: gocyclo
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001580func (mm *onuMetricsManager) populateEthernetBridgeHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
Girish Gowdrae0140f02021-02-02 16:55:09 -08001581 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001582 upstream := false
1583 if classID == me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID {
1584 upstream = true
1585 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001586 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1587 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1588 requestedAttributes["IntervalEndTime"] = 0
1589 }
1590 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1591 select {
1592 case meAttributes = <-mm.l2PmChan:
1593 logger.Debugw(ctx, "received ethernet pm history data metrics",
1594 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1595 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1596 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet pm history data",
1597 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1598 // The metrics will be empty in this case
1599 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-bridge-history-%v", mm.pDeviceHandler.deviceID)
1600 }
1601 // 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 -08001602 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1603 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 -08001604 }
1605 }
1606 for k := range EthernetBridgeHistory {
1607 // populate ethPMHistData only if metric key not already present (or populated), since it is possible that we populate
1608 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1609 if _, ok := ethPMHistData[k]; !ok {
1610 switch k {
1611 case "drop_events":
1612 if val, ok := meAttributes["DropEvents"]; ok && val != nil {
1613 ethPMHistData[k] = float32(val.(uint32))
1614 }
1615 case "octets":
1616 if val, ok := meAttributes["Octets"]; ok && val != nil {
1617 ethPMHistData[k] = float32(val.(uint32))
1618 }
1619 case "packets":
1620 if val, ok := meAttributes["Packets"]; ok && val != nil {
1621 ethPMHistData[k] = float32(val.(uint32))
1622 }
1623 case "broadcast_packets":
1624 if val, ok := meAttributes["BroadcastPackets"]; ok && val != nil {
1625 ethPMHistData[k] = float32(val.(uint32))
1626 }
1627 case "multicast_packets":
1628 if val, ok := meAttributes["MulticastPackets"]; ok && val != nil {
1629 ethPMHistData[k] = float32(val.(uint32))
1630 }
1631 case "crc_errored_packets":
1632 if val, ok := meAttributes["CrcErroredPackets"]; ok && val != nil {
1633 ethPMHistData[k] = float32(val.(uint32))
1634 }
1635 case "undersize_packets":
1636 if val, ok := meAttributes["UndersizePackets"]; ok && val != nil {
1637 ethPMHistData[k] = float32(val.(uint32))
1638 }
1639 case "oversize_packets":
1640 if val, ok := meAttributes["OversizePackets"]; ok && val != nil {
1641 ethPMHistData[k] = float32(val.(uint32))
1642 }
1643 case "64_octets":
1644 if val, ok := meAttributes["Packets64Octets"]; ok && val != nil {
1645 ethPMHistData[k] = float32(val.(uint32))
1646 }
1647 case "65_to_127_octets":
1648 if val, ok := meAttributes["Packets65To127Octets"]; ok && val != nil {
1649 ethPMHistData[k] = float32(val.(uint32))
1650 }
1651 case "128_to_255_octets":
1652 if val, ok := meAttributes["Packets128To255Octets"]; ok && val != nil {
1653 ethPMHistData[k] = float32(val.(uint32))
1654 }
1655 case "256_to_511_octets":
1656 if val, ok := meAttributes["Packets256To511Octets"]; ok && val != nil {
1657 ethPMHistData[k] = float32(val.(uint32))
1658 }
1659 case "512_to_1023_octets":
1660 if val, ok := meAttributes["Packets512To1023Octets"]; ok && val != nil {
1661 ethPMHistData[k] = float32(val.(uint32))
1662 }
1663 case "1024_to_1518_octets":
1664 if val, ok := meAttributes["Packets1024To1518Octets"]; ok && val != nil {
1665 ethPMHistData[k] = float32(val.(uint32))
1666 }
1667 default:
1668 // do nothing
1669 }
1670 }
1671 }
1672 return nil
1673}
1674
1675// nolint: gocyclo
1676func (mm *onuMetricsManager) populateEthernetUniHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1677 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMUniHistData map[string]float32, intervalEndTime *int) error {
1678 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1679 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1680 requestedAttributes["IntervalEndTime"] = 0
1681 }
1682 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1683 select {
1684 case meAttributes = <-mm.l2PmChan:
1685 logger.Debugw(ctx, "received ethernet uni history data metrics",
1686 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1687 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1688 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet uni history data",
1689 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1690 // The metrics will be empty in this case
1691 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-uni-history-%v", mm.pDeviceHandler.deviceID)
1692 }
1693 // 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 -08001694 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1695 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 -08001696 }
1697 }
1698 for k := range EthernetUniHistory {
1699 // populate ethPMUniHistData only if metric key not already present (or populated), since it is possible that we populate
1700 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1701 if _, ok := ethPMUniHistData[k]; !ok {
1702 switch k {
1703 case "fcs_errors":
1704 if val, ok := meAttributes["FcsErrors"]; ok && val != nil {
1705 ethPMUniHistData[k] = float32(val.(uint32))
1706 }
1707 case "excessive_collision_counter":
1708 if val, ok := meAttributes["ExcessiveCollisionCounter"]; ok && val != nil {
1709 ethPMUniHistData[k] = float32(val.(uint32))
1710 }
1711 case "late_collision_counter":
1712 if val, ok := meAttributes["LateCollisionCounter"]; ok && val != nil {
1713 ethPMUniHistData[k] = float32(val.(uint32))
1714 }
1715 case "frames_too_long":
1716 if val, ok := meAttributes["FramesTooLong"]; ok && val != nil {
1717 ethPMUniHistData[k] = float32(val.(uint32))
1718 }
1719 case "buffer_overflows_on_rx":
1720 if val, ok := meAttributes["BufferOverflowsOnReceive"]; ok && val != nil {
1721 ethPMUniHistData[k] = float32(val.(uint32))
1722 }
1723 case "buffer_overflows_on_tx":
1724 if val, ok := meAttributes["BufferOverflowsOnTransmit"]; ok && val != nil {
1725 ethPMUniHistData[k] = float32(val.(uint32))
1726 }
1727 case "single_collision_frame_counter":
1728 if val, ok := meAttributes["SingleCollisionFrameCounter"]; ok && val != nil {
1729 ethPMUniHistData[k] = float32(val.(uint32))
1730 }
1731 case "multiple_collisions_frame_counter":
1732 if val, ok := meAttributes["MultipleCollisionsFrameCounter"]; ok && val != nil {
1733 ethPMUniHistData[k] = float32(val.(uint32))
1734 }
1735 case "sqe_counter":
1736 if val, ok := meAttributes["SqeCounter"]; ok && val != nil {
1737 ethPMUniHistData[k] = float32(val.(uint32))
1738 }
1739 case "deferred_tx_counter":
1740 if val, ok := meAttributes["DeferredTransmissionCounter"]; ok && val != nil {
1741 ethPMUniHistData[k] = float32(val.(uint32))
1742 }
1743 case "internal_mac_tx_error_counter":
1744 if val, ok := meAttributes["InternalMacTransmitErrorCounter"]; ok && val != nil {
1745 ethPMUniHistData[k] = float32(val.(uint32))
1746 }
1747 case "carrier_sense_error_counter":
1748 if val, ok := meAttributes["CarrierSenseErrorCounter"]; ok && val != nil {
1749 ethPMUniHistData[k] = float32(val.(uint32))
1750 }
1751 case "alignment_error_counter":
1752 if val, ok := meAttributes["AlignmentErrorCounter"]; ok && val != nil {
1753 ethPMUniHistData[k] = float32(val.(uint32))
1754 }
1755 case "internal_mac_rx_error_counter":
1756 if val, ok := meAttributes["InternalMacReceiveErrorCounter"]; ok && val != nil {
1757 ethPMUniHistData[k] = float32(val.(uint32))
1758 }
1759 default:
1760 // do nothing
1761 }
1762 }
1763 }
1764 return nil
1765}
1766
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001767// nolint: gocyclo
1768func (mm *onuMetricsManager) populateFecHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1769 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, fecHistData map[string]float32, intervalEndTime *int) error {
1770 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1771 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1772 requestedAttributes["IntervalEndTime"] = 0
1773 }
1774 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1775 select {
1776 case meAttributes = <-mm.l2PmChan:
1777 logger.Debugw(ctx, "received fec history data metrics",
1778 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1779 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1780 logger.Errorw(ctx, "timeout waiting for omci-get response for fec history data",
1781 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1782 // The metrics will be empty in this case
1783 return fmt.Errorf("timeout-during-l2-pm-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1784 }
1785 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1786 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1787 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
1788 }
1789 }
1790 for k := range FecHistory {
1791 // populate fecHistData only if metric key not already present (or populated), since it is possible that we populate
1792 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1793 if _, ok := fecHistData[k]; !ok {
1794 switch k {
1795 case "corrected_bytes":
1796 if val, ok := meAttributes["CorrectedBytes"]; ok && val != nil {
1797 fecHistData[k] = float32(val.(uint32))
1798 }
1799 case "corrected_code_words":
1800 if val, ok := meAttributes["CorrectedCodeWords"]; ok && val != nil {
1801 fecHistData[k] = float32(val.(uint32))
1802 }
1803 case "uncorrectable_code_words":
1804 if val, ok := meAttributes["UncorrectableCodeWords"]; ok && val != nil {
1805 fecHistData[k] = float32(val.(uint32))
1806 }
1807 case "total_code_words":
1808 if val, ok := meAttributes["TotalCodeWords"]; ok && val != nil {
1809 fecHistData[k] = float32(val.(uint32))
1810 }
1811 case "fec_seconds":
1812 if val, ok := meAttributes["FecSeconds"]; ok && val != nil {
1813 fecHistData[k] = float32(val.(uint16))
1814 }
1815 default:
1816 // do nothing
1817 }
1818 }
1819 }
1820 return nil
1821}
1822
1823// nolint: gocyclo
1824func (mm *onuMetricsManager) populateGemPortMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
1825 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, gemPortHistData map[string]float32, intervalEndTime *int) error {
1826 // Make sure "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
1827 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
1828 requestedAttributes["IntervalEndTime"] = 0
1829 }
1830 if meInstance := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, ConstDefaultOmciTimeout, true, mm.pAdaptFsm.commChan); meInstance != nil {
1831 select {
1832 case meAttributes = <-mm.l2PmChan:
1833 logger.Debugw(ctx, "received gem port history data metrics",
1834 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1835 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
1836 logger.Errorw(ctx, "timeout waiting for omci-get response for gem port history data",
1837 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1838 // The metrics will be empty in this case
1839 return fmt.Errorf("timeout-during-l2-pm-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1840 }
1841 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
1842 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1843 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
1844 }
1845 }
1846 for k := range GemPortHistory {
1847 // populate gemPortHistData only if metric key not already present (or populated), since it is possible that we populate
1848 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1849 if _, ok := gemPortHistData[k]; !ok {
1850 switch k {
1851 case "transmitted_gem_frames":
1852 if val, ok := meAttributes["TransmittedGemFrames"]; ok && val != nil {
1853 gemPortHistData[k] = float32(val.(uint32))
1854 }
1855 case "received_gem_frames":
1856 if val, ok := meAttributes["ReceivedGemFrames"]; ok && val != nil {
1857 gemPortHistData[k] = float32(val.(uint32))
1858 }
1859 case "received_payload_bytes":
1860 if val, ok := meAttributes["ReceivedPayloadBytes"]; ok && val != nil {
1861 gemPortHistData[k] = float32(val.(uint64))
1862 }
1863 case "transmitted_payload_bytes":
1864 if val, ok := meAttributes["TransmittedPayloadBytes"]; ok && val != nil {
1865 gemPortHistData[k] = float32(val.(uint64))
1866 }
1867 case "encryption_key_errors":
1868 if val, ok := meAttributes["EncryptionKeyErrors"]; ok && val != nil {
1869 gemPortHistData[k] = float32(val.(uint32))
1870 }
1871 default:
1872 // do nothing
1873 }
1874 }
1875 }
1876 return nil
1877}
1878
Girish Gowdrae0140f02021-02-02 16:55:09 -08001879func (mm *onuMetricsManager) handleOmciCreateResponseMessage(ctx context.Context, msg OmciMessage) error {
1880 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
1881 if msgLayer == nil {
1882 logger.Errorw(ctx, "omci Msg layer could not be detected for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1883 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1884 }
1885 msgObj, msgOk := msgLayer.(*omci.CreateResponse)
1886 if !msgOk {
1887 logger.Errorw(ctx, "omci Msg layer could not be assigned for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1888 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1889 }
1890 logger.Debugw(ctx, "OMCI create response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1891 switch msgObj.EntityClass {
1892 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
1893 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001894 me.EthernetPerformanceMonitoringHistoryDataClassID,
1895 me.FecPerformanceMonitoringHistoryDataClassID,
1896 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001897 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
1898 if msgObj.Result == me.Success || msgObj.Result == me.InstanceExists {
1899 mm.l2PmCreateOrDeleteResponseChan <- true
1900 } else {
1901 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1902 mm.l2PmCreateOrDeleteResponseChan <- false
1903 }
1904 return nil
1905 default:
1906 logger.Errorw(ctx, "unhandled omci create response message",
1907 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1908 }
1909 return fmt.Errorf("unhandled-omci-create-response-message-%v", mm.pDeviceHandler.deviceID)
1910}
1911
1912func (mm *onuMetricsManager) handleOmciDeleteResponseMessage(ctx context.Context, msg OmciMessage) error {
1913 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDeleteResponse)
1914 if msgLayer == nil {
1915 logger.Errorw(ctx, "omci Msg layer could not be detected for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1916 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1917 }
1918 msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
1919 if !msgOk {
1920 logger.Errorw(ctx, "omci Msg layer could not be assigned for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1921 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1922 }
1923 logger.Debugw(ctx, "OMCI delete response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1924 switch msgObj.EntityClass {
1925 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
1926 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001927 me.EthernetPerformanceMonitoringHistoryDataClassID,
1928 me.FecPerformanceMonitoringHistoryDataClassID,
1929 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001930 // If the result is me.UnknownInstance it means the entity was already deleted. It is ok handled that as success
1931 if msgObj.Result == me.Success || msgObj.Result == me.UnknownInstance {
1932 mm.l2PmCreateOrDeleteResponseChan <- true
1933 } else {
1934 logger.Warnw(ctx, "failed to delete me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1935 mm.l2PmCreateOrDeleteResponseChan <- false
1936 }
1937 return nil
1938 default:
1939 logger.Errorw(ctx, "unhandled omci delete response message",
1940 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1941 }
1942 return fmt.Errorf("unhandled-omci-delete-response-message-%v", mm.pDeviceHandler.deviceID)
1943}
1944
1945func (mm *onuMetricsManager) generateTicks(ctx context.Context) {
1946 for {
1947 select {
1948 case <-time.After(L2PmCollectionInterval * time.Second):
1949 go func() {
1950 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1951 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1952 }
1953 }()
1954 case <-mm.stopTicks:
1955 logger.Infow(ctx, "stopping ticks", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1956 return
1957 }
1958 }
1959}
1960
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001961func (mm *onuMetricsManager) handleMetricsPublish(ctx context.Context, metricName string, metricInfoSlice []*voltha.MetricInformation) {
1962 // Publish metrics if it is valid
1963 if metricInfoSlice != nil {
1964 mm.publishMetrics(ctx, metricInfoSlice)
1965 } else {
1966 // If collectAttempts exceeds L2PmCollectAttempts then remove it from activeL2Pms
1967 // slice so that we do not collect data from that PM ME anymore
1968 mm.onuMetricsManagerLock.Lock()
1969 mm.groupMetricMap[metricName].collectAttempts++
1970 if mm.groupMetricMap[metricName].collectAttempts > L2PmCollectAttempts {
1971 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, metricName)
1972 }
1973 logger.Warnw(ctx, "state collect data - no metrics collected",
1974 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName, "collectAttempts": mm.groupMetricMap[metricName].collectAttempts})
1975 mm.onuMetricsManagerLock.Unlock()
1976 }
1977}
1978
1979func (mm *onuMetricsManager) populateGroupSpecificMetrics(ctx context.Context, mEnt *me.ManagedEntity, classID me.ClassID, entityID uint16,
1980 meAttributes me.AttributeValueMap, data map[string]float32, intervalEndTime *int) error {
1981 var grpFunc groupMetricPopulateFunc
1982 switch classID {
1983 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID, me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID:
1984 grpFunc = mm.populateEthernetBridgeHistoryMetrics
1985 case me.EthernetPerformanceMonitoringHistoryDataClassID:
1986 grpFunc = mm.populateEthernetUniHistoryMetrics
1987 case me.FecPerformanceMonitoringHistoryDataClassID:
1988 grpFunc = mm.populateFecHistoryMetrics
1989 case me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
1990 grpFunc = mm.populateGemPortMetrics
1991 default:
1992 return fmt.Errorf("unknown-classid-%v", classID)
1993 }
1994
1995 size := 0
1996 requestedAttributes := make(me.AttributeValueMap)
1997 for _, v := range mEnt.GetAttributeDefinitions() {
1998 if (v.Size + size) <= MaxL2PMGetPayLoadSize {
1999 requestedAttributes[v.Name] = v.DefValue
2000 size = v.Size + size
2001 } else { // We exceeded the allow omci get size
2002 // Let's collect the attributes via get now and collect remaining in the next iteration
2003 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2004 logger.Errorw(ctx, "error during metric collection",
2005 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2006 return err
2007 }
2008 size = 0 // reset size
2009 requestedAttributes = make(me.AttributeValueMap) // reset map
2010 }
2011 }
2012 // Collect the omci get attributes for the last bunch of attributes.
2013 if len(requestedAttributes) > 0 {
2014 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2015 logger.Errorw(ctx, "error during metric collection",
2016 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2017 return err
2018 }
2019 }
2020 return nil
2021}
2022
2023func (mm *onuMetricsManager) populateOnuMetricInfo(title string, data map[string]float32) voltha.MetricInformation {
2024 metricsContext := make(map[string]string)
2025 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
2026 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
2027 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
2028
2029 raisedTs := time.Now().Unix()
2030 mmd := voltha.MetricMetaData{
2031 Title: title,
2032 Ts: float64(raisedTs),
2033 Context: metricsContext,
2034 DeviceId: mm.pDeviceHandler.deviceID,
2035 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
2036 SerialNo: mm.pDeviceHandler.device.SerialNumber,
2037 }
2038
2039 // create slice of metrics given that there could be more than one VEIP instance
2040 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: data}
2041 return metricInfo
2042}
2043
2044func (mm *onuMetricsManager) updateAndValidateIntervalEndTime(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap, intervalEndTime *int) bool {
2045 valid := false
2046 if *intervalEndTime == -1 { // first time
2047 // Update the interval end time
2048 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2049 *intervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2050 valid = true
2051 }
2052 } else {
2053 var currIntervalEndTime int
2054 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2055 currIntervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2056 }
2057 if currIntervalEndTime != *intervalEndTime { // interval end time changed during metric collection
2058 logger.Errorw(ctx, "interval end time changed during metrics collection for ethernet pm history data",
2059 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID,
2060 "currIntervalEndTime": *intervalEndTime, "newIntervalEndTime": currIntervalEndTime})
2061 } else {
2062 valid = true
2063 }
2064 }
2065 return valid
2066}
2067
2068func (mm *onuMetricsManager) waitForResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassName string) bool {
2069 logger.Debugw(ctx, "waitForResponseOrTimeout", log.Fields{"create": create, "instID": instID, "meClassName": meClassName})
2070 select {
2071 case resp := <-mm.l2PmCreateOrDeleteResponseChan:
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002072 logger.Debugw(ctx, "received l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002073 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassName": meClassName, "instID": instID})
2074 return resp
2075 case <-time.After(time.Duration(ConstDefaultOmciTimeout) * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002076 logger.Errorw(ctx, "timeout waiting for l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002077 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassName": meClassName, "instID": instID})
2078 }
2079 return false
2080}
2081
2082func (mm *onuMetricsManager) initializeGroupMetric(grpMtrcs map[string]voltha.PmConfig_PmType, grpName string, grpEnabled bool, grpFreq uint32) {
2083 var pmConfigSlice []*voltha.PmConfig
2084 for k, v := range grpMtrcs {
2085 pmConfigSlice = append(pmConfigSlice, &voltha.PmConfig{Name: k, Type: v})
2086 }
2087 groupMetric := voltha.PmGroupConfig{
2088 GroupName: grpName,
2089 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2090 GroupFreq: grpFreq,
2091 Metrics: pmConfigSlice,
2092 }
2093 mm.pDeviceHandler.pmConfigs.Groups = append(mm.pDeviceHandler.pmConfigs.Groups, &groupMetric)
2094
2095}
2096
2097func (mm *onuMetricsManager) initializeL2PmFsm(ctx context.Context, aCommChannel chan Message) error {
2098 mm.pAdaptFsm = NewAdapterFsm("L2PmFSM", mm.pDeviceHandler.deviceID, aCommChannel)
2099 if mm.pAdaptFsm == nil {
2100 logger.Errorw(ctx, "L2PMFsm AdapterFsm could not be instantiated!!", log.Fields{
2101 "device-id": mm.pDeviceHandler.deviceID})
2102 return fmt.Errorf("nil-adapter-fsm")
2103 }
2104 // L2 PM FSM related state machine
2105 mm.pAdaptFsm.pFsm = fsm.NewFSM(
2106 l2PmStNull,
2107 fsm.Events{
2108 {Name: l2PmEventInit, Src: []string{l2PmStNull}, Dst: l2PmStStarting},
2109 {Name: l2PmEventTick, Src: []string{l2PmStStarting}, Dst: l2PmStSyncTime},
2110 {Name: l2PmEventTick, Src: []string{l2PmStIdle, l2PmEventDeleteMe, l2PmEventAddMe}, Dst: l2PmStCollectData},
2111 {Name: l2PmEventSuccess, Src: []string{l2PmStSyncTime, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2112 {Name: l2PmEventFailure, Src: []string{l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2113 {Name: l2PmEventFailure, Src: []string{l2PmStSyncTime}, Dst: l2PmStSyncTime},
2114 {Name: l2PmEventAddMe, Src: []string{l2PmStIdle}, Dst: l2PmStCreatePmMe},
2115 {Name: l2PmEventDeleteMe, Src: []string{l2PmStIdle}, Dst: l2PmStDeletePmMe},
2116 {Name: l2PmEventStop, Src: []string{l2PmStNull, l2PmStStarting, l2PmStSyncTime, l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStNull},
2117 },
2118 fsm.Callbacks{
2119 "enter_state": func(e *fsm.Event) { mm.pAdaptFsm.logFsmStateChange(ctx, e) },
2120 "enter_" + l2PmStNull: func(e *fsm.Event) { mm.l2PMFsmNull(ctx, e) },
2121 "enter_" + l2PmStIdle: func(e *fsm.Event) { mm.l2PMFsmIdle(ctx, e) },
2122 "enter_" + l2PmStStarting: func(e *fsm.Event) { mm.l2PMFsmStarting(ctx, e) },
2123 "enter_" + l2PmStSyncTime: func(e *fsm.Event) { mm.l2PMFsmSyncTime(ctx, e) },
2124 "enter_" + l2PmStCollectData: func(e *fsm.Event) { mm.l2PmFsmCollectData(ctx, e) },
2125 "enter_" + l2PmStCreatePmMe: func(e *fsm.Event) { mm.l2PmFsmCreatePM(ctx, e) },
2126 "enter_" + l2PmStDeletePmMe: func(e *fsm.Event) { mm.l2PmFsmDeletePM(ctx, e) },
2127 },
2128 )
2129 return nil
2130}
2131
2132func (mm *onuMetricsManager) initializeAllGroupMetrics() {
2133 mm.pDeviceHandler.pmConfigs = &voltha.PmConfigs{}
2134 mm.pDeviceHandler.pmConfigs.Id = mm.pDeviceHandler.deviceID
2135 mm.pDeviceHandler.pmConfigs.DefaultFreq = DefaultMetricCollectionFrequency
2136 mm.pDeviceHandler.pmConfigs.Grouped = GroupMetricEnabled
2137 mm.pDeviceHandler.pmConfigs.FreqOverride = DefaultFrequencyOverrideEnabled
2138
2139 // Populate group metrics.
2140 // Lets populate irrespective of GroupMetricEnabled is true or not.
2141 // The group metrics collection will decided on this flag later
2142
2143 mm.initializeGroupMetric(OpticalPowerGroupMetrics, OpticalPowerGroupMetricName,
2144 OpticalPowerGroupMetricEnabled, OpticalPowerMetricGroupCollectionFrequency)
2145
2146 mm.initializeGroupMetric(UniStatusGroupMetrics, UniStatusGroupMetricName,
2147 UniStatusGroupMetricEnabled, UniStatusMetricGroupCollectionFrequency)
2148
2149 // classical l2 pm counter start
2150
2151 mm.initializeGroupMetric(EthernetBridgeHistory, EthernetBridgeHistoryName,
2152 EthernetBridgeHistoryEnabled, EthernetBridgeHistoryFrequency)
2153
2154 mm.initializeGroupMetric(EthernetUniHistory, EthernetUniHistoryName,
2155 EthernetUniHistoryEnabled, EthernetUniHistoryFrequency)
2156
2157 mm.initializeGroupMetric(FecHistory, FecHistoryName,
2158 FecHistoryEnabled, FecHistoryFrequency)
2159
2160 mm.initializeGroupMetric(GemPortHistory, GemPortHistoryName,
2161 GemPortHistoryEnabled, GemPortHistoryFrequency)
2162
2163 // classical l2 pm counter end
2164
2165 // Add standalone metric (if present) after this (will be added to dh.pmConfigs.Metrics)
2166}
2167
2168func (mm *onuMetricsManager) populateLocalGroupMetricData(ctx context.Context) {
2169 // Populate local group metric structures
2170 for _, g := range mm.pDeviceHandler.pmConfigs.Groups {
2171 mm.groupMetricMap[g.GroupName] = &groupMetric{
2172 groupName: g.GroupName,
2173 enabled: g.Enabled,
2174 frequency: g.GroupFreq,
2175 }
2176 switch g.GroupName {
2177 case OpticalPowerGroupMetricName:
2178 mm.groupMetricMap[g.GroupName].metricMap = OpticalPowerGroupMetrics
2179 case UniStatusGroupMetricName:
2180 mm.groupMetricMap[g.GroupName].metricMap = UniStatusGroupMetrics
2181 case EthernetBridgeHistoryName:
2182 mm.groupMetricMap[g.GroupName].metricMap = EthernetBridgeHistory
2183 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2184 case EthernetUniHistoryName:
2185 mm.groupMetricMap[g.GroupName].metricMap = EthernetUniHistory
2186 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2187 case FecHistoryName:
2188 mm.groupMetricMap[g.GroupName].metricMap = FecHistory
2189 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2190 case GemPortHistoryName:
2191 mm.groupMetricMap[g.GroupName].metricMap = GemPortHistory
2192 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2193 default:
2194 logger.Errorw(ctx, "unhandled-group-name", log.Fields{"groupName": g.GroupName})
2195 }
2196 }
2197
2198 // Populate local standalone metric structures
2199 for _, m := range mm.pDeviceHandler.pmConfigs.Metrics {
2200 mm.standaloneMetricMap[m.Name] = &standaloneMetric{
2201 metricName: m.Name,
2202 enabled: m.Enabled,
2203 frequency: m.SampleFreq,
2204 }
2205 switch m.Name {
2206 // None exist as of now. Add when available.
2207 default:
2208 logger.Errorw(ctx, "unhandled-metric-name", log.Fields{"metricName": m.Name})
2209 }
2210 }
2211}
2212
2213func (mm *onuMetricsManager) AddGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2214 mm.onuMetricsManagerLock.Lock()
2215 defer mm.onuMetricsManagerLock.Unlock()
2216 // mark the instance for addition
2217 mm.gemPortNCTPPerfHistInstToAdd = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstToAdd, gemPortNTPInstID)
2218 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
2219 mm.gemPortNCTPPerfHistInstToDelete = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstToDelete, gemPortNTPInstID)
2220
2221 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, GemPortHistoryName)
2222 // We do not need to remove from l2PmToDelete slice as we could have Add and Delete of
2223 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2224 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2225 // gemPortNCTPPerfHistInstToAdd slice
2226}
2227
2228func (mm *onuMetricsManager) RemoveGemPortForPerfMonitoring(gemPortNTPInstID uint16) {
2229 mm.onuMetricsManagerLock.Lock()
2230 defer mm.onuMetricsManagerLock.Unlock()
2231 mm.gemPortNCTPPerfHistInstToDelete = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstToDelete, gemPortNTPInstID)
2232 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
2233 mm.gemPortNCTPPerfHistInstToAdd = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstToAdd, gemPortNTPInstID)
2234
2235 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, GemPortHistoryName)
2236 // We do not need to remove from l2PmToAdd slice as we could have Add and Delete of
2237 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2238 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2239 // gemPortNCTPPerfHistInstToAdd slice
2240}
2241
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002242func (mm *onuMetricsManager) updateGemPortNTPInstanceToAddForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002243 if mm.pDeviceHandler.pOnuTP != nil {
2244 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002245 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002246 for _, v := range gemPortInstIDs {
2247 // mark the instance for addition
2248 mm.gemPortNCTPPerfHistInstToAdd = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstToAdd, v)
2249 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
2250 mm.gemPortNCTPPerfHistInstToDelete = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstToDelete, v)
2251 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002252 logger.Debugw(ctx, "updateGemPortNTPInstanceToAddForPerfMonitoring",
2253 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.gemPortNCTPPerfHistInstToAdd, "gemToDel": mm.gemPortNCTPPerfHistInstToDelete})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002254 }
2255}
2256
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002257func (mm *onuMetricsManager) updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002258 if mm.pDeviceHandler.pOnuTP != nil {
2259 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002260 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002261 for _, v := range gemPortInstIDs {
2262 mm.gemPortNCTPPerfHistInstToDelete = mm.appendIfMissingUnt16(mm.gemPortNCTPPerfHistInstToDelete, v)
2263 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
2264 mm.gemPortNCTPPerfHistInstToAdd = mm.removeIfFoundUint16(mm.gemPortNCTPPerfHistInstToAdd, v)
2265 }
2266 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002267 logger.Debugw(ctx, "updateGemPortNTPInstanceToDeleteForPerfMonitoring",
2268 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.gemPortNCTPPerfHistInstToAdd, "gemToDel": mm.gemPortNCTPPerfHistInstToDelete})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002269}
2270
2271func (mm *onuMetricsManager) appendIfMissingString(slice []string, n string) []string {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002272 for _, ele := range slice {
2273 if ele == n {
2274 return slice
2275 }
2276 }
2277 return append(slice, n)
2278}
2279
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002280func (mm *onuMetricsManager) removeIfFoundString(slice []string, n string) []string {
2281 for i, ele := range slice {
2282 if ele == n {
2283 return append(slice[:i], slice[i+1:]...)
2284 }
2285 }
2286 return slice
2287}
2288
2289func (mm *onuMetricsManager) appendIfMissingUnt16(slice []uint16, n uint16) []uint16 {
2290 for _, ele := range slice {
2291 if ele == n {
2292 return slice
2293 }
2294 }
2295 return append(slice, n)
2296}
2297
2298func (mm *onuMetricsManager) removeIfFoundUint16(slice []uint16, n uint16) []uint16 {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002299 for i, ele := range slice {
2300 if ele == n {
2301 return append(slice[:i], slice[i+1:]...)
2302 }
2303 }
2304 return slice
Girish Gowdrae09a6202021-01-12 18:10:59 -08002305}