blob: 04e403f09c8af9ea2f5370b93a3f4cb5023c262d [file] [log] [blame]
Chip Bolingf04b0952018-07-23 16:18:17 -05001# 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
15from voltha.protos.device_pb2 import PmConfig, PmConfigs, PmGroupConfig
16from voltha.extensions.pki.adapter_pm_metrics import AdapterPmMetrics
17
18
19class OltPmMetrics(AdapterPmMetrics):
20 """
21 Shared OL Device Adapter PM Metrics Manager
22
23 This class specifically addresses ONU genernal PM (health, ...) area
24 specific PM (OMCI, PON, UNI) is supported in encapsulated classes accessible
25 from this object
26 """
27 def __init__(self, adapter_agent, device_id, grouped=False, freq_override=False,
28 **kwargs):
29 """
30 Initializer for shared ONU Device Adapter PM metrics
31
32 :param adapter_agent: (AdapterAgent) Adapter agent for the device
33 :param device_id: (str) Device ID
34 :param grouped: (bool) Flag indicating if statistics are managed as a group
35 :param freq_override: (bool) Flag indicating if frequency collection can be specified
36 on a per group basis
37 :param kwargs: (dict) Device Adapter specific values. For an ONU Device adapter, the
38 expected key-value pairs are listed below. If not provided, the
39 associated PM statistics are not gathered:
40
41 'nni-ports': List of objects that provide NNI (northbound) port statistics
42 'pon-ports': List of objects that provide PON port statistics
43 """
44 super(OltPmMetrics, self).__init__(adapter_agent, device_id,
45 grouped=grouped, freq_override=freq_override,
46 **kwargs)
47
48 # PM Config Types are COUNTER, GUAGE, and STATE # GAUGE is misspelled device.proto
49 self.nni_pm_names = {
50 ('admin_state', PmConfig.STATE),
51 ('oper_status', PmConfig.STATE),
52 ('port_no', PmConfig.GUAGE), # Device and logical_device port numbers same
53 ('rx_packets', PmConfig.COUNTER),
54 ('rx_bytes', PmConfig.COUNTER),
55 ('rx_dropped', PmConfig.COUNTER),
56 ('rx_errors', PmConfig.COUNTER),
57 ('rx_bcast', PmConfig.COUNTER),
58 ('rx_mcast', PmConfig.COUNTER),
59 ('tx_packets', PmConfig.COUNTER),
60 ('tx_bytes', PmConfig.COUNTER),
61 ('tx_dropped', PmConfig.COUNTER),
62 ('tx_bcast', PmConfig.COUNTER),
63 ('tx_mcast', PmConfig.COUNTER),
64 #
65 # Commented out are from spec. May not be supported or implemented yet
66 # ('rx_64', PmConfig.COUNTER),
67 # ('rx_65_127', PmConfig.COUNTER),
68 # ('rx_128_255', PmConfig.COUNTER),
69 # ('rx_256_511', PmConfig.COUNTER),
70 # ('rx_512_1023', PmConfig.COUNTER),
71 # ('rx_1024_1518', PmConfig.COUNTER),
72 # ('rx_frame_err', PmConfig.COUNTER),
73 # ('rx_over_err', PmConfig.COUNTER),
74 # ('rx_crc_err', PmConfig.COUNTER),
75 # ('rx_64', PmConfig.COUNTER),
76 # ('tx_65_127', PmConfig.COUNTER),
77 # ('tx_128_255', PmConfig.COUNTER),
78 # ('tx_256_511', PmConfig.COUNTER),
79 # ('tx_512_1023', PmConfig.COUNTER),
80 # ('tx_1024_1518', PmConfig.COUNTER),
81 # ('collisions', PmConfig.COUNTER),
82 }
83 self.pon_pm_names = {
84 ('admin_state', PmConfig.STATE),
85 ('oper_status', PmConfig.STATE),
86 ('port_no', PmConfig.GUAGE), # Physical device port number
87 ('pon_id', PmConfig.GUAGE),
88 ('rx_packets', PmConfig.COUNTER),
89 ('rx_bytes', PmConfig.COUNTER),
90 ('tx_packets', PmConfig.COUNTER),
91 ('tx_bytes', PmConfig.COUNTER),
92 ('tx_bip_errors', PmConfig.COUNTER),
93 ('in_service_onus', PmConfig.GUAGE),
94 ('closest_onu_distance', PmConfig.GUAGE)
95 }
96 self.onu_pm_names = {
97 ('pon_id', PmConfig.GUAGE),
98 ('onu_id', PmConfig.GUAGE),
99 ('fiber_length', PmConfig.GUAGE),
100 ('equalization_delay', PmConfig.GUAGE),
101 ('rssi', PmConfig.GUAGE), #
102 }
103 self.gem_pm_names = {
104 ('pon_id', PmConfig.GUAGE),
105 ('onu_id', PmConfig.GUAGE),
106 ('gem_id', PmConfig.GUAGE),
107 ('alloc_id', PmConfig.GUAGE),
108 ('rx_packets', PmConfig.COUNTER),
109 ('rx_bytes', PmConfig.COUNTER),
110 ('tx_packets', PmConfig.COUNTER),
111 ('tx_bytes', PmConfig.COUNTER),
112 }
113 self.nni_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
114 for (m, t) in self.nni_pm_names}
115 self.pon_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
116 for (m, t) in self.pon_pm_names}
117 self.onu_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
118 for (m, t) in self.onu_pm_names}
119 self.gem_metrics_config = {m: PmConfig(name=m, type=t, enabled=True)
120 for (m, t) in self.gem_pm_names}
121
122 self._nni_ports = kwargs.pop('nni-ports', None)
123 self._pon_ports = kwargs.pop('pon-ports', None)
124
125 def update(self, pm_config):
126 # TODO: Test both 'group' and 'non-group' functionality
127 # TODO: Test frequency override capability for a particular group
128 if self.default_freq != pm_config.default_freq:
129 # Update the callback to the new frequency.
130 self.default_freq = pm_config.default_freq
131 self.lc.stop()
132 self.lc.start(interval=self.default_freq / 10)
133
134 if pm_config.grouped:
135 for m in pm_config.groups:
136 # TODO: Need to support individual group enable/disable
137 pass
138 # self.pm_group_metrics[m.group_name].config.enabled = m.enabled
139 # if m.enabled is True:
140 # self.enable_pm_collection(m.group_name, remote)
141 # else:
142 # self.disable_pm_collection(m.group_name, remote)
143 else:
144 for m in pm_config.metrics:
145 self.nni_metrics_config[m.name].enabled = m.enabled
146 self.pon_metrics_config[m.name].enabled = m.enabled
147 self.onu_metrics_config[m.name].enabled = m.enabled
148 self.gem_metrics_config[m.name].enabled = m.enabled
149
150 def make_proto(self, pm_config=None):
151 if pm_config is None:
152 pm_config = PmConfigs(id=self.device_id, default_freq=self.default_freq,
153 grouped=self.grouped,
154 freq_override=self.freq_override)
155 metrics = set()
156 have_nni = self._nni_ports is not None and len(self._nni_ports) > 0
157 have_pon = self._pon_ports is not None and len(self._pon_ports) > 0
158
159 if self.grouped:
160 if have_nni:
161 pm_ether_stats = PmGroupConfig(group_name='Ethernet',
162 group_freq=self.default_freq,
163 enabled=True)
164 else:
165 pm_ether_stats = None
166
167 if have_pon:
168 pm_pon_stats = PmGroupConfig(group_name='PON',
169 group_freq=self.default_freq,
170 enabled=True)
171
172 pm_ont_stats = PmGroupConfig(group_name='ONT',
173 group_freq=self.default_freq,
174 enabled=True)
175
176 pm_gem_stats = PmGroupConfig(group_name='GEM',
177 group_freq=self.default_freq,
178 enabled=True)
179 else:
180 pm_pon_stats = None
181 pm_ont_stats = None
182 pm_gem_stats = None
183
184 else:
185 pm_ether_stats = pm_config if have_nni else None
186 pm_pon_stats = pm_config if have_pon else None
187 pm_ont_stats = pm_config if have_pon else None
188 pm_gem_stats = pm_config if have_pon else None
189
190 if have_nni:
191 for m in sorted(self.nni_metrics_config):
192 pm = self.nni_metrics_config[m]
193 if not self.grouped:
194 if pm.name in metrics:
195 continue
196 metrics.add(pm.name)
197 pm_ether_stats.metrics.extend([PmConfig(name=pm.name,
198 type=pm.type,
199 enabled=pm.enabled)])
200 if have_pon:
201 for m in sorted(self.pon_metrics_config):
202 pm = self.pon_metrics_config[m]
203 if not self.grouped:
204 if pm.name in metrics:
205 continue
206 metrics.add(pm.name)
207 pm_pon_stats.metrics.extend([PmConfig(name=pm.name,
208 type=pm.type,
209 enabled=pm.enabled)])
210
211 for m in sorted(self.onu_metrics_config):
212 pm = self.onu_metrics_config[m]
213 if not self.grouped:
214 if pm.name in metrics:
215 continue
216 metrics.add(pm.name)
217 pm_ont_stats.metrics.extend([PmConfig(name=pm.name,
218 type=pm.type,
219 enabled=pm.enabled)])
220
221 for m in sorted(self.gem_metrics_config):
222 pm = self.gem_metrics_config[m]
223 if not self.grouped:
224 if pm.name in metrics:
225 continue
226 metrics.add(pm.name)
227 pm_gem_stats.metrics.extend([PmConfig(name=pm.name,
228 type=pm.type,
229 enabled=pm.enabled)])
230 if self.grouped:
231 pm_groups = [stats for stats in (pm_ether_stats,
232 pm_pon_stats,
233 pm_ont_stats,
234 pm_gem_stats) if stats is not None]
235 pm_config.groups.extend(pm_groups)
236
237 return pm_config
238
239 def collect_group_metrics(self, metrics=None):
240 # TODO: Currently PM collection is done for all metrics/groups on a single timer
241 if metrics is None:
242 metrics = dict()
243
244 for port in self._nni_ports:
245 metrics['nni.{}'.format(port.port_no)] = self.collect_nni_metrics(port)
246
247 for port in self._pon_ports:
248 metrics['pon.{}'.format(port.pon_id)] = self.collect_pon_metrics(port)
249
250 for onu_id in port.onu_ids:
251 onu = port.onu(onu_id)
252 if onu is not None:
253 metrics['pon.{}.onu.{}'.format(port.pon_id, onu.onu_id)] = \
254 self.collect_onu_metrics(onu)
255 for gem in onu.gem_ports:
256 if gem.multicast:
257 continue
258
259 metrics['pon.{}.onu.{}.gem.{}'.format(port.pon_id,
260 onu.onu_id,
261 gem.gem_id)] = \
262 self.collect_gem_metrics(gem)
263 # TODO: Do any multicast GEM PORT metrics here...
264 return metrics
265
266 def collect_nni_metrics(self, nni_port):
267 stats = {metric: getattr(nni_port, metric) for (metric, t) in self.nni_pm_names}
268 return {metric: value for metric, value in stats.iteritems()
269 if self.nni_metrics_config[metric].enabled}
270
271 def collect_pon_metrics(self, pon_port):
272 stats = {metric: getattr(pon_port, metric) for (metric, t) in self.pon_pm_names}
273 return {metric: value for metric, value in stats.iteritems()
274 if self.pon_metrics_config[metric].enabled}
275
276 def collect_onu_metrics(self, onu):
277 stats = {metric: getattr(onu, metric) for (metric, t) in self.onu_pm_names}
278 return {metric: value for metric, value in stats.iteritems()
279 if self.onu_metrics_config[metric].enabled}
280
281 def collect_gem_metrics(self, gem):
282 stats = {metric: getattr(gem, metric) for (metric, t) in self.gem_pm_names}
283 return {metric: value for metric, value in stats.iteritems()
284 if self.gem_metrics_config[metric].enabled}