blob: 943fb669e0c6b56605bf7b25bd48e2a28233f861 [file] [log] [blame]
Shad Ansari2825d012018-02-22 23:57:46 +00001#
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#
Shad Ansari2825d012018-02-22 23:57:46 +000016import threading
Shad Ansari94250fc2018-07-04 06:52:11 +000017import binascii
Shad Ansari2825d012018-02-22 23:57:46 +000018import grpc
Shad Ansari2825d012018-02-22 23:57:46 +000019
Shad Ansari94250fc2018-07-04 06:52:11 +000020import structlog
Shad Ansari15928d12018-04-17 02:42:13 +000021from twisted.internet import reactor
Shad Ansari0346f0d2018-04-26 06:54:09 +000022from scapy.layers.l2 import Ether, Dot1Q
Shad Ansari3cd9bf22018-07-25 19:29:39 +000023from transitions import Machine
Shad Ansari15928d12018-04-17 02:42:13 +000024
Shad Ansari2825d012018-02-22 23:57:46 +000025from voltha.protos.device_pb2 import Port, Device
26from voltha.protos.common_pb2 import OperStatus, AdminState, ConnectStatus
27from voltha.protos.logical_device_pb2 import LogicalDevice
Shad Ansarif9d2d102018-06-13 02:15:26 +000028from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
29 OFPPS_LINK_DOWN, OFPPF_1GB_FD, OFPC_GROUP_STATS, OFPC_PORT_STATS, \
Nicolas Palpacuere7359fc2018-06-15 14:10:48 -040030 OFPC_TABLE_STATS, OFPC_FLOW_STATS, ofp_switch_features, ofp_port, \
Jonathan Hart05845412018-07-19 09:55:43 -070031 ofp_port_stats, ofp_desc
Shad Ansarif9d2d102018-06-13 02:15:26 +000032from voltha.protos.logical_device_pb2 import LogicalPort
Shad Ansari2825d012018-02-22 23:57:46 +000033from voltha.core.logical_device_agent import mac_str_to_tuple
34from voltha.registry import registry
35from voltha.adapters.openolt.protos import openolt_pb2_grpc, openolt_pb2
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -040036from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
37from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
Shad Ansari2825d012018-02-22 23:57:46 +000038
mzadig384783a2018-08-09 08:52:40 -040039from voltha.extensions.alarms.onu.onu_discovery_alarm import OnuDiscoveryAlarm
Shad Ansarif9d2d102018-06-13 02:15:26 +000040
41
Shad Ansari2825d012018-02-22 23:57:46 +000042class OpenoltDevice(object):
Shad Ansari94250fc2018-07-04 06:52:11 +000043 """
44 OpenoltDevice state machine:
Shad Ansari2825d012018-02-22 23:57:46 +000045
Shad Ansari94250fc2018-07-04 06:52:11 +000046 null ----> init ------> connected -----> up -----> down
47 ^ ^ | ^ | |
48 | | | | | |
49 | +-------------+ +---------+ |
50 | |
51 +-----------------------------------------+
52 """
53 # pylint: disable=too-many-instance-attributes
54 # pylint: disable=R0904
55 states = [
56 'state_null',
57 'state_init',
58 'state_connected',
59 'state_up',
60 'state_down']
61
Shad Ansari22efe832018-05-19 05:37:03 +000062 transitions = [
Shad Ansari0e7ad962018-09-28 01:42:26 +000063 {'trigger': 'go_state_init',
64 'source': ['state_null', 'state_connected', 'state_down'],
65 'dest': 'state_init',
66 'before': 'do_state_init',
67 'after': 'post_init'},
68 {'trigger': 'go_state_connected',
69 'source': 'state_init',
70 'dest': 'state_connected',
71 'before': 'do_state_connected'},
72 {'trigger': 'go_state_up',
73 'source': ['state_connected', 'state_down'],
74 'dest': 'state_up',
75 'before': 'do_state_up'},
76 {'trigger': 'go_state_down',
77 'source': ['state_up'],
78 'dest': 'state_down',
79 'before': 'do_state_down',
80 'after': 'post_down'}]
Shad Ansari22efe832018-05-19 05:37:03 +000081
Shad Ansari2825d012018-02-22 23:57:46 +000082 def __init__(self, **kwargs):
83 super(OpenoltDevice, self).__init__()
84
85 self.adapter_agent = kwargs['adapter_agent']
Shad Ansari5dbc9c82018-05-10 03:29:31 +000086 self.device_num = kwargs['device_num']
Shad Ansari2825d012018-02-22 23:57:46 +000087 device = kwargs['device']
Shad Ansaricd20a6d2018-10-02 14:36:33 +000088
89 self.platform_class = kwargs['support_classes']['platform']
Girish Gowdru1e77ea02018-09-24 09:10:35 -070090 self.resource_mgr_class = kwargs['support_classes']['resource_mgr']
Shad Ansaricd20a6d2018-10-02 14:36:33 +000091 self.flow_mgr_class = kwargs['support_classes']['flow_mgr']
92 self.alarm_mgr_class = kwargs['support_classes']['alarm_mgr']
93 self.stats_mgr_class = kwargs['support_classes']['stats_mgr']
94 self.bw_mgr_class = kwargs['support_classes']['bw_mgr']
95
Nicolas Palpacuer253461f2018-06-01 12:01:45 -040096 is_reconciliation = kwargs.get('reconciliation', False)
Shad Ansari2825d012018-02-22 23:57:46 +000097 self.device_id = device.id
98 self.host_and_port = device.host_and_port
Girish Gowdru141ced82018-09-17 20:19:14 -070099 self.extra_args = device.extra_args
Shad Ansarif9d2d102018-06-13 02:15:26 +0000100 self.log = structlog.get_logger(id=self.device_id,
101 ip=self.host_and_port)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400102 self.proxy = registry('core').get_proxy('/')
Shad Ansari2825d012018-02-22 23:57:46 +0000103
Nicolas Palpacuer253461f2018-06-01 12:01:45 -0400104 # Device already set in the event of reconciliation
105 if not is_reconciliation:
106 # It is a new device
107 # Update device
108 device.root = True
Shad Ansarif9d2d102018-06-13 02:15:26 +0000109 device.serial_number = self.host_and_port # FIXME
Shad Ansari94250fc2018-07-04 06:52:11 +0000110 device.connect_status = ConnectStatus.UNREACHABLE
Nicolas Palpacuer253461f2018-06-01 12:01:45 -0400111 device.oper_status = OperStatus.ACTIVATING
112 self.adapter_agent.update_device(device)
Shad Ansari2825d012018-02-22 23:57:46 +0000113
Nicolas Palpacuer28cc2662018-06-22 16:30:18 -0400114 # If logical device does not exist create it
Shad Ansari94250fc2018-07-04 06:52:11 +0000115 if not device.parent_id:
Nicolas Palpacuer28cc2662018-06-22 16:30:18 -0400116
117 dpid = '00:00:' + self.ip_hex(self.host_and_port.split(":")[0])
118
119 # Create logical OF device
120 ld = LogicalDevice(
121 root_device_id=self.device_id,
122 switch_features=ofp_switch_features(
123 n_buffers=256, # TODO fake for now
124 n_tables=2, # TODO ditto
125 capabilities=( # TODO and ditto
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700126 OFPC_FLOW_STATS
127 | OFPC_TABLE_STATS
128 | OFPC_PORT_STATS
129 | OFPC_GROUP_STATS
Nicolas Palpacuer28cc2662018-06-22 16:30:18 -0400130 )
Jonathan Hart05845412018-07-19 09:55:43 -0700131 ),
132 desc=ofp_desc(
133 serial_num=device.serial_number
Nicolas Palpacuer28cc2662018-06-22 16:30:18 -0400134 )
135 )
136 ld_init = self.adapter_agent.create_logical_device(ld,
137 dpid=dpid)
138 self.logical_device_id = ld_init.id
139 else:
140 # logical device already exists
141 self.logical_device_id = device.parent_id
142 if is_reconciliation:
143 self.adapter_agent.reconcile_logical_device(
144 self.logical_device_id)
145
Shad Ansari94250fc2018-07-04 06:52:11 +0000146 # Initialize the OLT state machine
147 self.machine = Machine(model=self, states=OpenoltDevice.states,
148 transitions=OpenoltDevice.transitions,
149 send_event=True, initial='state_null')
150 self.go_state_init()
151
152 def do_state_init(self, event):
Shad Ansari2825d012018-02-22 23:57:46 +0000153 # Initialize gRPC
154 self.channel = grpc.insecure_channel(self.host_and_port)
Shad Ansari8f1b2532018-04-21 07:51:39 +0000155 self.channel_ready_future = grpc.channel_ready_future(self.channel)
nick47b74372018-05-25 18:22:49 -0400156
Nicolas Palpacuer7183a3b2018-09-10 17:16:49 -0400157 self.log.info('openolt-device-created', device_id=self.device_id)
158
159 def post_init(self, event):
160 self.log.debug('post_init')
161
162 # We have reached init state, starting the indications thread
163
jasonhuang5f3e63b2018-07-27 01:32:48 +0800164 # Catch RuntimeError exception
165 try:
166 # Start indications thread
167 self.indications_thread_handle = threading.Thread(
168 target=self.indications_thread)
Shad Ansarif9521ad2018-09-08 10:46:43 +0000169 # Old getter/setter API for daemon; use it directly as a
jasonhuang5f3e63b2018-07-27 01:32:48 +0800170 # property instead. The Jinkins error will happon on the reason of
Shad Ansarif9521ad2018-09-08 10:46:43 +0000171 # Exception in thread Thread-1 (most likely raised # during
jasonhuang5f3e63b2018-07-27 01:32:48 +0800172 # interpreter shutdown)
173 self.indications_thread_handle.setDaemon(True)
174 self.indications_thread_handle.start()
Shad Ansarif9521ad2018-09-08 10:46:43 +0000175 except Exception as e:
Nicolas Palpacuer7183a3b2018-09-10 17:16:49 -0400176 self.log.exception('post_init failed', e=e)
Shad Ansari94250fc2018-07-04 06:52:11 +0000177
178 def do_state_connected(self, event):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400179 self.log.debug("do_state_connected")
180
Shad Ansari94250fc2018-07-04 06:52:11 +0000181 device = self.adapter_agent.get_device(self.device_id)
Shad Ansari94250fc2018-07-04 06:52:11 +0000182
183 self.stub = openolt_pb2_grpc.OpenoltStub(self.channel)
Nicolas Palpacuer33c2d3d2018-09-06 15:01:14 -0400184
185 device_info = self.stub.GetDeviceInfo(openolt_pb2.Empty())
186 self.log.info('Device connected', device_info=device_info)
187
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000188 self.platform = self.platform_class(self.log, device_info)
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700189 self.resource_mgr = self.resource_mgr_class(self.device_id,
190 self.host_and_port,
191 self.extra_args,
192 device_info)
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000193
194 self.flow_mgr = self.flow_mgr_class(self.log, self.stub,
195 self.device_id,
196 self.logical_device_id,
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700197 self.platform,
198 self.resource_mgr)
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000199 self.alarm_mgr = self.alarm_mgr_class(self.log, self.adapter_agent,
200 self.device_id,
201 self.logical_device_id,
202 self.platform)
203 self.stats_mgr = self.stats_mgr_class(self, self.log, self.platform)
204 self.bw_mgr = self.bw_mgr_class(self.log, self.proxy)
205
Nicolas Palpacuer33c2d3d2018-09-06 15:01:14 -0400206 device.vendor = device_info.vendor
207 device.model = device_info.model
208 device.hardware_version = device_info.hardware_version
209 device.firmware_version = device_info.firmware_version
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700210
211
212 # TODO: check for uptime and reboot if too long (VOL-1192)
213
Nicolas Palpacuer41141352018-08-31 14:11:38 -0400214 device.connect_status = ConnectStatus.REACHABLE
215 self.adapter_agent.update_device(device)
216
Shad Ansari94250fc2018-07-04 06:52:11 +0000217 def do_state_up(self, event):
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400218 self.log.debug("do_state_up")
219
Shad Ansari94250fc2018-07-04 06:52:11 +0000220 device = self.adapter_agent.get_device(self.device_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000221
Shad Ansari94250fc2018-07-04 06:52:11 +0000222 # Update phys OF device
223 device.parent_id = self.logical_device_id
224 device.oper_status = OperStatus.ACTIVE
225 self.adapter_agent.update_device(device)
nick47b74372018-05-25 18:22:49 -0400226
Shad Ansari94250fc2018-07-04 06:52:11 +0000227 def do_state_down(self, event):
228 self.log.debug("do_state_down")
229 oper_state = OperStatus.UNKNOWN
230 connect_state = ConnectStatus.UNREACHABLE
Nicolas Palpacuerd35d9bb2018-06-20 17:06:31 -0400231
Shad Ansari94250fc2018-07-04 06:52:11 +0000232 # Propagating to the children
Nicolas Palpacuer253461f2018-06-01 12:01:45 -0400233
Shad Ansari94250fc2018-07-04 06:52:11 +0000234 # Children ports
235 child_devices = self.adapter_agent.get_child_devices(self.device_id)
236 for onu_device in child_devices:
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000237 uni_no = self.platform.mk_uni_port_num(
Shad Ansari94250fc2018-07-04 06:52:11 +0000238 onu_device.proxy_address.channel_id,
239 onu_device.proxy_address.onu_id)
240 uni_name = self.port_name(uni_no, Port.ETHERNET_UNI,
241 serial_number=onu_device.serial_number)
Shad Ansari0e7ad962018-09-28 01:42:26 +0000242 onu_adapter_agent = \
243 registry('adapter_loader').get_agent(onu_device.adapter)
244 onu_adapter_agent.update_interface(onu_device,
245 {'oper_state': 'down'})
Shad Ansari94250fc2018-07-04 06:52:11 +0000246 self.onu_ports_down(onu_device, uni_no, uni_name, oper_state)
247 # Children devices
248 self.adapter_agent.update_child_devices_state(
249 self.device_id, oper_status=oper_state,
250 connect_status=connect_state)
251 # Device Ports
252 device_ports = self.adapter_agent.get_ports(self.device_id,
253 Port.ETHERNET_NNI)
254 logical_ports_ids = [port.label for port in device_ports]
255 device_ports += self.adapter_agent.get_ports(self.device_id,
256 Port.PON_OLT)
257
258 for port in device_ports:
259 port.oper_status = oper_state
260 self.adapter_agent.add_port(self.device_id, port)
261
262 # Device logical port
263 for logical_port_id in logical_ports_ids:
264 logical_port = self.adapter_agent.get_logical_port(
265 self.logical_device_id, logical_port_id)
266 logical_port.ofp_port.state = OFPPS_LINK_DOWN
267 self.adapter_agent.update_logical_port(self.logical_device_id,
268 logical_port)
269
270 # Device
271 device = self.adapter_agent.get_device(self.device_id)
272 device.oper_status = oper_state
273 device.connect_status = connect_state
274
Nicolas Palpacuer41141352018-08-31 14:11:38 -0400275 reactor.callLater(2, self.adapter_agent.update_device, device)
276
277 # def post_up(self, event):
278 # self.log.debug('post-up')
279 # self.flow_mgr.reseed_flows()
280
281 def post_down(self, event):
282 self.log.debug('post_down')
283 self.flow_mgr.reset_flows()
284
Shad Ansari94250fc2018-07-04 06:52:11 +0000285 def indications_thread(self):
nick47b74372018-05-25 18:22:49 -0400286 self.log.debug('starting-indications-thread')
Shad Ansari94250fc2018-07-04 06:52:11 +0000287 self.log.debug('connecting to olt', device_id=self.device_id)
288 self.channel_ready_future.result() # blocking call
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400289 self.log.info('connected to olt', device_id=self.device_id)
Shad Ansari94250fc2018-07-04 06:52:11 +0000290 self.go_state_connected()
Shad Ansari2dda4f32018-05-17 07:16:07 +0000291
Shad Ansari15928d12018-04-17 02:42:13 +0000292 self.indications = self.stub.EnableIndication(openolt_pb2.Empty())
Shad Ansari2dda4f32018-05-17 07:16:07 +0000293
Shad Ansari94250fc2018-07-04 06:52:11 +0000294 while True:
nick47b74372018-05-25 18:22:49 -0400295 try:
296 # get the next indication from olt
297 ind = next(self.indications)
298 except Exception as e:
Shad Ansari94250fc2018-07-04 06:52:11 +0000299 self.log.warn('gRPC connection lost', error=e)
300 reactor.callFromThread(self.go_state_down)
301 reactor.callFromThread(self.go_state_init)
302 break
nick47b74372018-05-25 18:22:49 -0400303 else:
304 self.log.debug("rx indication", indication=ind)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000305
nick47b74372018-05-25 18:22:49 -0400306 # indication handlers run in the main event loop
307 if ind.HasField('olt_ind'):
308 reactor.callFromThread(self.olt_indication, ind.olt_ind)
309 elif ind.HasField('intf_ind'):
310 reactor.callFromThread(self.intf_indication, ind.intf_ind)
311 elif ind.HasField('intf_oper_ind'):
Shad Ansarif9d2d102018-06-13 02:15:26 +0000312 reactor.callFromThread(self.intf_oper_indication,
313 ind.intf_oper_ind)
nick47b74372018-05-25 18:22:49 -0400314 elif ind.HasField('onu_disc_ind'):
Shad Ansarif9d2d102018-06-13 02:15:26 +0000315 reactor.callFromThread(self.onu_discovery_indication,
316 ind.onu_disc_ind)
nick47b74372018-05-25 18:22:49 -0400317 elif ind.HasField('onu_ind'):
318 reactor.callFromThread(self.onu_indication, ind.onu_ind)
319 elif ind.HasField('omci_ind'):
320 reactor.callFromThread(self.omci_indication, ind.omci_ind)
321 elif ind.HasField('pkt_ind'):
322 reactor.callFromThread(self.packet_indication, ind.pkt_ind)
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400323 elif ind.HasField('port_stats'):
Nicolas Palpacuere761c902018-07-05 16:30:52 -0400324 reactor.callFromThread(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700325 self.stats_mgr.port_statistics_indication,
326 ind.port_stats)
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400327 elif ind.HasField('flow_stats'):
Nicolas Palpacuere761c902018-07-05 16:30:52 -0400328 reactor.callFromThread(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700329 self.stats_mgr.flow_statistics_indication,
330 ind.flow_stats)
Shad Ansari905b8402018-07-03 00:04:50 +0000331 elif ind.HasField('alarm_ind'):
Nicolas Palpacuer16138de2018-07-03 14:35:18 -0400332 reactor.callFromThread(self.alarm_mgr.process_alarms,
333 ind.alarm_ind)
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400334 else:
335 self.log.warn('unknown indication type')
nick47b74372018-05-25 18:22:49 -0400336
Shad Ansari2825d012018-02-22 23:57:46 +0000337 def olt_indication(self, olt_indication):
Shad Ansari22efe832018-05-19 05:37:03 +0000338 if olt_indication.oper_state == "up":
Shad Ansari94250fc2018-07-04 06:52:11 +0000339 self.go_state_up()
Shad Ansari22efe832018-05-19 05:37:03 +0000340 elif olt_indication.oper_state == "down":
Shad Ansari94250fc2018-07-04 06:52:11 +0000341 self.go_state_down()
Shad Ansari2825d012018-02-22 23:57:46 +0000342
343 def intf_indication(self, intf_indication):
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400344 self.log.debug("intf indication", intf_id=intf_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000345 oper_state=intf_indication.oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000346
347 if intf_indication.oper_state == "up":
348 oper_status = OperStatus.ACTIVE
349 else:
350 oper_status = OperStatus.DISCOVERED
351
nick47b74372018-05-25 18:22:49 -0400352 # add_port update the port if it exists
Shad Ansari2825d012018-02-22 23:57:46 +0000353 self.add_port(intf_indication.intf_id, Port.PON_OLT, oper_status)
354
355 def intf_oper_indication(self, intf_oper_indication):
Shad Ansarif9d2d102018-06-13 02:15:26 +0000356 self.log.debug("Received interface oper state change indication",
357 intf_id=intf_oper_indication.intf_id,
358 type=intf_oper_indication.type,
359 oper_state=intf_oper_indication.oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000360
361 if intf_oper_indication.oper_state == "up":
362 oper_state = OperStatus.ACTIVE
363 else:
364 oper_state = OperStatus.DISCOVERED
365
366 if intf_oper_indication.type == "nni":
367
Shad Ansari0346f0d2018-04-26 06:54:09 +0000368 # FIXME - creating logical port for 2nd interface throws exception!
Shad Ansari2825d012018-02-22 23:57:46 +0000369 if intf_oper_indication.intf_id != 0:
370 return
371
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400372 # add_(logical_)port update the port if it exists
Shad Ansarif9d2d102018-06-13 02:15:26 +0000373 port_no, label = self.add_port(intf_oper_indication.intf_id,
374 Port.ETHERNET_NNI, oper_state)
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400375 self.log.debug("int_oper_indication", port_no=port_no, label=label)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000376 self.add_logical_port(port_no, intf_oper_indication.intf_id,
377 oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000378
379 elif intf_oper_indication.type == "pon":
380 # FIXME - handle PON oper state change
381 pass
382
383 def onu_discovery_indication(self, onu_disc_indication):
Shad Ansari803900a2018-05-02 06:26:00 +0000384 intf_id = onu_disc_indication.intf_id
Shad Ansarif9d2d102018-06-13 02:15:26 +0000385 serial_number = onu_disc_indication.serial_number
Shad Ansari2825d012018-02-22 23:57:46 +0000386
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400387 serial_number_str = self.stringify_serial_number(serial_number)
Shad Ansari803900a2018-05-02 06:26:00 +0000388
Shad Ansarif9d2d102018-06-13 02:15:26 +0000389 self.log.debug("onu discovery indication", intf_id=intf_id,
390 serial_number=serial_number_str)
Nicolas Palpacuer36a93442018-05-23 17:38:57 -0400391
mzadig384783a2018-08-09 08:52:40 -0400392 # Post ONU Discover alarm 20180809_0805
393 try:
Nicolas Palpacuere9bf83c2018-08-16 14:53:14 -0400394 OnuDiscoveryAlarm(self.alarm_mgr.alarms, pon_id=intf_id,
395 serial_number=serial_number_str).raise_alarm()
mzadig384783a2018-08-09 08:52:40 -0400396 except Exception as disc_alarm_error:
Nicolas Palpacuere9bf83c2018-08-16 14:53:14 -0400397 self.log.exception("onu-discovery-alarm-error",
398 errmsg=disc_alarm_error.message)
mzadig384783a2018-08-09 08:52:40 -0400399 # continue for now.
400
Shad Ansarif9d2d102018-06-13 02:15:26 +0000401 onu_device = self.adapter_agent.get_child_device(
402 self.device_id,
403 serial_number=serial_number_str)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400404
405 if onu_device is None:
Girish Gowdru1a3b7042018-09-19 07:08:48 -0700406 onu_id = self.new_onu_id(intf_id)
407
Shad Ansari15928d12018-04-17 02:42:13 +0000408 try:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700409 onu_id = self.resource_mgr.get_onu_id(intf_id)
410 if onu_id is None:
411 raise Exception("onu-id-unavailable")
412
413 pon_intf_onu_id = (intf_id, onu_id)
414 alloc_id = self.resource_mgr.get_alloc_id(
415 pon_intf_onu_id)
416 if alloc_id is None:
417 # Free up other PON resources if are unable to
418 # proceed ahead
419 self.resource_mgr.free_onu_id(intf_id, onu_id)
420 raise Exception("alloc-id-unavailable")
421
Shad Ansarif9d2d102018-06-13 02:15:26 +0000422 self.add_onu_device(
423 intf_id,
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000424 self.platform.intf_id_to_port_no(intf_id, Port.PON_OLT),
Shad Ansarif9d2d102018-06-13 02:15:26 +0000425 onu_id, serial_number)
Nicolas Palpacuer131790b2018-08-20 09:59:34 -0400426 self.activate_onu(intf_id, onu_id, serial_number,
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700427 serial_number_str, alloc_id)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400428 except Exception as e:
429 self.log.exception('onu-activation-failed', e=e)
430
Shad Ansari2825d012018-02-22 23:57:46 +0000431 else:
nick47b74372018-05-25 18:22:49 -0400432 if onu_device.connect_status != ConnectStatus.REACHABLE:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700433 onu_device.connect_status = ConnectStatus.REACHABLE
434 self.adapter_agent.update_device(onu_device)
nick47b74372018-05-25 18:22:49 -0400435
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400436 onu_id = onu_device.proxy_address.onu_id
Shad Ansarif9d2d102018-06-13 02:15:26 +0000437 if onu_device.oper_status == OperStatus.DISCOVERED \
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700438 or onu_device.oper_status == OperStatus.ACTIVATING:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000439 self.log.debug("ignore onu discovery indication, \
440 the onu has been discovered and should be \
441 activating shorlty", intf_id=intf_id,
442 onu_id=onu_id, state=onu_device.oper_status)
443 elif onu_device.oper_status == OperStatus.ACTIVE:
444 self.log.warn("onu discovery indication whereas onu is \
445 supposed to be active",
446 intf_id=intf_id, onu_id=onu_id,
447 state=onu_device.oper_status)
nick47b74372018-05-25 18:22:49 -0400448 elif onu_device.oper_status == OperStatus.UNKNOWN:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000449 self.log.info("onu in unknown state, recovering from olt \
Nicolas Palpacuer131790b2018-08-20 09:59:34 -0400450 reboot probably, activate onu", intf_id=intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000451 onu_id=onu_id, serial_number=serial_number_str)
nick47b74372018-05-25 18:22:49 -0400452
453 onu_device.oper_status = OperStatus.DISCOVERED
454 self.adapter_agent.update_device(onu_device)
Nicolas Palpacuer131790b2018-08-20 09:59:34 -0400455 try:
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700456 pon_intf_onu_id = (intf_id, onu_id)
457 # The ONU is already in the VOLTHA DB and resources were
458 # already allocated for this ONU. So we fetch the resource
459 # from local cache and not KV store.
460 alloc_id = self.resource_mgr.get_alloc_id(
461 pon_intf_onu_id)
Nicolas Palpacuer131790b2018-08-20 09:59:34 -0400462 self.activate_onu(intf_id, onu_id, serial_number,
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700463 serial_number_str, alloc_id)
Nicolas Palpacuer131790b2018-08-20 09:59:34 -0400464 except Exception as e:
465 self.log.error('onu-activation-error',
466 serial_number=serial_number_str, error=e)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400467 else:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000468 self.log.warn('unexpected state', onu_id=onu_id,
469 onu_device_oper_state=onu_device.oper_status)
Shad Ansari2825d012018-02-22 23:57:46 +0000470
Shad Ansari2825d012018-02-22 23:57:46 +0000471 def onu_indication(self, onu_indication):
Shad Ansaria0b37892018-06-12 21:34:30 +0000472 self.log.debug("onu indication", intf_id=onu_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000473 onu_id=onu_indication.onu_id,
474 serial_number=onu_indication.serial_number,
475 oper_state=onu_indication.oper_state,
476 admin_state=onu_indication.admin_state)
Nicolas Palpacuer28cc2662018-06-22 16:30:18 -0400477 try:
478 serial_number_str = self.stringify_serial_number(
479 onu_indication.serial_number)
Shad Ansari94250fc2018-07-04 06:52:11 +0000480 except Exception as e:
Nicolas Palpacuer28cc2662018-06-22 16:30:18 -0400481 serial_number_str = None
Shad Ansari94250fc2018-07-04 06:52:11 +0000482
Nicolas Palpacuer28cc2662018-06-22 16:30:18 -0400483 if serial_number_str is not None:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400484 onu_device = self.adapter_agent.get_child_device(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700485 self.device_id,
486 serial_number=serial_number_str)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000487 else:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400488 onu_device = self.adapter_agent.get_child_device(
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700489 self.device_id,
490 parent_port_no=self.platform.intf_id_to_port_no(
491 onu_indication.intf_id, Port.PON_OLT),
492 onu_id=onu_indication.onu_id)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400493
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400494 if onu_device is None:
Shad Ansaria0b37892018-06-12 21:34:30 +0000495 self.log.error('onu not found', intf_id=onu_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000496 onu_id=onu_indication.onu_id)
Shad Ansari803900a2018-05-02 06:26:00 +0000497 return
498
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700499 # We will use this alloc_id and gemport_id to pass on to the onu adapter
500 pon_intf_onu_id = (onu_indication.intf_id, onu_indication.onu_id)
501 alloc_id = self.resource_mgr.get_alloc_id(pon_intf_onu_id)
502 gemport_id = self.resource_mgr.get_gemport_id(pon_intf_onu_id)
503
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000504 if self.platform.intf_id_from_pon_port_no(onu_device.parent_port_no) \
Shad Ansarif9521ad2018-09-08 10:46:43 +0000505 != onu_indication.intf_id:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400506 self.log.warn('ONU-is-on-a-different-intf-id-now',
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000507 previous_intf_id=self.platform.intf_id_from_pon_port_no(
Shad Ansarif9d2d102018-06-13 02:15:26 +0000508 onu_device.parent_port_no),
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400509 current_intf_id=onu_indication.intf_id)
510 # FIXME - handle intf_id mismatch (ONU move?)
Shad Ansari2825d012018-02-22 23:57:46 +0000511
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400512 if onu_device.proxy_address.onu_id != onu_indication.onu_id:
513 # FIXME - handle onu id mismatch
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400514 self.log.warn('ONU-id-mismatch, can happen if both voltha and '
515 'the olt rebooted',
Shad Ansarif9d2d102018-06-13 02:15:26 +0000516 expected_onu_id=onu_device.proxy_address.onu_id,
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400517 received_onu_id=onu_indication.onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000518
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000519 uni_no = self.platform.mk_uni_port_num(onu_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000520 onu_indication.onu_id)
521 uni_name = self.port_name(uni_no, Port.ETHERNET_UNI,
522 serial_number=onu_device.serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000523
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400524 self.log.debug('port-number-ready', uni_no=uni_no, uni_name=uni_name)
Shad Ansari2825d012018-02-22 23:57:46 +0000525
Shad Ansarif9d2d102018-06-13 02:15:26 +0000526 # Admin state
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400527 if onu_indication.admin_state == 'down':
528 if onu_indication.oper_state != 'down':
Shad Ansarif9d2d102018-06-13 02:15:26 +0000529 self.log.error('ONU-admin-state-down-and-oper-status-not-down',
530 oper_state=onu_indication.oper_state)
531 # Forcing the oper state change code to execute
532 onu_indication.oper_state = 'down'
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400533
Shad Ansarif9d2d102018-06-13 02:15:26 +0000534 # Port and logical port update is taken care of by oper state block
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400535
536 elif onu_indication.admin_state == 'up':
Nicolas Palpacuer921f8cf2018-08-14 18:23:09 -0400537 pass
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400538
539 else:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000540 self.log.warn('Invalid-or-not-implemented-admin-state',
541 received_admin_state=onu_indication.admin_state)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400542
543 self.log.debug('admin-state-dealt-with')
544
Matt Jeanneret12cd5d02018-08-07 15:30:19 -0400545 onu_adapter_agent = \
546 registry('adapter_loader').get_agent(onu_device.adapter)
547 if onu_adapter_agent is None:
548 self.log.error('onu_adapter_agent-could-not-be-retrieved',
549 onu_device=onu_device)
550 return
551
Shad Ansarif9d2d102018-06-13 02:15:26 +0000552 # Operating state
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400553 if onu_indication.oper_state == 'down':
Nicolas Palpacuer4ea3a652018-08-22 10:33:17 -0400554
555 if onu_device.connect_status != ConnectStatus.UNREACHABLE:
556 onu_device.connect_status = ConnectStatus.UNREACHABLE
557 self.adapter_agent.update_device(onu_device)
558
Shad Ansarif9d2d102018-06-13 02:15:26 +0000559 # Move to discovered state
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400560 self.log.debug('onu-oper-state-is-down')
561
562 if onu_device.oper_status != OperStatus.DISCOVERED:
563 onu_device.oper_status = OperStatus.DISCOVERED
564 self.adapter_agent.update_device(onu_device)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000565 # Set port oper state to Discovered
566 self.onu_ports_down(onu_device, uni_no, uni_name,
567 OperStatus.DISCOVERED)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400568
Shad Ansari0e7ad962018-09-28 01:42:26 +0000569 onu_adapter_agent.update_interface(onu_device,
570 {'oper_state': 'down'})
Matt Jeanneret12cd5d02018-08-07 15:30:19 -0400571
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400572 elif onu_indication.oper_state == 'up':
573
Nicolas Palpacuer2824a992018-08-20 18:07:41 -0400574 if onu_device.connect_status != ConnectStatus.REACHABLE:
575 onu_device.connect_status = ConnectStatus.REACHABLE
576 self.adapter_agent.update_device(onu_device)
577
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400578 if onu_device.oper_status != OperStatus.DISCOVERED:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000579 self.log.debug("ignore onu indication",
580 intf_id=onu_indication.intf_id,
581 onu_id=onu_indication.onu_id,
582 state=onu_device.oper_status,
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400583 msg_oper_state=onu_indication.oper_state)
584 return
585
Shad Ansarif9d2d102018-06-13 02:15:26 +0000586 # Device was in Discovered state, setting it to active
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400587
Shad Ansarif9d2d102018-06-13 02:15:26 +0000588 # Prepare onu configuration
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400589
Shad Ansari0e7ad962018-09-28 01:42:26 +0000590 # tcont creation (onu)
591 tcont = TcontsConfigData()
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700592 tcont.alloc_id = alloc_id
Matt Jeannerete6a70332018-07-20 16:11:25 -0400593
Shad Ansari0e7ad962018-09-28 01:42:26 +0000594 # gem port creation
595 gem_port = GemportsConfigData()
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700596 gem_port.gemport_id = gemport_id
Matt Jeannerete6a70332018-07-20 16:11:25 -0400597
Shad Ansari0e7ad962018-09-28 01:42:26 +0000598 gem_port.tcont_ref = str(tcont.alloc_id)
Matt Jeannerete6a70332018-07-20 16:11:25 -0400599
Shad Ansari0e7ad962018-09-28 01:42:26 +0000600 self.log.info('inject-tcont-gem-data-onu-handler',
601 onu_indication=onu_indication, tcont=tcont,
602 gem_port=gem_port)
Girish Gowdru141ced82018-09-17 20:19:14 -0700603
Shad Ansari0e7ad962018-09-28 01:42:26 +0000604 onu_adapter_agent.create_tcont(onu_device, tcont,
605 traffic_descriptor_data=None)
606 onu_adapter_agent.create_gemport(onu_device, gem_port)
607 onu_adapter_agent.create_interface(onu_device, onu_indication)
Matt Jeannerete6a70332018-07-20 16:11:25 -0400608
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400609 else:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000610 self.log.warn('Not-implemented-or-invalid-value-of-oper-state',
611 oper_state=onu_indication.oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000612
nick47b74372018-05-25 18:22:49 -0400613 def onu_ports_down(self, onu_device, uni_no, uni_name, oper_state):
614 # Set port oper state to Discovered
615 # add port will update port if it exists
616 self.adapter_agent.add_port(
617 self.device_id,
618 Port(
619 port_no=uni_no,
620 label=uni_name,
621 type=Port.ETHERNET_UNI,
622 admin_state=onu_device.admin_state,
623 oper_status=oper_state))
624
625 # Disable logical port
nick47b74372018-05-25 18:22:49 -0400626 onu_ports = self.proxy.get('devices/{}/ports'.format(onu_device.id))
627 onu_port_id = None
628 for onu_port in onu_ports:
629 if onu_port.port_no == uni_no:
630 onu_port_id = onu_port.label
631 if onu_port_id is None:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000632 self.log.error('matching-onu-port-label-not-found',
633 onu_id=onu_device.id, olt_id=self.device_id,
nick47b74372018-05-25 18:22:49 -0400634 onu_ports=onu_ports)
635 return
636 try:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000637 onu_logical_port = self.adapter_agent.get_logical_port(
638 logical_device_id=self.logical_device_id, port_id=onu_port_id)
nick47b74372018-05-25 18:22:49 -0400639 onu_logical_port.ofp_port.state = OFPPS_LINK_DOWN
Shad Ansarif9d2d102018-06-13 02:15:26 +0000640 self.adapter_agent.update_logical_port(
641 logical_device_id=self.logical_device_id,
642 port=onu_logical_port)
nick47b74372018-05-25 18:22:49 -0400643 self.log.debug('cascading-oper-state-to-port-and-logical-port')
644 except KeyError as e:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000645 self.log.error('matching-onu-port-label-invalid',
646 onu_id=onu_device.id, olt_id=self.device_id,
647 onu_ports=onu_ports, onu_port_id=onu_port_id,
648 error=e)
nick47b74372018-05-25 18:22:49 -0400649
Shad Ansari2825d012018-02-22 23:57:46 +0000650 def omci_indication(self, omci_indication):
651
652 self.log.debug("omci indication", intf_id=omci_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000653 onu_id=omci_indication.onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000654
Shad Ansarif9d2d102018-06-13 02:15:26 +0000655 onu_device = self.adapter_agent.get_child_device(
Nicolas Palpacuer3d0878d2018-08-17 11:29:42 -0400656 self.device_id, onu_id=omci_indication.onu_id,
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000657 parent_port_no=self.platform.intf_id_to_port_no(
Girish Gowdru141ced82018-09-17 20:19:14 -0700658 omci_indication.intf_id, Port.PON_OLT), )
Shad Ansari0efa6512018-04-28 06:42:54 +0000659
660 self.adapter_agent.receive_proxied_message(onu_device.proxy_address,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000661 omci_indication.pkt)
Shad Ansari2825d012018-02-22 23:57:46 +0000662
Shad Ansari42db7342018-04-25 21:39:46 +0000663 def packet_indication(self, pkt_indication):
664
Shad Ansari0ff82622018-09-30 09:32:04 +0000665 self.log.debug("packet indication",
666 intf_type=pkt_indication.intf_type,
667 intf_id=pkt_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000668 gemport_id=pkt_indication.gemport_id,
669 flow_id=pkt_indication.flow_id)
Shad Ansari42db7342018-04-25 21:39:46 +0000670
Shad Ansari0ff82622018-09-30 09:32:04 +0000671 if pkt_indication.intf_type == "pon":
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700672 pon_intf_gemport = (pkt_indication.intf_id, pkt_indication.gemport_id)
673 try:
674 onu_id = int(self.resource_mgr.kv_store[pon_intf_gemport])
675 if onu_id is None:
676 raise Exception("onu-id-none")
677 except Exception as e:
678 self.log.error("no-onu-reference-for-gem",
679 gemport_id=pkt_indication.gemport_id, e=e)
680 return
681
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000682 logical_port_num = self.platform.mk_uni_port_num(pkt_indication.intf_id,
Shad Ansari0ff82622018-09-30 09:32:04 +0000683 onu_id)
684 elif pkt_indication.intf_type == "nni":
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000685 logical_port_num = self.platform.intf_id_to_port_no(
Shad Ansari0ff82622018-09-30 09:32:04 +0000686 pkt_indication.intf_id,
687 Port.ETHERNET_NNI)
Shad Ansari42db7342018-04-25 21:39:46 +0000688
689 pkt = Ether(pkt_indication.pkt)
Shad Ansari0ff82622018-09-30 09:32:04 +0000690
691 self.log.debug("packet indication",
692 logical_device_id=self.logical_device_id,
693 logical_port_no=logical_port_num)
694
695 self.adapter_agent.send_packet_in(
696 logical_device_id=self.logical_device_id,
697 logical_port_no=logical_port_num,
698 packet=str(pkt))
Shad Ansari42db7342018-04-25 21:39:46 +0000699
700 def packet_out(self, egress_port, msg):
Shad Ansari0346f0d2018-04-26 06:54:09 +0000701 pkt = Ether(msg)
Saurav Dasf87d6552018-09-26 17:05:42 -0700702 self.log.debug('packet out', egress_port=egress_port,
703 device_id=self.device_id,
704 logical_device_id=self.logical_device_id,
705 packet=str(pkt).encode("HEX"))
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400706
707 # Find port type
708 egress_port_type = self.port_type(egress_port)
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400709 if egress_port_type == Port.ETHERNET_UNI:
710
711 if pkt.haslayer(Dot1Q):
712 outer_shim = pkt.getlayer(Dot1Q)
713 if isinstance(outer_shim.payload, Dot1Q):
714 # If double tag, remove the outer tag
715 payload = (
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700716 Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
717 outer_shim.payload
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400718 )
719 else:
720 payload = pkt
Shad Ansari0346f0d2018-04-26 06:54:09 +0000721 else:
722 payload = pkt
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400723
724 send_pkt = binascii.unhexlify(str(payload).encode("HEX"))
725
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400726 self.log.debug(
Shad Ansarif9d2d102018-06-13 02:15:26 +0000727 'sending-packet-to-ONU', egress_port=egress_port,
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000728 intf_id=self.platform.intf_id_from_uni_port_num(egress_port),
729 onu_id=self.platform.onu_id_from_port_num(egress_port),
Shad Ansarif9d2d102018-06-13 02:15:26 +0000730 packet=str(payload).encode("HEX"))
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400731
Shad Ansarif9d2d102018-06-13 02:15:26 +0000732 onu_pkt = openolt_pb2.OnuPacket(
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000733 intf_id=self.platform.intf_id_from_uni_port_num(egress_port),
734 onu_id=self.platform.onu_id_from_port_num(egress_port),
Shad Ansarif9d2d102018-06-13 02:15:26 +0000735 pkt=send_pkt)
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400736
737 self.stub.OnuPacketOut(onu_pkt)
738
739 elif egress_port_type == Port.ETHERNET_NNI:
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400740 self.log.debug('sending-packet-to-uplink', egress_port=egress_port,
Shad Ansarif9521ad2018-09-08 10:46:43 +0000741 packet=str(pkt).encode("HEX"))
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400742
743 send_pkt = binascii.unhexlify(str(pkt).encode("HEX"))
744
Shad Ansarif9d2d102018-06-13 02:15:26 +0000745 uplink_pkt = openolt_pb2.UplinkPacket(
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000746 intf_id=self.platform.intf_id_from_nni_port_num(egress_port),
Shad Ansarif9d2d102018-06-13 02:15:26 +0000747 pkt=send_pkt)
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400748
749 self.stub.UplinkPacketOut(uplink_pkt)
750
Shad Ansari0346f0d2018-04-26 06:54:09 +0000751 else:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000752 self.log.warn('Packet-out-to-this-interface-type-not-implemented',
753 egress_port=egress_port,
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400754 port_type=egress_port_type)
Shad Ansari42db7342018-04-25 21:39:46 +0000755
Shad Ansari2825d012018-02-22 23:57:46 +0000756 def send_proxied_message(self, proxy_address, msg):
Shad Ansarif9521ad2018-09-08 10:46:43 +0000757 onu_device = self.adapter_agent.get_child_device(
Girish Gowdru141ced82018-09-17 20:19:14 -0700758 self.device_id, onu_id=proxy_address.onu_id,
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000759 parent_port_no=self.platform.intf_id_to_port_no(
Girish Gowdru141ced82018-09-17 20:19:14 -0700760 proxy_address.channel_id, Port.PON_OLT)
761 )
Nicolas Palpacuer3d0878d2018-08-17 11:29:42 -0400762 if onu_device.connect_status != ConnectStatus.REACHABLE:
763 self.log.debug('ONU is not reachable, cannot send OMCI',
764 serial_number=onu_device.serial_number,
765 intf_id=onu_device.proxy_address.channel_id,
766 onu_id=onu_device.proxy_address.onu_id)
767 return
Shad Ansarif9d2d102018-06-13 02:15:26 +0000768 omci = openolt_pb2.OmciMsg(intf_id=proxy_address.channel_id,
769 onu_id=proxy_address.onu_id, pkt=str(msg))
Shad Ansari2825d012018-02-22 23:57:46 +0000770 self.stub.OmciMsgOut(omci)
771
772 def add_onu_device(self, intf_id, port_no, onu_id, serial_number):
Shad Ansari2825d012018-02-22 23:57:46 +0000773 self.log.info("Adding ONU", port_no=port_no, onu_id=onu_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000774 serial_number=serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000775
776 # NOTE - channel_id of onu is set to intf_id
Shad Ansari0efa6512018-04-28 06:42:54 +0000777 proxy_address = Device.ProxyAddress(device_id=self.device_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000778 channel_id=intf_id, onu_id=onu_id,
779 onu_session_id=onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000780
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400781 self.log.debug("Adding ONU", proxy_address=proxy_address)
Shad Ansari2825d012018-02-22 23:57:46 +0000782
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400783 serial_number_str = self.stringify_serial_number(serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000784
Shad Ansarif9d2d102018-06-13 02:15:26 +0000785 self.adapter_agent.add_onu_device(
786 parent_device_id=self.device_id, parent_port_no=port_no,
787 vendor_id=serial_number.vendor_id, proxy_address=proxy_address,
788 root=True, serial_number=serial_number_str,
789 admin_state=AdminState.ENABLED)
Shad Ansari2825d012018-02-22 23:57:46 +0000790
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000791 def port_name(self, port_no, port_type, intf_id=None, serial_number=None):
Shad Ansari2825d012018-02-22 23:57:46 +0000792 if port_type is Port.ETHERNET_NNI:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400793 return "nni-" + str(port_no)
Shad Ansari2825d012018-02-22 23:57:46 +0000794 elif port_type is Port.PON_OLT:
Shad Ansari4a232ca2018-05-05 05:24:17 +0000795 return "pon" + str(intf_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000796 elif port_type is Port.ETHERNET_UNI:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400797 if serial_number is not None:
798 return serial_number
799 else:
800 return "uni-{}".format(port_no)
Shad Ansari2825d012018-02-22 23:57:46 +0000801
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400802 def port_type(self, port_no):
803 ports = self.adapter_agent.get_ports(self.device_id)
804 for port in ports:
805 if port.port_no == port_no:
806 return port.type
807 return None
808
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400809 def add_logical_port(self, port_no, intf_id, oper_state):
Shad Ansari2825d012018-02-22 23:57:46 +0000810 self.log.info('adding-logical-port', port_no=port_no)
811
812 label = self.port_name(port_no, Port.ETHERNET_NNI)
813
814 cap = OFPPF_1GB_FD | OFPPF_FIBER
815 curr_speed = OFPPF_1GB_FD
816 max_speed = OFPPF_1GB_FD
817
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400818 if oper_state == OperStatus.ACTIVE:
819 of_oper_state = OFPPS_LIVE
820 else:
821 of_oper_state = OFPPS_LINK_DOWN
822
Shad Ansarif9d2d102018-06-13 02:15:26 +0000823 ofp = ofp_port(
824 port_no=port_no,
Nicolas Palpacuer5780e152018-09-05 17:25:42 -0400825 hw_addr=mac_str_to_tuple(self._get_mac_form_port_no(port_no)),
Shad Ansarif9d2d102018-06-13 02:15:26 +0000826 name=label, config=0, state=of_oper_state, curr=cap,
827 advertised=cap, peer=cap, curr_speed=curr_speed,
828 max_speed=max_speed)
Shad Ansari2825d012018-02-22 23:57:46 +0000829
Nicolas Palpacuere7359fc2018-06-15 14:10:48 -0400830 ofp_stats = ofp_port_stats(port_no=port_no)
831
Shad Ansarif9d2d102018-06-13 02:15:26 +0000832 logical_port = LogicalPort(
833 id=label, ofp_port=ofp, device_id=self.device_id,
Nicolas Palpacuere7359fc2018-06-15 14:10:48 -0400834 device_port_no=port_no, root_port=True,
835 ofp_port_stats=ofp_stats)
Shad Ansari2825d012018-02-22 23:57:46 +0000836
Shad Ansarif9d2d102018-06-13 02:15:26 +0000837 self.adapter_agent.add_logical_port(self.logical_device_id,
838 logical_port)
Shad Ansari2825d012018-02-22 23:57:46 +0000839
Nicolas Palpacuer5780e152018-09-05 17:25:42 -0400840 def _get_mac_form_port_no(self, port_no):
841 mac = ''
842 for i in range(4):
843 mac = ':%02x' % ((port_no >> (i * 8)) & 0xff) + mac
844 return '00:00' + mac
845
Shad Ansari2825d012018-02-22 23:57:46 +0000846 def add_port(self, intf_id, port_type, oper_status):
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000847 port_no = self.platform.intf_id_to_port_no(intf_id, port_type)
Shad Ansari2825d012018-02-22 23:57:46 +0000848
Shad Ansari4a232ca2018-05-05 05:24:17 +0000849 label = self.port_name(port_no, port_type, intf_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000850
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -0400851 self.log.debug('adding-port', port_no=port_no, label=label,
Shad Ansarif9521ad2018-09-08 10:46:43 +0000852 port_type=port_type)
Shad Ansari0efa6512018-04-28 06:42:54 +0000853
854 port = Port(port_no=port_no, label=label, type=port_type,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000855 admin_state=AdminState.ENABLED, oper_status=oper_status)
Shad Ansari0efa6512018-04-28 06:42:54 +0000856
Shad Ansari2825d012018-02-22 23:57:46 +0000857 self.adapter_agent.add_port(self.device_id, port)
Shad Ansari0efa6512018-04-28 06:42:54 +0000858
Shad Ansari2825d012018-02-22 23:57:46 +0000859 return port_no, label
860
Nicolas Palpacuer3bd62092018-08-15 09:42:53 -0400861 def delete_logical_port(self, child_device_id):
862 logical_ports = self.proxy.get('/logical_devices/{}/ports'.format(
863 self.logical_device_id))
864 for logical_port in logical_ports:
865 if logical_port.device_id == child_device_id:
866 self.log.debug('delete-logical-port',
867 onu_device_id=child_device_id,
868 logical_port=logical_port)
869 self.adapter_agent.delete_logical_port(
870 self.logical_device_id, logical_port)
871 return
Shad Ansarif9521ad2018-09-08 10:46:43 +0000872
Nicolas Palpacuer3bd62092018-08-15 09:42:53 -0400873 def delete_port(self, child_serial_number):
874 ports = self.proxy.get('/devices/{}/ports'.format(
875 self.device_id))
876 for port in ports:
877 if port.label == child_serial_number:
878 self.log.debug('delete-port',
879 onu_serial_number=child_serial_number,
880 port=port)
881 self.adapter_agent.delete_port(self.device_id, port)
882 return
883
Girish Gowdru1a3b7042018-09-19 07:08:48 -0700884 def new_onu_id(self, intf_id):
885 onu_devices = self.adapter_agent.get_child_devices(self.device_id)
886 pon_onu_ids = [onu_device.proxy_address.onu_id
887 for onu_device in onu_devices
888 if onu_device.proxy_address.channel_id == intf_id]
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000889 for i in range(1, self.platform.max_onus_per_pon()):
Girish Gowdru1a3b7042018-09-19 07:08:48 -0700890 if i not in pon_onu_ids:
891 return i
892
893 self.log.error('All available onu_ids taken on this pon',
Shad Ansaricd20a6d2018-10-02 14:36:33 +0000894 intf_id=intf_id, ids_taken=self.platform.max_onus_per_pon())
Girish Gowdru1a3b7042018-09-19 07:08:48 -0700895 return None
896
Shad Ansari2825d012018-02-22 23:57:46 +0000897 def update_flow_table(self, flows):
Nicolas Palpacuer0c7c3162018-08-08 11:27:57 -0400898 self.log.debug('No updates here now, all is done in logical flows '
899 'update')
Shad Ansari5df91f62018-07-25 23:59:46 +0000900
Nicolas Palpacuer0c7c3162018-08-08 11:27:57 -0400901 def update_logical_flows(self, flows_to_add, flows_to_remove,
902 device_rules_map):
Nicolas Palpacuer3d0878d2018-08-17 11:29:42 -0400903 if not self.is_state_up():
904 self.log.info('The OLT is not up, we cannot update flows',
905 flows_to_add=[f.id for f in flows_to_add],
906 flows_to_remove=[f.id for f in flows_to_remove])
907 return
908
Nicolas Palpacuer41141352018-08-31 14:11:38 -0400909 try:
910 self.flow_mgr.update_children_flows(device_rules_map)
911 except Exception as e:
912 self.log.error('Error updating children flows', error=e)
Shad Ansari2825d012018-02-22 23:57:46 +0000913
Nicolas Palpacuer0c7c3162018-08-08 11:27:57 -0400914 self.log.debug('logical flows update', flows_to_add=flows_to_add,
Shad Ansarif9521ad2018-09-08 10:46:43 +0000915 flows_to_remove=flows_to_remove)
Shad Ansari2825d012018-02-22 23:57:46 +0000916
Nicolas Palpacuer0c7c3162018-08-08 11:27:57 -0400917 for flow in flows_to_add:
Nicolas Palpacuer2e0fa582018-07-16 16:04:12 -0400918
Nicolas Palpacuer0c7c3162018-08-08 11:27:57 -0400919 try:
920 self.flow_mgr.add_flow(flow)
Nicolas Palpacuer0c7c3162018-08-08 11:27:57 -0400921 except Exception as e:
922 self.log.error('failed to add flow', flow=flow, e=e)
923
Nicolas Palpacuer0c7c3162018-08-08 11:27:57 -0400924 for flow in flows_to_remove:
925
926 try:
927 self.flow_mgr.remove_flow(flow)
928 except Exception as e:
929 self.log.error('failed to remove flow', flow=flow, e=e)
930
Nicolas Palpacuer41141352018-08-31 14:11:38 -0400931 self.flow_mgr.repush_all_different_flows()
932
Nicolas Palpacuer0c7c3162018-08-08 11:27:57 -0400933 # There has to be a better way to do this
Shad Ansari89b09d52018-05-21 07:28:14 +0000934 def ip_hex(self, ip):
935 octets = ip.split(".")
936 hex_ip = []
937 for octet in octets:
938 octet_hex = hex(int(octet))
939 octet_hex = octet_hex.split('0x')[1]
940 octet_hex = octet_hex.rjust(2, '0')
941 hex_ip.append(octet_hex)
942 return ":".join(hex_ip)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400943
Nicolas Palpacuer131790b2018-08-20 09:59:34 -0400944 def stringify_vendor_specific(self, vendor_specific):
945 return ''.join(str(i) for i in [
946 hex(ord(vendor_specific[0]) >> 4 & 0x0f)[2:],
947 hex(ord(vendor_specific[0]) & 0x0f)[2:],
948 hex(ord(vendor_specific[1]) >> 4 & 0x0f)[2:],
949 hex(ord(vendor_specific[1]) & 0x0f)[2:],
950 hex(ord(vendor_specific[2]) >> 4 & 0x0f)[2:],
951 hex(ord(vendor_specific[2]) & 0x0f)[2:],
952 hex(ord(vendor_specific[3]) >> 4 & 0x0f)[2:],
953 hex(ord(vendor_specific[3]) & 0x0f)[2:]])
954
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400955 def stringify_serial_number(self, serial_number):
956 return ''.join([serial_number.vendor_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000957 self.stringify_vendor_specific(
958 serial_number.vendor_specific)])
Jonathan Davis0f917a22018-05-30 14:39:45 -0400959
Nicolas Palpacuer131790b2018-08-20 09:59:34 -0400960 def destringify_serial_number(self, serial_number_str):
961 serial_number = openolt_pb2.SerialNumber(
962 vendor_id=serial_number_str[:4].encode('utf-8'),
963 vendor_specific=binascii.unhexlify(serial_number_str[4:]))
964 return serial_number
965
Jonathan Davis0f917a22018-05-30 14:39:45 -0400966 def disable(self):
Nicolas Palpacuer62dbb9c2018-08-02 15:03:35 -0400967 self.log.debug('sending-deactivate-olt-message',
Shad Ansarif9521ad2018-09-08 10:46:43 +0000968 device_id=self.device_id)
Jonathan Davis0f917a22018-05-30 14:39:45 -0400969
Nicolas Palpacuer62dbb9c2018-08-02 15:03:35 -0400970 try:
971 # Send grpc call
972 self.stub.DisableOlt(openolt_pb2.Empty())
973 # The resulting indication will bring the OLT down
974 # self.go_state_down()
975 self.log.info('openolt device disabled')
976 except Exception as e:
977 self.log.error('Failure to disable openolt device', error=e)
Jonathan Davis0f917a22018-05-30 14:39:45 -0400978
Jonathan Davis0f917a22018-05-30 14:39:45 -0400979 def delete(self):
Nicolas Palpacuer0d44e682018-08-06 10:30:26 -0400980 self.log.info('deleting-olt', device_id=self.device_id,
981 logical_device_id=self.logical_device_id)
982
Girish Gowdru1e77ea02018-09-24 09:10:35 -0700983 # Clears up the data from the resource manager KV store
984 # for the device
985 del self.resource_mgr
986
Nicolas Palpacuer0d44e682018-08-06 10:30:26 -0400987 try:
988 # Rebooting to reset the state
989 self.reboot()
990 # Removing logical device
Saurav Dasf87d6552018-09-26 17:05:42 -0700991 ld = self.adapter_agent.get_logical_device(self.logical_device_id)
992 self.adapter_agent.delete_logical_device(ld)
Nicolas Palpacuer0d44e682018-08-06 10:30:26 -0400993 except Exception as e:
994 self.log.error('Failure to delete openolt device', error=e)
995 raise e
996 else:
997 self.log.info('successfully-deleted-olt', device_id=self.device_id)
Jonathan Davis0f917a22018-05-30 14:39:45 -0400998
Jonathan Davis0f917a22018-05-30 14:39:45 -0400999 def reenable(self):
Nicolas Palpacuer62dbb9c2018-08-02 15:03:35 -04001000 self.log.debug('reenabling-olt', device_id=self.device_id)
Jonathan Davis0f917a22018-05-30 14:39:45 -04001001
Nicolas Palpacuer62dbb9c2018-08-02 15:03:35 -04001002 try:
1003 self.stub.ReenableOlt(openolt_pb2.Empty())
Jonathan Davis0f917a22018-05-30 14:39:45 -04001004
Nicolas Palpacuer62dbb9c2018-08-02 15:03:35 -04001005 self.log.info('enabling-all-ports', device_id=self.device_id)
1006 self.adapter_agent.enable_all_ports(self.device_id)
Nicolas Palpacuer62dbb9c2018-08-02 15:03:35 -04001007 except Exception as e:
1008 self.log.error('Failure to reenable openolt device', error=e)
Nicolas Palpacuer324dcae2018-08-02 11:12:22 -04001009 else:
1010 self.log.info('openolt device reenabled')
1011
Nicolas Palpacuer131790b2018-08-20 09:59:34 -04001012 def activate_onu(self, intf_id, onu_id, serial_number,
Girish Gowdru1e77ea02018-09-24 09:10:35 -07001013 serial_number_str, alloc_id):
Nicolas Palpacuer131790b2018-08-20 09:59:34 -04001014 pir = self.bw_mgr.pir(serial_number_str)
1015 self.log.debug("activating-onu", intf_id=intf_id, onu_id=onu_id,
Shad Ansarif9521ad2018-09-08 10:46:43 +00001016 serial_number_str=serial_number_str,
Girish Gowdru1e77ea02018-09-24 09:10:35 -07001017 serial_number=serial_number, pir=pir,
1018 alloc_id=alloc_id)
Nicolas Palpacuer131790b2018-08-20 09:59:34 -04001019 onu = openolt_pb2.Onu(intf_id=intf_id, onu_id=onu_id,
Girish Gowdru1e77ea02018-09-24 09:10:35 -07001020 serial_number=serial_number, pir=pir,
1021 alloc_id=alloc_id)
Nicolas Palpacuer131790b2018-08-20 09:59:34 -04001022 self.stub.ActivateOnu(onu)
1023 self.log.info('onu-activated', serial_number=serial_number_str)
Nicolas Palpacuer62dbb9c2018-08-02 15:03:35 -04001024
Jonathan Davisb45bb372018-07-19 15:05:15 -04001025 def delete_child_device(self, child_device):
1026 self.log.debug('sending-deactivate-onu',
1027 olt_device_id=self.device_id,
1028 onu_device=child_device,
1029 onu_serial_number=child_device.serial_number)
Nicolas Palpacuer3bd62092018-08-15 09:42:53 -04001030 try:
1031 self.adapter_agent.delete_child_device(self.device_id,
Shad Ansarif9521ad2018-09-08 10:46:43 +00001032 child_device.id,
1033 child_device)
Nicolas Palpacuer3bd62092018-08-15 09:42:53 -04001034 except Exception as e:
1035 self.log.error('adapter_agent error', error=e)
1036 try:
1037 self.delete_logical_port(child_device.id)
1038 except Exception as e:
1039 self.log.error('logical_port delete error', error=e)
1040 try:
1041 self.delete_port(child_device.serial_number)
1042 except Exception as e:
1043 self.log.error('port delete error', error=e)
Shad Ansarif9521ad2018-09-08 10:46:43 +00001044 serial_number = self.destringify_serial_number(
1045 child_device.serial_number)
Girish Gowdru1e77ea02018-09-24 09:10:35 -07001046 pon_intf_id_onu_id = (child_device.proxy_address.channel_id,
1047 child_device.proxy_address.onu_id)
1048 alloc_id = self.resource_mgr.get_alloc_id(pon_intf_id_onu_id)
1049 # Free any PON resources that were reserved for the ONU
1050 self.resource_mgr.free_pon_resources_for_onu(pon_intf_id_onu_id)
1051
Jonathan Davisb45bb372018-07-19 15:05:15 -04001052 onu = openolt_pb2.Onu(intf_id=child_device.proxy_address.channel_id,
1053 onu_id=child_device.proxy_address.onu_id,
Girish Gowdru1e77ea02018-09-24 09:10:35 -07001054 serial_number=serial_number,
1055 alloc_id=alloc_id)
Shad Ansari3cd9bf22018-07-25 19:29:39 +00001056 self.stub.DeleteOnu(onu)
Nicolas Palpacuerfd365ac2018-08-02 11:37:37 -04001057
1058 def reboot(self):
Shad Ansarif9521ad2018-09-08 10:46:43 +00001059 self.log.debug('rebooting openolt device', device_id=self.device_id)
Nicolas Palpacuerfd365ac2018-08-02 11:37:37 -04001060 try:
1061 self.stub.Reboot(openolt_pb2.Empty())
1062 except Exception as e:
1063 self.log.error('something went wrong with the reboot', error=e)
1064 else:
1065 self.log.info('device rebooted')
1066
Nicolas Palpacuer30027f42018-09-06 15:55:54 -04001067 def trigger_statistics_collection(self):
1068 try:
1069 self.stub.CollectStatistics(openolt_pb2.Empty())
1070 except Exception as e:
1071 self.log.error('Error while triggering statistics collection',
1072 error=e)
1073 else:
1074 self.log.info('statistics requested')
Scott Bakerd3190952018-09-04 15:47:28 -07001075
1076 def simulate_alarm(self, alarm):
1077 self.alarm_mgr.simulate_alarm(alarm)