blob: 74413a4589fe205c7cbddcd6502572207ee4e7c0 [file] [log] [blame]
Chip Bolingf5af85d2019-02-12 15:36:17 -06001# Copyright 2017-present Adtran, Inc.
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 structlog
16
17log = structlog.get_logger()
18
19
20class OltState(object):
21 """
22 Class to wrap decode of olt-state container from the ADTRAN
23 gpon-olt-hw.yang YANG model
24 """
25
26 def __init__(self, packet):
27 self._packet = packet
28 self._pons = None
29
30 def __str__(self):
31 return "OltState: {}".format(self.software_version)
32
33 @property
34 def software_version(self):
35 """The software version of olt driver"""
36 return self._packet.get('software-version', '')
37
38 @property
39 def pons(self):
40 if self._pons is None:
41 self._pons = OltState.Pon.decode(self._packet.get('pon', None))
42 return self._pons
43
44 #############################################################
45 # Act like a container for simple access into PON list
46
47 def __len__(self):
48 return len(self.pons)
49
50 def __getitem__(self, key):
51 if not isinstance(key, int):
52 raise TypeError('Key should be of type int')
53 if key not in self.pons:
54 raise KeyError("key '{}' not found".format(key))
55
56 return self.pons[key]
57
58 def __iter__(self):
59 raise NotImplementedError('TODO: Not yet implemented')
60
61 def __contains__(self, item):
62 if not isinstance(item, int):
63 raise TypeError('Item should be of type int')
64 return item in self.pons
65
66 # TODO: Look at generator support and if it is useful
67
68 class Pon(object):
69 """
70 Provides decode of PON list from within
71 """
72 def __init__(self, packet):
73 assert 'pon-id' in packet
74 self._packet = packet
75 self._onus = None
76 self._gems = None
77
78 def __str__(self):
79 return "OltState.Pon: pon-id: {}".format(self.pon_id)
80
81 @staticmethod
82 def decode(pon_list):
83 # log.debug('Decoding PON List:{}{}'.format(os.linesep,
84 # pprint.PrettyPrinter().pformat(pon_list)))
85 pons = {}
86 for pon_data in pon_list:
87 pon = OltState.Pon(pon_data)
88 assert pon.pon_id not in pons
89 pons[pon.pon_id] = pon
90
91 return pons
92
93 @property
94 def pon_id(self):
95 """PON identifier"""
96 return self._packet['pon-id']
97
98 @property
99 def downstream_wavelength(self):
100 """The wavelength, in nanometers, being used in the downstream direction"""
101 return self._packet.get('downstream-wavelength', 0)
102
103 @property
104 def upstream_wavelength(self):
105 """The wavelength, in nanometers, being used in the upstream direction"""
106 return self._packet.get('upstream-wavelength', 0)
107
108 @property
109 def downstream_channel_id(self):
110 """Downstream wavelength channel identifier associated with this PON."""
111 return self._packet.get('downstream-channel-id', 0)
112
113 @property
114 def rx_packets(self):
115 """Sum all of the RX Packets of GEM ports that are not base TCONT's"""
116 return int(self._packet.get('rx-packets', 0))
117
118 @property
119 def tx_packets(self):
120 """Sum all of the TX Packets of GEM ports that are not base TCONT's"""
121 return int(self._packet.get('tx-packets', 0))
122
123 @property
124 def rx_bytes(self):
125 """Sum all of the RX Octets of GEM ports that are not base TCONT's"""
126 return int(self._packet.get('rx-bytes', 0))
127
128 @property
129 def tx_bytes(self):
130 """Sum all of the TX Octets of GEM ports that are not base TCONT's"""
131 return int(self._packet.get('tx-bytes', 0))
132
133 @property
134 def tx_bip_errors(self):
135 """Sum the TX ONU bip errors to get TX BIP's per PON"""
136 return int(self._packet.get('tx-bip-errors', 0))
137
138 @property
139 def wm_tuned_out_onus(self):
140 """
141 bit array indicates the list of tuned out ONU's that are in wavelength
142 mobility protecting state.
143 onu-bit-octects:
144 type binary { length "4 .. 1024"; }
145 description each bit position indicates corresponding ONU's status
146 (true or false) whether that ONU's is in
147 wavelength mobility protecting state or not
148 For 128 ONTs per PON, the size of this
149 array will be 16. onu-bit-octects[0] and MSB bit in that byte
150 represents ONU 0 etc.
151 """
152 return self._packet.get('wm-tuned-out-onus', bytes(0))
153
154 @property
155 def ont_los(self):
156 """List of configured ONTs that have been previously discovered and are in a los of signal state"""
157 return self._packet.get('ont-los', [])
158
159 @property
160 def discovered_onu(self):
161 """
162 Immutable Set of each Optical Network Unit(ONU) that has been activated via discovery
163 key/value: serial-number (string)
164 """
165 return frozenset([sn['serial-number'] for sn in self._packet.get('discovered-onu', [])
166 if 'serial-number' in sn and sn['serial-number'] != 'AAAAAAAAAAA='])
167
168 @property
169 def gems(self):
170 """This list is not in the proposed BBF model, the stats are part of ietf-interfaces"""
171 if self._gems is None:
172 self._gems = OltState.Pon.Gem.decode(self._packet.get('gem', []))
173 return self._gems
174
175 @property
176 def onus(self):
177 """
178 The map of each Optical Network Unit(ONU). Key: ONU ID (int)
179 """
180 if self._onus is None:
181 self._onus = OltState.Pon.Onu.decode(self._packet.get('onu', []))
182 return self._onus
183
184 class Onu(object):
185 """
186 Provides decode of onu list for a PON port
187 """
188 def __init__(self, packet):
189 assert 'onu-id' in packet, 'onu-id not found in packet'
190 self._packet = packet
191
192 def __str__(self):
193 return "OltState.Pon.Onu: onu-id: {}".format(self.onu_id)
194
195 @staticmethod
196 def decode(onu_list):
197 # log.debug('onus:{}{}'.format(os.linesep,
198 # pprint.PrettyPrinter().pformat(onu_list)))
199 onus = {}
200 for onu_data in onu_list:
201 onu = OltState.Pon.Onu(onu_data)
202 assert onu.onu_id not in onus
203 onus[onu.onu_id] = onu
204
205 return onus
206
207 @property
208 def onu_id(self):
209 """The ID used to identify the ONU"""
210 return self._packet['onu-id']
211
212 @property
213 def oper_status(self):
214 """The operational state of each ONU"""
215 return self._packet.get('oper-status', 'unknown')
216
217 @property
218 def reported_password(self):
219 """The password reported by the ONU (binary)"""
220 return self._packet.get('reported-password', bytes(0))
221
222 @property
223 def rssi(self):
224 """The received signal strength indication of the ONU"""
225 return self._packet.get('rssi', -9999)
226
227 @property
228 def equalization_delay(self):
229 """Equalization delay (bits)"""
230 return self._packet.get('equalization-delay', 0)
231
232 @property
233 def fiber_length(self):
234 """Distance to ONU"""
235 return self._packet.get('fiber-length', 0)
236
237 class Gem(object):
238 """
239 Provides decode of onu list for a PON port
240 """
241 def __init__(self, packet):
242 assert 'onu-id' in packet, 'onu-id not found in packet'
243 assert 'port-id' in packet, 'port-id not found in packet'
244 assert 'alloc-id' in packet, 'alloc-id not found in packet'
245 self._packet = packet
246
247 def __str__(self):
248 return "OltState.Pon.Gem: onu-id: {}, gem-id".\
249 format(self.onu_id, self.gem_id)
250
251 @staticmethod
252 def decode(gem_list):
253 # log.debug('gems:{}{}'.format(os.linesep,
254 # pprint.PrettyPrinter().pformat(gem_list)))
255 gems = {}
256 for gem_data in gem_list:
257 gem = OltState.Pon.Gem(gem_data)
258 assert gem.gem_id not in gems
259 gems[gem.gem_id] = gem
260
261 return gems
262
263 @property
264 def onu_id(self):
265 """The ID used to identify the ONU"""
266 return self._packet['onu-id']
267
268 @property
269 def alloc_id(self):
270 return self._packet['alloc-id']
271
272 @property
273 def gem_id(self):
274 return self._packet['port-id']
275
276 @property
277 def tx_packets(self):
278 return int(self._packet.get('tx-packets', 0))
279
280 @property
281 def tx_bytes(self):
282 return int(self._packet.get('tx-bytes', 0))
283
284 @property
285 def rx_packets(self):
286 return int(self._packet.get('rx-packets', 0))
287
288 @property
289 def rx_bytes(self):
290 return int(self._packet.get('rx-bytes', 0))