blob: c2a2ffbbad61d2dac597fb73c4922c232f2516cb [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"
khenaidoo7d3c5582021-08-11 18:09:44 -040031 "github.com/opencord/voltha-lib-go/v7/pkg/db"
32 "github.com/opencord/voltha-lib-go/v7/pkg/db/kvstore"
33 "github.com/opencord/voltha-lib-go/v7/pkg/log"
34 "github.com/opencord/voltha-protos/v5/go/extension"
35 "github.com/opencord/voltha-protos/v5/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 Chawlac77d5372021-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 Chawlac77d5372021-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 Chawlac77d5372021-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 Chawlac77d5372021-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
2962 key := fmt.Sprintf("%s/%s/%s", mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersVendorID,
2963 mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersEquipmentID,
2964 mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersActiveSwVersion)
2965 Value, err := mm.extPmKvStore.Get(ctx, key)
2966 if err == nil {
2967 if Value != nil {
2968 logger.Debugw(ctx, "me-type-read",
2969 log.Fields{"key": Value.Key, "device-id": mm.pDeviceHandler.deviceID})
2970 tmpBytes, _ := kvstore.ToByte(Value.Value)
2971
2972 if err = json.Unmarshal(tmpBytes, &data); err != nil {
2973 logger.Errorw(ctx, "unable-to-unmarshal-data", log.Fields{"error": err, "device-id": mm.pDeviceHandler.deviceID})
2974 return false, err
2975 }
2976 logger.Debugw(ctx, "me-ext-pm-class-data", log.Fields{"class-id": data, "device-id": mm.pDeviceHandler.deviceID})
2977 // We have found the data from db, no need to get through omci get message.
2978 mm.supportedEthernetFrameExtendedPMClass = data
2979 return true, nil
2980 }
2981 logger.Debugw(ctx, "no-me-ext-pm-class-data-found", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2982 return false, nil
2983 }
2984 logger.Errorw(ctx, "unable-to-read-from-kv-store", log.Fields{"device-id": mm.pDeviceHandler.deviceID})
2985 return false, err
2986}
2987
2988func (mm *onuMetricsManager) waitForEthernetFrameCreateOrDeleteResponseOrTimeout(ctx context.Context, create bool, instID uint16, meClassID me.ClassID, upstream bool) (bool, error) {
2989 logger.Debugw(ctx, "wait-for-ethernet-frame-create-or-delete-response-or-timeout", log.Fields{"create": create, "instID": instID, "meClassID": meClassID})
2990 select {
2991 case resp := <-mm.extendedPMCreateOrDeleteResponseChan:
2992 logger.Debugw(ctx, "received-extended-pm-me-response",
2993 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "create": create, "meClassID": meClassID, "instID": instID, "upstream": upstream})
2994 // If the result is me.InstanceExists it means the entity was already created. It is ok handled that as success
2995 if resp == me.Success || resp == me.InstanceExists {
2996 return true, nil
2997 } else if resp == me.UnknownEntity || resp == me.ParameterError ||
2998 resp == me.ProcessingError || resp == me.NotSupported || resp == me.AttributeFailure {
2999 return false, fmt.Errorf("not-supported-me--resp-code-%v", resp)
3000 } else {
3001 logger.Warnw(ctx, "failed to create me", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": resp, "class-id": meClassID, "instID": instID, "upstream": upstream})
3002 return true, fmt.Errorf("error-while-creating-me--resp-code-%v", resp)
3003 }
3004 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
3005 logger.Errorw(ctx, "timeout-waiting-for-ext-pm-me-response",
3006 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "resp": false, "create": create, "meClassID": meClassID, "instID": instID, "upstream": upstream})
3007 }
3008 return false, fmt.Errorf("timeout-while-waiting-for-response")
3009}
3010
3011func (mm *onuMetricsManager) tryCreateExtPmMe(ctx context.Context, meType me.ClassID) (bool, error) {
3012 cnt := 0
Himani Chawla43f95ff2021-06-03 00:24:12 +05303013 // Create ME twice, one for each direction. Boolean true is used to indicate upstream and false for downstream.
Himani Chawlac77d5372021-07-12 15:42:26 +05303014 for _, direction := range []bool{true, false} {
Himani Chawla43f95ff2021-06-03 00:24:12 +05303015 for _, uniPort := range mm.pDeviceHandler.uniEntityMap {
3016 var entityID uint16
3017 if direction {
3018 entityID = uniPort.entityID + 0x100
3019 } else {
3020 entityID = uniPort.entityID
3021 }
3022
3023 // parent entity id will be same for both direction
3024 controlBlock := mm.getControlBlockForExtendedPMDirection(ctx, direction, uniPort.entityID)
3025
3026 inner1:
3027 // retry ExtendedPmCreateAttempts times to create the instance of PM
3028 for cnt = 0; cnt < ExtendedPmCreateAttempts; cnt++ {
3029 meEnt, err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendCreateOrDeleteEthernetFrameExtendedPMME(
3030 ctx, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, direction, true,
3031 mm.pAdaptFsm.commChan, entityID, meType, controlBlock)
3032 if err != nil {
3033 logger.Errorw(ctx, "EthernetFrameExtendedPMME-create-or-delete-failed",
3034 log.Fields{"device-id": mm.pDeviceHandler.deviceID})
3035 return false, err
3036 }
3037 if supported, err := mm.waitForEthernetFrameCreateOrDeleteResponseOrTimeout(ctx, true, entityID, meType, direction); err == nil && supported {
3038 if direction {
Himani Chawlac77d5372021-07-12 15:42:26 +05303039 mm.ethernetFrameExtendedPmUpStreamMEByEntityID[entityID] = meEnt
Himani Chawla43f95ff2021-06-03 00:24:12 +05303040 } else {
Himani Chawlac77d5372021-07-12 15:42:26 +05303041 mm.ethernetFrameExtendedPmDownStreamMEByEntityID[entityID] = meEnt
Himani Chawla43f95ff2021-06-03 00:24:12 +05303042 }
3043 break inner1
3044 } else if err != nil {
3045 if !supported {
3046 // Need to return immediately
3047 return false, err
3048 }
3049 //In case of failure, go for a retry
3050 }
3051 }
3052 if cnt == ExtendedPmCreateAttempts {
3053 logger.Error(ctx, "exceeded-attempts-while-creating-me-for-ethernet-frame-extended-pm")
3054 return true, fmt.Errorf("unable-to-create-me")
3055 }
3056 }
3057 }
3058 return true, nil
3059}
3060
3061func (mm *onuMetricsManager) putExtPmMeKvStore(ctx context.Context) {
3062 key := fmt.Sprintf("%s/%s/%s", mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersVendorID,
3063 mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersEquipmentID,
3064 mm.pDeviceHandler.pOnuOmciDevice.sOnuPersistentData.PersActiveSwVersion)
3065 // check if we get the supported type me for ethernet frame extended pm class id
3066 if mm.supportedEthernetFrameExtendedPMClass == 0 {
3067 logger.Error(ctx, "unable-to-get-any-supported-extended-pm-me-class")
3068 }
3069 classSupported, err := json.Marshal(mm.supportedEthernetFrameExtendedPMClass)
3070 if err != nil {
3071 logger.Errorw(ctx, "unable-to-marshal-data", log.Fields{"err": err})
3072 }
3073 if err := mm.extPmKvStore.Put(ctx, key, classSupported); err != nil {
3074 logger.Errorw(ctx, "unable-to-add-data-in-db", log.Fields{"err": err})
3075 }
3076}
3077
3078func (mm *onuMetricsManager) setAllExtPmMeCreatedFlag() {
3079 mm.onuEthernetFrameExtendedPmLock.Lock()
3080 mm.isDeviceReadyToCollectExtendedPmStats = true
3081 mm.onuEthernetFrameExtendedPmLock.Unlock()
3082}
3083func (mm *onuMetricsManager) createEthernetFrameExtendedPMME(ctx context.Context) {
3084 //get the type of extended frame pm me supported by onu first
3085 exist, err := mm.getEthernetFrameExtendedMETypeFromKvStore(ctx)
3086 if err != nil {
3087 logger.Error(ctx, "unable-to-get-supported-me-for-ethernet-frame-extended-pm")
3088 return
3089 }
3090 if exist {
3091 // we have the me type, go ahead with the me type supported.
3092 if _, err := mm.tryCreateExtPmMe(ctx, mm.supportedEthernetFrameExtendedPMClass); err != nil {
3093 logger.Errorw(ctx, "unable-to-create-me-type", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
3094 "meClassID": mm.supportedEthernetFrameExtendedPMClass})
3095 return
3096 }
3097 mm.setAllExtPmMeCreatedFlag()
3098 return
3099 }
3100 // First try with 64 bit me
3101 // we have the me type, go ahead with the me type supported.
3102 supported64Bit, err := mm.tryCreateExtPmMe(ctx, me.EthernetFrameExtendedPm64BitClassID)
3103 if err != nil && !supported64Bit {
3104 logger.Errorw(ctx, "unable-to-create-me-type-as-it-is-not-supported",
3105 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "meClassID": me.EthernetFrameExtendedPm64BitClassID,
3106 "supported": supported64Bit})
3107 // Then Try with 32 bit type
3108 if supported32Bit, err := mm.tryCreateExtPmMe(ctx, me.EthernetFrameExtendedPmClassID); err != nil {
3109 logger.Errorw(ctx, "unable-to-create-me-type", log.Fields{"device-id": mm.pDeviceHandler.deviceID,
3110 "meClassID": me.EthernetFrameExtendedPmClassID, "supported": supported32Bit})
3111 } else if supported32Bit {
3112 mm.supportedEthernetFrameExtendedPMClass = me.EthernetFrameExtendedPmClassID
3113 mm.putExtPmMeKvStore(ctx)
3114 mm.setAllExtPmMeCreatedFlag()
3115 }
3116 } else if err == nil && supported64Bit {
3117 mm.supportedEthernetFrameExtendedPMClass = me.EthernetFrameExtendedPm64BitClassID
3118 mm.putExtPmMeKvStore(ctx)
3119 mm.setAllExtPmMeCreatedFlag()
3120 }
3121}
3122
3123func (mm *onuMetricsManager) collectEthernetFrameExtendedPMCounters(ctx context.Context) *extension.SingleGetValueResponse {
3124 errFunc := func(reason extension.GetValueResponse_ErrorReason) *extension.SingleGetValueResponse {
3125 return &extension.SingleGetValueResponse{
3126 Response: &extension.GetValueResponse{
3127 Status: extension.GetValueResponse_ERROR,
3128 ErrReason: reason,
3129 },
3130 }
3131 }
3132 mm.onuEthernetFrameExtendedPmLock.RLock()
3133 if !mm.isDeviceReadyToCollectExtendedPmStats {
3134 mm.onuEthernetFrameExtendedPmLock.RUnlock()
3135 return errFunc(extension.GetValueResponse_INTERNAL_ERROR)
3136 }
3137 mm.onuEthernetFrameExtendedPmLock.RUnlock()
3138 // Collect metrics for upstream for all the PM Mes per uni port and aggregate
3139 var pmUpstream extension.OmciEthernetFrameExtendedPm
3140 var pmDownstream extension.OmciEthernetFrameExtendedPm
Himani Chawlac77d5372021-07-12 15:42:26 +05303141 for entityID, meEnt := range mm.ethernetFrameExtendedPmUpStreamMEByEntityID {
Himani Chawla43f95ff2021-06-03 00:24:12 +05303142 var receivedMask uint16
3143 if metricInfo, errResp := mm.collectEthernetFrameExtendedPMData(ctx, meEnt, entityID, true, &receivedMask); metricInfo != nil { // upstream
3144 if receivedMask == 0 {
3145 pmUpstream = mm.aggregateEthernetFrameExtendedPM(metricInfo, pmUpstream, false)
3146 logger.Error(ctx, "all-the-attributes-of-ethernet-frame-extended-pm-counters-are-unsupported")
3147 pmDownstream = pmUpstream
3148 singleValResp := extension.SingleGetValueResponse{
3149 Response: &extension.GetValueResponse{
3150 Status: extension.GetValueResponse_OK,
3151 Response: &extension.GetValueResponse_OnuCounters{
3152 OnuCounters: &extension.GetOmciEthernetFrameExtendedPmResponse{
3153 Upstream: &pmUpstream,
3154 Downstream: &pmDownstream,
3155 },
3156 },
3157 },
3158 }
3159 return &singleValResp
3160 }
3161 // Aggregate the result for upstream
3162 pmUpstream = mm.aggregateEthernetFrameExtendedPM(metricInfo, pmUpstream, true)
3163 } else {
3164 return errFunc(errResp)
3165 }
3166 }
3167
Himani Chawlac77d5372021-07-12 15:42:26 +05303168 for entityID, meEnt := range mm.ethernetFrameExtendedPmDownStreamMEByEntityID {
Himani Chawla43f95ff2021-06-03 00:24:12 +05303169 var receivedMask uint16
3170 if metricInfo, errResp := mm.collectEthernetFrameExtendedPMData(ctx, meEnt, entityID, false, &receivedMask); metricInfo != nil { // downstream
3171 // Aggregate the result for downstream
3172 pmDownstream = mm.aggregateEthernetFrameExtendedPM(metricInfo, pmDownstream, true)
3173 } else {
3174 return errFunc(errResp)
3175 }
3176 }
3177 singleValResp := extension.SingleGetValueResponse{
3178 Response: &extension.GetValueResponse{
3179 Status: extension.GetValueResponse_OK,
3180 Response: &extension.GetValueResponse_OnuCounters{
3181 OnuCounters: &extension.GetOmciEthernetFrameExtendedPmResponse{
3182 Upstream: &pmUpstream,
3183 Downstream: &pmDownstream,
3184 },
3185 },
3186 },
3187 }
3188 return &singleValResp
3189}
3190
3191func (mm *onuMetricsManager) collectEthernetFrameExtendedPMData(ctx context.Context, meEnt *me.ManagedEntity, entityID uint16, upstream bool, receivedMask *uint16) (map[string]uint64, extension.GetValueResponse_ErrorReason) {
3192 var classID me.ClassID
3193 logger.Debugw(ctx, "collecting-data-for-ethernet-frame-extended-pm", log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "upstream": upstream})
3194
3195 classID = mm.supportedEthernetFrameExtendedPMClass
3196 attributeMaskList := maskToEthernetFrameExtendedPM64Bit
3197 if classID == me.EthernetFrameExtendedPmClassID {
3198 attributeMaskList = maskToEthernetFrameExtendedPM32Bit
3199 }
3200 ethPMData := make(map[string]uint64)
3201 var sumReceivedMask uint16
3202 for mask := range attributeMaskList {
3203 if errResp, err := mm.populateEthernetFrameExtendedPMMetrics(ctx, classID, entityID, mask, ethPMData, upstream, &sumReceivedMask); err != nil {
3204 logger.Errorw(ctx, "error-during-metric-collection",
3205 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "entityID": entityID, "err": err})
3206 return nil, errResp
3207 }
3208 if (mask == 0x3F00 || mask == 0x3800) && sumReceivedMask == 0 {
3209 //It means the first attributes fetch was a failure, hence instead of sending multiple failure get requests
3210 //populate all counters as failure and return
3211 mm.fillAllErrorCountersEthernetFrameExtendedPM(ethPMData)
3212 break
3213 }
3214 }
3215 *receivedMask = sumReceivedMask
3216 return ethPMData, extension.GetValueResponse_REASON_UNDEFINED
3217}
3218
3219// nolint: gocyclo
3220func (mm *onuMetricsManager) populateEthernetFrameExtendedPMMetrics(ctx context.Context, classID me.ClassID, entityID uint16,
3221 requestedAttributesMask uint16, ethFrameExtPMData map[string]uint64, upstream bool, sumReceivedMask *uint16) (extension.GetValueResponse_ErrorReason, error) {
3222 var meAttributes me.AttributeValueMap
3223 logger.Debugw(ctx, "requesting-attributes", log.Fields{"attributes-mask": requestedAttributesMask, "entityID": entityID, "classID": classID})
3224 err := mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.sendGetMeWithAttributeMask(ctx, classID, entityID, requestedAttributesMask, mm.pDeviceHandler.pOpenOnuAc.omciTimeout, true, mm.pAdaptFsm.commChan)
3225 if err != nil {
3226 logger.Errorw(ctx, "get-me-failed", log.Fields{"device-id": mm.pAdaptFsm.deviceID})
3227 return extension.GetValueResponse_INTERNAL_ERROR, err
3228 }
3229 select {
3230 case meAttributes = <-mm.extendedPmMeChan:
3231 logger.Debugw(ctx, "received-extended-pm-data",
3232 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
3233 case <-time.After(mm.pDeviceHandler.pOnuOmciDevice.PDevOmciCC.GetMaxOmciTimeoutWithRetries() * time.Second):
3234 logger.Errorw(ctx, "timeout-waiting-for-omci-get-response-for-received-extended-pm-data",
3235 log.Fields{"device-id": mm.pDeviceHandler.deviceID, "upstream": upstream, "entityID": entityID})
3236 return extension.GetValueResponse_TIMEOUT, fmt.Errorf("timeout-waiting-for-omci-get-response-for-received-extended-pm-data")
3237 }
3238 if mm.supportedEthernetFrameExtendedPMClass == me.EthernetFrameExtendedPmClassID {
3239 mask := mm.getEthFrameExtPMDataFromResponse(ctx, ethFrameExtPMData, meAttributes, requestedAttributesMask)
3240 *sumReceivedMask += mask
3241 logger.Debugw(ctx, "data-received-for-ethernet-frame-ext-pm", log.Fields{"data": ethFrameExtPMData, "entityID": entityID})
3242 } else {
3243 mask := mm.getEthFrameExtPM64BitDataFromResponse(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 }
3247
3248 return extension.GetValueResponse_REASON_UNDEFINED, nil
3249}
3250
3251func (mm *onuMetricsManager) fillAllErrorCountersEthernetFrameExtendedPM(ethFrameExtPMData map[string]uint64) {
3252 sourceMap := maskToEthernetFrameExtendedPM64Bit
3253 errorCounterValue := UnsupportedCounterValue64bit
3254 if mm.supportedEthernetFrameExtendedPMClass == me.EthernetFrameExtendedPmClassID {
3255 sourceMap = maskToEthernetFrameExtendedPM32Bit
3256 errorCounterValue = UnsupportedCounterValue32bit
3257 }
3258 for _, value := range sourceMap {
3259 for _, k := range value {
3260 if _, ok := ethFrameExtPMData[k]; !ok {
3261 ethFrameExtPMData[k] = errorCounterValue
3262 }
3263 }
3264 }
3265}
3266
3267// nolint: gocyclo
3268func (mm *onuMetricsManager) getEthFrameExtPMDataFromResponse(ctx context.Context, ethFrameExtPMData map[string]uint64, meAttributes me.AttributeValueMap, requestedAttributesMask uint16) uint16 {
3269 receivedMask := uint16(0)
3270 switch requestedAttributesMask {
3271 case 0x3F00:
3272 for _, k := range maskToEthernetFrameExtendedPM32Bit[requestedAttributesMask] {
3273 if _, ok := ethFrameExtPMData[k]; !ok {
3274 switch k {
3275 case "drop_events":
3276 if val, ok := meAttributes[dropEvents]; ok && val != nil {
3277 ethFrameExtPMData[k] = uint64(val.(uint32))
3278 receivedMask |= 0x2000
3279 } else if !ok {
3280 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3281 }
3282 case "octets":
3283 if val, ok := meAttributes[octets]; ok && val != nil {
3284 ethFrameExtPMData[k] = uint64(val.(uint32))
3285 receivedMask |= 0x1000
3286 } else if !ok {
3287 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3288 }
3289 case "frames":
3290 if val, ok := meAttributes[frames]; ok && val != nil {
3291 ethFrameExtPMData[k] = uint64(val.(uint32))
3292 receivedMask |= 0x800
3293 } else if !ok {
3294 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3295 }
3296 case "broadcast_frames":
3297 if val, ok := meAttributes[broadcastFrames]; ok && val != nil {
3298 ethFrameExtPMData[k] = uint64(val.(uint32))
3299 receivedMask |= 0x400
3300 } else if !ok {
3301 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3302 }
3303 case "multicast_frames":
3304 if val, ok := meAttributes[multicastFrames]; ok && val != nil {
3305 ethFrameExtPMData[k] = uint64(val.(uint32))
3306 receivedMask |= 0x200
3307 } else if !ok {
3308 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3309 }
3310 case "crc_errored_frames":
3311 if val, ok := meAttributes[crcErroredFrames]; ok && val != nil {
3312 ethFrameExtPMData[k] = uint64(val.(uint32))
3313 receivedMask |= 0x100
3314 } else if !ok {
3315 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3316 }
3317 default:
3318 //do nothing
3319 }
3320 }
3321 }
3322 case 0x00FC:
3323 for _, k := range maskToEthernetFrameExtendedPM32Bit[requestedAttributesMask] {
3324 if _, ok := ethFrameExtPMData[k]; !ok {
3325 switch k {
3326 case "undersize_frames":
3327 if val, ok := meAttributes[undersizeFrames]; ok && val != nil {
3328 ethFrameExtPMData[k] = uint64(val.(uint32))
3329 receivedMask |= 0x80
3330 } else if !ok {
3331 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3332 }
3333 case "oversize_frames":
3334 if val, ok := meAttributes[oversizeFrames]; ok && val != nil {
3335 ethFrameExtPMData[k] = uint64(val.(uint32))
3336 receivedMask |= 0x40
3337 } else if !ok {
3338 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3339 }
3340 case "64_octets":
3341 if val, ok := meAttributes[frames64Octets]; ok && val != nil {
3342 ethFrameExtPMData[k] = uint64(val.(uint32))
3343 receivedMask |= 0x20
3344 } else if !ok {
3345 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3346 }
3347 case "65_to_127_octets":
3348 if val, ok := meAttributes[frames65To127Octets]; ok && val != nil {
3349 ethFrameExtPMData[k] = uint64(val.(uint32))
3350 receivedMask |= 0x10
3351 } else if !ok {
3352 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3353 }
3354 case "128_to_255_octets":
3355 if val, ok := meAttributes[frames128To255Octets]; ok && val != nil {
3356 ethFrameExtPMData[k] = uint64(val.(uint32))
3357 receivedMask |= 0x8
3358 } else if !ok {
3359 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3360 }
3361 case "256_to_511_octets":
3362 if val, ok := meAttributes[frames256To511Octets]; ok && val != nil {
3363 ethFrameExtPMData[k] = uint64(val.(uint32))
3364 receivedMask |= 0x4
3365 } else if !ok {
3366 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3367 }
3368 default:
3369 //do nothing
3370 }
3371 }
3372 }
3373 case 0x0003:
3374 for _, k := range maskToEthernetFrameExtendedPM32Bit[requestedAttributesMask] {
3375 if _, ok := ethFrameExtPMData[k]; !ok {
3376 switch k {
3377 case "512_to_1023_octets":
3378 if val, ok := meAttributes[frames512To1023Octets]; ok && val != nil {
3379 ethFrameExtPMData[k] = uint64(val.(uint32))
3380 receivedMask |= 0x2
3381 } else if !ok {
3382 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3383 }
3384 case "1024_to_1518_octets":
3385 if val, ok := meAttributes[frames1024To1518Octets]; ok && val != nil {
3386 ethFrameExtPMData[k] = uint64(val.(uint32))
3387 receivedMask |= 0x1
3388 } else if !ok {
3389 ethFrameExtPMData[k] = UnsupportedCounterValue32bit
3390 }
3391 default:
3392 //do nothing
3393 }
3394 }
3395 }
3396 default:
3397 //do nothing
3398 }
3399 return receivedMask
3400}
3401
3402// nolint: gocyclo
3403func (mm *onuMetricsManager) getEthFrameExtPM64BitDataFromResponse(ctx context.Context, ethFrameExtPMData map[string]uint64, meAttributes me.AttributeValueMap, requestedAttributesMask uint16) uint16 {
3404 receivedMask := uint16(0)
3405 switch requestedAttributesMask {
3406 case 0x3800:
3407 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3408 if _, ok := ethFrameExtPMData[k]; !ok {
3409 switch k {
3410 case "drop_events":
3411 if val, ok := meAttributes[dropEvents]; ok && val != nil {
3412 ethFrameExtPMData[k] = val.(uint64)
3413 receivedMask |= 0x2000
3414 } else if !ok {
3415 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3416 }
3417 case "octets":
3418 if val, ok := meAttributes[octets]; ok && val != nil {
3419 ethFrameExtPMData[k] = val.(uint64)
3420 receivedMask |= 0x1000
3421 } else if !ok {
3422 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3423 }
3424 case "frames":
3425 if val, ok := meAttributes[frames]; ok && val != nil {
3426 ethFrameExtPMData[k] = val.(uint64)
3427 receivedMask |= 0x800
3428 } else if !ok {
3429 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3430 }
3431 }
3432 }
3433 }
3434 case 0x0700:
3435 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3436 if _, ok := ethFrameExtPMData[k]; !ok {
3437 switch k {
3438 case "broadcast_frames":
3439 if val, ok := meAttributes[broadcastFrames]; ok && val != nil {
3440 ethFrameExtPMData[k] = val.(uint64)
3441 receivedMask |= 0x400
3442 } else if !ok {
3443 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3444 }
3445 case "multicast_frames":
3446 if val, ok := meAttributes[multicastFrames]; ok && val != nil {
3447 ethFrameExtPMData[k] = val.(uint64)
3448 receivedMask |= 0x200
3449 } else if !ok {
3450 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3451 }
3452 case "crc_errored_frames":
3453 if val, ok := meAttributes[crcErroredFrames]; ok && val != nil {
3454 ethFrameExtPMData[k] = val.(uint64)
3455 receivedMask |= 0x100
3456 } else if !ok {
3457 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3458 }
3459 }
3460 }
3461 }
3462 case 0x00E0:
3463 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3464 if _, ok := ethFrameExtPMData[k]; !ok {
3465 switch k {
3466 case "undersize_frames":
3467 if val, ok := meAttributes[undersizeFrames]; ok && val != nil {
3468 ethFrameExtPMData[k] = val.(uint64)
3469 receivedMask |= 0x80
3470 } else if !ok {
3471 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3472 }
3473 case "oversize_frames":
3474 if val, ok := meAttributes[oversizeFrames]; ok && val != nil {
3475 ethFrameExtPMData[k] = val.(uint64)
3476 receivedMask |= 0x40
3477 } else if !ok {
3478 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3479 }
3480 case "64_octets":
3481 if val, ok := meAttributes[frames64Octets]; ok && val != nil {
3482 ethFrameExtPMData[k] = val.(uint64)
3483 receivedMask |= 0x20
3484 } else if !ok {
3485 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3486 }
3487 }
3488 }
3489 }
3490 case 0x001C:
3491 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3492 if _, ok := ethFrameExtPMData[k]; !ok {
3493 switch k {
3494 case "65_to_127_octets":
3495 if val, ok := meAttributes[frames65To127Octets]; ok && val != nil {
3496 ethFrameExtPMData[k] = val.(uint64)
3497 receivedMask |= 0x10
3498 } else if !ok {
3499 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3500 }
3501 case "128_to_255_octets":
3502 if val, ok := meAttributes[frames128To255Octets]; ok && val != nil {
3503 ethFrameExtPMData[k] = val.(uint64)
3504 receivedMask |= 0x8
3505 } else if !ok {
3506 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3507 }
3508 case "256_to_511_octets":
3509 if val, ok := meAttributes[frames256To511Octets]; ok && val != nil {
3510 ethFrameExtPMData[k] = val.(uint64)
3511 receivedMask |= 0x4
3512 } else if !ok {
3513 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3514 }
3515 default:
3516 //do nothing
3517 }
3518 }
3519 }
3520 case 0x0003:
3521 for _, k := range maskToEthernetFrameExtendedPM64Bit[requestedAttributesMask] {
3522 if _, ok := ethFrameExtPMData[k]; !ok {
3523 switch k {
3524 case "512_to_1023_octets":
3525 if val, ok := meAttributes[frames512To1023Octets]; ok && val != nil {
3526 ethFrameExtPMData[k] = val.(uint64)
3527 receivedMask |= 0x2
3528 } else if !ok {
3529 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3530 }
3531 case "1024_to_1518_octets":
3532 if val, ok := meAttributes[frames1024To1518Octets]; ok && val != nil {
3533 ethFrameExtPMData[k] = val.(uint64)
3534 receivedMask |= 0x1
3535 } else if !ok {
3536 ethFrameExtPMData[k] = UnsupportedCounterValue64bit
3537 }
3538 default:
3539 //do nothing
3540 }
3541 }
3542 }
3543 }
3544 return receivedMask
3545}
3546
3547func (mm *onuMetricsManager) aggregateEthernetFrameExtendedPM(pmDataIn map[string]uint64, pmData extension.OmciEthernetFrameExtendedPm, aggregate bool) extension.OmciEthernetFrameExtendedPm {
3548 mm.onuEthernetFrameExtendedPmLock.Lock()
3549 defer mm.onuEthernetFrameExtendedPmLock.Unlock()
3550 errorCounterValue := UnsupportedCounterValue64bit
3551 if mm.supportedEthernetFrameExtendedPMClass == me.EthernetFrameExtendedPmClassID {
3552 errorCounterValue = UnsupportedCounterValue32bit
3553 }
3554 var pmDataOut extension.OmciEthernetFrameExtendedPm
3555 if aggregate {
3556 if pmData.DropEvents != errorCounterValue {
3557 pmDataOut.DropEvents = pmData.DropEvents + pmDataIn["drop_events"]
3558 } else {
3559 pmDataOut.DropEvents = pmData.DropEvents
3560 }
3561 if pmData.Octets != errorCounterValue {
3562 pmDataOut.Octets = pmData.Octets + pmDataIn["octets"]
3563 } else {
3564 pmDataOut.Octets = pmData.Octets
3565 }
3566 if pmData.Frames != errorCounterValue {
3567 pmDataOut.Frames = pmData.Frames + pmDataIn["frames"]
3568 } else {
3569 pmDataOut.Frames = pmData.Frames
3570 }
3571 if pmData.BroadcastFrames != errorCounterValue {
3572 pmDataOut.BroadcastFrames = pmData.BroadcastFrames + pmDataIn["broadcast_frames"]
3573 } else {
3574 pmDataOut.BroadcastFrames = pmData.BroadcastFrames
3575 }
3576 if pmData.MulticastFrames != errorCounterValue {
3577 pmDataOut.MulticastFrames = pmData.MulticastFrames + pmDataIn["multicast_frames"]
3578 } else {
3579 pmDataOut.MulticastFrames = pmData.MulticastFrames
3580 }
3581 if pmData.CrcErroredFrames != errorCounterValue {
3582 pmDataOut.CrcErroredFrames = pmData.CrcErroredFrames + pmDataIn["crc_errored_frames"]
3583 } else {
3584 pmDataOut.CrcErroredFrames = pmData.CrcErroredFrames
3585 }
3586 if pmData.UndersizeFrames != errorCounterValue {
3587 pmDataOut.UndersizeFrames = pmData.UndersizeFrames + pmDataIn["undersize_frames"]
3588 } else {
3589 pmDataOut.UndersizeFrames = pmData.UndersizeFrames
3590 }
3591 if pmData.OversizeFrames != errorCounterValue {
3592 pmDataOut.OversizeFrames = pmData.OversizeFrames + pmDataIn["oversize_frames"]
3593 } else {
3594 pmDataOut.OversizeFrames = pmData.OversizeFrames
3595 }
3596 if pmData.Frames_64Octets != errorCounterValue {
3597 pmDataOut.Frames_64Octets = pmData.Frames_64Octets + pmDataIn["64_octets"]
3598 } else {
3599 pmDataOut.Frames_64Octets = pmData.Frames_64Octets
3600 }
3601 if pmData.Frames_65To_127Octets != errorCounterValue {
3602 pmDataOut.Frames_65To_127Octets = pmData.Frames_65To_127Octets + pmDataIn["65_to_127_octets"]
3603 } else {
3604 pmDataOut.Frames_65To_127Octets = pmData.Frames_65To_127Octets
3605 }
3606 if pmData.Frames_128To_255Octets != errorCounterValue {
3607 pmDataOut.Frames_128To_255Octets = pmData.Frames_128To_255Octets + pmDataIn["128_to_255_octets"]
3608 } else {
3609 pmDataOut.Frames_128To_255Octets = pmData.Frames_128To_255Octets
3610 }
3611 if pmData.Frames_256To_511Octets != errorCounterValue {
3612 pmDataOut.Frames_256To_511Octets = pmData.Frames_256To_511Octets + pmDataIn["256_to_511_octets"]
3613 } else {
3614 pmDataOut.Frames_256To_511Octets = pmData.Frames_256To_511Octets
3615 }
3616 if pmData.Frames_512To_1023Octets != errorCounterValue {
3617 pmDataOut.Frames_512To_1023Octets = pmData.Frames_512To_1023Octets + pmDataIn["512_to_1023_octets"]
3618 } else {
3619 pmDataOut.Frames_512To_1023Octets = pmData.Frames_512To_1023Octets
3620 }
3621 if pmData.Frames_1024To_1518Octets != errorCounterValue {
3622 pmDataOut.Frames_1024To_1518Octets = pmData.Frames_1024To_1518Octets + pmDataIn["1024_to_1518_octets"]
3623 } else {
3624 pmDataOut.Frames_1024To_1518Octets = pmData.Frames_1024To_1518Octets
3625 }
3626 } else {
3627 pmDataOut.DropEvents = pmDataIn["drop_events"]
3628 pmDataOut.Octets = pmDataIn["octets"]
3629 pmDataOut.Frames = pmDataIn["frames"]
3630 pmDataOut.BroadcastFrames = pmDataIn["broadcast_frames"]
3631 pmDataOut.MulticastFrames = pmDataIn["multicast_frames"]
3632 pmDataOut.CrcErroredFrames = pmDataIn["crc_errored_frames"]
3633 pmDataOut.UndersizeFrames = pmDataIn["undersize_frames"]
3634 pmDataOut.OversizeFrames = pmDataIn["oversize_frames"]
3635 pmDataOut.Frames_64Octets = pmDataIn["64_octets"]
3636 pmDataOut.Frames_65To_127Octets = pmDataIn["65_to_127_octets"]
3637 pmDataOut.Frames_128To_255Octets = pmDataIn["128_to_255_octets"]
3638 pmDataOut.Frames_256To_511Octets = pmDataIn["256_to_511_octets"]
3639 pmDataOut.Frames_512To_1023Octets = pmDataIn["512_to_1023_octets"]
3640 pmDataOut.Frames_1024To_1518Octets = pmDataIn["1024_to_1518_octets"]
3641 }
3642 return pmDataOut
3643}
3644
3645func (mm *onuMetricsManager) getControlBlockForExtendedPMDirection(ctx context.Context, upstream bool, entityID uint16) []uint16 {
3646 controlBlock := make([]uint16, 8)
3647 // Control Block First two bytes are for threshold data 1/2 id - does not matter here
3648 controlBlock[0] = 0
3649 // Next two bytes are for the parent class ID
3650 controlBlock[1] = (uint16)(me.PhysicalPathTerminationPointEthernetUniClassID)
3651 // Next two bytes are for the parent me instance id
3652 controlBlock[2] = entityID
3653 // Next two bytes are for accumulation disable
3654 controlBlock[3] = 0
3655 // Next two bytes are for tca disable
3656 controlBlock[4] = 0x4000 //tca global disable
3657 // Next two bytes are for control fields - bit 1(lsb) as 1 for continuous accumulation and bit 2(0 for upstream)
3658 if upstream {
3659 controlBlock[5] = 1 << 0
3660 } else {
3661 controlBlock[5] = (1 << 0) | (1 << 1)
3662 }
3663 // Next two bytes are for tci - does not matter here
3664 controlBlock[6] = 0
3665 // Next two bytes are for reserved bits - does not matter here
3666 controlBlock[7] = 0
3667 return controlBlock
3668}