blob: f00994b9c9bffcef019a18f4936a198d300ffdc5 [file] [log] [blame]
Shad Ansari134947d2019-02-14 23:45:03 -08001#
2# Copyright 2019 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#
16import structlog
17import socket
18from voltha.adapters.openolt.openolt_utils import OpenoltUtils
Shad Ansarid5577972019-02-22 09:35:03 -080019from voltha.protos.device_pb2 import Port, Device
Shad Ansari134947d2019-02-14 23:45:03 -080020from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
21 OFPPS_LINK_DOWN, OFPPF_1GB_FD, OFPC_PORT_STATS, OFPC_TABLE_STATS, \
22 OFPC_FLOW_STATS, OFPC_GROUP_STATS, ofp_port, ofp_port_stats, ofp_desc, \
23 ofp_switch_features
24from voltha.core.logical_device_agent import mac_str_to_tuple
25from voltha.protos.logical_device_pb2 import LogicalPort
Shad Ansarid5577972019-02-22 09:35:03 -080026from voltha.protos.common_pb2 import OperStatus, AdminState, ConnectStatus
Shad Ansari134947d2019-02-14 23:45:03 -080027from voltha.protos.logical_device_pb2 import LogicalDevice
28from voltha.registry import registry
29
30
31class OpenOltDataModel(object):
Shad Ansari134947d2019-02-14 23:45:03 -080032
Shad Ansarid5577972019-02-22 09:35:03 -080033 def __init__(self, device, adapter_agent, platform):
Shad Ansari134947d2019-02-14 23:45:03 -080034 self.log = structlog.get_logger()
35
Shad Ansarid5577972019-02-22 09:35:03 -080036 self.device = device
37 self.adapter_agent = adapter_agent
38 self.platform = platform
39 self.logical_device_id = None
40
41 self.device.root = True
42 self.device.connect_status = ConnectStatus.UNREACHABLE
43 self.device.oper_status = OperStatus.ACTIVATING
44
45 self.adapter_agent.update_device(device)
46
Shad Ansarief2029b2019-02-25 09:45:54 -080047 def __del__(self):
48 pass
49
Shad Ansarid5577972019-02-22 09:35:03 -080050 def reconcile(self):
51 assert self.logical_device_id is not None
52 self.adapter_agent.reconcile_logical_device(
53 self.logical_device_id)
54
55 def olt_create(self, device_info):
56 if self.logical_device_id is not None:
57 return
58
Shad Ansari134947d2019-02-14 23:45:03 -080059 dpid = device_info.device_id
60 serial_number = device_info.device_serial_number
61
Shad Ansari134947d2019-02-14 23:45:03 -080062 if dpid is None or dpid == '':
Shad Ansarid5577972019-02-22 09:35:03 -080063 uri = self.device.host_and_port.split(":")[0]
Shad Ansari134947d2019-02-14 23:45:03 -080064 try:
65 socket.inet_pton(socket.AF_INET, uri)
66 dpid = '00:00:' + OpenoltUtils.ip_hex(uri)
67 except socket.error:
68 # this is not an IP
69 dpid = OpenoltUtils.str_to_mac(uri)
70
71 self.log.info('creating-openolt-logical-device', dp_id=dpid,
72 serial_number=serial_number)
73
74 hw_desc = device_info.model
75 if device_info.hardware_version:
76 hw_desc += '-' + device_info.hardware_version
77
78 # Create logical OF device
79 ld = LogicalDevice(
Shad Ansarid5577972019-02-22 09:35:03 -080080 root_device_id=self.device.id,
Shad Ansari134947d2019-02-14 23:45:03 -080081 switch_features=ofp_switch_features(
82 n_buffers=256, # TODO fake for now
83 n_tables=2, # TODO ditto
84 capabilities=( # TODO and ditto
85 OFPC_FLOW_STATS
86 | OFPC_TABLE_STATS
87 | OFPC_PORT_STATS
88 | OFPC_GROUP_STATS
89 )
90 ),
91 desc=ofp_desc(
92 serial_num=serial_number
93 )
94 )
Shad Ansarid5577972019-02-22 09:35:03 -080095 self.logical_device_id = \
96 self.adapter_agent.create_logical_device(ld, dpid=dpid).id
Shad Ansari134947d2019-02-14 23:45:03 -080097
Shad Ansarid5577972019-02-22 09:35:03 -080098 self.device.vendor = device_info.vendor
99 self.device.model = device_info.model
100 self.device.hardware_version = device_info.hardware_version
101 self.device.firmware_version = device_info.firmware_version
102 self.device.connect_status = ConnectStatus.REACHABLE
103 self.device.serial_number = serial_number
104
105 self.adapter_agent.update_device(self.device)
Shad Ansari134947d2019-02-14 23:45:03 -0800106
107 self.log.info('created-openolt-logical-device',
Shad Ansarid5577972019-02-22 09:35:03 -0800108 logical_device_id=self.logical_device_id)
Shad Ansari134947d2019-02-14 23:45:03 -0800109
Shad Ansarid5577972019-02-22 09:35:03 -0800110 return self.logical_device_id
Shad Ansari134947d2019-02-14 23:45:03 -0800111
Shad Ansarief2029b2019-02-25 09:45:54 -0800112 def olt_oper_up(self):
113 self.device.parent_id = self.logical_device_id
114 self.device.oper_status = OperStatus.ACTIVE
115 self.adapter_agent.update_device(self.device)
Shad Ansari134947d2019-02-14 23:45:03 -0800116
Shad Ansarief2029b2019-02-25 09:45:54 -0800117 def olt_oper_down(self):
118 self._disable_logical_device()
119
120 def olt_delete(self):
121 ld = self.adapter_agent.get_logical_device(self.logical_device_id)
122 self.adapter_agent.delete_logical_device(ld)
123
124 def onu_create(self, intf_id, onu_id, serial_number):
125 onu_device = self.adapter_agent.get_child_device(
126 self.device.id,
127 serial_number=serial_number)
128
129 if onu_device:
130 self.log.debug("data_model onu update", intf_id=intf_id,
131 onu_id=onu_id, serial_number=serial_number)
132 onu_device.oper_status = OperStatus.DISCOVERED
133 onu_device.connect_status = ConnectStatus.REACHABLE
134 self.adapter_agent.update_device(onu_device)
135 return
136
137 self.log.debug("data_model onu create", intf_id=intf_id,
138 onu_id=onu_id, serial_number=serial_number)
139
140 # NOTE - channel_id of onu is set to intf_id
141 proxy_address = Device.ProxyAddress(device_id=self.device.id,
142 channel_id=intf_id, onu_id=onu_id,
143 onu_session_id=onu_id)
144 port_no = self.platform.intf_id_to_port_no(intf_id, Port.PON_OLT)
145 vendor_id = serial_number[:4]
146 self.adapter_agent.add_onu_device(
147 parent_device_id=self.device.id, parent_port_no=port_no,
148 vendor_id=vendor_id, proxy_address=proxy_address,
149 root=False, serial_number=serial_number,
150 admin_state=AdminState.ENABLED,
151 connect_status=ConnectStatus.REACHABLE
152 )
153
154 def onu_delete(self, serial_number):
155 onu_device = self.adapter_agent.get_child_device(
156 self.device.id,
157 serial_number=serial_number)
158 try:
159 self.adapter_agent.delete_child_device(self.device_id,
160 onu_device.id, onu_device)
161 except Exception as e:
162 self.log.error('adapter_agent error', error=e)
163
164 ofp_port_name = self._get_uni_ofp_port_name(onu_device)
165 if ofp_port_name is None:
166 self.log.exception("uni-ofp-port-not-found")
167 return
168
169 try:
170 self._delete_logical_port(onu_device)
171 except Exception as e:
172 self.log.error('logical_port delete error', error=e)
173 try:
174 self.delete_port(onu_device.serial_number)
175 except Exception as e:
176 self.log.error('port delete error', error=e)
177
178 def onu_id(self, serial_number):
179 onu_device = self.adapter_agent.get_child_device(
180 self.device.id,
181 serial_number=serial_number)
182
183 if onu_device:
184 return onu_device.proxy_address.onu_id
185 else:
186 return 0 # Invalid onu id
187
188 def onu_oper_down(self, intf_id, onu_id):
189
190 onu_device = self.adapter_agent.get_child_device(
191 self.device.id,
192 parent_port_no=self.platform.intf_id_to_port_no(intf_id,
193 Port.PON_OLT),
194 onu_id=onu_id)
195
196 if onu_device is None:
197 self.log.error('onu not found', intf_id=intf_id, onu_id=onu_id)
198 return
199
200 onu_adapter_agent = \
201 registry('adapter_loader').get_agent(onu_device.adapter)
202 if onu_adapter_agent is None:
203 self.log.error('onu_adapter_agent-could-not-be-retrieved',
204 onu_device=onu_device)
205 return
206
207 if onu_device.connect_status != ConnectStatus.UNREACHABLE:
208 onu_device.connect_status = ConnectStatus.UNREACHABLE
209 self.adapter_agent.update_device(onu_device)
210
211 # Move to discovered state
212 self.log.debug('onu-oper-state-is-down')
213
214 if onu_device.oper_status != OperStatus.DISCOVERED:
215 onu_device.oper_status = OperStatus.DISCOVERED
216 self.adapter_agent.update_device(onu_device)
217 # Set port oper state to Discovered
218 self.data_model._onu_ports_down(onu_device)
219
220 onu_adapter_agent.update_interface(onu_device,
221 {'oper_state': 'down'})
222
223 def onu_oper_up(self, intf_id, onu_id):
224
225 class _OnuIndication:
226 def __init__(self, intf_id, onu_id):
227 self.intf_id = intf_id
228 self.onu_id = onu_id
229
230 onu_device = self.adapter_agent.get_child_device(
231 self.device.id,
232 parent_port_no=self.platform.intf_id_to_port_no(intf_id,
233 Port.PON_OLT),
234 onu_id=onu_id)
235
236 if onu_device is None:
237 self.log.error('onu not found', intf_id=intf_id, onu_id=onu_id)
238 return
239
240 onu_adapter_agent = \
241 registry('adapter_loader').get_agent(onu_device.adapter)
242 if onu_adapter_agent is None:
243 self.log.error('onu_adapter_agent-could-not-be-retrieved',
244 onu_device=onu_device)
245 return
246 if onu_device.connect_status != ConnectStatus.REACHABLE:
247 onu_device.connect_status = ConnectStatus.REACHABLE
248 self.adapter_agent.update_device(onu_device)
249
250 if onu_device.oper_status != OperStatus.DISCOVERED:
251 self.log.debug("ignore onu indication",
252 intf_id=intf_id,
253 onu_id=onu_id,
254 state=onu_device.oper_status,
255 msg_oper_state="up")
256 return
257
258 onu_adapter_agent.create_interface(onu_device,
259 _OnuIndication(intf_id, onu_id))
260
261 def olt_port_add_update(self, intf_id, intf_type, oper):
262 if oper == "up":
263 oper_status = OperStatus.ACTIVE
264 else:
265 oper_status = OperStatus.DISCOVERED
266
267 if intf_type == "nni":
268 port_type = Port.ETHERNET_NNI
269 elif intf_type == "pon":
270 port_type = Port.PON_OLT
271
272 port_no, label = self._add_port(intf_id, port_type, oper_status)
273
274 if intf_type == "nni":
275 self._add_logical_port(port_no, intf_id, oper)
276
277 # #################
278 # Private functions
279 # #################
280
281 def _disable_logical_device(self):
Shad Ansari134947d2019-02-14 23:45:03 -0800282 oper_state = OperStatus.UNKNOWN
283 connect_state = ConnectStatus.UNREACHABLE
284
Shad Ansarief2029b2019-02-25 09:45:54 -0800285 onu_devices = self.adapter_agent.get_child_devices(self.device.id)
286 for onu_device in onu_devices:
Shad Ansari134947d2019-02-14 23:45:03 -0800287 onu_adapter_agent = \
288 registry('adapter_loader').get_agent(onu_device.adapter)
289 onu_adapter_agent.update_interface(onu_device,
290 {'oper_state': 'down'})
Shad Ansarief2029b2019-02-25 09:45:54 -0800291 self.onu_ports_down(onu_device)
Shad Ansari134947d2019-02-14 23:45:03 -0800292
293 # Children devices
294 self.adapter_agent.update_child_devices_state(
Shad Ansarid5577972019-02-22 09:35:03 -0800295 self.device.id, oper_status=oper_state,
Shad Ansari134947d2019-02-14 23:45:03 -0800296 connect_status=connect_state)
297 # Device Ports
Shad Ansarid5577972019-02-22 09:35:03 -0800298 device_ports = self.adapter_agent.get_ports(self.device.id,
Shad Ansari134947d2019-02-14 23:45:03 -0800299 Port.ETHERNET_NNI)
300 logical_ports_ids = [port.label for port in device_ports]
Shad Ansarid5577972019-02-22 09:35:03 -0800301 device_ports += self.adapter_agent.get_ports(self.device.id,
Shad Ansari134947d2019-02-14 23:45:03 -0800302 Port.PON_OLT)
303
304 for port in device_ports:
305 port.oper_status = oper_state
Shad Ansarid5577972019-02-22 09:35:03 -0800306 self.adapter_agent.add_port(self.device.id, port)
Shad Ansari134947d2019-02-14 23:45:03 -0800307
308 # Device logical port
309 for logical_port_id in logical_ports_ids:
310 logical_port = self.adapter_agent.get_logical_port(
Shad Ansarid5577972019-02-22 09:35:03 -0800311 self.logical_device_id, logical_port_id)
Shad Ansari134947d2019-02-14 23:45:03 -0800312 logical_port.ofp_port.state = OFPPS_LINK_DOWN
313 self.adapter_agent.update_logical_port(self.logical_device_id,
314 logical_port)
Shad Ansarid5577972019-02-22 09:35:03 -0800315 self.device.oper_status = oper_state
316 self.device.connect_status = connect_state
317 self.adapter_agent.update_device(self.device)
Shad Ansari134947d2019-02-14 23:45:03 -0800318
Shad Ansarief2029b2019-02-25 09:45:54 -0800319 def _add_logical_port(self, port_no, intf_id, oper_state):
Shad Ansari134947d2019-02-14 23:45:03 -0800320 self.log.info('adding-logical-port', port_no=port_no)
321
322 label = OpenoltUtils.port_name(port_no, Port.ETHERNET_NNI)
323
324 cap = OFPPF_1GB_FD | OFPPF_FIBER
325 curr_speed = OFPPF_1GB_FD
326 max_speed = OFPPF_1GB_FD
327
328 if oper_state == OperStatus.ACTIVE:
329 of_oper_state = OFPPS_LIVE
330 else:
331 of_oper_state = OFPPS_LINK_DOWN
332
333 ofp = ofp_port(
334 port_no=port_no,
335 hw_addr=mac_str_to_tuple(
336 OpenoltUtils.make_mac_from_port_no(port_no)),
337 name=label, config=0, state=of_oper_state, curr=cap,
338 advertised=cap, peer=cap, curr_speed=curr_speed,
339 max_speed=max_speed)
340
341 ofp_stats = ofp_port_stats(port_no=port_no)
342
343 logical_port = LogicalPort(
Shad Ansarid5577972019-02-22 09:35:03 -0800344 id=label, ofp_port=ofp, device_id=self.device.id,
Shad Ansari134947d2019-02-14 23:45:03 -0800345 device_port_no=port_no, root_port=True,
346 ofp_port_stats=ofp_stats)
347
Shad Ansarid5577972019-02-22 09:35:03 -0800348 self.adapter_agent.add_logical_port(self.logical_device_id,
349 logical_port)
350
Shad Ansarief2029b2019-02-25 09:45:54 -0800351 def _delete_logical_port(self, child_device):
352 logical_ports = self.proxy.get('/logical_devices/{}/ports'.format(
353 self.data_model.logical_device_id))
354 for logical_port in logical_ports:
355 if logical_port.device_id == child_device.id:
356 self.log.debug('delete-logical-port',
357 onu_device_id=child_device.id,
358 logical_port=logical_port)
359 self.flow_mgr.clear_flows_and_scheduler_for_logical_port(
360 child_device, logical_port)
361 self.adapter_agent.delete_logical_port(
362 self.data_model.logical_device_id, logical_port)
363 return
Shad Ansarid5577972019-02-22 09:35:03 -0800364
Shad Ansarief2029b2019-02-25 09:45:54 -0800365 def _onu_ports_down(self, onu_device):
366 onu_ports = self.proxy.get('devices/{}/ports'.format(onu_device.id))
367 for onu_port in onu_ports:
368 self.log.debug('onu-ports-down', onu_port=onu_port)
369 onu_port_id = onu_port.label
370 try:
371 onu_logical_port = self.adapter_agent.get_logical_port(
372 logical_device_id=self.data_model.logical_device_id,
373 port_id=onu_port_id)
374 onu_logical_port.ofp_port.state = OFPPS_LINK_DOWN
375 self.adapter_agent.update_logical_port(
376 logical_device_id=self.data_model.logical_device_id,
377 port=onu_logical_port)
378 self.log.debug('cascading-oper-state-to-port-and-logical-port')
379 except KeyError as e:
380 self.log.error('matching-onu-port-label-invalid',
381 onu_id=onu_device.id, olt_id=self.device.id,
382 onu_ports=onu_ports, onu_port_id=onu_port_id,
383 error=e)
Shad Ansarid5577972019-02-22 09:35:03 -0800384
Shad Ansarief2029b2019-02-25 09:45:54 -0800385 def _add_port(self, intf_id, port_type, oper_status):
386 port_no = self.platform.intf_id_to_port_no(intf_id, port_type)
Shad Ansarid5577972019-02-22 09:35:03 -0800387
Shad Ansarief2029b2019-02-25 09:45:54 -0800388 label = OpenoltUtils.port_name(port_no, port_type, intf_id)
Shad Ansarid5577972019-02-22 09:35:03 -0800389
Shad Ansarief2029b2019-02-25 09:45:54 -0800390 self.log.debug('adding-port', port_no=port_no, label=label,
391 port_type=port_type)
Shad Ansarid5577972019-02-22 09:35:03 -0800392
Shad Ansarief2029b2019-02-25 09:45:54 -0800393 port = Port(port_no=port_no, label=label, type=port_type,
394 admin_state=AdminState.ENABLED, oper_status=oper_status)
Shad Ansarid5577972019-02-22 09:35:03 -0800395
Shad Ansarief2029b2019-02-25 09:45:54 -0800396 self.adapter_agent.add_port(self.device.id, port)
Shad Ansarid5577972019-02-22 09:35:03 -0800397
Shad Ansarief2029b2019-02-25 09:45:54 -0800398 return port_no, label
Shad Ansarid5577972019-02-22 09:35:03 -0800399
Shad Ansarief2029b2019-02-25 09:45:54 -0800400 def _get_uni_ofp_port_name(self, child_device):
401 logical_ports = self.proxy.get('/logical_devices/{}/ports'.format(
402 self.data_model.logical_device_id))
403 for logical_port in logical_ports:
404 if logical_port.device_id == child_device.id:
405 return logical_port.ofp_port.name
406 return None