blob: ab3000ccda7423d13d7fdf903f6fb02cdbab14cf [file] [log] [blame]
Girish Gowdrae09a6202021-01-12 18:10:59 -08001/*
2 * Copyright 2021-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//Package adaptercoreonu provides the utility for onu devices, flows and statistics
18package adaptercoreonu
19
20import (
21 "context"
Girish Gowdra0e533642021-03-02 22:02:51 -080022 "encoding/json"
Girish Gowdrae09a6202021-01-12 18:10:59 -080023 "fmt"
Holger Hildebrandt44a0d4f2021-03-18 14:00:54 +000024 "math"
25 "sync"
26 "time"
27
Girish Gowdrae0140f02021-02-02 16:55:09 -080028 "github.com/looplab/fsm"
Girish Gowdrae09a6202021-01-12 18:10:59 -080029 "github.com/opencord/omci-lib-go"
30 me "github.com/opencord/omci-lib-go/generated"
Girish Gowdra50e56422021-06-01 16:46:04 -070031 "github.com/opencord/voltha-lib-go/v5/pkg/db"
32 "github.com/opencord/voltha-lib-go/v5/pkg/db/kvstore"
33 "github.com/opencord/voltha-lib-go/v5/pkg/log"
Himani Chawla43f95ff2021-06-03 00:24:12 +053034 "github.com/opencord/voltha-protos/v4/go/extension"
Girish Gowdrae09a6202021-01-12 18:10:59 -080035 "github.com/opencord/voltha-protos/v4/go/voltha"
Girish Gowdrae09a6202021-01-12 18:10:59 -080036)
37
Girish Gowdrae0140f02021-02-02 16:55:09 -080038const (
39 // events of L2 PM FSM
40 l2PmEventInit = "l2PmEventInit"
41 l2PmEventTick = "l2PmEventTick"
42 l2PmEventSuccess = "l2PmEventSuccess"
43 l2PmEventFailure = "l2PmEventFailure"
44 l2PmEventAddMe = "l2PmEventAddMe"
45 l2PmEventDeleteMe = "l2PmEventDeleteMe"
46 l2PmEventStop = "l2PmEventStop"
47)
48const (
49 // states of L2 PM FSM
50 l2PmStNull = "l2PmStNull"
51 l2PmStStarting = "l2PmStStarting"
52 l2PmStSyncTime = "l2PmStSyncTime"
53 l2PmStIdle = "l2PmStIdle"
54 l2PmStCreatePmMe = "l2PmStCreatePm"
55 l2PmStDeletePmMe = "l2PmStDeletePmMe"
56 l2PmStCollectData = "l2PmStCollectData"
57)
58
59const cL2PmFsmIdleState = l2PmStIdle
60
Girish Gowdra5a7c4922021-01-22 18:33:41 -080061// general constants used for overall Metric Collection management
62const (
63 DefaultMetricCollectionFrequency = 15 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
64 GroupMetricEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
65 DefaultFrequencyOverrideEnabled = true // This is READONLY and cannot be changed from VOLTHA NBI
66 FrequencyGranularity = 5 // The frequency (in seconds) has to be multiple of 5. This setting cannot changed later.
67)
68
Himani Chawla43f95ff2021-06-03 00:24:12 +053069// constants for ethernet frame extended pm collection
70const (
71 ExtendedPmCreateAttempts = 3
72 UnsupportedCounterValue32bit uint64 = 4294967294
73 UnsupportedCounterValue64bit uint64 = 18446744073709551614
74 dropEvents = "DropEvents"
75 octets = "Octets"
76 frames = "Frames"
77 broadcastFrames = "BroadcastFrames"
78 multicastFrames = "MulticastFrames"
79 crcErroredFrames = "CrcErroredFrames"
80 undersizeFrames = "UndersizeFrames"
81 oversizeFrames = "OversizeFrames"
82 frames64Octets = "Frames64Octets"
83 frames65To127Octets = "Frames65To127Octets"
84 frames128To255Octets = "Frames128To255Octets"
85 frames256To511Octets = "Frames256To511Octets"
86 frames512To1023Octets = "Frames512To1023Octets"
87 frames1024To1518Octets = "Frames1024To1518Octets"
88)
89
Girish Gowdra5a7c4922021-01-22 18:33:41 -080090// OpticalPowerGroupMetrics are supported optical pm names
91var OpticalPowerGroupMetrics = map[string]voltha.PmConfig_PmType{
Girish Gowdrae20a4f62021-03-09 16:06:23 -080092 "ani_g_instance_id": voltha.PmConfig_CONTEXT,
93 "transmit_power_dBm": voltha.PmConfig_GAUGE,
94 "receive_power_dBm": voltha.PmConfig_GAUGE,
Girish Gowdra5a7c4922021-01-22 18:33:41 -080095}
96
97// OpticalPowerGroupMetrics specific constants
98const (
Girish Gowdrae0140f02021-02-02 16:55:09 -080099 OpticalPowerGroupMetricName = "PON_Optical"
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800100 OpticalPowerGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
101 OpticalPowerMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
102)
103
104// UniStatusGroupMetrics are supported UNI status names
105var UniStatusGroupMetrics = map[string]voltha.PmConfig_PmType{
Girish Gowdrad3436802021-06-28 13:15:40 -0700106 "uni_port_no": voltha.PmConfig_CONTEXT,
107 "me_class_id": voltha.PmConfig_CONTEXT,
108 "entity_id": voltha.PmConfig_CONTEXT,
109 "configuration_ind": voltha.PmConfig_GAUGE,
110 "oper_status": voltha.PmConfig_GAUGE,
111 "uni_admin_state": voltha.PmConfig_GAUGE,
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800112}
113
114// UniStatusGroupMetrics specific constants
115const (
Girish Gowdrae0140f02021-02-02 16:55:09 -0800116 UniStatusGroupMetricName = "UNI_Status"
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800117 UniStatusGroupMetricEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
118 UniStatusMetricGroupCollectionFrequency = 5 * 60 // unit in seconds. This setting can be changed from voltha NBI PmConfig configuration
119)
120
Girish Gowdrae0140f02021-02-02 16:55:09 -0800121// *** Classical L2 PM Counters begin ***
122
123// EthernetBridgeHistory are supported ethernet bridge history counters fetched from
124// Ethernet Frame Performance Monitoring History Data Downstream and Ethernet Frame Performance Monitoring History Data Upstream MEs.
125var EthernetBridgeHistory = map[string]voltha.PmConfig_PmType{
126 "class_id": voltha.PmConfig_CONTEXT,
127 "entity_id": voltha.PmConfig_CONTEXT,
128 "interval_end_time": voltha.PmConfig_CONTEXT,
129 "parent_class_id": voltha.PmConfig_CONTEXT,
130 "parent_entity_id": voltha.PmConfig_CONTEXT,
131 "upstream": voltha.PmConfig_CONTEXT,
132
133 "drop_events": voltha.PmConfig_COUNTER,
134 "octets": voltha.PmConfig_COUNTER,
135 "packets": voltha.PmConfig_COUNTER,
136 "broadcast_packets": voltha.PmConfig_COUNTER,
137 "multicast_packets": voltha.PmConfig_COUNTER,
138 "crc_errored_packets": voltha.PmConfig_COUNTER,
139 "undersize_packets": voltha.PmConfig_COUNTER,
140 "oversize_packets": voltha.PmConfig_COUNTER,
141 "64_octets": voltha.PmConfig_COUNTER,
142 "65_to_127_octets": voltha.PmConfig_COUNTER,
143 "128_to_255_octets": voltha.PmConfig_COUNTER,
144 "256_to_511_octets": voltha.PmConfig_COUNTER,
145 "512_to_1023_octets": voltha.PmConfig_COUNTER,
146 "1024_to_1518_octets": voltha.PmConfig_COUNTER,
147}
148
149// EthernetUniHistory are supported ethernet uni history counters fetched from
150// Ethernet Performance Monitoring History Data ME.
151var EthernetUniHistory = map[string]voltha.PmConfig_PmType{
152 "class_id": voltha.PmConfig_CONTEXT,
153 "entity_id": voltha.PmConfig_CONTEXT,
154 "interval_end_time": voltha.PmConfig_CONTEXT,
155
156 "fcs_errors": voltha.PmConfig_COUNTER,
157 "excessive_collision_counter": voltha.PmConfig_COUNTER,
158 "late_collision_counter": voltha.PmConfig_COUNTER,
159 "frames_too_long": voltha.PmConfig_COUNTER,
160 "buffer_overflows_on_rx": voltha.PmConfig_COUNTER,
161 "buffer_overflows_on_tx": voltha.PmConfig_COUNTER,
162 "single_collision_frame_counter": voltha.PmConfig_COUNTER,
163 "multiple_collisions_frame_counter": voltha.PmConfig_COUNTER,
164 "sqe_counter": voltha.PmConfig_COUNTER,
165 "deferred_tx_counter": voltha.PmConfig_COUNTER,
166 "internal_mac_tx_error_counter": voltha.PmConfig_COUNTER,
167 "carrier_sense_error_counter": voltha.PmConfig_COUNTER,
168 "alignment_error_counter": voltha.PmConfig_COUNTER,
169 "internal_mac_rx_error_counter": voltha.PmConfig_COUNTER,
170}
171
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800172// FecHistory is supported FEC Performance Monitoring History Data related metrics
173var FecHistory = map[string]voltha.PmConfig_PmType{
174 "class_id": voltha.PmConfig_CONTEXT,
175 "entity_id": voltha.PmConfig_CONTEXT,
176 "interval_end_time": voltha.PmConfig_CONTEXT,
177
178 "corrected_bytes": voltha.PmConfig_COUNTER,
179 "corrected_code_words": voltha.PmConfig_COUNTER,
180 "uncorrectable_code_words": voltha.PmConfig_COUNTER,
181 "total_code_words": voltha.PmConfig_COUNTER,
182 "fec_seconds": voltha.PmConfig_COUNTER,
183}
184
185// GemPortHistory is supported GEM Port Network Ctp Performance Monitoring History Data
186// related metrics
187var GemPortHistory = map[string]voltha.PmConfig_PmType{
188 "class_id": voltha.PmConfig_CONTEXT,
189 "entity_id": voltha.PmConfig_CONTEXT,
190 "interval_end_time": voltha.PmConfig_CONTEXT,
191
192 "transmitted_gem_frames": voltha.PmConfig_COUNTER,
193 "received_gem_frames": voltha.PmConfig_COUNTER,
194 "received_payload_bytes": voltha.PmConfig_COUNTER,
195 "transmitted_payload_bytes": voltha.PmConfig_COUNTER,
196 "encryption_key_errors": voltha.PmConfig_COUNTER,
197}
198
Himani Chawla43f95ff2021-06-03 00:24:12 +0530199var maskToEthernetFrameExtendedPM32Bit = map[uint16][]string{
200 0x3F00: {"drop_events", "octets", "frames", "broadcast_frames", "multicast_frames", "crc_errored_frames"},
201 0x00FC: {"undersize_frames", "oversize_frames", "64_octets", "65_to_127_octets", "128_to_255_octets", "256_to_511_octets"},
202 0x0003: {"512_to_1023_octets", "1024_to_1518_octets"},
203}
204
205var maskToEthernetFrameExtendedPM64Bit = map[uint16][]string{
206 0x3800: {"drop_events", "octets", "frames"},
207 0x0700: {"broadcast_frames", "multicast_frames", "crc_errored_frames"},
208 0x00E0: {"undersize_frames", "oversize_frames", "64_octets"},
209 0x001C: {"65_to_127_octets", "128_to_255_octets", "256_to_511_octets"},
210 0x0003: {"512_to_1023_octets", "1024_to_1518_octets"},
211}
212
Girish Gowdrae0140f02021-02-02 16:55:09 -0800213// Constants specific for L2 PM collection
214const (
215 L2PmCollectionInterval = 15 * 60 // Unit in seconds. Do not change this as this fixed by OMCI specification for L2 PM counters
216 SyncTimeRetryInterval = 15 // Unit seconds
217 L2PmCreateAttempts = 3
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800218 L2PmDeleteAttempts = 3
Girish Gowdrae0140f02021-02-02 16:55:09 -0800219 L2PmCollectAttempts = 3
Girish Gowdra453750f2021-02-16 16:36:46 -0800220 // Per Table 11.2.9-1 – OMCI baseline message limitations in G.988 spec, the max GET Response
221 // payload size is 25. We define 24 (one less) to allow for dynamic insertion of IntervalEndTime
222 // attribute (1 byte) in L2 PM GET Requests.
Himani Chawla43f95ff2021-06-03 00:24:12 +0530223 MaxL2PMGetPayLoadSize = 24
224 MaxEthernetFrameExtPmPayloadSize = 25
Girish Gowdrae0140f02021-02-02 16:55:09 -0800225)
226
227// EthernetUniHistoryName specific constants
228const (
229 EthernetBridgeHistoryName = "Ethernet_Bridge_Port_History"
230 EthernetBridgeHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
231 EthernetBridgeHistoryFrequency = L2PmCollectionInterval
232)
233
234// EthernetBridgeHistory specific constants
235const (
236 EthernetUniHistoryName = "Ethernet_UNI_History"
237 EthernetUniHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
238 EthernetUniHistoryFrequency = L2PmCollectionInterval
239)
240
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800241// FecHistory specific constants
242const (
243 FecHistoryName = "FEC_History"
244 FecHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
245 FecHistoryFrequency = L2PmCollectionInterval
246)
247
248// GemPortHistory specific constants
249const (
250 GemPortHistoryName = "GEM_Port_History"
251 GemPortHistoryEnabled = true // This setting can be changed from voltha NBI PmConfig configuration
252 GemPortHistoryFrequency = L2PmCollectionInterval
253)
254
Girish Gowdra0e533642021-03-02 22:02:51 -0800255// KV Store related constants
256const (
Himani Chawla43f95ff2021-06-03 00:24:12 +0530257 cPmKvStorePrefix = "%s/openonu/pm-data/%s" // <some-base-path>/openonu/pm-data/<onu-device-id>
258 cPmAdd = "add"
259 cPmAdded = "added"
260 cPmRemove = "remove"
261 cPmRemoved = "removed"
262 cExtPmKvStorePrefix = "%s/omci_me" //<some-base-path>/omci_me/<onu_vendor>/<onu_equipment_id>/<onu_sw_version>
Girish Gowdra0e533642021-03-02 22:02:51 -0800263)
264
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800265// Defines the type for generic metric population function
266type groupMetricPopulateFunc func(context.Context, me.ClassID, uint16, me.AttributeValueMap, me.AttributeValueMap, map[string]float32, *int) error
267
Girish Gowdrae0140f02021-02-02 16:55:09 -0800268// *** Classical L2 PM Counters end ***
269
Girish Gowdra0e533642021-03-02 22:02:51 -0800270type pmMEData struct {
271 InstancesActive []uint16 `json:"instances_active"` // list of active ME instance IDs for the group
272 InstancesToDelete []uint16 `json:"instances_to_delete"` // list of ME instance IDs marked for deletion for the group
273 InstancesToAdd []uint16 `json:"instances_to_add"` // list of ME instance IDs marked for addition for the group
274}
275
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800276type groupMetric struct {
277 groupName string
278 enabled bool
279 frequency uint32 // valid only if FrequencyOverride is enabled.
280 metricMap map[string]voltha.PmConfig_PmType
281 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
Girish Gowdrae0140f02021-02-02 16:55:09 -0800282 isL2PMCounter bool // true for only L2 PM counters
283 collectAttempts uint32 // number of attempts to collect L2 PM data
Girish Gowdra0e533642021-03-02 22:02:51 -0800284 pmMEData *pmMEData
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800285}
286
287type standaloneMetric struct {
288 metricName string
289 enabled bool
290 frequency uint32 // valid only if FrequencyOverride is enabled.
291 nextCollectionInterval time.Time // valid only if FrequencyOverride is enabled.
292}
293
Girish Gowdrae09a6202021-01-12 18:10:59 -0800294type onuMetricsManager struct {
295 pDeviceHandler *deviceHandler
Girish Gowdrae0140f02021-02-02 16:55:09 -0800296 pAdaptFsm *AdapterFsm
Girish Gowdrae09a6202021-01-12 18:10:59 -0800297
Himani Chawla43f95ff2021-06-03 00:24:12 +0530298 opticalMetricsChan chan me.AttributeValueMap
299 uniStatusMetricsChan chan me.AttributeValueMap
300 l2PmChan chan me.AttributeValueMap
301 extendedPmMeChan chan me.AttributeValueMap
302 syncTimeResponseChan chan bool // true is success, false is fail
303 l2PmCreateOrDeleteResponseChan chan bool // true is success, false is fail
304 extendedPMCreateOrDeleteResponseChan chan me.Results // true is sucesss, false is fail
Girish Gowdrae0140f02021-02-02 16:55:09 -0800305
306 activeL2Pms []string // list of active l2 pm MEs created on the ONU.
307 l2PmToDelete []string // list of L2 PMs to delete
308 l2PmToAdd []string // list of L2 PM to add
Girish Gowdrae09a6202021-01-12 18:10:59 -0800309
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800310 groupMetricMap map[string]*groupMetric
311 standaloneMetricMap map[string]*standaloneMetric
312
Girish Gowdrae09a6202021-01-12 18:10:59 -0800313 stopProcessingOmciResponses chan bool
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -0700314 omciProcessingActive bool
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800315
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -0700316 stopTicks chan bool
317 tickGenerationActive bool
Girish Gowdrae0140f02021-02-02 16:55:09 -0800318
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800319 nextGlobalMetricCollectionTime time.Time // valid only if pmConfig.FreqOverride is set to false.
320
321 onuMetricsManagerLock sync.RWMutex
Girish Gowdra0e533642021-03-02 22:02:51 -0800322
323 pmKvStore *db.Backend
Himani Chawla43f95ff2021-06-03 00:24:12 +0530324
325 supportedEthernetFrameExtendedPMClass me.ClassID
Himani Chawla97531162021-07-12 15:42:26 +0530326 ethernetFrameExtendedPmUpStreamMEByEntityID map[uint16]*me.ManagedEntity
327 ethernetFrameExtendedPmDownStreamMEByEntityID map[uint16]*me.ManagedEntity
Himani Chawla43f95ff2021-06-03 00:24:12 +0530328 extPmKvStore *db.Backend
329 onuEthernetFrameExtendedPmLock sync.RWMutex
330 isDeviceReadyToCollectExtendedPmStats bool
Girish Gowdrae09a6202021-01-12 18:10:59 -0800331}
332
333// newonuMetricsManager returns a new instance of the newonuMetricsManager
Girish Gowdra0e533642021-03-02 22:02:51 -0800334// The metrics manager module is responsible for configuration and management of individual and group metrics.
335// Currently all the metrics are managed as a group which fall into two categories - L2 PM and "all others"
336// The L2 PM counters have a fixed 15min interval for PM collection while all other group counters have
337// the collection interval configurable.
338// The global PM config is part of the voltha.Device struct and is backed up on KV store (by rw-core).
339// This module also implements resiliency for L2 PM ME instances that are active/pending-delete/pending-add.
Girish Gowdrae09a6202021-01-12 18:10:59 -0800340func newonuMetricsManager(ctx context.Context, dh *deviceHandler) *onuMetricsManager {
341
342 var metricsManager onuMetricsManager
343 logger.Debugw(ctx, "init-onuMetricsManager", log.Fields{"device-id": dh.deviceID})
344 metricsManager.pDeviceHandler = dh
345
Girish Gowdrae0140f02021-02-02 16:55:09 -0800346 commMetricsChan := make(chan Message)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800347 metricsManager.opticalMetricsChan = make(chan me.AttributeValueMap)
348 metricsManager.uniStatusMetricsChan = make(chan me.AttributeValueMap)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800349 metricsManager.l2PmChan = make(chan me.AttributeValueMap)
Himani Chawla43f95ff2021-06-03 00:24:12 +0530350 metricsManager.extendedPmMeChan = make(chan me.AttributeValueMap)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800351
352 metricsManager.syncTimeResponseChan = make(chan bool)
353 metricsManager.l2PmCreateOrDeleteResponseChan = make(chan bool)
Himani Chawla43f95ff2021-06-03 00:24:12 +0530354 metricsManager.extendedPMCreateOrDeleteResponseChan = make(chan me.Results)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800355
Girish Gowdrae09a6202021-01-12 18:10:59 -0800356 metricsManager.stopProcessingOmciResponses = make(chan bool)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800357 metricsManager.stopTicks = make(chan bool)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800358
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800359 metricsManager.groupMetricMap = make(map[string]*groupMetric)
360 metricsManager.standaloneMetricMap = make(map[string]*standaloneMetric)
361
Himani Chawla97531162021-07-12 15:42:26 +0530362 metricsManager.ethernetFrameExtendedPmUpStreamMEByEntityID = make(map[uint16]*me.ManagedEntity)
363 metricsManager.ethernetFrameExtendedPmDownStreamMEByEntityID = make(map[uint16]*me.ManagedEntity)
Himani Chawla43f95ff2021-06-03 00:24:12 +0530364
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800365 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 -0800366 metricsManager.initializeAllGroupMetrics()
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800367 }
368
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800369 metricsManager.populateLocalGroupMetricData(ctx)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800370
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800371 if err := metricsManager.initializeL2PmFsm(ctx, commMetricsChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800372 return nil
373 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800374
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800375 // initialize the next metric collection intervals.
376 metricsManager.initializeMetricCollectionTime(ctx)
Girish Gowdra0e533642021-03-02 22:02:51 -0800377
378 baseKvStorePath := fmt.Sprintf(cPmKvStorePrefix, dh.pOpenOnuAc.cm.Backend.PathPrefix, dh.deviceID)
379 metricsManager.pmKvStore = dh.setBackend(ctx, baseKvStorePath)
380 if metricsManager.pmKvStore == nil {
381 logger.Errorw(ctx, "Can't initialize pmKvStore - no backend connection to PM module",
382 log.Fields{"device-id": dh.deviceID, "service": baseKvStorePath})
383 return nil
384 }
Girish Gowdra50e56422021-06-01 16:46:04 -0700385 // restore data from KV store
386 if err := metricsManager.restorePmData(ctx); err != nil {
387 logger.Errorw(ctx, "error restoring pm data", log.Fields{"err": err})
388 // we continue given that it does not effect the actual services for the ONU,
389 // but there may be some negative effect on PM collection (there may be some mismatch in
390 // the actual PM config and what is present on the device).
391 }
Girish Gowdra0e533642021-03-02 22:02:51 -0800392
Himani Chawla43f95ff2021-06-03 00:24:12 +0530393 baseExtPmKvStorePath := fmt.Sprintf(cExtPmKvStorePrefix, dh.pOpenOnuAc.cm.Backend.PathPrefix)
394 metricsManager.extPmKvStore = dh.setBackend(ctx, baseExtPmKvStorePath)
395 if metricsManager.extPmKvStore == nil {
396 logger.Errorw(ctx, "Can't initialize extPmKvStore - no backend connection to PM module",
397 log.Fields{"device-id": dh.deviceID, "service": baseExtPmKvStorePath})
398 return nil
399 }
400
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800401 logger.Info(ctx, "init-onuMetricsManager completed", log.Fields{"device-id": dh.deviceID})
Girish Gowdrae09a6202021-01-12 18:10:59 -0800402 return &metricsManager
403}
404
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800405func (mm *onuMetricsManager) initializeMetricCollectionTime(ctx context.Context) {
406 if mm.pDeviceHandler.pmConfigs.FreqOverride {
407 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to true, then group/standalone metric specific interval applies
408 mm.onuMetricsManagerLock.Lock()
409 defer mm.onuMetricsManagerLock.Unlock()
410 for _, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800411 if v.enabled && !v.isL2PMCounter { // L2 PM counter collection is managed in a L2PmFsm
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800412 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
413 }
414 }
415
416 for _, v := range mm.standaloneMetricMap {
417 if v.enabled {
418 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
419 }
420 }
421 } else {
422 // If mm.pDeviceHandler.pmConfigs.FreqOverride is set to false, then overall metric specific interval applies
423 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
424 }
425 logger.Infow(ctx, "initialized standalone group/metric collection time", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
426}
427
428func (mm *onuMetricsManager) updateDefaultFrequency(ctx context.Context, pmConfigs *voltha.PmConfigs) error {
429 // Verify that the configured DefaultFrequency is > 0 and is a multiple of FrequencyGranularity
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800430 if pmConfigs.DefaultFreq == 0 || (pmConfigs.DefaultFreq > 0 && pmConfigs.DefaultFreq%FrequencyGranularity != 0) {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800431 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", pmConfigs.DefaultFreq, FrequencyGranularity)
432 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", pmConfigs.DefaultFreq, FrequencyGranularity)
433 }
434 mm.pDeviceHandler.pmConfigs.DefaultFreq = pmConfigs.DefaultFreq
435 // re-set the nextGlobalMetricCollectionTime based on the new DefaultFreq
436 mm.nextGlobalMetricCollectionTime = time.Now().Add(time.Duration(mm.pDeviceHandler.pmConfigs.DefaultFreq) * time.Second)
437 logger.Debugw(ctx, "frequency-updated--new-frequency", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "frequency": mm.pDeviceHandler.pmConfigs.DefaultFreq})
438 return nil
439}
440
441func (mm *onuMetricsManager) updateGroupFreq(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
442 var newGroupFreq uint32
443 found := false
444 groupSliceIdx := 0
445 var group *voltha.PmGroupConfig
446 for groupSliceIdx, group = range pmConfigs.Groups {
447 if group.GroupName == aGroupName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800448 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
449 if group.GroupFreq == 0 || (group.GroupFreq > 0 && group.GroupFreq%FrequencyGranularity != 0) {
450 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", group.GroupFreq, FrequencyGranularity)
451 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", group.GroupFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800452 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800453 newGroupFreq = group.GroupFreq
454 found = true
455 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800456 }
457 }
458 // if not found update group freq and next collection interval for the group
459 if !found {
460 logger.Errorw(ctx, "group name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
461 return fmt.Errorf("group-name-not-found-%v", aGroupName)
462 }
463
464 updated := false
465 mm.onuMetricsManagerLock.Lock()
466 defer mm.onuMetricsManagerLock.Unlock()
467 for k, v := range mm.groupMetricMap {
Girish Gowdrae0140f02021-02-02 16:55:09 -0800468 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 -0800469 v.frequency = newGroupFreq
470 // update internal pm config
471 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].GroupFreq = newGroupFreq
472 // Also updated the next group metric collection time from now
473 v.nextCollectionInterval = time.Now().Add(time.Duration(newGroupFreq) * time.Second)
474 updated = true
475 logger.Infow(ctx, "group frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800476 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800477 }
478 }
479 if !updated {
480 logger.Errorw(ctx, "group frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newGroupFreq": newGroupFreq, "groupName": aGroupName})
481 return fmt.Errorf("internal-error-during-group-freq-update--groupname-%s-freq-%d", aGroupName, newGroupFreq)
482 }
483 return nil
484}
485
486func (mm *onuMetricsManager) updateMetricFreq(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
487 var newMetricFreq uint32
488 found := false
489 metricSliceIdx := 0
490 var metric *voltha.PmConfig
491 for metricSliceIdx, metric = range pmConfigs.Metrics {
492 if metric.Name == aMetricName {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800493 // freq 0 is not allowed and it should be multiple of FrequencyGranularity
494 if metric.SampleFreq == 0 || (metric.SampleFreq > 0 && metric.SampleFreq%FrequencyGranularity != 0) {
495 logger.Errorf(ctx, "frequency-%u-should-be-a-multiple-of-%u", metric.SampleFreq, FrequencyGranularity)
496 return fmt.Errorf("frequency-%d-should-be-a-multiple-of-%d", metric.SampleFreq, FrequencyGranularity)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800497 }
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800498 newMetricFreq = metric.SampleFreq
499 found = true
500 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800501 }
502 }
503 if !found {
504 logger.Errorw(ctx, "metric name not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
505 return fmt.Errorf("metric-name-not-found-%v", aMetricName)
506 }
507
508 updated := false
509 mm.onuMetricsManagerLock.Lock()
510 defer mm.onuMetricsManagerLock.Unlock()
511 for k, v := range mm.groupMetricMap {
Girish Gowdraaf0ad632021-01-27 13:00:01 -0800512 if k == aMetricName {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800513 v.frequency = newMetricFreq
514 // update internal pm config
515 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].SampleFreq = newMetricFreq
516 // Also updated the next standalone metric collection time from now
517 v.nextCollectionInterval = time.Now().Add(time.Duration(newMetricFreq) * time.Second)
518 updated = true
519 logger.Infow(ctx, "metric frequency updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800520 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800521 }
522 }
523 if !updated {
524 logger.Errorw(ctx, "metric frequency not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "newMetricFreq": newMetricFreq, "aMetricName": aMetricName})
525 return fmt.Errorf("internal-error-during-standalone-metric-update--matricnane-%s-freq-%d", aMetricName, newMetricFreq)
526 }
527 return nil
528}
529
530func (mm *onuMetricsManager) updateGroupSupport(ctx context.Context, aGroupName string, pmConfigs *voltha.PmConfigs) error {
531 groupSliceIdx := 0
532 var group *voltha.PmGroupConfig
533
534 for groupSliceIdx, group = range pmConfigs.Groups {
535 if group.GroupName == aGroupName {
536 break
537 }
538 }
539 if group == nil {
540 logger.Errorw(ctx, "group metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
541 return fmt.Errorf("group-not-found--groupName-%s", aGroupName)
542 }
543
544 updated := false
545 mm.onuMetricsManagerLock.Lock()
546 defer mm.onuMetricsManagerLock.Unlock()
547 for k, v := range mm.groupMetricMap {
548 if k == aGroupName && v.enabled != group.Enabled {
549 mm.pDeviceHandler.pmConfigs.Groups[groupSliceIdx].Enabled = group.Enabled
550 v.enabled = group.Enabled
Girish Gowdrae0140f02021-02-02 16:55:09 -0800551 if group.Enabled {
552 if v.isL2PMCounter {
553 // If it is a L2 PM counter we need to mark the PM to be added
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800554 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800555 // 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 -0800556 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, v.groupName)
557
558 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
559 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
560 // take further action
561 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800562 mm.updateGemPortNTPInstanceToAddForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800563 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800564 } else if mm.pDeviceHandler.pmConfigs.FreqOverride { // otherwise just update the next collection interval
565 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
566 }
567 } else { // group counter is disabled
568 if v.isL2PMCounter {
569 // If it is a L2 PM counter we need to mark the PM to be deleted
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800570 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, v.groupName)
Girish Gowdrae0140f02021-02-02 16:55:09 -0800571 // 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 -0800572 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, v.groupName)
573
574 // The GemPortHistory group requires some special handling as the instance IDs are not pre-defined
575 // unlike other L2 PM counters. We need to fetch the active gemport instance IDs in the system to
576 // take further action
577 if v.groupName == GemPortHistoryName {
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800578 mm.updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -0800579 }
Girish Gowdrae0140f02021-02-02 16:55:09 -0800580 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800581 }
582 updated = true
Girish Gowdrae0140f02021-02-02 16:55:09 -0800583 if v.isL2PMCounter {
584 logger.Infow(ctx, "l2 pm group metric support updated",
585 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled, "l2PmToAdd": mm.l2PmToAdd, "l2PmToDelete": mm.l2PmToDelete})
586 } else {
587 logger.Infow(ctx, "group metric support updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName, "enabled": group.Enabled})
588 }
589 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800590 }
591 }
592
593 if !updated {
594 logger.Errorw(ctx, "group metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": aGroupName})
595 return fmt.Errorf("internal-error-during-group-support-update--groupName-%s", aGroupName)
596 }
597 return nil
598}
599
600func (mm *onuMetricsManager) updateMetricSupport(ctx context.Context, aMetricName string, pmConfigs *voltha.PmConfigs) error {
601 metricSliceIdx := 0
602 var metric *voltha.PmConfig
603
604 for metricSliceIdx, metric = range pmConfigs.Metrics {
605 if metric.Name == aMetricName {
606 break
607 }
608 }
609
610 if metric == nil {
611 logger.Errorw(ctx, "standalone metric not found", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
612 return fmt.Errorf("metric-not-found--metricname-%s", aMetricName)
613 }
614
615 updated := false
616 mm.onuMetricsManagerLock.Lock()
617 defer mm.onuMetricsManagerLock.Unlock()
618 for k, v := range mm.standaloneMetricMap {
619 if k == aMetricName && v.enabled != metric.Enabled {
620 mm.pDeviceHandler.pmConfigs.Metrics[metricSliceIdx].Enabled = metric.Enabled
621 v.enabled = metric.Enabled
622 // If the standalone metric is now enabled and frequency override is enabled, set the next metric collection time
623 if metric.Enabled && mm.pDeviceHandler.pmConfigs.FreqOverride {
624 v.nextCollectionInterval = time.Now().Add(time.Duration(v.frequency) * time.Second)
625 }
626 updated = true
627 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 -0800628 break
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800629 }
630 }
631 if !updated {
632 logger.Errorw(ctx, "standalone metric support not updated", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": aMetricName})
633 return fmt.Errorf("internal-error-during-standalone-support-update--metricname-%s", aMetricName)
634 }
635 return nil
636}
637
638func (mm *onuMetricsManager) collectAllGroupAndStandaloneMetrics(ctx context.Context) {
639 if mm.pDeviceHandler.pmConfigs.Grouped { // metrics are managed as a group.
640 go mm.collectAllGroupMetrics(ctx)
641 } else {
642 go mm.collectAllStandaloneMetrics(ctx)
643 }
644}
645
646func (mm *onuMetricsManager) collectAllGroupMetrics(ctx context.Context) {
647 go func() {
648 logger.Debug(ctx, "startCollector before collecting optical metrics")
ozgecanetsiab36ed572021-04-01 10:38:48 +0300649 metricInfo, err := mm.collectOpticalMetrics(ctx)
650 if err != nil {
651 logger.Errorw(ctx, "collectOpticalMetrics failed",
652 log.Fields{"device-id": mm.pAdaptFsm.deviceID, "Error": err})
653 return
654 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800655 if metricInfo != nil {
656 mm.publishMetrics(ctx, metricInfo)
657 }
658 }()
659
660 go func() {
661 logger.Debug(ctx, "startCollector before collecting uni metrics")
ozgecanetsiab36ed572021-04-01 10:38:48 +0300662 metricInfo, err := mm.collectUniStatusMetrics(ctx)
663 if err != nil {
664 logger.Errorw(ctx, "collectOpticalMetrics failed",
665 log.Fields{"device-id": mm.pAdaptFsm.deviceID, "Error": err})
666 return
667 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800668 if metricInfo != nil {
669 mm.publishMetrics(ctx, metricInfo)
670 }
671 }()
672
673 // Add more here
674}
675
676func (mm *onuMetricsManager) collectAllStandaloneMetrics(ctx context.Context) {
677 // None exists as of now, add when available here
678}
679
680func (mm *onuMetricsManager) collectGroupMetric(ctx context.Context, groupName string) {
681 switch groupName {
682 case OpticalPowerGroupMetricName:
683 go func() {
ozgecanetsiab36ed572021-04-01 10:38:48 +0300684 if mi, _ := mm.collectOpticalMetrics(ctx); mi != nil {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800685 mm.publishMetrics(ctx, mi)
686 }
687 }()
688 case UniStatusGroupMetricName:
689 go func() {
ozgecanetsiab36ed572021-04-01 10:38:48 +0300690 if mi, _ := mm.collectUniStatusMetrics(ctx); mi != nil {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800691 mm.publishMetrics(ctx, mi)
692 }
693 }()
694 default:
695 logger.Errorw(ctx, "unhandled group metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName})
696 }
697}
698
699func (mm *onuMetricsManager) collectStandaloneMetric(ctx context.Context, metricName string) {
700 switch metricName {
701 // None exist as of now, add when available
702 default:
703 logger.Errorw(ctx, "unhandled standalone metric name", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName})
704 }
705}
706
707// collectOpticalMetrics collects groups metrics related to optical power from ani-g ME.
ozgecanetsiab36ed572021-04-01 10:38:48 +0300708func (mm *onuMetricsManager) collectOpticalMetrics(ctx context.Context) ([]*voltha.MetricInformation, error) {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800709 logger.Debugw(ctx, "collectOpticalMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800710
711 mm.onuMetricsManagerLock.RLock()
712 if !mm.groupMetricMap[OpticalPowerGroupMetricName].enabled {
713 mm.onuMetricsManagerLock.RUnlock()
714 logger.Debugw(ctx, "optical power group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
ozgecanetsiab36ed572021-04-01 10:38:48 +0300715 return nil, nil
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800716 }
717 mm.onuMetricsManagerLock.RUnlock()
718
Girish Gowdrae09a6202021-01-12 18:10:59 -0800719 var metricInfoSlice []*voltha.MetricInformation
720 metricsContext := make(map[string]string)
721 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
722 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
723 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
724
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800725 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800726 mmd := voltha.MetricMetaData{
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800727 Title: OpticalPowerGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800728 Ts: float64(raisedTs),
729 Context: metricsContext,
730 DeviceId: mm.pDeviceHandler.deviceID,
731 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
732 SerialNo: mm.pDeviceHandler.device.SerialNumber,
733 }
734
Girish Gowdrae09a6202021-01-12 18:10:59 -0800735 // get the ANI-G instance IDs
736 anigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID)
737loop:
738 for _, anigInstID := range anigInstKeys {
739 var meAttributes me.AttributeValueMap
740 opticalMetrics := make(map[string]float32)
741 // Get the ANI-G instance optical power attributes
742 requestedAttributes := me.AttributeValueMap{"OpticalSignalLevel": 0, "TransmitOpticalLevel": 0}
ozgecanetsiab36ed572021-04-01 10:38:48 +0300743 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.AniGClassID, anigInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
744 if err != nil {
745 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
746 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
747 return nil, err
748 }
749
750 if meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800751 select {
752 case meAttributes = <-mm.opticalMetricsChan:
753 logger.Debugw(ctx, "received optical metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +0000754 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -0800755 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 -0800756 // The metrics will be empty in this case
757 break loop
758 }
759 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800760 for k := range OpticalPowerGroupMetrics {
761 switch k {
762 case "ani_g_instance_id":
763 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
764 opticalMetrics[k] = float32(val.(uint16))
765 }
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800766 case "transmit_power_dBm":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800767 if val, ok := meAttributes["TransmitOpticalLevel"]; ok && val != nil {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700768 opticalMetrics[k] = float32(math.Round((float64(TwosComplementToSignedInt16(val.(uint16)))/500.0)*10) / 10) // convert to dBm rounded of to single decimal place
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800769 }
Girish Gowdrae20a4f62021-03-09 16:06:23 -0800770 case "receive_power_dBm":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800771 if val, ok := meAttributes["OpticalSignalLevel"]; ok && val != nil {
Girish Gowdra6afb56a2021-04-27 17:47:57 -0700772 opticalMetrics[k] = float32(math.Round((float64(TwosComplementToSignedInt16(val.(uint16)))/500.0)*10) / 10) // convert to dBm rounded of to single decimal place
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800773 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800774 default:
775 // do nothing
776 }
777 }
778 }
779 // create slice of metrics given that there could be more than one ANI-G instance and
780 // optical metrics are collected per ANI-G instance
781 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: opticalMetrics}
782 metricInfoSlice = append(metricInfoSlice, &metricInfo)
783 }
784
ozgecanetsiab36ed572021-04-01 10:38:48 +0300785 return metricInfoSlice, nil
Girish Gowdrae09a6202021-01-12 18:10:59 -0800786}
787
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800788// collectUniStatusMetrics collects UNI status group metric from various MEs (uni-g, pptp and veip).
Girish Gowdrae09a6202021-01-12 18:10:59 -0800789// nolint: gocyclo
ozgecanetsiab36ed572021-04-01 10:38:48 +0300790func (mm *onuMetricsManager) collectUniStatusMetrics(ctx context.Context) ([]*voltha.MetricInformation, error) {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800791 logger.Debugw(ctx, "collectUniStatusMetrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800792 mm.onuMetricsManagerLock.RLock()
793 if !mm.groupMetricMap[UniStatusGroupMetricName].enabled {
794 mm.onuMetricsManagerLock.RUnlock()
795 logger.Debugw(ctx, "uni status group metric is not enabled", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
ozgecanetsiab36ed572021-04-01 10:38:48 +0300796 return nil, nil
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800797 }
798 mm.onuMetricsManagerLock.RUnlock()
799
Girish Gowdrae09a6202021-01-12 18:10:59 -0800800 var metricInfoSlice []*voltha.MetricInformation
801 metricsContext := make(map[string]string)
802 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
803 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
804 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
805
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800806 raisedTs := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -0800807 mmd := voltha.MetricMetaData{
Girish Gowdra9b1577b2021-04-21 12:56:13 -0700808 Title: UniStatusGroupMetricName,
Girish Gowdrae09a6202021-01-12 18:10:59 -0800809 Ts: float64(raisedTs),
810 Context: metricsContext,
811 DeviceId: mm.pDeviceHandler.deviceID,
812 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
813 SerialNo: mm.pDeviceHandler.device.SerialNumber,
814 }
815
Girish Gowdrae09a6202021-01-12 18:10:59 -0800816 // get the UNI-G instance IDs
817 unigInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.UniGClassID)
818loop1:
819 for _, unigInstID := range unigInstKeys {
820 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
821 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
822 unigMetrics := make(map[string]float32)
823 var meAttributes me.AttributeValueMap
824 // Get the UNI-G instance optical power attributes
825 requestedAttributes := me.AttributeValueMap{"AdministrativeState": 0}
ozgecanetsiab36ed572021-04-01 10:38:48 +0300826 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.UniGClassID, unigInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
827 if err != nil {
828 logger.Errorw(ctx, "UNI-G failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
829 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
830 return nil, err
831 }
832 if meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800833 // Wait for metrics or timeout
834 select {
835 case meAttributes = <-mm.uniStatusMetricsChan:
836 logger.Debugw(ctx, "received uni-g metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +0000837 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800838 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
839 // The metrics could be empty in this case
840 break loop1
841 }
842 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800843 for k := range UniStatusGroupMetrics {
844 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800845 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800846 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
847 unigMetrics[k] = float32(val.(byte))
848 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800849 default:
850 // do nothing
851 }
852 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800853 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800854 entityID := val.(uint16)
855 unigMetrics["entity_id"] = float32(entityID)
856 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
857 for _, uni := range mm.pDeviceHandler.uniEntityMap {
858 if uni.entityID == entityID {
859 unigMetrics["uni_port_no"] = float32(uni.portNo)
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700860 break
Girish Gowdra0e533642021-03-02 22:02:51 -0800861 }
862 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800863 }
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700864 unigMetrics["me_class_id"] = float32(me.UniGClassID)
Girish Gowdra0e533642021-03-02 22:02:51 -0800865
Girish Gowdrae09a6202021-01-12 18:10:59 -0800866 // create slice of metrics given that there could be more than one UNI-G instance
867 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: unigMetrics}
868 metricInfoSlice = append(metricInfoSlice, &metricInfo)
869 }
870 }
871
872 // get the PPTP instance IDs
873 pptpInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.PhysicalPathTerminationPointEthernetUniClassID)
874loop2:
875 for _, pptpInstID := range pptpInstKeys {
876 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
877 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
878 var meAttributes me.AttributeValueMap
879 pptpMetrics := make(map[string]float32)
880
Girish Gowdrad3436802021-06-28 13:15:40 -0700881 requestedAttributes := me.AttributeValueMap{"ConfigurationInd": 0, "OperationalState": 0, "AdministrativeState": 0}
ozgecanetsiab36ed572021-04-01 10:38:48 +0300882 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.PhysicalPathTerminationPointEthernetUniClassID, pptpInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
883 if err != nil {
884 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
885 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
886 return nil, err
887 }
888 if meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800889 // Wait for metrics or timeout
890 select {
891 case meAttributes = <-mm.uniStatusMetricsChan:
892 logger.Debugw(ctx, "received pptp metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +0000893 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800894 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
895 // The metrics could be empty in this case
896 break loop2
897 }
898
899 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800900 for k := range UniStatusGroupMetrics {
901 switch k {
Girish Gowdrad3436802021-06-28 13:15:40 -0700902 case "configuration_ind":
903 if val, ok := meAttributes["ConfigurationInd"]; ok && val != nil {
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800904 pptpMetrics[k] = float32(val.(byte))
905 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800906 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800907 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
908 pptpMetrics[k] = float32(val.(byte))
909 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800910 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800911 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
912 pptpMetrics[k] = float32(val.(byte))
913 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800914 default:
915 // do nothing
916 }
917 }
918 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800919 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800920 entityID := val.(uint16)
921 pptpMetrics["entity_id"] = float32(entityID)
922 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
923 for _, uni := range mm.pDeviceHandler.uniEntityMap {
924 if uni.entityID == entityID {
925 pptpMetrics["uni_port_no"] = float32(uni.portNo)
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700926 break
Girish Gowdra0e533642021-03-02 22:02:51 -0800927 }
928 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800929 }
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700930 pptpMetrics["me_class_id"] = float32(me.PhysicalPathTerminationPointEthernetUniClassID)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800931
Girish Gowdrae09a6202021-01-12 18:10:59 -0800932 // create slice of metrics given that there could be more than one PPTP instance and
933 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: pptpMetrics}
934 metricInfoSlice = append(metricInfoSlice, &metricInfo)
935 }
936
937 // get the VEIP instance IDs
938 veipInstKeys := mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.VirtualEthernetInterfacePointClassID)
939loop3:
940 for _, veipInstID := range veipInstKeys {
941 // TODO: Include additional information in the voltha.MetricMetaData - like portno, uni-id, instance-id
942 // to uniquely identify this ME instance and also to correlate the ME instance to physical instance
943 var meAttributes me.AttributeValueMap
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800944 veipMetrics := make(map[string]float32)
Girish Gowdrae09a6202021-01-12 18:10:59 -0800945
946 requestedAttributes := me.AttributeValueMap{"OperationalState": 0, "AdministrativeState": 0}
ozgecanetsiab36ed572021-04-01 10:38:48 +0300947 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, me.VirtualEthernetInterfacePointClassID, veipInstID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
948 if err != nil {
949 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
950 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
951 return nil, err
952 }
953 if meInstance != nil {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800954 // Wait for metrics or timeout
955 select {
956 case meAttributes = <-mm.uniStatusMetricsChan:
957 logger.Debugw(ctx, "received veip metrics", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +0000958 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae09a6202021-01-12 18:10:59 -0800959 logger.Errorw(ctx, "timeout waiting for omci-get response for uni status", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
960 // The metrics could be empty in this case
961 break loop3
962 }
963
964 // Populate metric only if it was enabled.
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800965 for k := range UniStatusGroupMetrics {
966 switch k {
Girish Gowdrae09a6202021-01-12 18:10:59 -0800967 case "oper_status":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800968 if val, ok := meAttributes["OperationalState"]; ok && val != nil {
969 veipMetrics[k] = float32(val.(byte))
970 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800971 case "uni_admin_state":
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800972 if val, ok := meAttributes["AdministrativeState"]; ok && val != nil {
973 veipMetrics[k] = float32(val.(byte))
974 }
Girish Gowdrae09a6202021-01-12 18:10:59 -0800975 default:
976 // do nothing
977 }
978 }
979 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800980
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800981 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
Girish Gowdra0e533642021-03-02 22:02:51 -0800982 entityID := val.(uint16)
983 veipMetrics["entity_id"] = float32(entityID)
984 // TODO: Rlock needed for reading uniEntityMap? May not be needed given uniEntityMap is populated setup at initial ONU bring up
985 for _, uni := range mm.pDeviceHandler.uniEntityMap {
986 if uni.entityID == entityID {
987 veipMetrics["uni_port_no"] = float32(uni.portNo)
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700988 break
Girish Gowdra0e533642021-03-02 22:02:51 -0800989 }
990 }
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800991 }
Girish Gowdrada3a52f2021-03-17 11:24:11 -0700992 veipMetrics["me_class_id"] = float32(me.VirtualEthernetInterfacePointClassID)
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800993
Girish Gowdrae09a6202021-01-12 18:10:59 -0800994 // create slice of metrics given that there could be more than one VEIP instance
Girish Gowdra5a7c4922021-01-22 18:33:41 -0800995 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: veipMetrics}
Girish Gowdrae09a6202021-01-12 18:10:59 -0800996 metricInfoSlice = append(metricInfoSlice, &metricInfo)
997 }
998
ozgecanetsiab36ed572021-04-01 10:38:48 +0300999 return metricInfoSlice, nil
Girish Gowdrae09a6202021-01-12 18:10:59 -08001000}
1001
1002// publishMetrics publishes the metrics on kafka
1003func (mm *onuMetricsManager) publishMetrics(ctx context.Context, metricInfo []*voltha.MetricInformation) {
1004 var ke voltha.KpiEvent2
Girish Gowdra5a7c4922021-01-22 18:33:41 -08001005 ts := time.Now().Unix()
Girish Gowdrae09a6202021-01-12 18:10:59 -08001006 ke.SliceData = metricInfo
1007 ke.Type = voltha.KpiEventType_slice
1008 ke.Ts = float64(ts)
1009
1010 if err := mm.pDeviceHandler.EventProxy.SendKpiEvent(ctx, "STATS_EVENT", &ke, voltha.EventCategory_EQUIPMENT, voltha.EventSubCategory_ONU, ts); err != nil {
1011 logger.Errorw(ctx, "failed-to-send-pon-stats", log.Fields{"err": err})
1012 }
1013}
1014
1015func (mm *onuMetricsManager) processOmciMessages(ctx context.Context) {
1016 logger.Infow(ctx, "Start routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1017 // Flush metric collection channels to be safe.
1018 // It is possible that there is stale data on this channel if the processOmciMessages routine
1019 // is stopped right after issuing a OMCI-GET request and started again.
1020 // The processOmciMessages routine will get stopped if startCollector routine (in device_handler.go)
1021 // is stopped - as a result of ONU going down.
1022 mm.flushMetricCollectionChannels(ctx)
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07001023 mm.updateOmciProcessingStatus(true)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001024 for {
1025 select {
1026 case <-mm.stopProcessingOmciResponses: // stop this routine
1027 logger.Infow(ctx, "Stop routine to process OMCI-GET messages for device-id", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07001028 mm.updateOmciProcessingStatus(false)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001029 return
Girish Gowdrae0140f02021-02-02 16:55:09 -08001030 case message, ok := <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -08001031 if !ok {
1032 logger.Errorw(ctx, "Message couldn't be read from channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1033 continue
1034 }
1035 logger.Debugw(ctx, "Received message on ONU metrics channel", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1036
1037 switch message.Type {
1038 case OMCI:
1039 msg, _ := message.Data.(OmciMessage)
1040 mm.handleOmciMessage(ctx, msg)
1041 default:
1042 logger.Warn(ctx, "Unknown message type received", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "message.Type": message.Type})
1043 }
1044 }
1045 }
1046}
1047
1048func (mm *onuMetricsManager) handleOmciMessage(ctx context.Context, msg OmciMessage) {
1049 logger.Debugw(ctx, "omci Msg", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
1050 "msgType": msg.OmciMsg.MessageType, "msg": msg})
1051 switch msg.OmciMsg.MessageType {
1052 case omci.GetResponseType:
1053 //TODO: error handling
1054 _ = mm.handleOmciGetResponseMessage(ctx, msg)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001055 case omci.SynchronizeTimeResponseType:
1056 _ = mm.handleOmciSynchronizeTimeResponseMessage(ctx, msg)
1057 case omci.CreateResponseType:
1058 _ = mm.handleOmciCreateResponseMessage(ctx, msg)
1059 case omci.DeleteResponseType:
1060 _ = mm.handleOmciDeleteResponseMessage(ctx, msg)
Himani Chawla43f95ff2021-06-03 00:24:12 +05301061 case omci.GetCurrentDataResponseType:
1062 _ = mm.handleOmciGetCurrentDataResponseMessage(ctx, msg)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001063 default:
1064 logger.Warnw(ctx, "Unknown Message Type", log.Fields{"msgType": msg.OmciMsg.MessageType})
1065
1066 }
1067}
1068
1069func (mm *onuMetricsManager) handleOmciGetResponseMessage(ctx context.Context, msg OmciMessage) error {
1070 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetResponse)
1071 if msgLayer == nil {
1072 logger.Errorw(ctx, "omci Msg layer could not be detected for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1073 return fmt.Errorf("omci Msg layer could not be detected for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
1074 }
1075 msgObj, msgOk := msgLayer.(*omci.GetResponse)
1076 if !msgOk {
1077 logger.Errorw(ctx, "omci Msg layer could not be assigned for GetResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1078 return fmt.Errorf("omci Msg layer could not be assigned for GetResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
1079 }
Himani Chawla43f95ff2021-06-03 00:24:12 +05301080 logger.Debugw(ctx, "OMCI GetResponse Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj, "result": msgObj.Result})
Girish Gowdrae09a6202021-01-12 18:10:59 -08001081 if msgObj.Result == me.Success {
1082 meAttributes := msgObj.Attributes
1083 switch msgObj.EntityClass {
1084 case me.AniGClassID:
1085 mm.opticalMetricsChan <- meAttributes
1086 return nil
1087 case me.UniGClassID:
1088 mm.uniStatusMetricsChan <- meAttributes
1089 return nil
1090 case me.PhysicalPathTerminationPointEthernetUniClassID:
1091 mm.uniStatusMetricsChan <- meAttributes
1092 return nil
1093 case me.VirtualEthernetInterfacePointClassID:
1094 mm.uniStatusMetricsChan <- meAttributes
1095 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001096 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
1097 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001098 me.EthernetPerformanceMonitoringHistoryDataClassID,
1099 me.FecPerformanceMonitoringHistoryDataClassID,
1100 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001101 mm.l2PmChan <- meAttributes
Himani Chawla43f95ff2021-06-03 00:24:12 +05301102 return nil
1103 case me.EthernetFrameExtendedPmClassID,
1104 me.EthernetFrameExtendedPm64BitClassID:
1105 mm.extendedPmMeChan <- meAttributes
1106 return nil
1107 default:
1108 logger.Errorw(ctx, "unhandled omci get response message",
1109 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1110 }
1111 } else {
1112 meAttributes := msgObj.Attributes
1113 switch msgObj.EntityClass {
1114 case me.EthernetFrameExtendedPmClassID,
1115 me.EthernetFrameExtendedPm64BitClassID:
1116 // not all counters may be supported in which case we have seen some ONUs throwing
1117 // AttributeFailure error code, while correctly populating other counters it supports
1118 mm.extendedPmMeChan <- meAttributes
1119 return nil
Girish Gowdrae09a6202021-01-12 18:10:59 -08001120 default:
1121 logger.Errorw(ctx, "unhandled omci get response message",
1122 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1123 }
1124 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001125 return fmt.Errorf("unhandled-omci-get-response-message")
1126}
1127
Himani Chawla43f95ff2021-06-03 00:24:12 +05301128func (mm *onuMetricsManager) handleOmciGetCurrentDataResponseMessage(ctx context.Context, msg OmciMessage) error {
1129 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeGetCurrentDataResponse)
1130 if msgLayer == nil {
1131 logger.Errorw(ctx, "omci Msg layer could not be detected for GetCurrentDataResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1132 return fmt.Errorf("omci Msg layer could not be detected for GetCurrentDataResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
1133 }
1134 msgObj, msgOk := msgLayer.(*omci.GetCurrentDataResponse)
1135 if !msgOk {
1136 logger.Errorw(ctx, "omci Msg layer could not be assigned for GetCurrentDataResponse - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1137 return fmt.Errorf("omci Msg layer could not be assigned for GetCurrentDataResponse - handling stopped: %s", mm.pDeviceHandler.deviceID)
1138 }
1139 logger.Debugw(ctx, "OMCI GetCurrentDataResponse Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj, "result": msgObj.Result})
1140 if msgObj.Result == me.Success {
1141 meAttributes := msgObj.Attributes
1142 switch msgObj.EntityClass {
1143 case me.EthernetFrameExtendedPmClassID,
1144 me.EthernetFrameExtendedPm64BitClassID:
1145 mm.extendedPmMeChan <- meAttributes
1146 return nil
1147 default:
1148 logger.Errorw(ctx, "unhandled omci get current data response message",
1149 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1150 }
1151 } else {
1152 meAttributes := msgObj.Attributes
1153 switch msgObj.EntityClass {
1154 case me.EthernetFrameExtendedPmClassID,
1155 me.EthernetFrameExtendedPm64BitClassID:
1156 // not all counters may be supported in which case we have seen some ONUs throwing
1157 // AttributeFailure error code, while correctly populating other counters it supports
1158 mm.extendedPmMeChan <- meAttributes
1159 return nil
1160 default:
1161 logger.Errorw(ctx, "unhandled omci get current data response message",
1162 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1163 }
1164 }
1165 return fmt.Errorf("unhandled-omci-get-current-data-response-message")
1166}
1167
Girish Gowdrae0140f02021-02-02 16:55:09 -08001168func (mm *onuMetricsManager) handleOmciSynchronizeTimeResponseMessage(ctx context.Context, msg OmciMessage) error {
1169 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeSynchronizeTimeResponse)
1170 if msgLayer == nil {
1171 logger.Errorw(ctx, "omci Msg layer could not be detected for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1172 return fmt.Errorf("omci Msg layer could not be detected for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1173 }
1174 msgObj, msgOk := msgLayer.(*omci.SynchronizeTimeResponse)
1175 if !msgOk {
1176 logger.Errorw(ctx, "omci Msg layer could not be assigned for synchronize time response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1177 return fmt.Errorf("omci Msg layer could not be assigned for synchronize time response - handling stopped: %s", mm.pDeviceHandler.deviceID)
1178 }
1179 logger.Debugw(ctx, "OMCI synchronize time response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
1180 if msgObj.Result == me.Success {
1181 switch msgObj.EntityClass {
1182 case me.OnuGClassID:
1183 logger.Infow(ctx, "omci synchronize time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1184 mm.syncTimeResponseChan <- true
1185 return nil
1186 default:
1187 logger.Errorw(ctx, "unhandled omci message",
1188 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
1189 }
1190 }
1191 mm.syncTimeResponseChan <- false
1192 logger.Errorf(ctx, "unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
1193 return fmt.Errorf("unhandled-omci-synchronize-time-response-message--error-code-%v", msgObj.Result)
Girish Gowdrae09a6202021-01-12 18:10:59 -08001194}
1195
1196// flushMetricCollectionChannels flushes all metric collection channels for any stale OMCI responses
1197func (mm *onuMetricsManager) flushMetricCollectionChannels(ctx context.Context) {
1198 // flush commMetricsChan
1199 select {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001200 case <-mm.pAdaptFsm.commChan:
Girish Gowdrae09a6202021-01-12 18:10:59 -08001201 logger.Debug(ctx, "flushed common metrics channel")
1202 default:
1203 }
1204
1205 // flush opticalMetricsChan
1206 select {
1207 case <-mm.opticalMetricsChan:
1208 logger.Debug(ctx, "flushed optical metrics channel")
1209 default:
1210 }
1211
1212 // flush uniStatusMetricsChan
1213 select {
1214 case <-mm.uniStatusMetricsChan:
1215 logger.Debug(ctx, "flushed uni status metrics channel")
1216 default:
1217 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001218
1219 // flush syncTimeResponseChan
1220 select {
1221 case <-mm.syncTimeResponseChan:
1222 logger.Debug(ctx, "flushed sync time response channel")
1223 default:
1224 }
1225
1226 // flush l2PmChan
1227 select {
1228 case <-mm.l2PmChan:
1229 logger.Debug(ctx, "flushed L2 PM collection channel")
1230 default:
1231 }
1232
1233 // flush stopTicks
1234 select {
1235 case <-mm.stopTicks:
1236 logger.Debug(ctx, "flushed stopTicks channel")
1237 default:
1238 }
1239
1240}
1241
1242// ** L2 PM FSM Handlers start **
1243
1244func (mm *onuMetricsManager) l2PMFsmStarting(ctx context.Context, e *fsm.Event) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001245
Girish Gowdrae0140f02021-02-02 16:55:09 -08001246 // Loop through all the group metrics
1247 // If it is a L2 PM Interval metric and it is enabled, then if it is not in the
1248 // list of active L2 PM list then mark it for creation
1249 // It it is a L2 PM Interval metric and it is disabled, then if it is in the
1250 // list of active L2 PM list then mark it for deletion
1251 mm.onuMetricsManagerLock.Lock()
1252 for n, g := range mm.groupMetricMap {
1253 if g.isL2PMCounter { // it is a l2 pm counter
1254 if g.enabled { // metric enabled.
1255 found := false
1256 inner1:
1257 for _, v := range mm.activeL2Pms {
1258 if v == n {
1259 found = true // metric already present in active l2 pm list
1260 break inner1
1261 }
1262 }
1263 if !found { // metric not in active l2 pm list. Mark this to be added later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001264 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001265 }
1266 } else { // metric not enabled.
1267 found := false
1268 inner2:
1269 for _, v := range mm.activeL2Pms {
1270 if v == n {
1271 found = true // metric is found in active l2 pm list
1272 break inner2
1273 }
1274 }
1275 if found { // metric is found in active l2 pm list. Mark this to be deleted later
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001276 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, n)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001277 }
1278 }
1279 }
1280 }
1281 mm.onuMetricsManagerLock.Unlock()
1282 logger.Debugw(ctx, "pms to add and delete",
1283 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd, "pms-to-delete": mm.l2PmToDelete})
1284 go func() {
1285 // push a tick event to move to next state
1286 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
1287 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1288 }
1289 }()
1290}
1291
1292func (mm *onuMetricsManager) l2PMFsmSyncTime(ctx context.Context, e *fsm.Event) {
1293 // Sync time with the ONU to establish 15min boundary for PM collection.
1294 if err := mm.syncTime(ctx); err != nil {
1295 go func() {
1296 time.Sleep(SyncTimeRetryInterval * time.Second) // retry to sync time after this timeout
1297 // This will result in FSM attempting to sync time again
1298 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventFailure); err != nil {
1299 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1300 }
1301 }()
1302 }
1303 // Initiate a tick generation routine every L2PmCollectionInterval
1304 go mm.generateTicks(ctx)
1305
1306 go func() {
1307 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1308 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1309 }
1310 }()
1311}
1312
1313func (mm *onuMetricsManager) l2PMFsmNull(ctx context.Context, e *fsm.Event) {
1314 // 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
1315 mm.onuMetricsManagerLock.Lock()
1316 mm.activeL2Pms = nil
1317 mm.l2PmToAdd = nil
1318 mm.l2PmToDelete = nil
1319 mm.onuMetricsManagerLock.Unlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001320 // If the FSM was stopped, then clear PM data from KV store
1321 // The FSM is stopped when ONU goes down. It is time to clear its data from store
1322 if e.Event == l2PmEventStop {
1323 _ = mm.clearPmGroupData(ctx) // ignore error
1324 }
1325
Girish Gowdrae0140f02021-02-02 16:55:09 -08001326}
1327func (mm *onuMetricsManager) l2PMFsmIdle(ctx context.Context, e *fsm.Event) {
1328 logger.Debugw(ctx, "Enter state idle", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1329
1330 mm.onuMetricsManagerLock.RLock()
1331 numOfPmToDelete := len(mm.l2PmToDelete)
1332 numOfPmToAdd := len(mm.l2PmToAdd)
1333 mm.onuMetricsManagerLock.RUnlock()
1334
1335 if numOfPmToDelete > 0 {
1336 logger.Debugw(ctx, "state idle - pms to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": numOfPmToDelete})
1337 go func() {
1338 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
1339 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1340 }
1341 }()
1342 } else if numOfPmToAdd > 0 {
1343 logger.Debugw(ctx, "state idle - pms to add", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": numOfPmToAdd})
1344 go func() {
1345 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
1346 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1347 }
1348 }()
1349 }
1350}
1351
1352func (mm *onuMetricsManager) l2PmFsmCollectData(ctx context.Context, e *fsm.Event) {
1353 logger.Debugw(ctx, "state collect data", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1354 // Copy the activeL2Pms for which we want to collect the metrics since activeL2Pms can change dynamically
1355 mm.onuMetricsManagerLock.RLock()
1356 copyOfActiveL2Pms := make([]string, len(mm.activeL2Pms))
1357 _ = copy(copyOfActiveL2Pms, mm.activeL2Pms)
1358 mm.onuMetricsManagerLock.RUnlock()
1359
1360 for _, n := range copyOfActiveL2Pms {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001361 var metricInfoSlice []*voltha.MetricInformation
Girish Gowdra0e533642021-03-02 22:02:51 -08001362
1363 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1364 mm.onuMetricsManagerLock.RLock()
1365 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1366 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1367 mm.onuMetricsManagerLock.RUnlock()
1368
Girish Gowdrae0140f02021-02-02 16:55:09 -08001369 switch n {
1370 case EthernetBridgeHistoryName:
1371 logger.Debugw(ctx, "state collect data - collecting data for EthernetFramePerformanceMonitoringHistoryData ME", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0e533642021-03-02 22:02:51 -08001372 for _, entityID := range copyOfEntityIDs {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001373 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, true, entityID); metricInfo != nil { // upstream
1374 metricInfoSlice = append(metricInfoSlice, metricInfo)
1375 }
1376 if metricInfo := mm.collectEthernetFramePerformanceMonitoringHistoryData(ctx, false, entityID); metricInfo != nil { // downstream
1377 metricInfoSlice = append(metricInfoSlice, metricInfo)
1378 }
1379 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001380 case EthernetUniHistoryName:
1381 logger.Debugw(ctx, "state collect data - collecting data for EthernetPerformanceMonitoringHistoryData ME", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra0e533642021-03-02 22:02:51 -08001382 for _, entityID := range copyOfEntityIDs {
1383 if metricInfo := mm.collectEthernetUniHistoryData(ctx, entityID); metricInfo != nil { // upstream
1384 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001385 }
1386 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001387
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001388 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001389 for _, entityID := range copyOfEntityIDs {
1390 if metricInfo := mm.collectFecHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001391 metricInfoSlice = append(metricInfoSlice, metricInfo)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001392 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001393 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001394 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001395 for _, entityID := range copyOfEntityIDs {
1396 if metricInfo := mm.collectGemHistoryData(ctx, entityID); metricInfo != nil { // upstream
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001397 metricInfoSlice = append(metricInfoSlice, metricInfo)
1398 }
1399 }
1400
Girish Gowdrae0140f02021-02-02 16:55:09 -08001401 default:
1402 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1403 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001404 mm.handleMetricsPublish(ctx, n, metricInfoSlice)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001405 }
1406 // Does not matter we send success or failure here.
1407 // Those PMs that we failed to collect data will be attempted to collect again in the next PM collection cycle (assuming
1408 // we have not exceed max attempts to collect the PM data)
1409 go func() {
1410 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1411 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1412 }
1413 }()
1414}
1415
Girish Gowdra0e533642021-03-02 22:02:51 -08001416// nolint: gocyclo
ozgecanetsiab36ed572021-04-01 10:38:48 +03001417func (mm *onuMetricsManager) l2PmFsmCreatePM(ctx context.Context, e *fsm.Event) error {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001418 // Copy the l2PmToAdd for which we want to collect the metrics since l2PmToAdd can change dynamically
1419 mm.onuMetricsManagerLock.RLock()
1420 copyOfL2PmToAdd := make([]string, len(mm.l2PmToAdd))
1421 _ = copy(copyOfL2PmToAdd, mm.l2PmToAdd)
1422 mm.onuMetricsManagerLock.RUnlock()
1423
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001424 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 -08001425 for _, n := range copyOfL2PmToAdd {
1426 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001427 atLeastOneSuccess := false // flag indicates if at least one ME instance of the PM was successfully created.
1428 cnt := 0
Girish Gowdrae0140f02021-02-02 16:55:09 -08001429 switch n {
1430 case EthernetBridgeHistoryName:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001431 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
Himani Chawla97531162021-07-12 15:42:26 +05301432 for _, direction := range []bool{true, false} {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001433 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1434 // Attach the EthernetFramePerformanceMonitoringHistoryData ME to MacBridgePortConfigData on the UNI port
Mahir Gunyel6781f962021-05-16 23:30:08 -07001435 entityID := macBridgePortAniBaseEID + uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001436 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1437 inner1:
1438 // retry L2PmCreateAttempts times to create the instance of PM
1439 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001440 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001441 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, true, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001442 if err != nil {
1443 logger.Errorw(ctx, "EthernetPerformanceMonitoringHistoryME create or delete failed, failure PM FSM!",
1444 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1445 pPMFsm := mm.pAdaptFsm
1446 if pPMFsm != nil {
1447 go func(p_pmFsm *AdapterFsm) {
1448 _ = p_pmFsm.pFsm.Event(l2PmEventFailure)
1449 }(pPMFsm)
1450 }
1451 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteEthernetPerformanceMonitoringHistoryMe-failed-%s-%s",
1452 mm.pDeviceHandler.deviceID, err))
1453 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001454 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetFramePerformanceMonitoringHistoryData"); resp {
1455 atLeastOneSuccess = true
1456 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1457 break inner1
1458 }
1459 }
1460 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1461 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001462 }
1463 }
1464 }
1465 case EthernetUniHistoryName:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001466 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
1467 if uniPort.portType == uniPPTP { // This metric is only applicable for PPTP Uni Type
Girish Gowdra0e533642021-03-02 22:02:51 -08001468 // Attach the EthernetPerformanceMonitoringHistoryData ME to PPTP port instance
Girish Gowdrae0140f02021-02-02 16:55:09 -08001469 entityID := uniPort.entityID
Girish Gowdra0e533642021-03-02 22:02:51 -08001470 _ = mm.updatePmData(ctx, n, entityID, cPmAdd) // TODO: ignore error for now
1471 inner2:
1472 // retry L2PmCreateAttempts times to create the instance of PM
1473 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001474 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001475 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001476 if err != nil {
1477 logger.Errorw(ctx, "CreateOrDeleteEthernetUNIHistoryME failed, failure PM FSM!",
1478 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1479 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1480 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteEthernetUniHistoryMe-failed-%s-%s",
1481 mm.pDeviceHandler.deviceID, err))
1482 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001483 if resp = mm.waitForResponseOrTimeout(ctx, true, entityID, "EthernetPerformanceMonitoringHistoryData"); resp {
1484 atLeastOneSuccess = true
1485 _ = mm.updatePmData(ctx, n, entityID, cPmAdded) // TODO: ignore error for now
1486 break inner2
1487 }
1488 }
1489 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1490 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001491 }
1492 }
1493 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001494 case FecHistoryName:
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001495 for _, anigInstID := range mm.pDeviceHandler.pOnuOmciDevice.pOnuDB.getSortedInstKeys(ctx, me.AniGClassID) {
Girish Gowdra0e533642021-03-02 22:02:51 -08001496 // Attach the FecPerformanceMonitoringHistoryData ME to the ANI-G ME instance
ozgecanetsiab36ed572021-04-01 10:38:48 +03001497 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001498 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, anigInstID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001499 if err != nil {
1500 logger.Errorw(ctx, "CreateOrDeleteFecHistoryME failed, failure PM FSM!",
1501 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1502 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1503 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteFecHistoryMe-failed-%s-%s",
1504 mm.pDeviceHandler.deviceID, err))
1505 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001506 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdd) // TODO: ignore error for now
1507 inner3:
1508 // retry L2PmCreateAttempts times to create the instance of PM
1509 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1510 if resp = mm.waitForResponseOrTimeout(ctx, true, anigInstID, "FecPerformanceMonitoringHistoryData"); resp {
1511 atLeastOneSuccess = true
1512 _ = mm.updatePmData(ctx, n, anigInstID, cPmAdded) // TODO: ignore error for now
1513 break inner3
1514 }
1515 }
1516 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1517 _ = mm.updatePmData(ctx, n, anigInstID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001518 }
1519 }
1520 case GemPortHistoryName:
1521
1522 mm.onuMetricsManagerLock.RLock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001523 copyOfGemPortInstIDsToAdd := make([]uint16, len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd))
1524 _ = copy(copyOfGemPortInstIDsToAdd, mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001525 mm.onuMetricsManagerLock.RUnlock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001526
1527 if len(copyOfGemPortInstIDsToAdd) == 0 {
1528 // If there are no gemport history MEs to be created, just skip further processing
1529 // Otherwise down below (after 'switch' case handling) we assume the ME creation failed because resp and atLeastOneSuccess flag are false.
1530 // Normally there are no GemPortHistory MEs to create at start up. They come in only after provisioning service on the ONU.
1531 mm.onuMetricsManagerLock.Lock()
1532 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1533 mm.onuMetricsManagerLock.Unlock()
1534 continue
1535 }
1536
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001537 for _, v := range copyOfGemPortInstIDsToAdd {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001538 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001539 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, true, mm.pAdaptFsm.commChan, v)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001540 if err != nil {
1541 logger.Errorw(ctx, "CreateOrDeleteGemPortHistoryME failed, failure PM FSM!",
1542 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1543 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1544 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteGemPortHistoryMe-failed-%s-%s",
1545 mm.pDeviceHandler.deviceID, err))
1546 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001547 _ = mm.updatePmData(ctx, n, v, cPmAdd) // TODO: ignore error for now
1548 inner4:
1549 // retry L2PmCreateAttempts times to create the instance of PM
1550 for cnt = 0; cnt < L2PmCreateAttempts; cnt++ {
1551 if resp = mm.waitForResponseOrTimeout(ctx, true, v, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); resp {
1552 atLeastOneSuccess = true
1553 _ = mm.updatePmData(ctx, n, v, cPmAdded) // TODO: ignore error for now
1554 break inner4
1555 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001556 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001557 if cnt == L2PmCreateAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1558 _ = mm.updatePmData(ctx, n, v, cPmRemoved) // TODO: ignore error for now
1559 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001560 }
1561
Girish Gowdrae0140f02021-02-02 16:55:09 -08001562 default:
1563 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1564 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001565 // On success of at least one instance of the PM for a given ME, update the local list maintained for active PMs and PMs to add
1566 if atLeastOneSuccess {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001567 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001568 mm.activeL2Pms = mm.appendIfMissingString(mm.activeL2Pms, n)
Girish Gowdra69570d92021-04-22 18:26:20 -07001569 // gem ports can be added dynamically for perf monitoring. We want to clear the GemPortHistoryName from mm.l2PmToAdd
1570 // only if no more new gem port instances created.
1571 if n != GemPortHistoryName || (n == GemPortHistoryName && len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd) == 0) {
1572 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
1573 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001574 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 -08001575 mm.onuMetricsManagerLock.Unlock()
1576 } else {
Girish Gowdra0e533642021-03-02 22:02:51 -08001577 // If we are here then no instance of the PM of the given ME were created successfully, so locally disable the PM
Girish Gowdrae0140f02021-02-02 16:55:09 -08001578 // and also remove it from l2PmToAdd slice so that we do not try to create the PM ME anymore
1579 mm.onuMetricsManagerLock.Lock()
Girish Gowdra0e533642021-03-02 22:02:51 -08001580 logger.Debugw(ctx, "exceeded-max-add-retry-attempts--disabling-group", log.Fields{"groupName": n})
1581 mm.groupMetricMap[n].enabled = false
1582 mm.l2PmToAdd = mm.removeIfFoundString(mm.l2PmToAdd, n)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001583
Girish Gowdrae0140f02021-02-02 16:55:09 -08001584 logger.Warnw(ctx, "state create pm - failed to create pm",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001585 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
Girish Gowdra0e533642021-03-02 22:02:51 -08001586 "active-l2-pms": mm.activeL2Pms, "pms-to-add": mm.l2PmToAdd})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001587 mm.onuMetricsManagerLock.Unlock()
1588 }
1589 }
Girish Gowdra754ffb12021-06-30 16:30:12 -07001590 mm.onuMetricsManagerLock.RLock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001591 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 Gowdra754ffb12021-06-30 16:30:12 -07001592 mm.onuMetricsManagerLock.RUnlock()
Girish Gowdrae0140f02021-02-02 16:55:09 -08001593 // Does not matter we send success or failure here.
1594 // Those PMs that we failed to create will be attempted to create again in the next PM creation cycle (assuming
1595 // we have not exceed max attempts to create the PM ME)
1596 go func() {
1597 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1598 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1599 }
1600 }()
ozgecanetsiab36ed572021-04-01 10:38:48 +03001601 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001602}
1603
Girish Gowdra0e533642021-03-02 22:02:51 -08001604// nolint: gocyclo
ozgecanetsiab36ed572021-04-01 10:38:48 +03001605func (mm *onuMetricsManager) l2PmFsmDeletePM(ctx context.Context, e *fsm.Event) error {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001606 // Copy the l2PmToDelete for which we want to collect the metrics since l2PmToDelete can change dynamically
1607 mm.onuMetricsManagerLock.RLock()
1608 copyOfL2PmToDelete := make([]string, len(mm.l2PmToDelete))
1609 _ = copy(copyOfL2PmToDelete, mm.l2PmToDelete)
1610 mm.onuMetricsManagerLock.RUnlock()
1611
Girish Gowdra754ffb12021-06-30 16:30:12 -07001612 logger.Debugw(ctx, "state delete pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": copyOfL2PmToDelete})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001613 for _, n := range copyOfL2PmToDelete {
1614 resp := false
Girish Gowdra0e533642021-03-02 22:02:51 -08001615 cnt := 0
1616 atLeastOneDeleteFailure := false
1617
1618 // mm.groupMetricMap[n].pmMEData.InstancesActive could dynamically change, so make a copy
1619 mm.onuMetricsManagerLock.RLock()
1620 copyOfEntityIDs := make([]uint16, len(mm.groupMetricMap[n].pmMEData.InstancesActive))
1621 _ = copy(copyOfEntityIDs, mm.groupMetricMap[n].pmMEData.InstancesActive)
1622 mm.onuMetricsManagerLock.RUnlock()
1623
1624 if len(copyOfEntityIDs) == 0 {
1625 // if there are no enityIDs to remove for the PM ME just clear the PM name entry from cache and continue
1626 mm.onuMetricsManagerLock.Lock()
1627 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1628 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1629 logger.Debugw(ctx, "success-resp", log.Fields{"pm-name": n, "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1630 mm.onuMetricsManagerLock.Unlock()
1631 continue
1632 }
1633 logger.Debugw(ctx, "entities to delete", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n, "entityIDs": copyOfEntityIDs})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001634 switch n {
1635 case EthernetBridgeHistoryName:
Girish Gowdrae0140f02021-02-02 16:55:09 -08001636 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
Himani Chawla97531162021-07-12 15:42:26 +05301637 for _, direction := range []bool{true, false} {
Girish Gowdra0e533642021-03-02 22:02:51 -08001638 for _, entityID := range copyOfEntityIDs {
1639 inner1:
1640 // retry L2PmDeleteAttempts times to delete the instance of PM
1641 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001642 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetPerformanceMonitoringHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001643 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, false, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001644 if err != nil {
1645 logger.Errorw(ctx, "CreateOrDeleteEthernetPerformanceMonitoringHistoryME failed, failure PM FSM!",
1646 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1647 pPMFsm := mm.pAdaptFsm
1648 if pPMFsm != nil {
1649 go func(p_pmFsm *AdapterFsm) {
1650 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1651 }(pPMFsm)
1652 }
1653 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteEthernetPerformanceMonitoringHistoryMe-failed-%s-%s",
1654 mm.pDeviceHandler.deviceID, err))
1655 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001656 _ = mm.updatePmData(ctx, n, entityID, cPmRemove) // TODO: ignore error for now
1657 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetFramePerformanceMonitoringHistoryData"); !resp {
1658 atLeastOneDeleteFailure = true
1659 } else {
1660 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1661 break inner1
1662 }
1663 }
1664 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1665 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdrae0140f02021-02-02 16:55:09 -08001666 }
1667 }
1668 }
1669 case EthernetUniHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001670 for _, entityID := range copyOfEntityIDs {
1671 inner2:
1672 // retry L2PmDeleteAttempts times to delete the instance of PM
1673 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001674 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetUniHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001675 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001676 if err != nil {
1677 logger.Errorw(ctx, "CreateOrDeleteEthernetUniHistoryME failed, failure PM FSM!",
1678 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1679 pmFsm := mm.pAdaptFsm
1680 if pmFsm != nil {
1681 go func(p_pmFsm *AdapterFsm) {
1682 _ = p_pmFsm.pFsm.Event(l2PmEventFailure)
1683 }(pmFsm)
1684 return err
1685 }
1686 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteEthernetUniHistoryMe-failed-%s-%s",
1687 mm.pDeviceHandler.deviceID, err))
1688 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001689 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "EthernetPerformanceMonitoringHistoryData"); !resp {
Girish Gowdra0e533642021-03-02 22:02:51 -08001690 atLeastOneDeleteFailure = true
1691 } else {
1692 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001693 break inner2
Girish Gowdrae0140f02021-02-02 16:55:09 -08001694 }
1695 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001696 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1697 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1698 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001699 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001700 case FecHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001701 for _, entityID := range copyOfEntityIDs {
1702 inner3:
1703 // retry L2PmDeleteAttempts times to delete the instance of PM
1704 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001705 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteFecHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001706 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001707 if err != nil {
1708 logger.Errorw(ctx, "CreateOrDeleteFecHistoryME failed, failure PM FSM!",
1709 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1710 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1711 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteFecHistoryMe-failed-%s-%s",
1712 mm.pDeviceHandler.deviceID, err))
1713 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001714 if resp := mm.waitForResponseOrTimeout(ctx, false, entityID, "FecPerformanceMonitoringHistoryData"); !resp {
1715 atLeastOneDeleteFailure = true
1716 } else {
1717 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1718 break inner3
1719 }
1720 }
1721 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1722 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001723 }
1724 }
1725 case GemPortHistoryName:
Girish Gowdra0e533642021-03-02 22:02:51 -08001726 for _, entityID := range copyOfEntityIDs {
1727 inner4:
1728 // retry L2PmDeleteAttempts times to delete the instance of PM
1729 for cnt = 0; cnt < L2PmDeleteAttempts; cnt++ {
ozgecanetsiab36ed572021-04-01 10:38:48 +03001730 _, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteGemPortHistoryME(
Girish Gowdra0b235842021-03-09 13:06:46 -08001731 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, false, mm.pAdaptFsm.commChan, entityID)
ozgecanetsiab36ed572021-04-01 10:38:48 +03001732 if err != nil {
1733 logger.Errorw(ctx, "CreateOrDeleteGemPortHistoryME failed, failure PM FSM!",
1734 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1735 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
1736 return fmt.Errorf(fmt.Sprintf("CreateOrDeleteGemPortHistoryMe-failed-%s-%s",
1737 mm.pDeviceHandler.deviceID, err))
1738 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001739 if resp = mm.waitForResponseOrTimeout(ctx, false, entityID, "GemPortNetworkCtpPerformanceMonitoringHistoryData"); !resp {
1740 atLeastOneDeleteFailure = true
1741 } else {
1742 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1743 break inner4
1744 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001745 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001746 if cnt == L2PmDeleteAttempts { // if we reached max attempts just give up hope on this given instance of the PM ME
1747 _ = mm.updatePmData(ctx, n, entityID, cPmRemoved) // TODO: ignore error for now
1748 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001749 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001750 default:
1751 logger.Errorw(ctx, "unsupported l2 pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "name": n})
1752 }
Girish Gowdra0e533642021-03-02 22:02:51 -08001753 // If we could not completely clean up the PM ME then just give up.
1754 if atLeastOneDeleteFailure {
1755 logger.Warnw(ctx, "state delete pm - failed to delete at least one instance of the PM ME",
1756 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": n,
1757 "active-l2-pms": mm.activeL2Pms, "pms-to-delete": mm.l2PmToDelete})
1758 mm.onuMetricsManagerLock.Lock()
1759 logger.Debugw(ctx, "exceeded-max-delete-retry-attempts--disabling-group", log.Fields{"groupName": n})
1760 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
1761 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1762 mm.groupMetricMap[n].enabled = false
1763 mm.onuMetricsManagerLock.Unlock()
1764 } else { // success case
Girish Gowdrae0140f02021-02-02 16:55:09 -08001765 mm.onuMetricsManagerLock.Lock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001766 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, n)
Girish Gowdra69570d92021-04-22 18:26:20 -07001767 // gem ports can be deleted dynamically from perf monitoring. We want to clear the GemPortHistoryName from mm.l2PmToDelete
1768 // only if no more new gem port instances removed.
1769 if n != GemPortHistoryName || (n == GemPortHistoryName && len(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete) == 0) {
1770 mm.l2PmToDelete = mm.removeIfFoundString(mm.l2PmToDelete, n)
1771 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001772 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 -08001773 mm.onuMetricsManagerLock.Unlock()
1774 }
1775 }
Girish Gowdra754ffb12021-06-30 16:30:12 -07001776 mm.onuMetricsManagerLock.RLock()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001777 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 Gowdra754ffb12021-06-30 16:30:12 -07001778 mm.onuMetricsManagerLock.RUnlock()
Girish Gowdrae0140f02021-02-02 16:55:09 -08001779 // Does not matter we send success or failure here.
1780 // Those PMs that we failed to delete will be attempted to create again in the next PM collection cycle
1781 go func() {
1782 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventSuccess); err != nil {
1783 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
1784 }
1785 }()
ozgecanetsiab36ed572021-04-01 10:38:48 +03001786 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001787}
1788
1789// ** L2 PM FSM Handlers end **
1790
1791// syncTime synchronizes time with the ONU to establish a 15 min boundary for PM collection and reporting.
1792func (mm *onuMetricsManager) syncTime(ctx context.Context) error {
Girish Gowdra0b235842021-03-09 13:06:46 -08001793 if err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendSyncTime(ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan); err != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001794 logger.Errorw(ctx, "cannot send sync time request", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1795 return err
1796 }
1797
1798 select {
Holger Hildebrandt366ef192021-05-05 11:07:44 +00001799 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07001800 logger.Errorw(ctx, "timed out waiting for sync time response from onu", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdrae0140f02021-02-02 16:55:09 -08001801 return fmt.Errorf("timed-out-waiting-for-sync-time-response-%v", mm.pDeviceHandler.deviceID)
1802 case syncTimeRes := <-mm.syncTimeResponseChan:
1803 if !syncTimeRes {
1804 return fmt.Errorf("failed-to-sync-time-%v", mm.pDeviceHandler.deviceID)
1805 }
1806 logger.Infow(ctx, "sync time success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
1807 return nil
1808 }
1809}
1810
1811func (mm *onuMetricsManager) collectEthernetFramePerformanceMonitoringHistoryData(ctx context.Context, upstream bool, entityID uint16) *voltha.MetricInformation {
1812 var mEnt *me.ManagedEntity
1813 var omciErr me.OmciErrors
1814 var classID me.ClassID
1815 var meAttributes me.AttributeValueMap
1816 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1817 meParam := me.ParamData{EntityID: entityID}
1818 if upstream {
1819 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataUpstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1820 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1821 return nil
1822 }
1823 classID = me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID
1824 } else {
1825 if mEnt, omciErr = me.NewEthernetFramePerformanceMonitoringHistoryDataDownstream(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1826 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
1827 return nil
1828 }
1829 classID = me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID
1830 }
1831
Girish Gowdrae0140f02021-02-02 16:55:09 -08001832 intervalEndTime := -1
1833 ethPMHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001834 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethPMHistData, &intervalEndTime); err != nil {
1835 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001836 }
1837
1838 // Populate some relevant context for the EthernetFramePerformanceMonitoringHistoryData PM
1839 ethPMHistData["class_id"] = float32(classID)
1840 ethPMHistData["interval_end_time"] = float32(intervalEndTime)
1841 ethPMHistData["parent_class_id"] = float32(me.MacBridgeConfigurationDataClassID) // EthernetFramePerformanceMonitoringHistoryData is attached to MBPCD ME
1842 ethPMHistData["parent_entity_id"] = float32(entityID)
1843 if upstream {
1844 ethPMHistData["upstream"] = float32(1)
1845 } else {
1846 ethPMHistData["upstream"] = float32(0)
1847 }
1848
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001849 metricInfo := mm.populateOnuMetricInfo(EthernetBridgeHistoryName, ethPMHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001850
Girish Gowdrae0140f02021-02-02 16:55:09 -08001851 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData successful",
1852 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream, "metricInfo": metricInfo})
1853 return &metricInfo
1854}
1855
1856func (mm *onuMetricsManager) collectEthernetUniHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1857 var mEnt *me.ManagedEntity
1858 var omciErr me.OmciErrors
1859 var classID me.ClassID
1860 var meAttributes me.AttributeValueMap
1861 logger.Debugw(ctx, "collecting data for EthernetFramePerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1862 meParam := me.ParamData{EntityID: entityID}
1863 if mEnt, omciErr = me.NewEthernetPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1864 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1865 return nil
1866 }
1867 classID = me.EthernetPerformanceMonitoringHistoryDataClassID
1868
Girish Gowdrae0140f02021-02-02 16:55:09 -08001869 intervalEndTime := -1
1870 ethUniHistData := make(map[string]float32)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001871 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, ethUniHistData, &intervalEndTime); err != nil {
1872 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08001873 }
1874
1875 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1876 ethUniHistData["class_id"] = float32(classID)
1877 ethUniHistData["interval_end_time"] = float32(intervalEndTime)
1878
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001879 metricInfo := mm.populateOnuMetricInfo(EthernetUniHistoryName, ethUniHistData)
Girish Gowdrae0140f02021-02-02 16:55:09 -08001880
Girish Gowdrae0140f02021-02-02 16:55:09 -08001881 logger.Debugw(ctx, "collecting data for EthernetPerformanceMonitoringHistoryData successful",
1882 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1883 return &metricInfo
1884}
1885
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001886func (mm *onuMetricsManager) collectFecHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1887 var mEnt *me.ManagedEntity
1888 var omciErr me.OmciErrors
1889 var classID me.ClassID
1890 var meAttributes me.AttributeValueMap
1891 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1892 meParam := me.ParamData{EntityID: entityID}
1893 if mEnt, omciErr = me.NewFecPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1894 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1895 return nil
1896 }
1897 classID = me.FecPerformanceMonitoringHistoryDataClassID
1898
1899 intervalEndTime := -1
1900 fecHistData := make(map[string]float32)
1901 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, fecHistData, &intervalEndTime); err != nil {
1902 return nil
1903 }
1904
1905 // Populate some relevant context for the EthernetPerformanceMonitoringHistoryData PM
1906 fecHistData["class_id"] = float32(classID)
1907 fecHistData["interval_end_time"] = float32(intervalEndTime)
1908
1909 metricInfo := mm.populateOnuMetricInfo(FecHistoryName, fecHistData)
1910
1911 logger.Debugw(ctx, "collecting data for FecPerformanceMonitoringHistoryData successful",
1912 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1913 return &metricInfo
1914}
1915
1916func (mm *onuMetricsManager) collectGemHistoryData(ctx context.Context, entityID uint16) *voltha.MetricInformation {
1917 var mEnt *me.ManagedEntity
1918 var omciErr me.OmciErrors
1919 var classID me.ClassID
1920 var meAttributes me.AttributeValueMap
1921 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1922 meParam := me.ParamData{EntityID: entityID}
1923 if mEnt, omciErr = me.NewGemPortNetworkCtpPerformanceMonitoringHistoryData(meParam); omciErr == nil || mEnt == nil || omciErr.GetError() != nil {
1924 logger.Errorw(ctx, "error creating me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
1925 return nil
1926 }
1927 classID = me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID
1928
1929 intervalEndTime := -1
1930 gemHistData := make(map[string]float32)
1931 if err := mm.populateGroupSpecificMetrics(ctx, mEnt, classID, entityID, meAttributes, gemHistData, &intervalEndTime); err != nil {
1932 return nil
1933 }
1934
1935 // Populate some relevant context for the GemPortNetworkCtpPerformanceMonitoringHistoryData PM
1936 gemHistData["class_id"] = float32(classID)
1937 gemHistData["interval_end_time"] = float32(intervalEndTime)
1938
1939 metricInfo := mm.populateOnuMetricInfo(GemPortHistoryName, gemHistData)
1940
1941 logger.Debugw(ctx, "collecting data for GemPortNetworkCtpPerformanceMonitoringHistoryData successful",
1942 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "metricInfo": metricInfo})
1943 return &metricInfo
1944}
1945
Girish Gowdrae0140f02021-02-02 16:55:09 -08001946// nolint: gocyclo
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001947func (mm *onuMetricsManager) populateEthernetBridgeHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
Girish Gowdrae0140f02021-02-02 16:55:09 -08001948 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08001949 upstream := false
1950 if classID == me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID {
1951 upstream = true
1952 }
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07001953 // Insert "IntervalEndTime" as part of the requested attributes as we need this to compare the get responses when get request is multipart
1954 requestedAttributes["IntervalEndTime"] = 0
ozgecanetsiab36ed572021-04-01 10:38:48 +03001955 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
1956 if err != nil {
1957 logger.Errorw(ctx, "GetME failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
1958 pmFsm := mm.pAdaptFsm
1959 if pmFsm != nil {
1960 go func(p_pmFsm *AdapterFsm) {
1961 _ = p_pmFsm.pFsm.Event(l2PmEventFailure)
1962 }(pmFsm)
1963 return err
1964 }
1965 return fmt.Errorf(fmt.Sprintf("GetME-failed-%s-%s", mm.pDeviceHandler.deviceID, err))
1966 }
1967 if meInstance != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -08001968 select {
1969 case meAttributes = <-mm.l2PmChan:
1970 logger.Debugw(ctx, "received ethernet pm history data metrics",
1971 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +00001972 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08001973 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet pm history data",
1974 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
1975 // The metrics will be empty in this case
1976 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-bridge-history-%v", mm.pDeviceHandler.deviceID)
1977 }
1978 // 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 -08001979 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
1980 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 -08001981 }
1982 }
1983 for k := range EthernetBridgeHistory {
1984 // populate ethPMHistData only if metric key not already present (or populated), since it is possible that we populate
1985 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
1986 if _, ok := ethPMHistData[k]; !ok {
1987 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08001988 case "entity_id":
1989 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
1990 ethPMHistData[k] = float32(val.(uint16))
1991 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08001992 case "drop_events":
1993 if val, ok := meAttributes["DropEvents"]; ok && val != nil {
1994 ethPMHistData[k] = float32(val.(uint32))
1995 }
1996 case "octets":
1997 if val, ok := meAttributes["Octets"]; ok && val != nil {
1998 ethPMHistData[k] = float32(val.(uint32))
1999 }
2000 case "packets":
2001 if val, ok := meAttributes["Packets"]; ok && val != nil {
2002 ethPMHistData[k] = float32(val.(uint32))
2003 }
2004 case "broadcast_packets":
2005 if val, ok := meAttributes["BroadcastPackets"]; ok && val != nil {
2006 ethPMHistData[k] = float32(val.(uint32))
2007 }
2008 case "multicast_packets":
2009 if val, ok := meAttributes["MulticastPackets"]; ok && val != nil {
2010 ethPMHistData[k] = float32(val.(uint32))
2011 }
2012 case "crc_errored_packets":
2013 if val, ok := meAttributes["CrcErroredPackets"]; ok && val != nil {
2014 ethPMHistData[k] = float32(val.(uint32))
2015 }
2016 case "undersize_packets":
2017 if val, ok := meAttributes["UndersizePackets"]; ok && val != nil {
2018 ethPMHistData[k] = float32(val.(uint32))
2019 }
2020 case "oversize_packets":
2021 if val, ok := meAttributes["OversizePackets"]; ok && val != nil {
2022 ethPMHistData[k] = float32(val.(uint32))
2023 }
2024 case "64_octets":
2025 if val, ok := meAttributes["Packets64Octets"]; ok && val != nil {
2026 ethPMHistData[k] = float32(val.(uint32))
2027 }
2028 case "65_to_127_octets":
2029 if val, ok := meAttributes["Packets65To127Octets"]; ok && val != nil {
2030 ethPMHistData[k] = float32(val.(uint32))
2031 }
2032 case "128_to_255_octets":
2033 if val, ok := meAttributes["Packets128To255Octets"]; ok && val != nil {
2034 ethPMHistData[k] = float32(val.(uint32))
2035 }
2036 case "256_to_511_octets":
2037 if val, ok := meAttributes["Packets256To511Octets"]; ok && val != nil {
2038 ethPMHistData[k] = float32(val.(uint32))
2039 }
2040 case "512_to_1023_octets":
2041 if val, ok := meAttributes["Packets512To1023Octets"]; ok && val != nil {
2042 ethPMHistData[k] = float32(val.(uint32))
2043 }
2044 case "1024_to_1518_octets":
2045 if val, ok := meAttributes["Packets1024To1518Octets"]; ok && val != nil {
2046 ethPMHistData[k] = float32(val.(uint32))
2047 }
2048 default:
2049 // do nothing
2050 }
2051 }
2052 }
2053 return nil
2054}
2055
2056// nolint: gocyclo
2057func (mm *onuMetricsManager) populateEthernetUniHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
2058 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, ethPMUniHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002059 // Insert "IntervalEndTime" as part of the requested attributes as we need this to compare the get responses when get request is multipart
ozgecanetsiab36ed572021-04-01 10:38:48 +03002060 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
2061 requestedAttributes["IntervalEndTime"] = 0
2062 }
2063 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
2064 if err != nil {
2065 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
2066 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
2067 return fmt.Errorf(fmt.Sprintf("GetME-failed-%s-%s", mm.pDeviceHandler.deviceID, err))
2068 }
2069 if meInstance != nil {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002070 select {
2071 case meAttributes = <-mm.l2PmChan:
2072 logger.Debugw(ctx, "received ethernet uni history data metrics",
2073 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +00002074 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdrae0140f02021-02-02 16:55:09 -08002075 logger.Errorw(ctx, "timeout waiting for omci-get response for ethernet uni history data",
2076 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
2077 // The metrics will be empty in this case
2078 return fmt.Errorf("timeout-during-l2-pm-collection-for-ethernet-uni-history-%v", mm.pDeviceHandler.deviceID)
2079 }
2080 // 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 -08002081 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
2082 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 -08002083 }
2084 }
2085 for k := range EthernetUniHistory {
2086 // populate ethPMUniHistData only if metric key not already present (or populated), since it is possible that we populate
2087 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
2088 if _, ok := ethPMUniHistData[k]; !ok {
2089 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08002090 case "entity_id":
2091 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
2092 ethPMUniHistData[k] = float32(val.(uint16))
2093 }
Girish Gowdrae0140f02021-02-02 16:55:09 -08002094 case "fcs_errors":
2095 if val, ok := meAttributes["FcsErrors"]; ok && val != nil {
2096 ethPMUniHistData[k] = float32(val.(uint32))
2097 }
2098 case "excessive_collision_counter":
2099 if val, ok := meAttributes["ExcessiveCollisionCounter"]; ok && val != nil {
2100 ethPMUniHistData[k] = float32(val.(uint32))
2101 }
2102 case "late_collision_counter":
2103 if val, ok := meAttributes["LateCollisionCounter"]; ok && val != nil {
2104 ethPMUniHistData[k] = float32(val.(uint32))
2105 }
2106 case "frames_too_long":
2107 if val, ok := meAttributes["FramesTooLong"]; ok && val != nil {
2108 ethPMUniHistData[k] = float32(val.(uint32))
2109 }
2110 case "buffer_overflows_on_rx":
2111 if val, ok := meAttributes["BufferOverflowsOnReceive"]; ok && val != nil {
2112 ethPMUniHistData[k] = float32(val.(uint32))
2113 }
2114 case "buffer_overflows_on_tx":
2115 if val, ok := meAttributes["BufferOverflowsOnTransmit"]; ok && val != nil {
2116 ethPMUniHistData[k] = float32(val.(uint32))
2117 }
2118 case "single_collision_frame_counter":
2119 if val, ok := meAttributes["SingleCollisionFrameCounter"]; ok && val != nil {
2120 ethPMUniHistData[k] = float32(val.(uint32))
2121 }
2122 case "multiple_collisions_frame_counter":
2123 if val, ok := meAttributes["MultipleCollisionsFrameCounter"]; ok && val != nil {
2124 ethPMUniHistData[k] = float32(val.(uint32))
2125 }
2126 case "sqe_counter":
2127 if val, ok := meAttributes["SqeCounter"]; ok && val != nil {
2128 ethPMUniHistData[k] = float32(val.(uint32))
2129 }
2130 case "deferred_tx_counter":
2131 if val, ok := meAttributes["DeferredTransmissionCounter"]; ok && val != nil {
2132 ethPMUniHistData[k] = float32(val.(uint32))
2133 }
2134 case "internal_mac_tx_error_counter":
2135 if val, ok := meAttributes["InternalMacTransmitErrorCounter"]; ok && val != nil {
2136 ethPMUniHistData[k] = float32(val.(uint32))
2137 }
2138 case "carrier_sense_error_counter":
2139 if val, ok := meAttributes["CarrierSenseErrorCounter"]; ok && val != nil {
2140 ethPMUniHistData[k] = float32(val.(uint32))
2141 }
2142 case "alignment_error_counter":
2143 if val, ok := meAttributes["AlignmentErrorCounter"]; ok && val != nil {
2144 ethPMUniHistData[k] = float32(val.(uint32))
2145 }
2146 case "internal_mac_rx_error_counter":
2147 if val, ok := meAttributes["InternalMacReceiveErrorCounter"]; ok && val != nil {
2148 ethPMUniHistData[k] = float32(val.(uint32))
2149 }
2150 default:
2151 // do nothing
2152 }
2153 }
2154 }
2155 return nil
2156}
2157
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002158// nolint: gocyclo
2159func (mm *onuMetricsManager) populateFecHistoryMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
2160 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, fecHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002161 // Insert "IntervalEndTime" as part of the requested attributes as we need this to compare the get responses when get request is multipart
ozgecanetsiab36ed572021-04-01 10:38:48 +03002162 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
2163 requestedAttributes["IntervalEndTime"] = 0
2164 }
2165 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
2166 if err != nil {
2167 logger.Errorw(ctx, "GetMe failed, failure PM FSM!", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
2168 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
2169 return fmt.Errorf(fmt.Sprintf("GetME-failed-%s-%s", mm.pDeviceHandler.deviceID, err))
2170 }
2171 if meInstance != nil {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002172 select {
2173 case meAttributes = <-mm.l2PmChan:
2174 logger.Debugw(ctx, "received fec history data metrics",
2175 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +00002176 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002177 logger.Errorw(ctx, "timeout waiting for omci-get response for fec history data",
2178 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
2179 // The metrics will be empty in this case
2180 return fmt.Errorf("timeout-during-l2-pm-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
2181 }
2182 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
2183 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
2184 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-fec-history-%v", mm.pDeviceHandler.deviceID)
2185 }
2186 }
2187 for k := range FecHistory {
2188 // populate fecHistData only if metric key not already present (or populated), since it is possible that we populate
2189 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
2190 if _, ok := fecHistData[k]; !ok {
2191 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08002192 case "entity_id":
2193 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
2194 fecHistData[k] = float32(val.(uint16))
2195 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002196 case "corrected_bytes":
2197 if val, ok := meAttributes["CorrectedBytes"]; ok && val != nil {
2198 fecHistData[k] = float32(val.(uint32))
2199 }
2200 case "corrected_code_words":
2201 if val, ok := meAttributes["CorrectedCodeWords"]; ok && val != nil {
2202 fecHistData[k] = float32(val.(uint32))
2203 }
2204 case "uncorrectable_code_words":
2205 if val, ok := meAttributes["UncorrectableCodeWords"]; ok && val != nil {
2206 fecHistData[k] = float32(val.(uint32))
2207 }
2208 case "total_code_words":
2209 if val, ok := meAttributes["TotalCodeWords"]; ok && val != nil {
2210 fecHistData[k] = float32(val.(uint32))
2211 }
2212 case "fec_seconds":
2213 if val, ok := meAttributes["FecSeconds"]; ok && val != nil {
2214 fecHistData[k] = float32(val.(uint16))
2215 }
2216 default:
2217 // do nothing
2218 }
2219 }
2220 }
2221 return nil
2222}
2223
2224// nolint: gocyclo
2225func (mm *onuMetricsManager) populateGemPortMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
2226 meAttributes me.AttributeValueMap, requestedAttributes me.AttributeValueMap, gemPortHistData map[string]float32, intervalEndTime *int) error {
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002227 // Insert "IntervalEndTime" is part of the requested attributes as we need this to compare the get responses when get request is multipart
ozgecanetsiab36ed572021-04-01 10:38:48 +03002228 if _, ok := requestedAttributes["IntervalEndTime"]; !ok {
2229 requestedAttributes["IntervalEndTime"] = 0
2230 }
2231 meInstance, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMe(ctx, classID, entityID, requestedAttributes, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
2232 if err != nil {
2233 logger.Errorw(ctx, "GetMe failed", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
2234 _ = mm.pAdaptFsm.pFsm.Event(l2PmEventFailure)
2235 return fmt.Errorf(fmt.Sprintf("GetME-failed-%s-%s", mm.pDeviceHandler.deviceID, err))
2236 }
2237 if meInstance != nil {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002238 select {
2239 case meAttributes = <-mm.l2PmChan:
2240 logger.Debugw(ctx, "received gem port history data metrics",
2241 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
Holger Hildebrandt366ef192021-05-05 11:07:44 +00002242 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002243 logger.Errorw(ctx, "timeout waiting for omci-get response for gem port history data",
2244 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID})
2245 // The metrics will be empty in this case
2246 return fmt.Errorf("timeout-during-l2-pm-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
2247 }
2248 // verify that interval end time has not changed during metric collection. If it changed, we abort the procedure
2249 if valid := mm.updateAndValidateIntervalEndTime(ctx, entityID, meAttributes, intervalEndTime); !valid {
2250 return fmt.Errorf("interval-end-time-changed-during-metric-collection-for-gemport-history-%v", mm.pDeviceHandler.deviceID)
2251 }
2252 }
2253 for k := range GemPortHistory {
2254 // populate gemPortHistData only if metric key not already present (or populated), since it is possible that we populate
2255 // the attributes in multiple iterations for a given L2 PM ME as there is a limit on the max OMCI GET payload size.
2256 if _, ok := gemPortHistData[k]; !ok {
2257 switch k {
Girish Gowdra0e533642021-03-02 22:02:51 -08002258 case "entity_id":
2259 if val, ok := meAttributes["ManagedEntityId"]; ok && val != nil {
2260 gemPortHistData[k] = float32(val.(uint16))
2261 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002262 case "transmitted_gem_frames":
2263 if val, ok := meAttributes["TransmittedGemFrames"]; ok && val != nil {
2264 gemPortHistData[k] = float32(val.(uint32))
2265 }
2266 case "received_gem_frames":
2267 if val, ok := meAttributes["ReceivedGemFrames"]; ok && val != nil {
2268 gemPortHistData[k] = float32(val.(uint32))
2269 }
2270 case "received_payload_bytes":
2271 if val, ok := meAttributes["ReceivedPayloadBytes"]; ok && val != nil {
2272 gemPortHistData[k] = float32(val.(uint64))
2273 }
2274 case "transmitted_payload_bytes":
2275 if val, ok := meAttributes["TransmittedPayloadBytes"]; ok && val != nil {
2276 gemPortHistData[k] = float32(val.(uint64))
2277 }
2278 case "encryption_key_errors":
2279 if val, ok := meAttributes["EncryptionKeyErrors"]; ok && val != nil {
2280 gemPortHistData[k] = float32(val.(uint32))
2281 }
2282 default:
2283 // do nothing
2284 }
2285 }
2286 }
2287 return nil
2288}
2289
Girish Gowdrae0140f02021-02-02 16:55:09 -08002290func (mm *onuMetricsManager) handleOmciCreateResponseMessage(ctx context.Context, msg OmciMessage) error {
2291 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeCreateResponse)
2292 if msgLayer == nil {
2293 logger.Errorw(ctx, "omci Msg layer could not be detected for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2294 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2295 }
2296 msgObj, msgOk := msgLayer.(*omci.CreateResponse)
2297 if !msgOk {
2298 logger.Errorw(ctx, "omci Msg layer could not be assigned for create response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2299 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2300 }
2301 logger.Debugw(ctx, "OMCI create response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2302 switch msgObj.EntityClass {
2303 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2304 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002305 me.EthernetPerformanceMonitoringHistoryDataClassID,
2306 me.FecPerformanceMonitoringHistoryDataClassID,
2307 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002308 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
2309 if msgObj.Result == me.Success || msgObj.Result == me.InstanceExists {
2310 mm.l2PmCreateOrDeleteResponseChan <- true
2311 } else {
2312 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2313 mm.l2PmCreateOrDeleteResponseChan <- false
2314 }
2315 return nil
Himani Chawla43f95ff2021-06-03 00:24:12 +05302316 case me.EthernetFrameExtendedPmClassID,
2317 me.EthernetFrameExtendedPm64BitClassID:
2318 mm.extendedPMCreateOrDeleteResponseChan <- msgObj.Result
2319 return nil
Girish Gowdrae0140f02021-02-02 16:55:09 -08002320 default:
2321 logger.Errorw(ctx, "unhandled omci create response message",
2322 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2323 }
2324 return fmt.Errorf("unhandled-omci-create-response-message-%v", mm.pDeviceHandler.deviceID)
2325}
2326
2327func (mm *onuMetricsManager) handleOmciDeleteResponseMessage(ctx context.Context, msg OmciMessage) error {
2328 msgLayer := (*msg.OmciPacket).Layer(omci.LayerTypeDeleteResponse)
2329 if msgLayer == nil {
2330 logger.Errorw(ctx, "omci Msg layer could not be detected for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2331 return fmt.Errorf("omci Msg layer could not be detected for create response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2332 }
2333 msgObj, msgOk := msgLayer.(*omci.DeleteResponse)
2334 if !msgOk {
2335 logger.Errorw(ctx, "omci Msg layer could not be assigned for delete response - handling stopped", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2336 return fmt.Errorf("omci Msg layer could not be assigned for delete response - handling stopped: %s", mm.pDeviceHandler.deviceID)
2337 }
2338 logger.Debugw(ctx, "OMCI delete response Data", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "data-fields": msgObj})
2339 switch msgObj.EntityClass {
2340 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID,
2341 me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID,
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002342 me.EthernetPerformanceMonitoringHistoryDataClassID,
2343 me.FecPerformanceMonitoringHistoryDataClassID,
2344 me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
Girish Gowdrae0140f02021-02-02 16:55:09 -08002345 // If the result is me.UnknownInstance it means the entity was already deleted. It is ok handled that as success
2346 if msgObj.Result == me.Success || msgObj.Result == me.UnknownInstance {
2347 mm.l2PmCreateOrDeleteResponseChan <- true
2348 } else {
2349 logger.Warnw(ctx, "failed to delete me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2350 mm.l2PmCreateOrDeleteResponseChan <- false
2351 }
2352 return nil
2353 default:
2354 logger.Errorw(ctx, "unhandled omci delete response message",
2355 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "class-id": msgObj.EntityClass})
2356 }
2357 return fmt.Errorf("unhandled-omci-delete-response-message-%v", mm.pDeviceHandler.deviceID)
2358}
2359
2360func (mm *onuMetricsManager) generateTicks(ctx context.Context) {
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07002361 mm.updateTickGenerationStatus(true)
Girish Gowdrae0140f02021-02-02 16:55:09 -08002362 for {
2363 select {
2364 case <-time.After(L2PmCollectionInterval * time.Second):
2365 go func() {
2366 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventTick); err != nil {
2367 logger.Errorw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2368 }
2369 }()
2370 case <-mm.stopTicks:
2371 logger.Infow(ctx, "stopping ticks", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07002372 mm.updateTickGenerationStatus(false)
Girish Gowdrae0140f02021-02-02 16:55:09 -08002373 return
2374 }
2375 }
2376}
2377
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002378func (mm *onuMetricsManager) handleMetricsPublish(ctx context.Context, metricName string, metricInfoSlice []*voltha.MetricInformation) {
2379 // Publish metrics if it is valid
2380 if metricInfoSlice != nil {
2381 mm.publishMetrics(ctx, metricInfoSlice)
2382 } else {
2383 // If collectAttempts exceeds L2PmCollectAttempts then remove it from activeL2Pms
2384 // slice so that we do not collect data from that PM ME anymore
2385 mm.onuMetricsManagerLock.Lock()
2386 mm.groupMetricMap[metricName].collectAttempts++
2387 if mm.groupMetricMap[metricName].collectAttempts > L2PmCollectAttempts {
2388 mm.activeL2Pms = mm.removeIfFoundString(mm.activeL2Pms, metricName)
2389 }
2390 logger.Warnw(ctx, "state collect data - no metrics collected",
2391 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "metricName": metricName, "collectAttempts": mm.groupMetricMap[metricName].collectAttempts})
2392 mm.onuMetricsManagerLock.Unlock()
2393 }
2394}
2395
2396func (mm *onuMetricsManager) populateGroupSpecificMetrics(ctx context.Context, mEnt *me.ManagedEntity, classID me.ClassID, entityID uint16,
2397 meAttributes me.AttributeValueMap, data map[string]float32, intervalEndTime *int) error {
2398 var grpFunc groupMetricPopulateFunc
2399 switch classID {
2400 case me.EthernetFramePerformanceMonitoringHistoryDataUpstreamClassID, me.EthernetFramePerformanceMonitoringHistoryDataDownstreamClassID:
2401 grpFunc = mm.populateEthernetBridgeHistoryMetrics
2402 case me.EthernetPerformanceMonitoringHistoryDataClassID:
2403 grpFunc = mm.populateEthernetUniHistoryMetrics
2404 case me.FecPerformanceMonitoringHistoryDataClassID:
2405 grpFunc = mm.populateFecHistoryMetrics
2406 case me.GemPortNetworkCtpPerformanceMonitoringHistoryDataClassID:
2407 grpFunc = mm.populateGemPortMetrics
2408 default:
2409 return fmt.Errorf("unknown-classid-%v", classID)
2410 }
2411
2412 size := 0
2413 requestedAttributes := make(me.AttributeValueMap)
2414 for _, v := range mEnt.GetAttributeDefinitions() {
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002415 if v.Name == "ManagedEntityId" || v.Name == "IntervalEndTime" || v.Name == "ThresholdData12Id" {
2416 // Exclude the ManagedEntityId , it will be inserted by omci library based on 'entityID' information
2417 // Exclude IntervalEndTime. It will be inserted by the group PM populater function.
2418 // Exclude ThresholdData12Id as that is of no particular relevance for metrics collection.
2419 continue
2420 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002421 if (v.Size + size) <= MaxL2PMGetPayLoadSize {
2422 requestedAttributes[v.Name] = v.DefValue
2423 size = v.Size + size
2424 } else { // We exceeded the allow omci get size
2425 // Let's collect the attributes via get now and collect remaining in the next iteration
2426 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2427 logger.Errorw(ctx, "error during metric collection",
2428 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2429 return err
2430 }
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002431 requestedAttributes = make(me.AttributeValueMap) // reset map
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002432 requestedAttributes[v.Name] = v.DefValue // populate the metric that was missed in the current iteration
2433 size = v.Size // reset size
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002434 }
2435 }
2436 // Collect the omci get attributes for the last bunch of attributes.
Girish Gowdra6c04fbc2021-04-22 15:34:49 -07002437 if err := grpFunc(ctx, classID, entityID, meAttributes, requestedAttributes, data, intervalEndTime); err != nil {
2438 logger.Errorw(ctx, "error during metric collection",
2439 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
2440 return err
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002441 }
2442 return nil
2443}
2444
2445func (mm *onuMetricsManager) populateOnuMetricInfo(title string, data map[string]float32) voltha.MetricInformation {
2446 metricsContext := make(map[string]string)
2447 metricsContext["onuID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.OnuId)
2448 metricsContext["intfID"] = fmt.Sprintf("%d", mm.pDeviceHandler.device.ProxyAddress.ChannelId)
2449 metricsContext["devicetype"] = mm.pDeviceHandler.DeviceType
2450
2451 raisedTs := time.Now().Unix()
2452 mmd := voltha.MetricMetaData{
2453 Title: title,
2454 Ts: float64(raisedTs),
2455 Context: metricsContext,
2456 DeviceId: mm.pDeviceHandler.deviceID,
2457 LogicalDeviceId: mm.pDeviceHandler.logicalDeviceID,
2458 SerialNo: mm.pDeviceHandler.device.SerialNumber,
2459 }
2460
2461 // create slice of metrics given that there could be more than one VEIP instance
2462 metricInfo := voltha.MetricInformation{Metadata: &mmd, Metrics: data}
2463 return metricInfo
2464}
2465
2466func (mm *onuMetricsManager) updateAndValidateIntervalEndTime(ctx context.Context, entityID uint16, meAttributes me.AttributeValueMap, intervalEndTime *int) bool {
2467 valid := false
2468 if *intervalEndTime == -1 { // first time
2469 // Update the interval end time
2470 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2471 *intervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2472 valid = true
2473 }
2474 } else {
2475 var currIntervalEndTime int
2476 if val, ok := meAttributes["IntervalEndTime"]; ok && val != nil {
2477 currIntervalEndTime = int(meAttributes["IntervalEndTime"].(uint8))
2478 }
2479 if currIntervalEndTime != *intervalEndTime { // interval end time changed during metric collection
2480 logger.Errorw(ctx, "interval end time changed during metrics collection for ethernet pm history data",
2481 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID,
2482 "currIntervalEndTime": *intervalEndTime, "newIntervalEndTime": currIntervalEndTime})
2483 } else {
2484 valid = true
2485 }
2486 }
2487 return valid
2488}
2489
2490func (mm *onuMetricsManager) waitForResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassName string) bool {
2491 logger.Debugw(ctx, "waitForResponseOrTimeout", log.Fields{"create": create, "instID": instID, "meClassName": meClassName})
2492 select {
2493 case resp := <-mm.l2PmCreateOrDeleteResponseChan:
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002494 logger.Debugw(ctx, "received l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002495 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassName": meClassName, "instID": instID})
2496 return resp
Holger Hildebrandt366ef192021-05-05 11:07:44 +00002497 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002498 logger.Errorw(ctx, "timeout waiting for l2 pm me response",
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002499 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassName": meClassName, "instID": instID})
2500 }
2501 return false
2502}
2503
2504func (mm *onuMetricsManager) initializeGroupMetric(grpMtrcs map[string]voltha.PmConfig_PmType, grpName string, grpEnabled bool, grpFreq uint32) {
2505 var pmConfigSlice []*voltha.PmConfig
2506 for k, v := range grpMtrcs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002507 pmConfigSlice = append(pmConfigSlice,
2508 &voltha.PmConfig{
2509 Name: k,
2510 Type: v,
2511 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2512 SampleFreq: grpFreq})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002513 }
2514 groupMetric := voltha.PmGroupConfig{
2515 GroupName: grpName,
2516 Enabled: grpEnabled && mm.pDeviceHandler.pOpenOnuAc.metricsEnabled,
2517 GroupFreq: grpFreq,
2518 Metrics: pmConfigSlice,
2519 }
2520 mm.pDeviceHandler.pmConfigs.Groups = append(mm.pDeviceHandler.pmConfigs.Groups, &groupMetric)
2521
2522}
2523
2524func (mm *onuMetricsManager) initializeL2PmFsm(ctx context.Context, aCommChannel chan Message) error {
2525 mm.pAdaptFsm = NewAdapterFsm("L2PmFSM", mm.pDeviceHandler.deviceID, aCommChannel)
2526 if mm.pAdaptFsm == nil {
2527 logger.Errorw(ctx, "L2PMFsm AdapterFsm could not be instantiated!!", log.Fields{
2528 "device-id": mm.pDeviceHandler.deviceID})
2529 return fmt.Errorf("nil-adapter-fsm")
2530 }
2531 // L2 PM FSM related state machine
2532 mm.pAdaptFsm.pFsm = fsm.NewFSM(
2533 l2PmStNull,
2534 fsm.Events{
2535 {Name: l2PmEventInit, Src: []string{l2PmStNull}, Dst: l2PmStStarting},
2536 {Name: l2PmEventTick, Src: []string{l2PmStStarting}, Dst: l2PmStSyncTime},
Girish Gowdra69570d92021-04-22 18:26:20 -07002537 {Name: l2PmEventTick, Src: []string{l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe}, Dst: l2PmStCollectData},
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002538 {Name: l2PmEventSuccess, Src: []string{l2PmStSyncTime, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2539 {Name: l2PmEventFailure, Src: []string{l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStIdle},
2540 {Name: l2PmEventFailure, Src: []string{l2PmStSyncTime}, Dst: l2PmStSyncTime},
2541 {Name: l2PmEventAddMe, Src: []string{l2PmStIdle}, Dst: l2PmStCreatePmMe},
2542 {Name: l2PmEventDeleteMe, Src: []string{l2PmStIdle}, Dst: l2PmStDeletePmMe},
2543 {Name: l2PmEventStop, Src: []string{l2PmStNull, l2PmStStarting, l2PmStSyncTime, l2PmStIdle, l2PmStCreatePmMe, l2PmStDeletePmMe, l2PmStCollectData}, Dst: l2PmStNull},
2544 },
2545 fsm.Callbacks{
2546 "enter_state": func(e *fsm.Event) { mm.pAdaptFsm.logFsmStateChange(ctx, e) },
2547 "enter_" + l2PmStNull: func(e *fsm.Event) { mm.l2PMFsmNull(ctx, e) },
2548 "enter_" + l2PmStIdle: func(e *fsm.Event) { mm.l2PMFsmIdle(ctx, e) },
2549 "enter_" + l2PmStStarting: func(e *fsm.Event) { mm.l2PMFsmStarting(ctx, e) },
2550 "enter_" + l2PmStSyncTime: func(e *fsm.Event) { mm.l2PMFsmSyncTime(ctx, e) },
2551 "enter_" + l2PmStCollectData: func(e *fsm.Event) { mm.l2PmFsmCollectData(ctx, e) },
ozgecanetsiab36ed572021-04-01 10:38:48 +03002552 "enter_" + l2PmStCreatePmMe: func(e *fsm.Event) { _ = mm.l2PmFsmCreatePM(ctx, e) },
2553 "enter_" + l2PmStDeletePmMe: func(e *fsm.Event) { _ = mm.l2PmFsmDeletePM(ctx, e) },
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002554 },
2555 )
2556 return nil
2557}
2558
2559func (mm *onuMetricsManager) initializeAllGroupMetrics() {
2560 mm.pDeviceHandler.pmConfigs = &voltha.PmConfigs{}
2561 mm.pDeviceHandler.pmConfigs.Id = mm.pDeviceHandler.deviceID
2562 mm.pDeviceHandler.pmConfigs.DefaultFreq = DefaultMetricCollectionFrequency
2563 mm.pDeviceHandler.pmConfigs.Grouped = GroupMetricEnabled
2564 mm.pDeviceHandler.pmConfigs.FreqOverride = DefaultFrequencyOverrideEnabled
2565
2566 // Populate group metrics.
2567 // Lets populate irrespective of GroupMetricEnabled is true or not.
2568 // The group metrics collection will decided on this flag later
2569
2570 mm.initializeGroupMetric(OpticalPowerGroupMetrics, OpticalPowerGroupMetricName,
2571 OpticalPowerGroupMetricEnabled, OpticalPowerMetricGroupCollectionFrequency)
2572
2573 mm.initializeGroupMetric(UniStatusGroupMetrics, UniStatusGroupMetricName,
2574 UniStatusGroupMetricEnabled, UniStatusMetricGroupCollectionFrequency)
2575
2576 // classical l2 pm counter start
2577
2578 mm.initializeGroupMetric(EthernetBridgeHistory, EthernetBridgeHistoryName,
2579 EthernetBridgeHistoryEnabled, EthernetBridgeHistoryFrequency)
2580
2581 mm.initializeGroupMetric(EthernetUniHistory, EthernetUniHistoryName,
2582 EthernetUniHistoryEnabled, EthernetUniHistoryFrequency)
2583
2584 mm.initializeGroupMetric(FecHistory, FecHistoryName,
2585 FecHistoryEnabled, FecHistoryFrequency)
2586
2587 mm.initializeGroupMetric(GemPortHistory, GemPortHistoryName,
2588 GemPortHistoryEnabled, GemPortHistoryFrequency)
2589
2590 // classical l2 pm counter end
2591
2592 // Add standalone metric (if present) after this (will be added to dh.pmConfigs.Metrics)
2593}
2594
2595func (mm *onuMetricsManager) populateLocalGroupMetricData(ctx context.Context) {
2596 // Populate local group metric structures
2597 for _, g := range mm.pDeviceHandler.pmConfigs.Groups {
2598 mm.groupMetricMap[g.GroupName] = &groupMetric{
2599 groupName: g.GroupName,
2600 enabled: g.Enabled,
2601 frequency: g.GroupFreq,
2602 }
2603 switch g.GroupName {
2604 case OpticalPowerGroupMetricName:
2605 mm.groupMetricMap[g.GroupName].metricMap = OpticalPowerGroupMetrics
2606 case UniStatusGroupMetricName:
2607 mm.groupMetricMap[g.GroupName].metricMap = UniStatusGroupMetrics
2608 case EthernetBridgeHistoryName:
2609 mm.groupMetricMap[g.GroupName].metricMap = EthernetBridgeHistory
2610 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2611 case EthernetUniHistoryName:
2612 mm.groupMetricMap[g.GroupName].metricMap = EthernetUniHistory
2613 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2614 case FecHistoryName:
2615 mm.groupMetricMap[g.GroupName].metricMap = FecHistory
2616 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2617 case GemPortHistoryName:
2618 mm.groupMetricMap[g.GroupName].metricMap = GemPortHistory
2619 mm.groupMetricMap[g.GroupName].isL2PMCounter = true
2620 default:
2621 logger.Errorw(ctx, "unhandled-group-name", log.Fields{"groupName": g.GroupName})
2622 }
2623 }
2624
2625 // Populate local standalone metric structures
2626 for _, m := range mm.pDeviceHandler.pmConfigs.Metrics {
2627 mm.standaloneMetricMap[m.Name] = &standaloneMetric{
2628 metricName: m.Name,
2629 enabled: m.Enabled,
2630 frequency: m.SampleFreq,
2631 }
2632 switch m.Name {
2633 // None exist as of now. Add when available.
2634 default:
2635 logger.Errorw(ctx, "unhandled-metric-name", log.Fields{"metricName": m.Name})
2636 }
2637 }
2638}
2639
Girish Gowdra69570d92021-04-22 18:26:20 -07002640func (mm *onuMetricsManager) AddGemPortForPerfMonitoring(ctx context.Context, gemPortNTPInstID uint16) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002641 mm.onuMetricsManagerLock.Lock()
2642 defer mm.onuMetricsManagerLock.Unlock()
Girish Gowdra69570d92021-04-22 18:26:20 -07002643 logger.Debugw(ctx, "add gemport for perf monitoring - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "gemPortID": gemPortNTPInstID})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002644 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002645 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002646 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002647 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002648
2649 mm.l2PmToAdd = mm.appendIfMissingString(mm.l2PmToAdd, GemPortHistoryName)
2650 // We do not need to remove from l2PmToDelete slice as we could have Add and Delete of
2651 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2652 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2653 // gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra69570d92021-04-22 18:26:20 -07002654
2655 logger.Debugw(ctx, "add gemport for perf monitoring - end",
2656 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-add": mm.l2PmToAdd,
2657 "instances-to-add": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd})
2658 go func() {
2659 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventAddMe); err != nil {
2660 // log at warn level as the gem port for monitoring is going to be added eventually
2661 logger.Warnw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2662 }
2663 }()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002664}
2665
Girish Gowdra69570d92021-04-22 18:26:20 -07002666func (mm *onuMetricsManager) RemoveGemPortForPerfMonitoring(ctx context.Context, gemPortNTPInstID uint16) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002667 mm.onuMetricsManagerLock.Lock()
2668 defer mm.onuMetricsManagerLock.Unlock()
Girish Gowdra69570d92021-04-22 18:26:20 -07002669 logger.Debugw(ctx, "remove gemport for perf monitoring - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "gemPortID": gemPortNTPInstID})
Girish Gowdra0e533642021-03-02 22:02:51 -08002670 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002671 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002672 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, gemPortNTPInstID)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002673
2674 mm.l2PmToDelete = mm.appendIfMissingString(mm.l2PmToDelete, GemPortHistoryName)
2675 // We do not need to remove from l2PmToAdd slice as we could have Add and Delete of
2676 // GemPortPerfHistory ME simultaneously for different instances of the ME.
2677 // The creation or deletion of an instance is decided based on its presence in gemPortNCTPPerfHistInstToDelete or
2678 // gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra69570d92021-04-22 18:26:20 -07002679
2680 logger.Debugw(ctx, "remove gemport from perf monitoring - end",
2681 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pms-to-delete": mm.l2PmToDelete,
2682 "instances-to-delete": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
2683 go func() {
2684 if err := mm.pAdaptFsm.pFsm.Event(l2PmEventDeleteMe); err != nil {
2685 // log at warn level as the gem port for monitoring is going to be removed eventually
2686 logger.Warnw(ctx, "error calling event", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "err": err})
2687 }
2688 }()
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002689}
2690
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002691func (mm *onuMetricsManager) updateGemPortNTPInstanceToAddForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002692 if mm.pDeviceHandler.pOnuTP != nil {
2693 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002694 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002695 for _, v := range gemPortInstIDs {
2696 // mark the instance for addition
Girish Gowdra0e533642021-03-02 22:02:51 -08002697 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002698 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToDelete slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002699 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002700 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002701 logger.Debugw(ctx, "updateGemPortNTPInstanceToAddForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002702 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, "gemToDel": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002703 }
2704}
2705
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002706func (mm *onuMetricsManager) updateGemPortNTPInstanceToDeleteForPerfMonitoring(ctx context.Context) {
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002707 if mm.pDeviceHandler.pOnuTP != nil {
2708 gemPortInstIDs := mm.pDeviceHandler.pOnuTP.GetAllBidirectionalGemPortIDsForOnu()
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002709 // NOTE: It is expected that caller of this function has acquired the required mutex for synchronization purposes
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002710 for _, v := range gemPortInstIDs {
Girish Gowdra0e533642021-03-02 22:02:51 -08002711 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002712 // If the instance presence toggles too soon, we need to remove it from gemPortNCTPPerfHistInstToAdd slice
Girish Gowdra0e533642021-03-02 22:02:51 -08002713 mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd = mm.removeIfFoundUint16(mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, v)
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002714 }
2715 }
Girish Gowdra36ccf7d2021-02-25 20:42:51 -08002716 logger.Debugw(ctx, "updateGemPortNTPInstanceToDeleteForPerfMonitoring",
Girish Gowdra0e533642021-03-02 22:02:51 -08002717 log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "gemToAdd": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToAdd, "gemToDel": mm.groupMetricMap[GemPortHistoryName].pmMEData.InstancesToDelete})
2718}
2719
2720// restorePmData restores any PM data available on the KV store to local cache
2721func (mm *onuMetricsManager) restorePmData(ctx context.Context) error {
2722 logger.Debugw(ctx, "restorePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2723 if mm.pmKvStore == nil {
2724 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2725 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2726 }
2727 var errorsList []error
2728 for groupName, group := range mm.groupMetricMap {
2729 group.pmMEData = &pmMEData{}
2730 Value, err := mm.pmKvStore.Get(ctx, groupName)
2731 if err == nil {
2732 if Value != nil {
2733 logger.Debugw(ctx, "PM data read",
2734 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2735 tmpBytes, _ := kvstore.ToByte(Value.Value)
2736
2737 if err = json.Unmarshal(tmpBytes, &group.pmMEData); err != nil {
2738 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2739 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-unmarshal-PM-data-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2740 continue
2741 }
2742 logger.Debugw(ctx, "restorePmData - success", log.Fields{"pmData": group.pmMEData, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2743 } else {
2744 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2745 continue
2746 }
2747 } else {
2748 logger.Errorw(ctx, "restorePmData - fail", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "err": err})
2749 errorsList = append(errorsList, fmt.Errorf(fmt.Sprintf("unable-to-read-from-KVstore-%s-for-group-%s", mm.pDeviceHandler.deviceID, groupName)))
2750 continue
2751 }
2752 }
2753 if len(errorsList) > 0 {
2754 return fmt.Errorf("errors-restoring-pm-data-for-one-or-more-groups--errors:%v", errorsList)
2755 }
2756 logger.Debugw(ctx, "restorePmData - complete success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2757 return nil
2758}
2759
2760// getPmData gets pmMEData from cache. Since we have write through cache implementation for pmMEData,
2761// the data must be available in cache.
2762// Note, it is expected that caller of this function manages the required synchronization (like using locks etc.).
2763func (mm *onuMetricsManager) getPmData(ctx context.Context, groupName string) (*pmMEData, error) {
2764 if grp, ok := mm.groupMetricMap[groupName]; ok {
2765 return grp.pmMEData, nil
2766 }
2767 // Data not in cache, try to fetch from kv store.
2768 data := &pmMEData{}
2769 if mm.pmKvStore == nil {
2770 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2771 return data, fmt.Errorf("pmKvStore not set. device-id - %s", mm.pDeviceHandler.deviceID)
2772 }
2773 Value, err := mm.pmKvStore.Get(ctx, groupName)
2774 if err == nil {
2775 if Value != nil {
2776 logger.Debugw(ctx, "PM data read",
2777 log.Fields{"Key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2778 tmpBytes, _ := kvstore.ToByte(Value.Value)
2779
2780 if err = json.Unmarshal(tmpBytes, data); err != nil {
2781 logger.Errorw(ctx, "unable to unmarshal PM data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2782 return data, err
2783 }
2784 logger.Debugw(ctx, "PM data", log.Fields{"pmData": data, "groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2785 } else {
2786 logger.Debugw(ctx, "no PM data found", log.Fields{"groupName": groupName, "device-id": mm.pDeviceHandler.deviceID})
2787 return data, err
2788 }
2789 } else {
2790 logger.Errorw(ctx, "unable to read from KVstore", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2791 return data, err
2792 }
2793
2794 return data, nil
2795}
2796
2797// updatePmData update pmMEData to store. It is write through cache, i.e., write to cache first and then update store
2798func (mm *onuMetricsManager) updatePmData(ctx context.Context, groupName string, meInstanceID uint16, pmAction string) error {
2799 logger.Debugw(ctx, "updatePmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "entityID": meInstanceID, "pmAction": pmAction})
2800 mm.onuMetricsManagerLock.Lock()
2801 defer mm.onuMetricsManagerLock.Unlock()
2802
2803 if mm.pmKvStore == nil {
2804 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2805 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2806 }
2807
2808 pmMEData, err := mm.getPmData(ctx, groupName)
2809 if err != nil || pmMEData == nil {
2810 // error already logged in called function.
2811 return err
2812 }
2813 switch pmAction {
2814 case cPmAdd:
2815 pmMEData.InstancesToAdd = mm.appendIfMissingUnt16(pmMEData.InstancesToAdd, meInstanceID)
2816 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2817 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2818 case cPmAdded:
2819 pmMEData.InstancesActive = mm.appendIfMissingUnt16(pmMEData.InstancesActive, meInstanceID)
2820 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2821 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2822 case cPmRemove:
2823 pmMEData.InstancesToDelete = mm.appendIfMissingUnt16(pmMEData.InstancesToDelete, meInstanceID)
2824 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2825 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2826 case cPmRemoved:
2827 pmMEData.InstancesToDelete = mm.removeIfFoundUint16(pmMEData.InstancesToDelete, meInstanceID)
2828 pmMEData.InstancesToAdd = mm.removeIfFoundUint16(pmMEData.InstancesToAdd, meInstanceID)
2829 pmMEData.InstancesActive = mm.removeIfFoundUint16(pmMEData.InstancesActive, meInstanceID)
2830 default:
2831 logger.Errorw(ctx, "unknown pm action", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "pmAction": pmAction, "groupName": groupName})
2832 return fmt.Errorf(fmt.Sprintf("unknown-pm-action-deviceid-%s-groupName-%s-pmaction-%s", mm.pDeviceHandler.deviceID, groupName, pmAction))
2833 }
2834 // write through cache
2835 mm.groupMetricMap[groupName].pmMEData = pmMEData
2836
2837 Value, err := json.Marshal(*pmMEData)
2838 if err != nil {
2839 logger.Errorw(ctx, "unable to marshal PM data", log.Fields{"groupName": groupName, "pmAction": pmAction, "pmData": *pmMEData, "err": err})
2840 return err
2841 }
2842 // Update back to kv store
2843 if err = mm.pmKvStore.Put(ctx, groupName, Value); err != nil {
2844 logger.Errorw(ctx, "unable to put PM data to kv store", log.Fields{"groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction, "err": err})
2845 return err
2846 }
2847 logger.Debugw(ctx, "updatePmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": groupName, "pmData": *pmMEData, "pmAction": pmAction})
2848
2849 return nil
2850}
2851
2852// clearPmGroupData cleans PM Group data from store
2853func (mm *onuMetricsManager) clearPmGroupData(ctx context.Context) error {
2854 mm.onuMetricsManagerLock.Lock()
2855 defer mm.onuMetricsManagerLock.Unlock()
2856 logger.Debugw(ctx, "clearPmGroupData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2857 if mm.pmKvStore == nil {
2858 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2859 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2860 }
2861
2862 for n := range mm.groupMetricMap {
2863 if err := mm.pmKvStore.Delete(ctx, n); err != nil {
2864 logger.Errorw(ctx, "clearPmGroupData - fail", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "groupName": n, "err": err})
2865 // do not abort this procedure. continue to delete next group.
2866 } else {
2867 logger.Debugw(ctx, "clearPmGroupData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": n})
2868 }
2869 }
2870
2871 return nil
2872}
2873
2874// clearAllPmData clears all PM data associated with the device from KV store
2875func (mm *onuMetricsManager) clearAllPmData(ctx context.Context) error {
2876 mm.onuMetricsManagerLock.Lock()
2877 defer mm.onuMetricsManagerLock.Unlock()
2878 logger.Debugw(ctx, "clearAllPmData - start", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2879 if mm.pmKvStore == nil {
2880 logger.Errorw(ctx, "pmKvStore not set - abort", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2881 return fmt.Errorf(fmt.Sprintf("pmKvStore-not-set-abort-%s", mm.pDeviceHandler.deviceID))
2882 }
Holger Hildebrandt44a0d4f2021-03-18 14:00:54 +00002883 var value error
2884 for n := range mm.groupMetricMap {
2885 if err := mm.pmKvStore.Delete(ctx, n); err != nil {
2886 logger.Errorw(ctx, "clearPmGroupData - fail", log.Fields{"deviceID": mm.pDeviceHandler.deviceID, "groupName": n, "err": err})
2887 value = err
2888 // do not abort this procedure - continue to delete next group.
2889 } else {
2890 logger.Debugw(ctx, "clearPmGroupData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "groupName": n})
2891 }
Girish Gowdra0e533642021-03-02 22:02:51 -08002892 }
Holger Hildebrandt44a0d4f2021-03-18 14:00:54 +00002893 if value == nil {
2894 logger.Debugw(ctx, "clearAllPmData - success", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2895 }
2896 return value
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002897}
2898
Girish Gowdra7b0ee5c2021-03-19 21:48:15 -07002899func (mm *onuMetricsManager) updateOmciProcessingStatus(status bool) {
2900 mm.onuMetricsManagerLock.Lock()
2901 defer mm.onuMetricsManagerLock.Unlock()
2902 mm.omciProcessingActive = status
2903}
2904
2905func (mm *onuMetricsManager) updateTickGenerationStatus(status bool) {
2906 mm.onuMetricsManagerLock.Lock()
2907 defer mm.onuMetricsManagerLock.Unlock()
2908 mm.tickGenerationActive = status
2909}
2910
2911func (mm *onuMetricsManager) getOmciProcessingStatus() bool {
2912 mm.onuMetricsManagerLock.RLock()
2913 defer mm.onuMetricsManagerLock.RUnlock()
2914 return mm.omciProcessingActive
2915}
2916
2917func (mm *onuMetricsManager) getTickGenerationStatus() bool {
2918 mm.onuMetricsManagerLock.RLock()
2919 defer mm.onuMetricsManagerLock.RUnlock()
2920 return mm.tickGenerationActive
2921}
2922
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002923func (mm *onuMetricsManager) appendIfMissingString(slice []string, n string) []string {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002924 for _, ele := range slice {
2925 if ele == n {
2926 return slice
2927 }
2928 }
2929 return append(slice, n)
2930}
2931
Girish Gowdra5c5aaf42021-02-17 19:40:50 -08002932func (mm *onuMetricsManager) removeIfFoundString(slice []string, n string) []string {
2933 for i, ele := range slice {
2934 if ele == n {
2935 return append(slice[:i], slice[i+1:]...)
2936 }
2937 }
2938 return slice
2939}
2940
2941func (mm *onuMetricsManager) appendIfMissingUnt16(slice []uint16, n uint16) []uint16 {
2942 for _, ele := range slice {
2943 if ele == n {
2944 return slice
2945 }
2946 }
2947 return append(slice, n)
2948}
2949
2950func (mm *onuMetricsManager) removeIfFoundUint16(slice []uint16, n uint16) []uint16 {
Girish Gowdrae0140f02021-02-02 16:55:09 -08002951 for i, ele := range slice {
2952 if ele == n {
2953 return append(slice[:i], slice[i+1:]...)
2954 }
2955 }
2956 return slice
Girish Gowdrae09a6202021-01-12 18:10:59 -08002957}
Himani Chawla43f95ff2021-06-03 00:24:12 +05302958
2959func (mm *onuMetricsManager) getEthernetFrameExtendedMETypeFromKvStore(ctx context.Context) (bool, error) {
2960 // Check if the data is already available in KV store, if yes, do not send the request for get me.
2961 var data me.ClassID
mpagenkob59fbed2021-11-23 16:55:20 +00002962 mm.pDeviceHandler.pOnuOmciDevice.mutexPersOnuConfig.RLock()
Himani Chawla43f95ff2021-06-03 00:24:12 +05302963 key := fmt.Sprintf("%s/%s/%s", mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersVendorID,
2964 mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersEquipmentID,
2965 mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersActiveSwVersion)
mpagenkob59fbed2021-11-23 16:55:20 +00002966 mm.pDeviceHandler.pOnuOmciDevice.mutexPersOnuConfig.RUnlock()
Himani Chawla43f95ff2021-06-03 00:24:12 +05302967 Value, err := mm.extPmKvStore.Get(ctx, key)
2968 if err == nil {
2969 if Value != nil {
2970 logger.Debugw(ctx, "me-type-read",
2971 log.Fields{"key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2972 tmpBytes, _ := kvstore.ToByte(Value.Value)
2973
2974 if err = json.Unmarshal(tmpBytes, &data); err != nil {
2975 logger.Errorw(ctx, "unable-to-unmarshal-data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2976 return false, err
2977 }
2978 logger.Debugw(ctx, "me-ext-pm-class-data", log.Fields{"class-id": data, "device-id": mm.pDeviceHandler.deviceID})
2979 // We have found the data from db, no need to get through omci get message.
2980 mm.supportedEthernetFrameExtendedPMClass = data
2981 return true, nil
2982 }
2983 logger.Debugw(ctx, "no-me-ext-pm-class-data-found", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2984 return false, nil
2985 }
2986 logger.Errorw(ctx, "unable-to-read-from-kv-store", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2987 return false, err
2988}
2989
2990func (mm *onuMetricsManager) waitForEthernetFrameCreateOrDeleteResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassID me.ClassID, upstream bool) (bool, error) {
2991 logger.Debugw(ctx, "wait-for-ethernet-frame-create-or-delete-response-or-timeout", log.Fields{"create": create, "instID": instID, "meClassID": meClassID})
2992 select {
2993 case resp := <-mm.extendedPMCreateOrDeleteResponseChan:
2994 logger.Debugw(ctx, "received-extended-pm-me-response",
2995 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassID": meClassID, "instID": instID, "upstream": upstream})
2996 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
2997 if resp == me.Success || resp == me.InstanceExists {
2998 return true, nil
2999 } else if resp == me.UnknownEntity || resp == me.ParameterError ||
3000 resp == me.ProcessingError || resp == me.NotSupported || resp == me.AttributeFailure {
3001 return false, fmt.Errorf("not-supported-me--resp-code-%v", resp)
3002 } else {
3003 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "class-id": meClassID, "instID": instID, "upstream": upstream})
3004 return true, fmt.Errorf("error-while-creating-me--resp-code-%v", resp)
3005 }
3006 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
3007 logger.Errorw(ctx, "timeout-waiting-for-ext-pm-me-response",
3008 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassID": meClassID, "instID": instID, "upstream": upstream})
3009 }
3010 return false, fmt.Errorf("timeout-while-waiting-for-response")
3011}
3012
3013func (mm *onuMetricsManager) tryCreateExtPmMe(ctx context.Context, meType me.ClassID) (bool, error) {
3014 cnt := 0
Himani Chawla43f95ff2021-06-03 00:24:12 +05303015 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
Himani Chawla97531162021-07-12 15:42:26 +05303016 for _, direction := range []bool{true, false} {
Himani Chawla43f95ff2021-06-03 00:24:12 +05303017 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
3018 var entityID uint16
3019 if direction {
3020 entityID = uniPort.entityID + 0x100
3021 } else {
3022 entityID = uniPort.entityID
3023 }
3024
3025 // parent entity id will be same for both direction
3026 controlBlock := mm.getControlBlockForExtendedPMDirection(ctx, direction, uniPort.entityID)
3027
3028 inner1:
3029 // retry ExtendedPmCreateAttempts times to create the instance of PM
3030 for cnt = 0; cnt < ExtendedPmCreateAttempts; cnt++ {
3031 meEnt, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetFrameExtendedPMME(
3032 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, true,
3033 mm.pAdaptFsm.commChan, entityID, meType, controlBlock)
3034 if err != nil {
3035 logger.Errorw(ctx, "EthernetFrameExtendedPMME-create-or-delete-failed",
3036 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
3037 return false, err
3038 }
3039 if supported, err := mm.waitForEthernetFrameCreateOrDeleteResponseOrTimeout(ctx, true, entityID, meType, direction); err == nil && supported {
3040 if direction {
Himani Chawla97531162021-07-12 15:42:26 +05303041 mm.ethernetFrameExtendedPmUpStreamMEByEntityID[entityID] = meEnt
Himani Chawla43f95ff2021-06-03 00:24:12 +05303042 } else {
Himani Chawla97531162021-07-12 15:42:26 +05303043 mm.ethernetFrameExtendedPmDownStreamMEByEntityID[entityID] = meEnt
Himani Chawla43f95ff2021-06-03 00:24:12 +05303044 }
3045 break inner1
3046 } else if err != nil {
3047 if !supported {
3048 // Need to return immediately
3049 return false, err
3050 }
3051 //In case of failure, go for a retry
3052 }
3053 }
3054 if cnt == ExtendedPmCreateAttempts {
3055 logger.Error(ctx, "exceeded-attempts-while-creating-me-for-ethernet-frame-extended-pm")
3056 return true, fmt.Errorf("unable-to-create-me")
3057 }
3058 }
3059 }
3060 return true, nil
3061}
3062
3063func (mm *onuMetricsManager) putExtPmMeKvStore(ctx context.Context) {
mpagenkob59fbed2021-11-23 16:55:20 +00003064 mm.pDeviceHandler.pOnuOmciDevice.mutexPersOnuConfig.RLock()
Himani Chawla43f95ff2021-06-03 00:24:12 +05303065 key := fmt.Sprintf("%s/%s/%s", mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersVendorID,
3066 mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersEquipmentID,
3067 mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersActiveSwVersion)
mpagenkob59fbed2021-11-23 16:55:20 +00003068 mm.pDeviceHandler.pOnuOmciDevice.mutexPersOnuConfig.RUnlock()
Himani Chawla43f95ff2021-06-03 00:24:12 +05303069 // check if we get the supported type me for ethernet frame extended pm class id
3070 if mm.supportedEthernetFrameExtendedPMClass == 0 {
3071 logger.Error(ctx, "unable-to-get-any-supported-extended-pm-me-class")
3072 }
3073 classSupported, err := json.Marshal(mm.supportedEthernetFrameExtendedPMClass)
3074 if err != nil {
3075 logger.Errorw(ctx, "unable-to-marshal-data", log.Fields{"err": err})
3076 }
3077 if err := mm.extPmKvStore.Put(ctx, key, classSupported); err != nil {
3078 logger.Errorw(ctx, "unable-to-add-data-in-db", log.Fields{"err": err})
3079 }
3080}
3081
3082func (mm *onuMetricsManager) setAllExtPmMeCreatedFlag() {
3083 mm.onuEthernetFrameExtendedPmLock.Lock()
3084 mm.isDeviceReadyToCollectExtendedPmStats = true
3085 mm.onuEthernetFrameExtendedPmLock.Unlock()
3086}
3087func (mm *onuMetricsManager) createEthernetFrameExtendedPMME(ctx context.Context) {
3088 //get the type of extended frame pm me supported by onu first
3089 exist, err := mm.getEthernetFrameExtendedMETypeFromKvStore(ctx)
3090 if err != nil {
3091 logger.Error(ctx, "unable-to-get-supported-me-for-ethernet-frame-extended-pm")
3092 return
3093 }
3094 if exist {
3095 // we have the me type, go ahead with the me type supported.
3096 if _, err := mm.tryCreateExtPmMe(ctx, mm.supportedEthernetFrameExtendedPMClass); err != nil {
3097 logger.Errorw(ctx, "unable-to-create-me-type", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
3098 "meClassID": mm.supportedEthernetFrameExtendedPMClass})
3099 return
3100 }
3101 mm.setAllExtPmMeCreatedFlag()
3102 return
3103 }
3104 // First try with 64 bit me
3105 // we have the me type, go ahead with the me type supported.
3106 supported64Bit, err := mm.tryCreateExtPmMe(ctx, me.EthernetFrameExtendedPm64BitClassID)
3107 if err != nil && !supported64Bit {
3108 logger.Errorw(ctx, "unable-to-create-me-type-as-it-is-not-supported",
3109 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "meClassID": me.EthernetFrameExtendedPm64BitClassID,
3110 "supported": supported64Bit})
3111 // Then Try with 32 bit type
3112 if supported32Bit, err := mm.tryCreateExtPmMe(ctx, me.EthernetFrameExtendedPmClassID); err != nil {
3113 logger.Errorw(ctx, "unable-to-create-me-type", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
3114 "meClassID": me.EthernetFrameExtendedPmClassID, "supported": supported32Bit})
3115 } else if supported32Bit {
3116 mm.supportedEthernetFrameExtendedPMClass = me.EthernetFrameExtendedPmClassID
3117 mm.putExtPmMeKvStore(ctx)
3118 mm.setAllExtPmMeCreatedFlag()
3119 }
3120 } else if err == nil && supported64Bit {
3121 mm.supportedEthernetFrameExtendedPMClass = me.EthernetFrameExtendedPm64BitClassID
3122 mm.putExtPmMeKvStore(ctx)
3123 mm.setAllExtPmMeCreatedFlag()
3124 }
3125}
3126
3127func (mm *onuMetricsManager) collectEthernetFrameExtendedPMCounters(ctx context.Context) *extension.SingleGetValueResponse {
3128 errFunc := func(reason extension.GetValueResponse_ErrorReason) *extension.SingleGetValueResponse {
3129 return &extension.SingleGetValueResponse{
3130 Response: &extension.GetValueResponse{
3131 Status: extension.GetValueResponse_ERROR,
3132 ErrReason: reason,
3133 },
3134 }
3135 }
3136 mm.onuEthernetFrameExtendedPmLock.RLock()
3137 if !mm.isDeviceReadyToCollectExtendedPmStats {
3138 mm.onuEthernetFrameExtendedPmLock.RUnlock()
3139 return errFunc(extension.GetValueResponse_INTERNAL_ERROR)
3140 }
3141 mm.onuEthernetFrameExtendedPmLock.RUnlock()
3142 // Collect metrics for upstream for all the PM Mes per uni port and aggregate
3143 var pmUpstream extension.OmciEthernetFrameExtendedPm
3144 var pmDownstream extension.OmciEthernetFrameExtendedPm
Himani Chawla97531162021-07-12 15:42:26 +05303145 for entityID, meEnt := range mm.ethernetFrameExtendedPmUpStreamMEByEntityID {
Himani Chawla43f95ff2021-06-03 00:24:12 +05303146 var receivedMask uint16
3147 if metricInfo, errResp := mm.collectEthernetFrameExtendedPMData(ctx, meEnt, entityID, true, &receivedMask); metricInfo != nil { // upstream
3148 if receivedMask == 0 {
3149 pmUpstream = mm.aggregateEthernetFrameExtendedPM(metricInfo, pmUpstream, false)
3150 logger.Error(ctx, "all-the-attributes-of-ethernet-frame-extended-pm-counters-are-unsupported")
3151 pmDownstream = pmUpstream
3152 singleValResp := extension.SingleGetValueResponse{
3153 Response: &extension.GetValueResponse{
3154 Status: extension.GetValueResponse_OK,
3155 Response: &extension.GetValueResponse_OnuCounters{
3156 OnuCounters: &extension.GetOmciEthernetFrameExtendedPmResponse{
3157 Upstream: &pmUpstream,
3158 Downstream: &pmDownstream,
3159 },
3160 },
3161 },
3162 }
3163 return &singleValResp
3164 }
3165 // Aggregate the result for upstream
3166 pmUpstream = mm.aggregateEthernetFrameExtendedPM(metricInfo, pmUpstream, true)
3167 } else {
3168 return errFunc(errResp)
3169 }
3170 }
3171
Himani Chawla97531162021-07-12 15:42:26 +05303172 for entityID, meEnt := range mm.ethernetFrameExtendedPmDownStreamMEByEntityID {
Himani Chawla43f95ff2021-06-03 00:24:12 +05303173 var receivedMask uint16
3174 if metricInfo, errResp := mm.collectEthernetFrameExtendedPMData(ctx, meEnt, entityID, false, &receivedMask); metricInfo != nil { // downstream
3175 // Aggregate the result for downstream
3176 pmDownstream = mm.aggregateEthernetFrameExtendedPM(metricInfo, pmDownstream, true)
3177 } else {
3178 return errFunc(errResp)
3179 }
3180 }
3181 singleValResp := extension.SingleGetValueResponse{
3182 Response: &extension.GetValueResponse{
3183 Status: extension.GetValueResponse_OK,
3184 Response: &extension.GetValueResponse_OnuCounters{
3185 OnuCounters: &extension.GetOmciEthernetFrameExtendedPmResponse{
3186 Upstream: &pmUpstream,
3187 Downstream: &pmDownstream,
3188 },
3189 },
3190 },
3191 }
3192 return &singleValResp
3193}
3194
3195func (mm *onuMetricsManager) collectEthernetFrameExtendedPMData(ctx context.Context, meEnt *me.ManagedEntity, entityID uint16, upstream bool, receivedMask *uint16) (map[string]uint64, extension.GetValueResponse_ErrorReason) {
3196 var classID me.ClassID
3197 logger.Debugw(ctx, "collecting-data-for-ethernet-frame-extended-pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
3198
3199 classID = mm.supportedEthernetFrameExtendedPMClass
3200 attributeMaskList := maskToEthernetFrameExtendedPM64Bit
3201 if classID == me.EthernetFrameExtendedPmClassID {
3202 attributeMaskList = maskToEthernetFrameExtendedPM32Bit
3203 }
3204 ethPMData := make(map[string]uint64)
3205 var sumReceivedMask uint16
3206 for mask := range attributeMaskList {
3207 if errResp, err := mm.populateEthernetFrameExtendedPMMetrics(ctx, classID, entityID, mask, ethPMData, upstream, &sumReceivedMask); err != nil {
3208 logger.Errorw(ctx, "error-during-metric-collection",
3209 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
3210 return nil, errResp
3211 }
3212 if (mask == 0x3F00 || mask == 0x3800) && sumReceivedMask == 0 {
3213 //It means the first attributes fetch was a failure, hence instead of sending multiple failure get requests
3214 //populate all counters as failure and return
3215 mm.fillAllErrorCountersEthernetFrameExtendedPM(ethPMData)
3216 break
3217 }
3218 }
3219 *receivedMask = sumReceivedMask
3220 return ethPMData, extension.GetValueResponse_REASON_UNDEFINED
3221}
3222
3223// nolint: gocyclo
3224func (mm *onuMetricsManager) populateEthernetFrameExtendedPMMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
3225 requestedAttributesMask uint16, ethFrameExtPMData map[string]uint64, upstream bool, sumReceivedMask *uint16) (extension.GetValueResponse_ErrorReason, error) {
3226 var meAttributes me.AttributeValueMap
3227 logger.Debugw(ctx, "requesting-attributes", log.Fields{"attributes-mask": requestedAttributesMask, "entityID": entityID, "classID": classID})
3228 err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMeWithAttributeMask(ctx, classID, entityID, requestedAttributesMask, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
3229 if err != nil {
3230 logger.Errorw(ctx, "get-me-failed", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
3231 return extension.GetValueResponse_INTERNAL_ERROR, err
3232 }
3233 select {
3234 case meAttributes = <-mm.extendedPmMeChan:
3235 logger.Debugw(ctx, "received-extended-pm-data",
3236 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
3237 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
3238 logger.Errorw(ctx, "timeout-waiting-for-omci-get-response-for-received-extended-pm-data",
3239 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
3240 return extension.GetValueResponse_TIMEOUT, fmt.Errorf("timeout-waiting-for-omci-get-response-for-received-extended-pm-data")
3241 }
3242 if mm.supportedEthernetFrameExtendedPMClass == me.EthernetFrameExtendedPmClassID {
3243 mask := mm.getEthFrameExtPMDataFromResponse(ctx, ethFrameExtPMData, meAttributes, requestedAttributesMask)
3244 *sumReceivedMask += mask
3245 logger.Debugw(ctx, "data-received-for-ethernet-frame-ext-pm", log.Fields{"data": ethFrameExtPMData, "entityID": entityID})
3246 } else {
3247 mask := mm.getEthFrameExtPM64BitDataFromResponse(ctx, ethFrameExtPMData, meAttributes, requestedAttributesMask)
3248 *sumReceivedMask += mask
3249 logger.Debugw(ctx, "data-received-for-ethernet-frame-ext-pm", log.Fields{"data": ethFrameExtPMData, "entityID": entityID})
3250 }
3251
3252 return extension.GetValueResponse_REASON_UNDEFINED, nil
3253}
3254
3255func (mm *onuMetricsManager) fillAllErrorCountersEthernetFrameExtendedPM(ethFrameExtPMData map[string]uint64) {
3256 sourceMap := maskToEthernetFrameExtendedPM64Bit
3257 errorCounterValue := UnsupportedCounterValue64bit
3258 if mm.supportedEthernetFrameExtendedPMClass == me.EthernetFrameExtendedPmClassID {
3259 sourceMap = maskToEthernetFrameExtendedPM32Bit
3260 errorCounterValue = UnsupportedCounterValue32bit
3261 }
3262 for _, value := range sourceMap {
3263 for _, k := range value {
3264 if _, ok := ethFrameExtPMData[k]; !ok {
3265 ethFrameExtPMData[k] = errorCounterValue
3266 }
3267 }
3268 }
3269}
3270
3271// nolint: gocyclo
3272func (mm *onuMetricsManager) getEthFrameExtPMDataFromResponse(ctx context.Context, ethFrameExtPMData map[string]uint64, meAttributes me.AttributeValueMap, requestedAttributesMask uint16) uint16 {
3273 receivedMask := uint16(0)
3274 switch requestedAttributesMask {
3275 case 0x3F00:
3276 for _, k := range maskToEthernetFrameExtendedPM32Bit[requestedAttributesMask] {
3277 if _, ok := ethFrameExtPMData[k]; !ok {
3278 switch k {
3279 case "drop_events":
3280 if val, ok := meAttributes[dropEvents]; ok && val != nil {
3281 ethFrameExtPMData[k] = uint64(val.(uint32))
3282 receivedMask |= 0x2000
3283 } else if !ok {
3284 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3285 }
3286 case "octets":
3287 if val, ok := meAttributes[octets]; ok && val != nil {
3288 ethFrameExtPMData[k] = uint64(val.(uint32))
3289 receivedMask |= 0x1000
3290 } else if !ok {
3291 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3292 }
3293 case "frames":
3294 if val, ok := meAttributes[frames]; ok && val != nil {
3295 ethFrameExtPMData[k] = uint64(val.(uint32))
3296 receivedMask |= 0x800
3297 } else if !ok {
3298 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3299 }
3300 case "broadcast_frames":
3301 if val, ok := meAttributes[broadcastFrames]; ok && val != nil {
3302 ethFrameExtPMData[k] = uint64(val.(uint32))
3303 receivedMask |= 0x400
3304 } else if !ok {
3305 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3306 }
3307 case "multicast_frames":
3308 if val, ok := meAttributes[multicastFrames]; ok && val != nil {
3309 ethFrameExtPMData[k] = uint64(val.(uint32))
3310 receivedMask |= 0x200
3311 } else if !ok {
3312 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3313 }
3314 case "crc_errored_frames":
3315 if val, ok := meAttributes[crcErroredFrames]; ok && val != nil {
3316 ethFrameExtPMData[k] = uint64(val.(uint32))
3317 receivedMask |= 0x100
3318 } else if !ok {
3319 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3320 }
3321 default:
3322 //do nothing
3323 }
3324 }
3325 }
3326 case 0x00FC:
3327 for _, k := range maskToEthernetFrameExtendedPM32Bit[requestedAttributesMask] {
3328 if _, ok := ethFrameExtPMData[k]; !ok {
3329 switch k {
3330 case "undersize_frames":
3331 if val, ok := meAttributes[undersizeFrames]; ok && val != nil {
3332 ethFrameExtPMData[k] = uint64(val.(uint32))
3333 receivedMask |= 0x80
3334 } else if !ok {
3335 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3336 }
3337 case "oversize_frames":
3338 if val, ok := meAttributes[oversizeFrames]; ok && val != nil {
3339 ethFrameExtPMData[k] = uint64(val.(uint32))
3340 receivedMask |= 0x40
3341 } else if !ok {
3342 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3343 }
3344 case "64_octets":
3345 if val, ok := meAttributes[frames64Octets]; ok && val != nil {
3346 ethFrameExtPMData[k] = uint64(val.(uint32))
3347 receivedMask |= 0x20
3348 } else if !ok {
3349 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3350 }
3351 case "65_to_127_octets":
3352 if val, ok := meAttributes[frames65To127Octets]; ok && val != nil {
3353 ethFrameExtPMData[k] = uint64(val.(uint32))
3354 receivedMask |= 0x10
3355 } else if !ok {
3356 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3357 }
3358 case "128_to_255_octets":
3359 if val, ok := meAttributes[frames128To255Octets]; ok && val != nil {
3360 ethFrameExtPMData[k] = uint64(val.(uint32))
3361 receivedMask |= 0x8
3362 } else if !ok {
3363 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3364 }
3365 case "256_to_511_octets":
3366 if val, ok := meAttributes[frames256To511Octets]; ok && val != nil {
3367 ethFrameExtPMData[k] = uint64(val.(uint32))
3368 receivedMask |= 0x4
3369 } else if !ok {
3370 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3371 }
3372 default:
3373 //do nothing
3374 }
3375 }
3376 }
3377 case 0x0003:
3378 for _, k := range maskToEthernetFrameExtendedPM32Bit[requestedAttributesMask] {
3379 if _, ok := ethFrameExtPMData[k]; !ok {
3380 switch k {
3381 case "512_to_1023_octets":
3382 if val, ok := meAttributes[frames512To1023Octets]; ok && val != nil {
3383 ethFrameExtPMData[k] = uint64(val.(uint32))
3384 receivedMask |= 0x2
3385 } else if !ok {
3386 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3387 }
3388 case "1024_to_1518_octets":
3389 if val, ok := meAttributes[frames1024To1518Octets]; ok && val != nil {
3390 ethFrameExtPMData[k] = uint64(val.(uint32))
3391 receivedMask |= 0x1
3392 } else if !ok {
3393 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3394 }
3395 default:
3396 //do nothing
3397 }
3398 }
3399 }
3400 default:
3401 //do nothing
3402 }
3403 return receivedMask
3404}
3405
3406// nolint: gocyclo
3407func (mm *onuMetricsManager) getEthFrameExtPM64BitDataFromResponse(ctx context.Context, ethFrameExtPMData map[string]uint64, meAttributes me.AttributeValueMap, requestedAttributesMask uint16) uint16 {
3408 receivedMask := uint16(0)
3409 switch requestedAttributesMask {
3410 case 0x3800:
3411 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3412 if _, ok := ethFrameExtPMData[k]; !ok {
3413 switch k {
3414 case "drop_events":
3415 if val, ok := meAttributes[dropEvents]; ok && val != nil {
3416 ethFrameExtPMData[k] = val.(uint64)
3417 receivedMask |= 0x2000
3418 } else if !ok {
3419 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3420 }
3421 case "octets":
3422 if val, ok := meAttributes[octets]; ok && val != nil {
3423 ethFrameExtPMData[k] = val.(uint64)
3424 receivedMask |= 0x1000
3425 } else if !ok {
3426 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3427 }
3428 case "frames":
3429 if val, ok := meAttributes[frames]; ok && val != nil {
3430 ethFrameExtPMData[k] = val.(uint64)
3431 receivedMask |= 0x800
3432 } else if !ok {
3433 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3434 }
3435 }
3436 }
3437 }
3438 case 0x0700:
3439 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3440 if _, ok := ethFrameExtPMData[k]; !ok {
3441 switch k {
3442 case "broadcast_frames":
3443 if val, ok := meAttributes[broadcastFrames]; ok && val != nil {
3444 ethFrameExtPMData[k] = val.(uint64)
3445 receivedMask |= 0x400
3446 } else if !ok {
3447 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3448 }
3449 case "multicast_frames":
3450 if val, ok := meAttributes[multicastFrames]; ok && val != nil {
3451 ethFrameExtPMData[k] = val.(uint64)
3452 receivedMask |= 0x200
3453 } else if !ok {
3454 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3455 }
3456 case "crc_errored_frames":
3457 if val, ok := meAttributes[crcErroredFrames]; ok && val != nil {
3458 ethFrameExtPMData[k] = val.(uint64)
3459 receivedMask |= 0x100
3460 } else if !ok {
3461 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3462 }
3463 }
3464 }
3465 }
3466 case 0x00E0:
3467 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3468 if _, ok := ethFrameExtPMData[k]; !ok {
3469 switch k {
3470 case "undersize_frames":
3471 if val, ok := meAttributes[undersizeFrames]; ok && val != nil {
3472 ethFrameExtPMData[k] = val.(uint64)
3473 receivedMask |= 0x80
3474 } else if !ok {
3475 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3476 }
3477 case "oversize_frames":
3478 if val, ok := meAttributes[oversizeFrames]; ok && val != nil {
3479 ethFrameExtPMData[k] = val.(uint64)
3480 receivedMask |= 0x40
3481 } else if !ok {
3482 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3483 }
3484 case "64_octets":
3485 if val, ok := meAttributes[frames64Octets]; ok && val != nil {
3486 ethFrameExtPMData[k] = val.(uint64)
3487 receivedMask |= 0x20
3488 } else if !ok {
3489 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3490 }
3491 }
3492 }
3493 }
3494 case 0x001C:
3495 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3496 if _, ok := ethFrameExtPMData[k]; !ok {
3497 switch k {
3498 case "65_to_127_octets":
3499 if val, ok := meAttributes[frames65To127Octets]; ok && val != nil {
3500 ethFrameExtPMData[k] = val.(uint64)
3501 receivedMask |= 0x10
3502 } else if !ok {
3503 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3504 }
3505 case "128_to_255_octets":
3506 if val, ok := meAttributes[frames128To255Octets]; ok && val != nil {
3507 ethFrameExtPMData[k] = val.(uint64)
3508 receivedMask |= 0x8
3509 } else if !ok {
3510 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3511 }
3512 case "256_to_511_octets":
3513 if val, ok := meAttributes[frames256To511Octets]; ok && val != nil {
3514 ethFrameExtPMData[k] = val.(uint64)
3515 receivedMask |= 0x4
3516 } else if !ok {
3517 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3518 }
3519 default:
3520 //do nothing
3521 }
3522 }
3523 }
3524 case 0x0003:
3525 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3526 if _, ok := ethFrameExtPMData[k]; !ok {
3527 switch k {
3528 case "512_to_1023_octets":
3529 if val, ok := meAttributes[frames512To1023Octets]; ok && val != nil {
3530 ethFrameExtPMData[k] = val.(uint64)
3531 receivedMask |= 0x2
3532 } else if !ok {
3533 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3534 }
3535 case "1024_to_1518_octets":
3536 if val, ok := meAttributes[frames1024To1518Octets]; ok && val != nil {
3537 ethFrameExtPMData[k] = val.(uint64)
3538 receivedMask |= 0x1
3539 } else if !ok {
3540 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3541 }
3542 default:
3543 //do nothing
3544 }
3545 }
3546 }
3547 }
3548 return receivedMask
3549}
3550
3551func (mm *onuMetricsManager) aggregateEthernetFrameExtendedPM(pmDataIn map[string]uint64, pmData extension.OmciEthernetFrameExtendedPm, aggregate bool) extension.OmciEthernetFrameExtendedPm {
3552 mm.onuEthernetFrameExtendedPmLock.Lock()
3553 defer mm.onuEthernetFrameExtendedPmLock.Unlock()
3554 errorCounterValue := UnsupportedCounterValue64bit
3555 if mm.supportedEthernetFrameExtendedPMClass == me.EthernetFrameExtendedPmClassID {
3556 errorCounterValue = UnsupportedCounterValue32bit
3557 }
3558 var pmDataOut extension.OmciEthernetFrameExtendedPm
3559 if aggregate {
3560 if pmData.DropEvents != errorCounterValue {
3561 pmDataOut.DropEvents = pmData.DropEvents + pmDataIn["drop_events"]
3562 } else {
3563 pmDataOut.DropEvents = pmData.DropEvents
3564 }
3565 if pmData.Octets != errorCounterValue {
3566 pmDataOut.Octets = pmData.Octets + pmDataIn["octets"]
3567 } else {
3568 pmDataOut.Octets = pmData.Octets
3569 }
3570 if pmData.Frames != errorCounterValue {
3571 pmDataOut.Frames = pmData.Frames + pmDataIn["frames"]
3572 } else {
3573 pmDataOut.Frames = pmData.Frames
3574 }
3575 if pmData.BroadcastFrames != errorCounterValue {
3576 pmDataOut.BroadcastFrames = pmData.BroadcastFrames + pmDataIn["broadcast_frames"]
3577 } else {
3578 pmDataOut.BroadcastFrames = pmData.BroadcastFrames
3579 }
3580 if pmData.MulticastFrames != errorCounterValue {
3581 pmDataOut.MulticastFrames = pmData.MulticastFrames + pmDataIn["multicast_frames"]
3582 } else {
3583 pmDataOut.MulticastFrames = pmData.MulticastFrames
3584 }
3585 if pmData.CrcErroredFrames != errorCounterValue {
3586 pmDataOut.CrcErroredFrames = pmData.CrcErroredFrames + pmDataIn["crc_errored_frames"]
3587 } else {
3588 pmDataOut.CrcErroredFrames = pmData.CrcErroredFrames
3589 }
3590 if pmData.UndersizeFrames != errorCounterValue {
3591 pmDataOut.UndersizeFrames = pmData.UndersizeFrames + pmDataIn["undersize_frames"]
3592 } else {
3593 pmDataOut.UndersizeFrames = pmData.UndersizeFrames
3594 }
3595 if pmData.OversizeFrames != errorCounterValue {
3596 pmDataOut.OversizeFrames = pmData.OversizeFrames + pmDataIn["oversize_frames"]
3597 } else {
3598 pmDataOut.OversizeFrames = pmData.OversizeFrames
3599 }
3600 if pmData.Frames_64Octets != errorCounterValue {
3601 pmDataOut.Frames_64Octets = pmData.Frames_64Octets + pmDataIn["64_octets"]
3602 } else {
3603 pmDataOut.Frames_64Octets = pmData.Frames_64Octets
3604 }
3605 if pmData.Frames_65To_127Octets != errorCounterValue {
3606 pmDataOut.Frames_65To_127Octets = pmData.Frames_65To_127Octets + pmDataIn["65_to_127_octets"]
3607 } else {
3608 pmDataOut.Frames_65To_127Octets = pmData.Frames_65To_127Octets
3609 }
3610 if pmData.Frames_128To_255Octets != errorCounterValue {
3611 pmDataOut.Frames_128To_255Octets = pmData.Frames_128To_255Octets + pmDataIn["128_to_255_octets"]
3612 } else {
3613 pmDataOut.Frames_128To_255Octets = pmData.Frames_128To_255Octets
3614 }
3615 if pmData.Frames_256To_511Octets != errorCounterValue {
3616 pmDataOut.Frames_256To_511Octets = pmData.Frames_256To_511Octets + pmDataIn["256_to_511_octets"]
3617 } else {
3618 pmDataOut.Frames_256To_511Octets = pmData.Frames_256To_511Octets
3619 }
3620 if pmData.Frames_512To_1023Octets != errorCounterValue {
3621 pmDataOut.Frames_512To_1023Octets = pmData.Frames_512To_1023Octets + pmDataIn["512_to_1023_octets"]
3622 } else {
3623 pmDataOut.Frames_512To_1023Octets = pmData.Frames_512To_1023Octets
3624 }
3625 if pmData.Frames_1024To_1518Octets != errorCounterValue {
3626 pmDataOut.Frames_1024To_1518Octets = pmData.Frames_1024To_1518Octets + pmDataIn["1024_to_1518_octets"]
3627 } else {
3628 pmDataOut.Frames_1024To_1518Octets = pmData.Frames_1024To_1518Octets
3629 }
3630 } else {
3631 pmDataOut.DropEvents = pmDataIn["drop_events"]
3632 pmDataOut.Octets = pmDataIn["octets"]
3633 pmDataOut.Frames = pmDataIn["frames"]
3634 pmDataOut.BroadcastFrames = pmDataIn["broadcast_frames"]
3635 pmDataOut.MulticastFrames = pmDataIn["multicast_frames"]
3636 pmDataOut.CrcErroredFrames = pmDataIn["crc_errored_frames"]
3637 pmDataOut.UndersizeFrames = pmDataIn["undersize_frames"]
3638 pmDataOut.OversizeFrames = pmDataIn["oversize_frames"]
3639 pmDataOut.Frames_64Octets = pmDataIn["64_octets"]
3640 pmDataOut.Frames_65To_127Octets = pmDataIn["65_to_127_octets"]
3641 pmDataOut.Frames_128To_255Octets = pmDataIn["128_to_255_octets"]
3642 pmDataOut.Frames_256To_511Octets = pmDataIn["256_to_511_octets"]
3643 pmDataOut.Frames_512To_1023Octets = pmDataIn["512_to_1023_octets"]
3644 pmDataOut.Frames_1024To_1518Octets = pmDataIn["1024_to_1518_octets"]
3645 }
3646 return pmDataOut
3647}
3648
3649func (mm *onuMetricsManager) getControlBlockForExtendedPMDirection(ctx context.Context, upstream bool, entityID uint16) []uint16 {
3650 controlBlock := make([]uint16, 8)
3651 // Control Block First two bytes are for threshold data 1/2 id - does not matter here
3652 controlBlock[0] = 0
3653 // Next two bytes are for the parent class ID
3654 controlBlock[1] = (uint16)(me.PhysicalPathTerminationPointEthernetUniClassID)
3655 // Next two bytes are for the parent me instance id
3656 controlBlock[2] = entityID
3657 // Next two bytes are for accumulation disable
3658 controlBlock[3] = 0
3659 // Next two bytes are for tca disable
3660 controlBlock[4] = 0x4000 //tca global disable
3661 // Next two bytes are for control fields - bit 1(lsb) as 1 for continuous accumulation and bit 2(0 for upstream)
3662 if upstream {
3663 controlBlock[5] = 1 << 0
3664 } else {
3665 controlBlock[5] = (1 << 0) | (1 << 1)
3666 }
3667 // Next two bytes are for tci - does not matter here
3668 controlBlock[6] = 0
3669 // Next two bytes are for reserved bits - does not matter here
3670 controlBlock[7] = 0
3671 return controlBlock
3672}