blob: 11f45cd917d6b2501db9cc5f242a299d5c0dbb4c [file] [log] [blame]
Chip Boling67b674a2019-02-08 11:42:18 -06001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Zack Williams84a71e92019-11-15 09:00:19 -070015from __future__ import absolute_import, division
Chip Boling67b674a2019-02-08 11:42:18 -060016import arrow
William Kurkianede82e92019-03-05 13:02:57 -050017from voltha_protos.device_pb2 import PmConfig, PmGroupConfig
18from voltha_protos.events_pb2 import MetricInformation, MetricMetaData
Devmalya Paul0d3abf02019-07-31 18:34:27 -040019from pyvoltha.adapters.extensions.events.kpi.adapter_pm_metrics import AdapterPmMetrics
20from pyvoltha.adapters.extensions.events.kpi.onu.onu_pm_interval_metrics import OnuPmIntervalMetrics
Chip Boling67b674a2019-02-08 11:42:18 -060021from pyvoltha.adapters.extensions.omci.omci_entities import UniG
22from pyvoltha.adapters.extensions.omci.omci_entities import PptpEthernetUni
23
24
25class OnuOmciPmMetrics(AdapterPmMetrics):
26 """ ONU OMCI related metrics """
27
28 # Metric default settings
29 #
30 # Frequency values are in 1/10ths of a second
31 #
32 OMCI_DEV_KEY = 'omci-onu-dev'
33 OMCI_CC_GROUP_NAME = 'OMCI_CC'
34 DEFAULT_OMCI_CC_ENABLED = False
35 DEFAULT_OMCI_CC_FREQUENCY = (2 * 60) * 10
36
37 OPTICAL_GROUP_NAME = 'PON_Optical'
38 DEFAULT_OPTICAL_ENABLED = True
39 DEFAULT_OPTICAL_FREQUENCY = (15 * 60 * 10)
40
41 UNI_STATUS_GROUP_NAME = 'UNI_Status'
42 DEFAULT_UNI_STATUS_ENABLED = True
43 DEFAULT_UNI_STATUS_FREQUENCY = (15 * 60 * 10)
44
Devmalya Paul0d3abf02019-07-31 18:34:27 -040045 def __init__(self, event_mgr, core_proxy, device_id, logical_device_id, serial_number,
Chip Boling67b674a2019-02-08 11:42:18 -060046 grouped=False, freq_override=False, **kwargs):
47 """
48 Initializer for shared ONU Device Adapter OMCI CC PM metrics
49
William Kurkian6eda8182019-05-03 15:51:54 -040050 :param core_proxy: (CoreProxy) Core proxy for the device
Chip Boling67b674a2019-02-08 11:42:18 -060051 :param device_id: (str) Device ID
52 :param logical_device_id: (str) VOLTHA Logical Device ID
53 :param grouped: (bool) Flag indicating if statistics are managed as a group
54 :param freq_override: (bool) Flag indicating if frequency collection can be specified
55 on a per group basis
56 :param kwargs: (dict) Device Adapter specific values. For an ONU Device adapter, the
57 expected key-value pairs are listed below. If not provided, the
58 associated PM statistics are not gathered:
59
60 'omci-onu-dev': Reference to the OMCI OnuDeviceEtnry object for
61 retrieval of OpenOMCI Communications channel statistics
62 and retrieval of polled statistics.
63 """
Devmalya Paul0d3abf02019-07-31 18:34:27 -040064 super(OnuOmciPmMetrics, self).__init__(event_mgr, core_proxy, device_id, logical_device_id, serial_number,
Chip Boling67b674a2019-02-08 11:42:18 -060065 grouped=grouped, freq_override=freq_override,
66 **kwargs)
67
68 self._omci_onu_device = kwargs.pop(OnuOmciPmMetrics.OMCI_DEV_KEY, None)
69 self._omci_cc = self._omci_onu_device.omci_cc if self._omci_onu_device is not None else None
70
71 self.omci_cc_pm_names = {
72 ('tx_frames', PmConfig.COUNTER),
73 ('tx_errors', PmConfig.COUNTER),
74 ('rx_frames', PmConfig.COUNTER),
75 ('rx_unknown_tid', PmConfig.COUNTER),
76 ('rx_onu_frames', PmConfig.COUNTER), # Rx ONU autonomous messages
77 ('rx_unknown_me', PmConfig.COUNTER), # Managed Entities without a decode definition
78 ('rx_timeouts', PmConfig.COUNTER),
79 ('rx_late', PmConfig.COUNTER),
80 ('consecutive_errors', PmConfig.COUNTER),
81 ('reply_min', PmConfig.GAUGE), # Milliseconds
82 ('reply_max', PmConfig.GAUGE), # Milliseconds
83 ('reply_average', PmConfig.GAUGE), # Milliseconds
84 ('hp_tx_queue_len', PmConfig.GAUGE),
85 ('lp_tx_queue_len', PmConfig.GAUGE),
86 ('max_hp_tx_queue', PmConfig.GAUGE),
87 ('max_lp_tx_queue', PmConfig.GAUGE),
88 }
89 self.omci_cc_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
90 for (m, t) in self.omci_cc_pm_names}
91
92 self.omci_optical_pm_names = {
93 ('intf_id', PmConfig.CONTEXT),
94
95 ('transmit_power', PmConfig.GAUGE),
96 ('receive_power', PmConfig.GAUGE),
97 }
98 self.omci_optical_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
99 for (m, t) in self.omci_optical_pm_names}
100
101 self.omci_uni_pm_names = {
102 ('intf_id', PmConfig.CONTEXT),
103
104 ('ethernet_type', PmConfig.GAUGE), # PPTP Ethernet ME
105 ('oper_status', PmConfig.GAUGE), # PPTP Ethernet ME
106 ('pptp_admin_state', PmConfig.GAUGE), # PPTP Ethernet ME
107 ('uni_admin_state', PmConfig.GAUGE), # UNI-G ME
108 }
109 self.omci_uni_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
110 for (m, t) in self.omci_uni_pm_names}
111
Devmalya Paul0d3abf02019-07-31 18:34:27 -0400112 self.openomci_interval_pm = OnuPmIntervalMetrics(event_mgr, core_proxy, device_id, logical_device_id,
Yongjie Zhang415a2962019-07-03 15:46:50 -0400113 serial_number)
Chip Boling67b674a2019-02-08 11:42:18 -0600114
115 def update(self, pm_config):
116 # TODO: Test frequency override capability for a particular group
117 if self.default_freq != pm_config.default_freq:
118 # Update the callback to the new frequency.
119 self.default_freq = pm_config.default_freq
120 self.lc.stop()
121 self.lc.start(interval=self.default_freq / 10)
122
123 if pm_config.grouped:
124 for group in pm_config.groups:
125 group_config = self.pm_group_metrics.get(group.group_name)
126 if group_config is not None:
127 group_config.enabled = group.enabled
128 else:
129 msg = 'There are on independent OMCI metrics, only group metrics at this time'
130 raise NotImplemented(msg)
131
132 self.openomci_interval_pm.update(pm_config)
133
134 def make_proto(self, pm_config=None):
135 assert pm_config is not None
136
137 # OMCI only supports grouped metrics
138 if self._omci_onu_device is None or not self.grouped:
139 return pm_config
140
141 pm_omci_cc_stats = PmGroupConfig(group_name=OnuOmciPmMetrics.OMCI_CC_GROUP_NAME,
142 group_freq=OnuOmciPmMetrics.DEFAULT_OMCI_CC_FREQUENCY,
143 enabled=OnuOmciPmMetrics.DEFAULT_OMCI_CC_ENABLED)
144 self.pm_group_metrics[pm_omci_cc_stats.group_name] = pm_omci_cc_stats
145
146 pm_omci_optical_stats = PmGroupConfig(group_name=OnuOmciPmMetrics.OPTICAL_GROUP_NAME,
147 group_freq=OnuOmciPmMetrics.DEFAULT_OPTICAL_FREQUENCY,
148 enabled=OnuOmciPmMetrics.DEFAULT_OPTICAL_ENABLED)
149 self.pm_group_metrics[pm_omci_optical_stats.group_name] = pm_omci_optical_stats
150
151 pm_omci_uni_stats = PmGroupConfig(group_name=OnuOmciPmMetrics.UNI_STATUS_GROUP_NAME,
152 group_freq=OnuOmciPmMetrics.DEFAULT_UNI_STATUS_FREQUENCY,
153 enabled=OnuOmciPmMetrics.DEFAULT_UNI_STATUS_ENABLED)
154 self.pm_group_metrics[pm_omci_uni_stats.group_name] = pm_omci_uni_stats
155
156 stats_and_config = [(pm_omci_cc_stats, self.omci_cc_metrics_config),
157 (pm_omci_optical_stats, self.omci_optical_metrics_config),
158 (pm_omci_uni_stats, self.omci_cc_metrics_config)]
159
160 for stats, config in stats_and_config:
161 for m in sorted(config):
162 pm = config[m]
163 stats.metrics.extend([PmConfig(name=pm.name,
164 type=pm.type,
165 enabled=pm.enabled)])
166 pm_config.groups.extend([stats])
167
168 # Also create OMCI Interval PM configs
169 return self.openomci_interval_pm.make_proto(pm_config)
170
171 def collect_metrics(self, data=None):
172 """
173 Collect metrics for this adapter.
174
175 The data collected (or passed in) is a list of pairs/tuples. Each
176 pair is composed of a MetricMetaData metadata-portion and list of MetricValuePairs
177 that contains a single individual metric or list of metrics if this is a
178 group metric.
179
180 This method is called for each adapter at a fixed frequency.
181 TODO: Currently all group metrics are collected on a single timer tick.
182 This needs to be fixed as independent group or instance collection is
183 desirable.
184
185 :param data: (list) Existing list of collected metrics (MetricInformation).
186 This is provided to allow derived classes to call into
187 further encapsulated classes.
188
189 :return: (list) metadata and metrics pairs - see description above
190 """
191 if data is None:
192 data = list()
193
194 # Note: Interval PM is collection done autonomously, not through this method
195
196 if self._omci_cc is not None:
197 group_name = OnuOmciPmMetrics.OMCI_CC_GROUP_NAME
198 if self.pm_group_metrics[group_name].enabled:
199 group_data = self.collect_group_metrics(group_name,
200 self._omci_cc,
201 self.omci_cc_pm_names,
202 self.omci_cc_metrics_config)
203 if group_data is not None:
204 data.append(group_data)
205
206 # Optical and UNI data is collected on a per-port basis
207 data.extend(self.collect_optical_metrics())
208 data.extend(self.collect_uni_status_metrics())
209
210 return data
211
212 def collect_optical_metrics(self):
213 """
214 Collect the metrics for optical information from all ANI/PONs
215
216 :return: (list) collected metrics (MetricInformation)
217 """
218 now = self._omci_onu_device.timestamp
219
220 group_name = OnuOmciPmMetrics.OPTICAL_GROUP_NAME
221 if now is None or not self.pm_group_metrics[group_name].enabled:
222 return []
223
224 # Scan all ANI-G ports
225 ani_g_entities = self._omci_onu_device.configuration.ani_g_entities
Zack Williams84a71e92019-11-15 09:00:19 -0700226 ani_g_entities_ids = list(ani_g_entities.keys()) if ani_g_entities is not None else None
Chip Boling67b674a2019-02-08 11:42:18 -0600227 metrics_info = []
228
229 if ani_g_entities_ids is not None and len(ani_g_entities_ids):
230 from pyvoltha.adapters.extensions.omci.omci_entities import AniG
231 ani_g_items = ['optical_signal_level', 'transmit_optical_level']
232
233 for entity_id in ani_g_entities_ids:
234 metrics = dict()
235 data = self._omci_onu_device.query_mib(class_id=AniG.class_id,
236 instance_id=entity_id,
237 attributes=ani_g_items)
238 if len(data):
239 if 'optical_signal_level' in data:
240 metrics['receive_power'] = data['optical_signal_level']
241
242 if 'transmit_optical_level' in data:
243 metrics['transmit_power'] = data['transmit_optical_level']
244
245 if len(metrics):
246 metric_data = MetricInformation(metadata=MetricMetaData(title=group_name,
247 ts=now,
248 logical_device_id=self.logical_device_id,
249 serial_no=self.serial_number,
250 device_id=self.device_id,
251 context={
252 'intf_id': str(entity_id)
253 }),
254 metrics=metrics)
255 metrics_info.append(metric_data)
256
257 return metrics_info
258
259 def collect_uni_status_metrics(self):
260 """
261 Collect the metrics for optical information from all ANI/PONs
262
263 :return: (list) collected metrics (MetricInformation)
264 """
265 now = self._omci_onu_device.timestamp
266
267 group_name = OnuOmciPmMetrics.UNI_STATUS_GROUP_NAME
268 if now is None or not self.pm_group_metrics[group_name].enabled:
269 return []
270
271 # Scan all UNI-G and PPTP ports
272 uni_g_entities = self._omci_onu_device.configuration.uni_g_entities
Zack Williams84a71e92019-11-15 09:00:19 -0700273 uni_g_entities_ids = list(uni_g_entities.keys()) if uni_g_entities is not None else None
Chip Boling67b674a2019-02-08 11:42:18 -0600274 pptp_entities = self._omci_onu_device.configuration.pptp_entities
Zack Williams84a71e92019-11-15 09:00:19 -0700275 pptp_entities_ids = list(pptp_entities.keys()) if pptp_entities is not None else None
Chip Boling67b674a2019-02-08 11:42:18 -0600276
277 metrics_info = []
278
279 if uni_g_entities_ids and pptp_entities_ids and len(uni_g_entities_ids) and \
280 len(uni_g_entities_ids) <= len(pptp_entities_ids):
281
282 uni_g_items = ['administrative_state']
283 pptp_items = ['administrative_state', 'operational_state', 'sensed_type']
284
285 for entity_id in pptp_entities_ids:
286 metrics = dict()
287 data = self._omci_onu_device.query_mib(class_id=UniG.class_id,
288 instance_id=entity_id,
289 attributes=uni_g_items)
290 if len(data):
291 if 'administrative_state' in data:
292 metrics['uni_admin_state'] = data['administrative_state']
293
294 data = self._omci_onu_device.query_mib(class_id=PptpEthernetUni.class_id,
295 instance_id=entity_id,
296 attributes=pptp_items)
297 if len(data):
298 if 'administrative_state' in data:
299 metrics['pptp_admin_state'] = data['administrative_state']
300
301 if 'operational_state' in data:
302 metrics['oper_status'] = data['operational_state']
303
304 if 'sensed_type' in data:
305 metrics['ethernet_type'] = data['sensed_type']
306
307 if len(metrics):
308 metric_data = MetricInformation(metadata=MetricMetaData(title=group_name,
309 ts=now,
310 logical_device_id=self.logical_device_id,
311 serial_no=self.serial_number,
312 device_id=self.device_id,
313 context={
314 'intf_id': str(entity_id & 0xFF)
315 }),
316 metrics=metrics)
317 metrics_info.append(metric_data)
318
319 return metrics_info