blob: 111f1f5e00a79e293e0c381f6fb3fdb09f896aba [file] [log] [blame]
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001#
2# Copyright 2018 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -050016from __future__ import absolute_import
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050017import structlog
18from twisted.internet.defer import inlineCallbacks, returnValue
William Kurkian8235c1e2019-03-05 12:58:28 -050019from voltha_protos.common_pb2 import AdminState, OperStatus
20from voltha_protos.device_pb2 import Port
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050021from pyvoltha.adapters.extensions.omci.tasks.task import Task
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050022
23BRDCM_DEFAULT_VLAN = 4091
24TASK_PRIORITY = Task.DEFAULT_PRIORITY + 10
25DEFAULT_TPID = 0x8100
26DEFAULT_GEM_PAYLOAD = 48
27
28
29class PonPort(object):
30 """Wraps northbound-port/ANI support for ONU"""
31 # TODO: possibly get from olt
32 MIN_GEM_ENTITY_ID = 0x408
33 MAX_GEM_ENTITY_ID = 0x4FF # TODO: This limits is internal to specific ONU. It should be more "discoverable"?
34
35 def __init__(self, handler, port_no):
36 self.log = structlog.get_logger(device_id=handler.device_id, port_no=port_no)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050037
38 self._enabled = False
39 self._valid = True
40 self._handler = handler
41 self._deferred = None
42 self._port = None
43 self._port_number = port_no
Matt Jeanneret0c287892019-02-28 11:48:00 -050044 self._peers = []
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050045 self._next_entity_id = PonPort.MIN_GEM_ENTITY_ID
46
47 self._admin_state = AdminState.ENABLED
48 self._oper_status = OperStatus.ACTIVE
49
Girish Gowdrae933cd32019-11-21 21:04:41 +053050 self._gem_ports = {} # gem-id -> GemPort
51 self._tconts = {} # alloc-id -> TCont
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050052
53 self.ieee_mapper_service_profile_entity_id = 0x8001
54 self.mac_bridge_port_ani_entity_id = 0x2102 # TODO: can we just use the entity id from the anis list?
55
56 def __str__(self):
57 return "PonPort - port_number: {}, next_entity_id: {}, num_gem_ports: {}, num_tconts: {}".format(
58 self._port_number, self._next_entity_id, len(self._gem_ports), len(self._tconts))
59
60 def __repr__(self):
61 return str(self)
62
63 @staticmethod
64 def create(handler, port_no):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050065 port = PonPort(handler, port_no)
66
67 return port
68
69 def _start(self):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050070 self._cancel_deferred()
71
72 self._admin_state = AdminState.ENABLED
73 self._oper_status = OperStatus.ACTIVE
74 self._update_adapter_agent()
75
76 def _stop(self):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050077 self._cancel_deferred()
78
79 self._admin_state = AdminState.DISABLED
80 self._oper_status = OperStatus.UNKNOWN
81 self._update_adapter_agent()
82
83 # TODO: stop h/w sync
84
85 def _cancel_deferred(self):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050086 d1, self._deferred = self._deferred, None
87
88 for d in [d1]:
89 try:
90 if d is not None and not d.called:
91 d.cancel()
92 except:
93 pass
94
95 def delete(self):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050096 self.enabled = False
97 self._valid = False
98 self._handler = None
99
100 @property
101 def enabled(self):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500102 return self._enabled
103
104 @enabled.setter
105 def enabled(self, value):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500106 if self._enabled != value:
107 self._enabled = value
108
109 if value:
110 self._start()
111 else:
112 self._stop()
113
114 @property
115 def port_number(self):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500116 return self._port_number
117
118 @property
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500119 def tconts(self):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500120 return self._tconts
121
122 @property
123 def gem_ports(self):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500124 return self._gem_ports
125
Girish Gowdrac5117452020-08-03 11:20:53 -0700126 def get_gem_port(self, gem_port_id, direction="downstream"):
127 try:
128 return self._gem_ports[(gem_port_id, direction)]
129 except Exception as e:
130 self.log.error("error-fetching-gem-port", gem_port_id=gem_port_id, e=e)
131 return None
132
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500133 def get_port(self):
134 """
135 Get the VOLTHA PORT object for this port
136 :return: VOLTHA Port object
137 """
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500138
Matt Jeanneret0c287892019-02-28 11:48:00 -0500139 self._port = Port(port_no=self.port_number,
140 label='PON port',
141 type=Port.PON_ONU,
142 admin_state=self._admin_state,
143 oper_status=self._oper_status,
144 peers=self._peers)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500145 return self._port
146
Matt Jeanneret0c287892019-02-28 11:48:00 -0500147 def add_peer(self, parent_device_id, parent_port_no):
148 self.log.debug('add-peer-port', parent_device_id=parent_device_id, parent_port_no=parent_port_no)
149 new_peer = Port.PeerPort(device_id=parent_device_id, port_no=parent_port_no)
150 self._peers.extend([new_peer])
151
Matt Jeanneret84e56f62019-02-26 10:48:09 -0500152 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500153 def _update_adapter_agent(self):
154 """
155 Update the port status and state in the core
156 """
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500157 self.log.debug('update-adapter-agent', admin_state=self._admin_state,
158 oper_status=self._oper_status)
159
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
165 try:
Matt Jeannereta32441c2019-03-07 05:16:37 -0500166 yield self._handler.core_proxy.port_state_update(self._handler.device_id, self._port.type,
Girish Gowdrae933cd32019-11-21 21:04:41 +0530167 self._port.port_no, self._port.oper_status)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500168 except Exception as e:
169 self.log.exception('update-port', e=e)
170
171 def add_tcont(self, tcont, reflow=False):
172 """
173 Creates/ a T-CONT with the given alloc-id
174
175 :param tcont: (TCont) Object that maintains the TCONT properties
176 :param reflow: (boolean) If true, force add (used during h/w resync)
177 :return: (deferred)
178 """
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500179
180 if not self._valid:
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500181 return False # Deleting
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500182
183 if not reflow and tcont.alloc_id in self._tconts:
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500184 return False # already created
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500185
186 self.log.info('add-tcont', tcont=tcont.alloc_id, reflow=reflow)
Girish Gowdra7c1240c2020-07-15 15:06:42 -0700187 if tcont.alloc_id not in self._tconts:
188 self._tconts[tcont.alloc_id] = tcont
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500189 return True
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500190
Girish Gowdra8777c852020-07-23 12:00:23 -0700191 def get_tcont(self, alloc_id):
192 try:
193 return self._tconts[alloc_id]
194 except Exception as e:
195 self.log.error("error-fetching-tcont", alloc_id=alloc_id, e=e)
196 return None
197
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500198 @inlineCallbacks
Girish Gowdrae933cd32019-11-21 21:04:41 +0530199 def remove_tcont(self, alloc_id, remove_from_hw=True):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500200
201 tcont = self._tconts.get(alloc_id)
202
203 if tcont is None:
204 returnValue('nop')
205
206 try:
207 del self._tconts[alloc_id]
Girish Gowdrae933cd32019-11-21 21:04:41 +0530208 if remove_from_hw:
209 results = yield tcont.remove_from_hardware(self._handler.openomci.omci_cc)
210 returnValue(results)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500211
212 except Exception as e:
213 self.log.exception('delete', e=e)
214 raise
215
216 def gem_port(self, gem_id, direction):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500217 return self._gem_ports.get((gem_id, direction))
218
219 @property
220 def gem_ids(self):
221 """Get all GEM Port IDs used by this ONU"""
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500222 return sorted([gem_id_and_direction[0] for gem_id_and_direction, gem in self._gem_ports.items()])
223
224 def add_gem_port(self, gem_port, reflow=False):
225 """
226 Add a GEM Port to this ONU
227
228 :param gem_port: (GemPort) GEM Port to add
229 :param reflow: (boolean) If true, force add (used during h/w resync)
230 :return: (deferred)
231 """
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500232
233 if not self._valid:
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500234 return False # Deleting
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500235
236 if not reflow and (gem_port.gem_id, gem_port.direction) in self._gem_ports:
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500237 return False # nop
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500238
Girish Gowdrae933cd32019-11-21 21:04:41 +0530239 # The gem_port entity id is set to be same as gem_id
240 gem_port.entity_id = gem_port.gem_id
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500241 self.log.info('add-gem-port', gem_port=gem_port, reflow=reflow)
242 self._gem_ports[(gem_port.gem_id, gem_port.direction)] = gem_port
Matt Jeanneret2ca384f2020-03-06 13:49:31 -0500243 return True
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500244
245 @inlineCallbacks
Girish Gowdrae933cd32019-11-21 21:04:41 +0530246 def remove_gem_id(self, gem_id, direction, remove_from_hw=True):
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500247 """
248 Remove a GEM Port from this ONU
249
250 :param gem_id: (GemPort) GEM Port to remove
251 :param direction: Direction of the gem port
Girish Gowdrae933cd32019-11-21 21:04:41 +0530252 :param remove_from_hw: Remove the GemPort from hardware (remove if True else not)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500253 :return: deferred
254 """
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500255
256 gem_port = self._gem_ports.get((gem_id, direction))
257
258 if gem_port is None:
259 returnValue('nop')
260
261 try:
262 del self._gem_ports[(gem_id, direction)]
Girish Gowdrae933cd32019-11-21 21:04:41 +0530263 if remove_from_hw:
264 results = yield gem_port.remove_from_hardware(self._handler.openomci.omci_cc)
265 returnValue(results)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500266
267 except Exception as ex:
268 self.log.exception('gem-port-delete', e=ex)
269 raise