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