Chip Boling | f5af85d | 2019-02-12 15:36:17 -0600 | [diff] [blame] | 1 | # 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 | |
| 15 | import structlog |
| 16 | |
| 17 | log = structlog.get_logger() |
| 18 | |
| 19 | |
| 20 | class OltConfig(object): |
| 21 | """ |
| 22 | Class to wrap decode of olt container (config) from the ADTRAN |
| 23 | gpon-olt-hw.yang YANG model |
| 24 | """ |
| 25 | def __init__(self, packet): |
| 26 | self._packet = packet |
| 27 | self._pons = None |
| 28 | |
| 29 | def __str__(self): |
| 30 | return "OltConfig: {}".format(self.olt_id) |
| 31 | |
| 32 | @property |
| 33 | def olt_id(self): |
| 34 | """Unique OLT identifier""" |
| 35 | return self._packet.get('olt-id', '') |
| 36 | |
| 37 | @property |
| 38 | def debug_output(self): |
| 39 | """least important level that will output everything""" |
| 40 | return self._packet.get('debug-output', 'warning') |
| 41 | |
| 42 | @property |
| 43 | def pons(self): |
| 44 | if self._pons is None: |
| 45 | self._pons = OltConfig.Pon.decode(self._packet.get('pon', None)) |
| 46 | return self._pons |
| 47 | |
| 48 | class Pon(object): |
| 49 | """ |
| 50 | Provides decode of PON list from within |
| 51 | """ |
| 52 | def __init__(self, packet): |
| 53 | assert 'pon-id' in packet, 'pon-id not found' |
| 54 | self._packet = packet |
| 55 | self._onus = None |
| 56 | |
| 57 | def __str__(self): |
| 58 | return "OltConfig.Pon: pon-id: {}".format(self.pon_id) |
| 59 | |
| 60 | @staticmethod |
| 61 | def decode(pon_list): |
| 62 | pons = {} |
| 63 | |
| 64 | if pon_list is not None: |
| 65 | for pon_data in pon_list: |
| 66 | pon = OltConfig.Pon(pon_data) |
| 67 | assert pon.pon_id not in pons |
| 68 | pons[pon.pon_id] = pon |
| 69 | |
| 70 | return pons |
| 71 | |
| 72 | @property |
| 73 | def pon_id(self): |
| 74 | """PON identifier""" |
| 75 | return self._packet['pon-id'] |
| 76 | |
| 77 | @property |
| 78 | def enabled(self): |
| 79 | """The desired state of the interface""" |
| 80 | return self._packet.get('enabled', False) |
| 81 | |
| 82 | @property |
| 83 | def downstream_fec_enable(self): |
| 84 | """Enables downstream Forward Error Correction""" |
| 85 | return self._packet.get('downstream-fec-enable', False) |
| 86 | |
| 87 | @property |
| 88 | def upstream_fec_enable(self): |
| 89 | """Enables upstream Forward Error Correction""" |
| 90 | return self._packet.get('upstream-fec-enable', False) |
| 91 | |
| 92 | @property |
| 93 | def deployment_range(self): |
| 94 | """Maximum deployment distance (meters)""" |
| 95 | return self._packet.get('deployment-range', 25000) |
| 96 | |
| 97 | @property |
| 98 | def onus(self): |
| 99 | if self._onus is None: |
| 100 | self._onus = OltConfig.Pon.Onu.decode(self._packet.get('onus', None)) |
| 101 | return self._onus |
| 102 | |
| 103 | class Onu(object): |
| 104 | """ |
| 105 | Provides decode of onu list for a PON port |
| 106 | """ |
| 107 | def __init__(self, packet): |
| 108 | assert 'onu-id' in packet, 'onu-id not found' |
| 109 | self._packet = packet |
| 110 | self._tconts = None |
| 111 | self._tconts_dict = None |
| 112 | self._gem_ports = None |
| 113 | self._gem_ports_dict = None |
| 114 | |
| 115 | def __str__(self): |
| 116 | return "OltConfig.Pon.Onu: onu-id: {}".format(self.onu_id) |
| 117 | |
| 118 | @staticmethod |
| 119 | def decode(onu_dict): |
| 120 | onus = {} |
| 121 | |
| 122 | if onu_dict is not None: |
| 123 | if 'onu' in onu_dict: |
| 124 | for onu_data in onu_dict['onu']: |
| 125 | onu = OltConfig.Pon.Onu(onu_data) |
| 126 | assert onu.onu_id not in onus |
| 127 | onus[onu.onu_id] = onu |
| 128 | elif len(onu_dict) > 0 and 'onu-id' in onu_dict[0]: |
| 129 | onu = OltConfig.Pon.Onu(onu_dict[0]) |
| 130 | assert onu.onu_id not in onus |
| 131 | onus[onu.onu_id] = onu |
| 132 | |
| 133 | return onus |
| 134 | |
| 135 | @property |
| 136 | def onu_id(self): |
| 137 | """The ID used to identify the ONU""" |
| 138 | return self._packet['onu-id'] |
| 139 | |
| 140 | @property |
| 141 | def serial_number_64(self): |
| 142 | """The serial number (base-64) is unique for each ONU""" |
| 143 | return self._packet.get('serial-number', '') |
| 144 | |
| 145 | @property |
| 146 | def password(self): |
| 147 | """ONU Password""" |
| 148 | return self._packet.get('password', bytes(0)) |
| 149 | |
| 150 | @property |
| 151 | def enable(self): |
| 152 | """If true, places the ONU in service""" |
| 153 | return self._packet.get('enable', False) |
| 154 | |
| 155 | @property |
| 156 | def tconts(self): |
| 157 | if self._tconts is None: |
| 158 | self._tconts = OltConfig.Pon.Onu.TCont.decode(self._packet.get('t-conts', None)) |
| 159 | return self._tconts |
| 160 | |
| 161 | @property |
| 162 | def tconts_dict(self): # TODO: Remove if not used |
| 163 | if self._tconts_dict is None: |
| 164 | self._tconts_dict = {tcont.alloc_id: tcont for tcont in self.tconts} |
| 165 | return self._tconts_dict |
| 166 | |
| 167 | @property |
| 168 | def gem_ports(self): |
| 169 | if self._gem_ports is None: |
| 170 | self._gem_ports = OltConfig.Pon.Onu.GemPort.decode(self._packet.get('gem-ports', None)) |
| 171 | return self._gem_ports |
| 172 | |
| 173 | @property |
| 174 | def gem_ports_dict(self): # TODO: Remove if not used |
| 175 | if self._gem_ports_dict is None: |
| 176 | self._gem_ports_dict = {gem.gem_id: gem for gem in self.gem_ports} |
| 177 | return self._gem_ports_dict |
| 178 | |
| 179 | class TCont(object): |
| 180 | """ |
| 181 | Provides decode of onu list for the T-CONT container |
| 182 | """ |
| 183 | def __init__(self, packet): |
| 184 | assert 'alloc-id' in packet, 'alloc-id not found' |
| 185 | self._packet = packet |
| 186 | self._traffic_descriptor = None |
| 187 | self._best_effort = None |
| 188 | |
| 189 | def __str__(self): |
| 190 | return "OltConfig.Pon.Onu.TCont: alloc-id: {}".format(self.alloc_id) |
| 191 | |
| 192 | @staticmethod |
| 193 | def decode(tcont_container): |
| 194 | tconts = {} |
| 195 | |
| 196 | if tcont_container is not None: |
| 197 | for tcont_data in tcont_container.get('t-cont', []): |
| 198 | tcont = OltConfig.Pon.Onu.TCont(tcont_data) |
| 199 | assert tcont.alloc_id not in tconts |
| 200 | tconts[tcont.alloc_id] = tcont |
| 201 | |
| 202 | return tconts |
| 203 | |
| 204 | @property |
| 205 | def alloc_id(self): |
| 206 | """The ID used to identify the T-CONT""" |
| 207 | return self._packet['alloc-id'] |
| 208 | |
| 209 | @property |
| 210 | def traffic_descriptor(self): |
| 211 | """ |
| 212 | Each Alloc-ID is provisioned with a traffic descriptor that specifies |
| 213 | the three bandwidth component parameters: fixed bandwidth, assured |
| 214 | bandwidth, and maximum bandwidth, as well as the ternary eligibility |
| 215 | indicator for additional bandwidth assignment |
| 216 | """ |
| 217 | if self._traffic_descriptor is None and 'traffic-descriptor' in self._packet: |
| 218 | self._traffic_descriptor = OltConfig.Pon.Onu.TCont.\ |
| 219 | TrafficDescriptor(self._packet['traffic-descriptor']) |
| 220 | return self._traffic_descriptor |
| 221 | |
| 222 | class TrafficDescriptor(object): |
| 223 | def __init__(self, packet): |
| 224 | self._packet = packet |
| 225 | |
| 226 | def __str__(self): |
| 227 | return "OltConfig.Pon.Onu.TCont.TrafficDescriptor: {}/{}/{}".\ |
| 228 | format(self.fixed_bandwidth, self.assured_bandwidth, |
| 229 | self.maximum_bandwidth) |
| 230 | |
| 231 | @property |
| 232 | def fixed_bandwidth(self): |
| 233 | try: |
| 234 | return int(self._packet.get('fixed-bandwidth', 0)) |
| 235 | except: |
| 236 | return 0 |
| 237 | |
| 238 | @property |
| 239 | def assured_bandwidth(self): |
| 240 | try: |
| 241 | return int(self._packet.get('assured-bandwidth', 0)) |
| 242 | except: |
| 243 | return 0 |
| 244 | |
| 245 | @property |
| 246 | def maximum_bandwidth(self): |
| 247 | try: |
| 248 | return int(self._packet.get('maximum-bandwidth', 0)) |
| 249 | except: |
| 250 | return 0 |
| 251 | |
| 252 | @property |
| 253 | def additional_bandwidth_eligibility(self): |
| 254 | return self._packet.get('additional-bandwidth-eligibility', 'none') |
| 255 | |
| 256 | @property |
| 257 | def best_effort(self): |
| 258 | if self._best_effort is None: |
| 259 | self._best_effort = OltConfig.Pon.Onu.TCont.BestEffort.decode( |
| 260 | self._packet.get('best-effort', None)) |
| 261 | return self._best_effort |
| 262 | |
| 263 | class BestEffort(object): |
| 264 | def __init__(self, packet): |
| 265 | self._packet = packet |
| 266 | |
| 267 | def __str__(self): |
| 268 | return "OltConfig.Pon.Onu.TCont.BestEffort: {}".format(self.bandwidth) |
| 269 | |
| 270 | @property |
| 271 | def bandwidth(self): |
| 272 | return self._packet['bandwidth'] |
| 273 | |
| 274 | @property |
| 275 | def priority(self): |
| 276 | return self._packet['priority'] |
| 277 | |
| 278 | @property |
| 279 | def weight(self): |
| 280 | return self._packet['weight'] |
| 281 | |
| 282 | class GemPort(object): |
| 283 | """ |
| 284 | Provides decode of onu list for the gem-ports container |
| 285 | """ |
| 286 | def __init__(self, packet): |
| 287 | assert 'port-id' in packet, 'port-id not found' |
| 288 | self._packet = packet |
| 289 | |
| 290 | def __str__(self): |
| 291 | return "OltConfig.Pon.Onu.GemPort: port-id: {}/{}".\ |
| 292 | format(self.port_id, self.alloc_id) |
| 293 | |
| 294 | @staticmethod |
| 295 | def decode(gem_port_container): |
| 296 | gem_ports = {} |
| 297 | |
| 298 | if gem_port_container is not None: |
| 299 | for gem_port_data in gem_port_container.get('gem-port', []): |
| 300 | gem_port = OltConfig.Pon.Onu.GemPort(gem_port_data) |
| 301 | assert gem_port.port_id not in gem_ports |
| 302 | gem_ports[gem_port.port_id] = gem_port |
| 303 | |
| 304 | return gem_ports |
| 305 | |
| 306 | @property |
| 307 | def port_id(self): |
| 308 | """The ID used to identify the GEM Port""" |
| 309 | return self._packet['port-id'] |
| 310 | |
| 311 | @property |
| 312 | def gem_id(self): |
| 313 | """The ID used to identify the GEM Port""" |
| 314 | return self.port_id |
| 315 | |
| 316 | @property |
| 317 | def alloc_id(self): |
| 318 | """The Alloc-ID of the T-CONT to which this GEM port is mapped""" |
| 319 | return self._packet['alloc-id'] |
| 320 | |
| 321 | @property |
| 322 | def omci_transport(self): |
| 323 | """If true, this GEM port is used to transport the OMCI virtual connection""" |
| 324 | return self._packet.get('omci-transport', False) |
| 325 | |
| 326 | @property |
| 327 | def encryption(self): |
| 328 | """If true, enable encryption using the advanced encryption standard(AES)""" |
| 329 | return self._packet.get('encryption', False) |