blob: 4f00c0d1311df0882ad62075382e8ba11bff24da [file] [log] [blame]
Chip Bolingfd1fd372017-12-20 13:34:12 -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
Chip Bolinge9313592018-06-08 13:36:18 -050016from twisted.internet.defer import inlineCallbacks, returnValue
17from voltha.protos.common_pb2 import AdminState, OperStatus
18from voltha.protos.device_pb2 import Port
Chip Bolingfd1fd372017-12-20 13:34:12 -060019
20
21class PonPort(object):
Chip Bolinge9313592018-06-08 13:36:18 -050022 """Wraps northbound-port/ANI support for ONU"""
Chip Bolinge84aca92018-03-27 11:45:56 -070023 MIN_GEM_ENTITY_ID = 0x4900
24 MAX_GEM_ENTITY_ID = 0x4AFF
Chip Bolingfd1fd372017-12-20 13:34:12 -060025
26 def __init__(self, handler, port_no):
Chip Bolinge9313592018-06-08 13:36:18 -050027 self.log = structlog.get_logger(device_id=handler.device_id, port_no=port_no)
28
Chip Bolingfd1fd372017-12-20 13:34:12 -060029 self._enabled = False
30 self._valid = True
31 self._handler = handler
32 self._deferred = None
33 self._port = None
34 self._port_number = port_no
Chip Boling040f8d52018-07-19 12:48:12 -050035 self._entity_id = None # ANI entity ID
Chip Bolinge84aca92018-03-27 11:45:56 -070036 self._next_entity_id = PonPort.MIN_GEM_ENTITY_ID
Chip Bolingfd1fd372017-12-20 13:34:12 -060037
38 self._admin_state = AdminState.ENABLED
39 self._oper_status = OperStatus.ACTIVE
40
41 self._gem_ports = {} # gem-id -> GemPort
42 self._tconts = {} # alloc-id -> TCont
Chip Bolingfd1fd372017-12-20 13:34:12 -060043
Chip Boling78503602018-09-26 15:05:20 -050044 # OMCI resources
45 # TODO: These could be dynamically chosen (can be most any value)
46 self.hsi_8021p_mapper_entity_id = 0x100
47 self.hsi_mac_bridge_port_ani_entity_id = 0x100
48
Chip Bolingfd1fd372017-12-20 13:34:12 -060049 def __str__(self):
50 return "PonPort" # TODO: Encode current state
51
52 @staticmethod
53 def create(handler, port_no):
54 port = PonPort(handler, port_no)
55 return port
56
57 def _start(self):
58 self._cancel_deferred()
59
60 self._admin_state = AdminState.ENABLED
61 self._oper_status = OperStatus.ACTIVE
62 self._update_adapter_agent()
63
Chip Bolingfd1fd372017-12-20 13:34:12 -060064 def _stop(self):
65 self._cancel_deferred()
66
Chip Bolingfd1fd372017-12-20 13:34:12 -060067 self._admin_state = AdminState.DISABLED
68 self._oper_status = OperStatus.UNKNOWN
69 self._update_adapter_agent()
Chip Boling3971d242018-06-06 10:26:34 -050070
Chip Bolingfd1fd372017-12-20 13:34:12 -060071 # TODO: stop h/w sync
Chip Bolingfd1fd372017-12-20 13:34:12 -060072
73 def _cancel_deferred(self):
Chip Bolinge84aca92018-03-27 11:45:56 -070074 d1, self._deferred = self._deferred, None
Chip Bolingfd1fd372017-12-20 13:34:12 -060075
Chip Bolinge9313592018-06-08 13:36:18 -050076 for d in [d1]:
Chip Bolinge84aca92018-03-27 11:45:56 -070077 try:
78 if d is not None and not d.called:
79 d.cancel()
80 except:
81 pass
82
Chip Bolingfd1fd372017-12-20 13:34:12 -060083 def delete(self):
84 self.enabled = False
85 self._valid = False
86 self._handler = None
Chip Bolingfd1fd372017-12-20 13:34:12 -060087
88 @property
89 def enabled(self):
90 return self._enabled
91
92 @enabled.setter
93 def enabled(self, value):
94 if self._enabled != value:
95 self._enabled = value
96
97 if value:
98 self._start()
99 else:
100 self._stop()
101
102 @property
Chip Bolingfd1fd372017-12-20 13:34:12 -0600103 def port_number(self):
104 return self._port_number
105
Chip Bolinge84aca92018-03-27 11:45:56 -0700106 @property
Chip Boling040f8d52018-07-19 12:48:12 -0500107 def entity_id(self):
108 """
109 OMCI ANI_G entity ID for port
110 """
111 return self._entity_id
112
113 @entity_id.setter
114 def entity_id(self, value):
Chip Boling3815b5f2018-09-29 10:30:12 -0500115 assert self._entity_id is None or self._entity_id == value, 'Cannot reset the Entity ID'
Chip Boling040f8d52018-07-19 12:48:12 -0500116 self._entity_id = value
117
118 @property
Chip Bolinge84aca92018-03-27 11:45:56 -0700119 def next_gem_entity_id(self):
120 entity_id = self._next_entity_id
121
122 self._next_entity_id = self._next_entity_id + 1
123 if self._next_entity_id > PonPort.MAX_GEM_ENTITY_ID:
124 self._next_entity_id = PonPort.MIN_GEM_ENTITY_ID
125
126 return entity_id
127
Chip Bolinge9313592018-06-08 13:36:18 -0500128 @property
129 def tconts(self):
130 return self._tconts
131
132 @property
133 def gem_ports(self):
134 return self._gem_ports
135
Chip Bolingfd1fd372017-12-20 13:34:12 -0600136 def get_port(self):
137 """
138 Get the VOLTHA PORT object for this port
139 :return: VOLTHA Port object
140 """
141 if self._port is None:
142 device = self._handler.adapter_agent.get_device(self._handler.device_id)
143
144 self._port = Port(port_no=self.port_number,
145 label='PON port',
146 type=Port.PON_ONU,
147 admin_state=self._admin_state,
148 oper_status=self._oper_status,
Chip Boling8536d1b2018-01-19 12:44:54 -0600149 peers=[Port.PeerPort(device_id=device.parent_id,
150 port_no=device.parent_port_no)])
Chip Bolingfd1fd372017-12-20 13:34:12 -0600151 return self._port
152
153 def _update_adapter_agent(self):
Chip Bolingee366632018-04-20 15:08:52 -0500154 """
155 Update the port status and state in the core
156 """
157 self.log.debug('update-adapter-agent', admin_state=self._admin_state,
Chip Boling16075f52018-04-26 10:38:46 -0500158 oper_status=self._oper_status)
Chip Bolingee366632018-04-20 15:08:52 -0500159
160 if self._port is not None:
161 self._port.admin_state = self._admin_state
162 self._port.oper_status = self._oper_status
163
164 # adapter_agent add_port also does an update of port status
Chip Boling16075f52018-04-26 10:38:46 -0500165 try:
166 self._handler.adapter_agent.add_port(self._handler.device_id, self.get_port())
Chip Boling16075f52018-04-26 10:38:46 -0500167 except Exception as e:
168 self.log.exception('update-port', e=e)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600169
Chip Bolingfd1fd372017-12-20 13:34:12 -0600170 def add_tcont(self, tcont, reflow=False):
171 """
172 Creates/ a T-CONT with the given alloc-id
173
174 :param tcont: (TCont) Object that maintains the TCONT properties
175 :param reflow: (boolean) If true, force add (used during h/w resync)
176 :return: (deferred)
177 """
178 if not self._valid:
Chip Bolinge84aca92018-03-27 11:45:56 -0700179 return # Deleting
Chip Bolingfd1fd372017-12-20 13:34:12 -0600180
181 if not reflow and tcont.alloc_id in self._tconts:
Chip Bolinge84aca92018-03-27 11:45:56 -0700182 return # already created
Chip Bolingfd1fd372017-12-20 13:34:12 -0600183
184 self.log.info('add', tcont=tcont, reflow=reflow)
185 self._tconts[tcont.alloc_id] = tcont
186
Chip Bolingfd1fd372017-12-20 13:34:12 -0600187 @inlineCallbacks
188 def remove_tcont(self, alloc_id):
189 tcont = self._tconts.get(alloc_id)
190
191 if tcont is None:
192 returnValue('nop')
193
Chip Bolingfd1fd372017-12-20 13:34:12 -0600194 try:
Chip Bolinge84aca92018-03-27 11:45:56 -0700195 del self._tconts[alloc_id]
Chip Bolinge9313592018-06-08 13:36:18 -0500196 results = yield tcont.remove_from_hardware(self._handler.openomci.omci_cc)
Chip Bolinge84aca92018-03-27 11:45:56 -0700197 returnValue(results)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600198
199 except Exception as e:
200 self.log.exception('delete', e=e)
Chip Bolinge84aca92018-03-27 11:45:56 -0700201 raise
Chip Bolingfd1fd372017-12-20 13:34:12 -0600202
203 def gem_port(self, gem_id):
204 return self._gem_ports.get(gem_id)
205
206 @property
207 def gem_ids(self):
208 """Get all GEM Port IDs used by this ONU"""
209 return sorted([gem_id for gem_id, gem in self._gem_ports.items()])
210
Chip Bolingfd1fd372017-12-20 13:34:12 -0600211 def add_gem_port(self, gem_port, reflow=False):
212 """
213 Add a GEM Port to this ONU
214
215 :param gem_port: (GemPort) GEM Port to add
216 :param reflow: (boolean) If true, force add (used during h/w resync)
217 :return: (deferred)
218 """
219 if not self._valid:
Chip Bolinge84aca92018-03-27 11:45:56 -0700220 return # Deleting
Chip Bolingfd1fd372017-12-20 13:34:12 -0600221
222 if not reflow and gem_port.gem_id in self._gem_ports:
Chip Bolinge84aca92018-03-27 11:45:56 -0700223 return # nop
Chip Bolingfd1fd372017-12-20 13:34:12 -0600224
225 self.log.info('add', gem_port=gem_port, reflow=reflow)
226 self._gem_ports[gem_port.gem_id] = gem_port
227
Chip Bolingfd1fd372017-12-20 13:34:12 -0600228 @inlineCallbacks
229 def remove_gem_id(self, gem_id):
Chip Bolinge84aca92018-03-27 11:45:56 -0700230 """
231 Remove a GEM Port from this ONU
232
233 :param gem_port: (GemPort) GEM Port to remove
234 :return: deferred
235 """
Chip Bolingfd1fd372017-12-20 13:34:12 -0600236 gem_port = self._gem_ports.get(gem_id)
237
238 if gem_port is None:
239 returnValue('nop')
240
Chip Bolingfd1fd372017-12-20 13:34:12 -0600241 try:
Chip Bolinge84aca92018-03-27 11:45:56 -0700242 del self._gem_ports[gem_id]
Chip Bolinge9313592018-06-08 13:36:18 -0500243 results = yield gem_port.remove_from_hardware(self._handler.openomci.omci_cc)
Chip Bolinge84aca92018-03-27 11:45:56 -0700244 returnValue(results)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600245
246 except Exception as ex:
247 self.log.exception('gem-port-delete', e=ex)
248 raise