blob: 97062a35ed82bfd58d26fd1dce4b7a5e6ef2303e [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#
16
17import structlog
18import threading
19import grpc
nick47b74372018-05-25 18:22:49 -040020import time
Shad Ansari2825d012018-02-22 23:57:46 +000021
Shad Ansari15928d12018-04-17 02:42:13 +000022from twisted.internet import reactor
Shad Ansari0346f0d2018-04-26 06:54:09 +000023from scapy.layers.l2 import Ether, Dot1Q
24import binascii
Shad Ansari22efe832018-05-19 05:37:03 +000025from transitions import Machine
Shad Ansari15928d12018-04-17 02:42:13 +000026
Shad Ansari2825d012018-02-22 23:57:46 +000027from voltha.protos.device_pb2 import Port, Device
28from voltha.protos.common_pb2 import OperStatus, AdminState, ConnectStatus
29from voltha.protos.logical_device_pb2 import LogicalDevice
Shad Ansarif9d2d102018-06-13 02:15:26 +000030from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
31 OFPPS_LINK_DOWN, OFPPF_1GB_FD, OFPC_GROUP_STATS, OFPC_PORT_STATS, \
Nicolas Palpacuere7359fc2018-06-15 14:10:48 -040032 OFPC_TABLE_STATS, OFPC_FLOW_STATS, ofp_switch_features, ofp_port, \
33 ofp_port_stats
34from voltha.protos.events_pb2 import KpiEvent, MetricValuePairs
35from voltha.protos.events_pb2 import KpiEventType
Shad Ansarif9d2d102018-06-13 02:15:26 +000036from voltha.protos.logical_device_pb2 import LogicalPort
Shad Ansari2825d012018-02-22 23:57:46 +000037from voltha.core.logical_device_agent import mac_str_to_tuple
38from voltha.registry import registry
39from voltha.adapters.openolt.protos import openolt_pb2_grpc, openolt_pb2
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -040040from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
41from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
42from voltha.protos.bbf_fiber_base_pb2 import VEnetConfig
Shad Ansari2825d012018-02-22 23:57:46 +000043import voltha.core.flow_decomposer as fd
44
Shad Ansari22920932018-05-17 00:33:34 +000045import openolt_platform as platform
Shad Ansari2dda4f32018-05-17 07:16:07 +000046from openolt_flow_mgr import OpenOltFlowMgr
Shad Ansari801f7372018-04-27 02:15:41 +000047
nick47b74372018-05-25 18:22:49 -040048MAX_HEARTBEAT_MISS = 3
49HEARTBEAT_PERIOD = 1
50GRPC_TIMEOUT = 5
Shad Ansari2825d012018-02-22 23:57:46 +000051
52"""
53OpenoltDevice represents an OLT.
54"""
Shad Ansarif9d2d102018-06-13 02:15:26 +000055
56
Shad Ansari2825d012018-02-22 23:57:46 +000057class OpenoltDevice(object):
58
Shad Ansari22efe832018-05-19 05:37:03 +000059 states = ['up', 'down']
60 transitions = [
Shad Ansarif9d2d102018-06-13 02:15:26 +000061 {'trigger': 'olt_up', 'source': 'down', 'dest': 'up',
62 'before': 'olt_indication_up'},
63 {'trigger': 'olt_down', 'source': 'up', 'dest': 'down',
64 'before': 'olt_indication_down'}
Shad Ansari22efe832018-05-19 05:37:03 +000065 ]
66
Shad Ansari2825d012018-02-22 23:57:46 +000067 def __init__(self, **kwargs):
68 super(OpenoltDevice, self).__init__()
69
70 self.adapter_agent = kwargs['adapter_agent']
Shad Ansari5dbc9c82018-05-10 03:29:31 +000071 self.device_num = kwargs['device_num']
Shad Ansari2825d012018-02-22 23:57:46 +000072 device = kwargs['device']
Nicolas Palpacuer253461f2018-06-01 12:01:45 -040073 is_reconciliation = kwargs.get('reconciliation', False)
Shad Ansari2825d012018-02-22 23:57:46 +000074 self.device_id = device.id
75 self.host_and_port = device.host_and_port
Shad Ansarif9d2d102018-06-13 02:15:26 +000076 self.log = structlog.get_logger(id=self.device_id,
77 ip=self.host_and_port)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -040078 self.proxy = registry('core').get_proxy('/')
Shad Ansari2825d012018-02-22 23:57:46 +000079
Nicolas Palpacuer253461f2018-06-01 12:01:45 -040080 # Device already set in the event of reconciliation
81 if not is_reconciliation:
82 # It is a new device
83 # Update device
84 device.root = True
Shad Ansarif9d2d102018-06-13 02:15:26 +000085 device.serial_number = self.host_and_port # FIXME
Nicolas Palpacuer253461f2018-06-01 12:01:45 -040086 device.connect_status = ConnectStatus.REACHABLE
87 device.oper_status = OperStatus.ACTIVATING
88 self.adapter_agent.update_device(device)
Shad Ansari2825d012018-02-22 23:57:46 +000089
Shad Ansari22efe832018-05-19 05:37:03 +000090 # Initialize the OLT state machine
91 self.machine = Machine(model=self, states=OpenoltDevice.states,
Shad Ansarif9d2d102018-06-13 02:15:26 +000092 transitions=OpenoltDevice.transitions,
93 send_event=True, initial='down',
94 ignore_invalid_triggers=True)
95 self.machine.add_transition(trigger='olt_ind_up', source='down',
96 dest='up')
97 self.machine.add_transition(trigger='olt_ind_loss', source='up',
98 dest='down')
Shad Ansari22efe832018-05-19 05:37:03 +000099
Shad Ansari2825d012018-02-22 23:57:46 +0000100 # Initialize gRPC
101 self.channel = grpc.insecure_channel(self.host_and_port)
Shad Ansari8f1b2532018-04-21 07:51:39 +0000102 self.channel_ready_future = grpc.channel_ready_future(self.channel)
nick47b74372018-05-25 18:22:49 -0400103 self.stub = openolt_pb2_grpc.OpenoltStub(self.channel)
104
Nicolas Palpacuer61815162018-06-20 18:12:04 -0400105 self.flow_mgr = OpenOltFlowMgr(self.log, self.stub, self.device_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000106
nick369a5062018-05-29 17:11:06 -0400107 # Indications thread plcaholder (started by heartbeat thread)
108 self.indications_thread = None
109 self.indications_thread_active = False
Shad Ansari2825d012018-02-22 23:57:46 +0000110
nick47b74372018-05-25 18:22:49 -0400111 # Start heartbeat thread
112 self.heartbeat_thread = threading.Thread(target=self.heartbeat)
113 self.heartbeat_thread.setDaemon(True)
114 self.heartbeat_thread_active = True
115 self.heartbeat_miss = 0
116 self.heartbeat_signature = None
117 self.heartbeat_thread.start()
118
Nicolas Palpacuerd35d9bb2018-06-20 17:06:31 -0400119 if is_reconciliation:
120 # Put state machine in state up
121 reactor.callFromThread(self.olt_up, reconciliation=True)
122
Nicolas Palpacuer253461f2018-06-01 12:01:45 -0400123 self.log.debug('openolt-device-created', device_id=self.device_id)
124
Shad Ansari8f1b2532018-04-21 07:51:39 +0000125 def process_indications(self):
Shad Ansari2dda4f32018-05-17 07:16:07 +0000126
nick47b74372018-05-25 18:22:49 -0400127 self.log.debug('starting-indications-thread')
Shad Ansari2dda4f32018-05-17 07:16:07 +0000128
Shad Ansari15928d12018-04-17 02:42:13 +0000129 self.indications = self.stub.EnableIndication(openolt_pb2.Empty())
Shad Ansari2dda4f32018-05-17 07:16:07 +0000130
nick47b74372018-05-25 18:22:49 -0400131 while self.indications_thread_active:
132 try:
133 # get the next indication from olt
134 ind = next(self.indications)
135 except Exception as e:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000136 self.log.warn('GRPC-connection-lost-stoping-indication-thread',
137 error=e)
nick47b74372018-05-25 18:22:49 -0400138 self.indications_thread_active = False
139 else:
140 self.log.debug("rx indication", indication=ind)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000141
nick47b74372018-05-25 18:22:49 -0400142 # indication handlers run in the main event loop
143 if ind.HasField('olt_ind'):
144 reactor.callFromThread(self.olt_indication, ind.olt_ind)
145 elif ind.HasField('intf_ind'):
146 reactor.callFromThread(self.intf_indication, ind.intf_ind)
147 elif ind.HasField('intf_oper_ind'):
Shad Ansarif9d2d102018-06-13 02:15:26 +0000148 reactor.callFromThread(self.intf_oper_indication,
149 ind.intf_oper_ind)
nick47b74372018-05-25 18:22:49 -0400150 elif ind.HasField('onu_disc_ind'):
Shad Ansarif9d2d102018-06-13 02:15:26 +0000151 reactor.callFromThread(self.onu_discovery_indication,
152 ind.onu_disc_ind)
nick47b74372018-05-25 18:22:49 -0400153 elif ind.HasField('onu_ind'):
154 reactor.callFromThread(self.onu_indication, ind.onu_ind)
155 elif ind.HasField('omci_ind'):
156 reactor.callFromThread(self.omci_indication, ind.omci_ind)
157 elif ind.HasField('pkt_ind'):
158 reactor.callFromThread(self.packet_indication, ind.pkt_ind)
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400159 elif ind.HasField('port_stats'):
160 reactor.callFromThread(self.port_statistics_indication,
161 ind.port_stats)
162 elif ind.HasField('flow_stats'):
163 reactor.callFromThread(self.flow_statistics_indication,
164 ind.flow_stats)
165 else:
166 self.log.warn('unknown indication type')
nick47b74372018-05-25 18:22:49 -0400167
168 self.log.debug('stopping-indications-thread', device_id=self.device_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000169
170 def olt_indication(self, olt_indication):
Shad Ansari22efe832018-05-19 05:37:03 +0000171 if olt_indication.oper_state == "up":
172 self.olt_up(ind=olt_indication)
173 elif olt_indication.oper_state == "down":
174 self.olt_down(ind=olt_indication)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000175
Shad Ansari22efe832018-05-19 05:37:03 +0000176 def olt_indication_up(self, event):
177 olt_indication = event.kwargs.get('ind', None)
Nicolas Palpacuerd35d9bb2018-06-20 17:06:31 -0400178 is_reconciliation = event.kwargs.get('reconciliation', False)
179 self.log.debug("olt indication", olt_ind=olt_indication,
180 reconciliation=is_reconciliation)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000181
nick47b74372018-05-25 18:22:49 -0400182 device = self.adapter_agent.get_device(self.device_id)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000183
nick47b74372018-05-25 18:22:49 -0400184 # If logical device does not exist create it
185 if len(device.parent_id) == 0:
186
187 dpid = '00:00:' + self.ip_hex(self.host_and_port.split(":")[0])
188
189 # Create logical OF device
190 ld = LogicalDevice(
191 root_device_id=self.device_id,
192 switch_features=ofp_switch_features(
193 n_buffers=256, # TODO fake for now
194 n_tables=2, # TODO ditto
195 capabilities=( # TODO and ditto
196 OFPC_FLOW_STATS
197 | OFPC_TABLE_STATS
198 | OFPC_PORT_STATS
199 | OFPC_GROUP_STATS
200 )
Jonathan Hart7687e0a2018-05-16 10:54:47 -0700201 )
202 )
Shad Ansarif9d2d102018-06-13 02:15:26 +0000203 ld_init = self.adapter_agent.create_logical_device(ld,
204 dpid=dpid)
205 self.logical_device_id = ld_init.id
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400206 else:
207 # logical device already exists
208 self.logical_device_id = device.parent_id
Nicolas Palpacuerd35d9bb2018-06-20 17:06:31 -0400209 if is_reconciliation:
210 self.adapter_agent.reconcile_logical_device(
211 self.logical_device_id)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000212
213 # Update phys OF device
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000214 device.parent_id = self.logical_device_id
215 device.oper_status = OperStatus.ACTIVE
216 self.adapter_agent.update_device(device)
217
Shad Ansari22efe832018-05-19 05:37:03 +0000218 def olt_indication_down(self, event):
219 olt_indication = event.kwargs.get('ind', None)
nick47b74372018-05-25 18:22:49 -0400220 new_admin_state = event.kwargs.get('admin_state', None)
221 new_oper_state = event.kwargs.get('oper_state', None)
222 new_connect_state = event.kwargs.get('connect_state', None)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000223 self.log.debug("olt indication", olt_ind=olt_indication,
224 admin_state=new_admin_state, oper_state=new_oper_state,
nick47b74372018-05-25 18:22:49 -0400225 connect_state=new_connect_state)
226
nick369a5062018-05-29 17:11:06 -0400227 # Propagating to the children
228
229 # Children ports
230 child_devices = self.adapter_agent.get_child_devices(self.device_id)
231 for onu_device in child_devices:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000232 uni_no = platform.mk_uni_port_num(
233 onu_device.proxy_address.channel_id,
234 onu_device.proxy_address.onu_id)
235 uni_name = self.port_name(uni_no, Port.ETHERNET_UNI,
236 serial_number=onu_device.serial_number)
nick369a5062018-05-29 17:11:06 -0400237
238 self.onu_ports_down(onu_device, uni_no, uni_name, new_oper_state)
239 # Children devices
Shad Ansarif9d2d102018-06-13 02:15:26 +0000240 self.adapter_agent.update_child_devices_state(
241 self.device_id, oper_status=new_oper_state,
242 connect_status=ConnectStatus.UNREACHABLE,
243 admin_state=new_admin_state)
nick369a5062018-05-29 17:11:06 -0400244 # Device Ports
Shad Ansarif9d2d102018-06-13 02:15:26 +0000245 device_ports = self.adapter_agent.get_ports(self.device_id,
246 Port.ETHERNET_NNI)
nick369a5062018-05-29 17:11:06 -0400247 logical_ports_ids = [port.label for port in device_ports]
Shad Ansarif9d2d102018-06-13 02:15:26 +0000248 device_ports += self.adapter_agent.get_ports(self.device_id,
249 Port.PON_OLT)
nick369a5062018-05-29 17:11:06 -0400250
251 for port in device_ports:
252 if new_admin_state is not None:
253 port.admin_state = new_admin_state
254 if new_oper_state is not None:
255 port.oper_status = new_oper_state
256 self.adapter_agent.add_port(self.device_id, port)
257
258 # Device logical port
259 for logical_port_id in logical_ports_ids:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000260 logical_port = self.adapter_agent.get_logical_port(
261 self.logical_device_id, logical_port_id)
nick369a5062018-05-29 17:11:06 -0400262 logical_port.ofp_port.state = OFPPS_LINK_DOWN
Shad Ansarif9d2d102018-06-13 02:15:26 +0000263 self.adapter_agent.update_logical_port(self.logical_device_id,
264 logical_port)
nick369a5062018-05-29 17:11:06 -0400265
266 # Device
nick47b74372018-05-25 18:22:49 -0400267 device = self.adapter_agent.get_device(self.device_id)
nick369a5062018-05-29 17:11:06 -0400268 if new_admin_state is not None:
nick47b74372018-05-25 18:22:49 -0400269 device.admin_state = new_admin_state
270 if new_oper_state is not None:
271 device.oper_status = new_oper_state
272 if new_connect_state is not None:
273 device.connect_status = new_connect_state
274
275 self.adapter_agent.update_device(device)
Shad Ansari2825d012018-02-22 23:57:46 +0000276
277 def intf_indication(self, intf_indication):
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400278 self.log.debug("intf indication", intf_id=intf_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000279 oper_state=intf_indication.oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000280
281 if intf_indication.oper_state == "up":
282 oper_status = OperStatus.ACTIVE
283 else:
284 oper_status = OperStatus.DISCOVERED
285
nick47b74372018-05-25 18:22:49 -0400286 # add_port update the port if it exists
Shad Ansari2825d012018-02-22 23:57:46 +0000287 self.add_port(intf_indication.intf_id, Port.PON_OLT, oper_status)
288
289 def intf_oper_indication(self, intf_oper_indication):
Shad Ansarif9d2d102018-06-13 02:15:26 +0000290 self.log.debug("Received interface oper state change indication",
291 intf_id=intf_oper_indication.intf_id,
292 type=intf_oper_indication.type,
293 oper_state=intf_oper_indication.oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000294
295 if intf_oper_indication.oper_state == "up":
296 oper_state = OperStatus.ACTIVE
297 else:
298 oper_state = OperStatus.DISCOVERED
299
300 if intf_oper_indication.type == "nni":
301
Shad Ansari0346f0d2018-04-26 06:54:09 +0000302 # FIXME - creating logical port for 2nd interface throws exception!
Shad Ansari2825d012018-02-22 23:57:46 +0000303 if intf_oper_indication.intf_id != 0:
304 return
305
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400306 # add_(logical_)port update the port if it exists
Shad Ansarif9d2d102018-06-13 02:15:26 +0000307 port_no, label = self.add_port(intf_oper_indication.intf_id,
308 Port.ETHERNET_NNI, oper_state)
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400309 self.log.debug("int_oper_indication", port_no=port_no, label=label)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000310 self.add_logical_port(port_no, intf_oper_indication.intf_id,
311 oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000312
313 elif intf_oper_indication.type == "pon":
314 # FIXME - handle PON oper state change
315 pass
316
317 def onu_discovery_indication(self, onu_disc_indication):
Shad Ansari803900a2018-05-02 06:26:00 +0000318 intf_id = onu_disc_indication.intf_id
Shad Ansarif9d2d102018-06-13 02:15:26 +0000319 serial_number = onu_disc_indication.serial_number
Shad Ansari2825d012018-02-22 23:57:46 +0000320
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400321 serial_number_str = self.stringify_serial_number(serial_number)
Shad Ansari803900a2018-05-02 06:26:00 +0000322
Shad Ansarif9d2d102018-06-13 02:15:26 +0000323 self.log.debug("onu discovery indication", intf_id=intf_id,
324 serial_number=serial_number_str)
Nicolas Palpacuer36a93442018-05-23 17:38:57 -0400325
Shad Ansarif9d2d102018-06-13 02:15:26 +0000326 onu_device = self.adapter_agent.get_child_device(
327 self.device_id,
328 serial_number=serial_number_str)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400329
330 if onu_device is None:
Shad Ansari803900a2018-05-02 06:26:00 +0000331 onu_id = self.new_onu_id(intf_id)
Shad Ansari15928d12018-04-17 02:42:13 +0000332 try:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000333 self.add_onu_device(
334 intf_id,
335 platform.intf_id_to_port_no(intf_id, Port.PON_OLT),
336 onu_id, serial_number)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400337 self.log.info("activate-onu", intf_id=intf_id, onu_id=onu_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000338 serial_number=serial_number_str)
339 onu = openolt_pb2.Onu(intf_id=intf_id, onu_id=onu_id,
340 serial_number=serial_number)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400341 self.stub.ActivateOnu(onu)
342 except Exception as e:
343 self.log.exception('onu-activation-failed', e=e)
344
Shad Ansari2825d012018-02-22 23:57:46 +0000345 else:
nick47b74372018-05-25 18:22:49 -0400346 if onu_device.connect_status != ConnectStatus.REACHABLE:
347 onu_device.connect_status = ConnectStatus.REACHABLE
348 self.adapter_agent.update_device(onu_device)
349
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400350 onu_id = onu_device.proxy_address.onu_id
Shad Ansarif9d2d102018-06-13 02:15:26 +0000351 if onu_device.oper_status == OperStatus.DISCOVERED \
352 or onu_device.oper_status == OperStatus.ACTIVATING:
353 self.log.debug("ignore onu discovery indication, \
354 the onu has been discovered and should be \
355 activating shorlty", intf_id=intf_id,
356 onu_id=onu_id, state=onu_device.oper_status)
357 elif onu_device.oper_status == OperStatus.ACTIVE:
358 self.log.warn("onu discovery indication whereas onu is \
359 supposed to be active",
360 intf_id=intf_id, onu_id=onu_id,
361 state=onu_device.oper_status)
nick47b74372018-05-25 18:22:49 -0400362 elif onu_device.oper_status == OperStatus.UNKNOWN:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000363 self.log.info("onu in unknown state, recovering from olt \
364 reboot, activate onu", intf_id=intf_id,
365 onu_id=onu_id, serial_number=serial_number_str)
nick47b74372018-05-25 18:22:49 -0400366
367 onu_device.oper_status = OperStatus.DISCOVERED
368 self.adapter_agent.update_device(onu_device)
369
Shad Ansarif9d2d102018-06-13 02:15:26 +0000370 onu = openolt_pb2.Onu(intf_id=intf_id, onu_id=onu_id,
371 serial_number=serial_number)
nick47b74372018-05-25 18:22:49 -0400372 self.stub.ActivateOnu(onu)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400373 else:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000374 self.log.warn('unexpected state', onu_id=onu_id,
375 onu_device_oper_state=onu_device.oper_status)
Shad Ansari2825d012018-02-22 23:57:46 +0000376
Shad Ansari2825d012018-02-22 23:57:46 +0000377 def onu_indication(self, onu_indication):
Shad Ansaria0b37892018-06-12 21:34:30 +0000378 self.log.debug("onu indication", intf_id=onu_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000379 onu_id=onu_indication.onu_id,
380 serial_number=onu_indication.serial_number,
381 oper_state=onu_indication.oper_state,
382 admin_state=onu_indication.admin_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000383
Shad Ansaria0b37892018-06-12 21:34:30 +0000384 if onu_indication.serial_number:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400385 onu_device = self.adapter_agent.get_child_device(
Shad Ansaria0b37892018-06-12 21:34:30 +0000386 self.device_id,
387 serial_number=self.stringify_serial_number(
388 onu_indication.serial_number))
Shad Ansarif9d2d102018-06-13 02:15:26 +0000389 else:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400390 onu_device = self.adapter_agent.get_child_device(
Shad Ansaria0b37892018-06-12 21:34:30 +0000391 self.device_id,
392 parent_port_no=platform.intf_id_to_port_no(
393 onu_indication.intf_id, Port.PON_OLT),
394 onu_id=onu_indication.onu_id)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400395
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400396 if onu_device is None:
Shad Ansaria0b37892018-06-12 21:34:30 +0000397 self.log.error('onu not found', intf_id=onu_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000398 onu_id=onu_indication.onu_id)
Shad Ansari803900a2018-05-02 06:26:00 +0000399 return
400
nick47b74372018-05-25 18:22:49 -0400401 if onu_device.connect_status != ConnectStatus.REACHABLE:
402 onu_device.connect_status = ConnectStatus.REACHABLE
403 self.adapter_agent.update_device(onu_device)
404
Shad Ansarif9d2d102018-06-13 02:15:26 +0000405 if platform.intf_id_from_pon_port_no(onu_device.parent_port_no) \
406 != onu_indication.intf_id:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400407 self.log.warn('ONU-is-on-a-different-intf-id-now',
Shad Ansarif9d2d102018-06-13 02:15:26 +0000408 previous_intf_id=platform.intf_id_from_pon_port_no(
409 onu_device.parent_port_no),
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400410 current_intf_id=onu_indication.intf_id)
411 # FIXME - handle intf_id mismatch (ONU move?)
Shad Ansari2825d012018-02-22 23:57:46 +0000412
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400413 if onu_device.proxy_address.onu_id != onu_indication.onu_id:
414 # FIXME - handle onu id mismatch
Shad Ansarif9d2d102018-06-13 02:15:26 +0000415 self.log.warn('ONU-id-mismatch',
416 expected_onu_id=onu_device.proxy_address.onu_id,
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400417 received_onu_id=onu_indication.onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000418
Shad Ansarif9d2d102018-06-13 02:15:26 +0000419 uni_no = platform.mk_uni_port_num(onu_indication.intf_id,
420 onu_indication.onu_id)
421 uni_name = self.port_name(uni_no, Port.ETHERNET_UNI,
422 serial_number=onu_device.serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000423
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400424 self.log.debug('port-number-ready', uni_no=uni_no, uni_name=uni_name)
Shad Ansari2825d012018-02-22 23:57:46 +0000425
Shad Ansarif9d2d102018-06-13 02:15:26 +0000426 # Admin state
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400427 if onu_indication.admin_state == 'down':
428 if onu_indication.oper_state != 'down':
Shad Ansarif9d2d102018-06-13 02:15:26 +0000429 self.log.error('ONU-admin-state-down-and-oper-status-not-down',
430 oper_state=onu_indication.oper_state)
431 # Forcing the oper state change code to execute
432 onu_indication.oper_state = 'down'
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400433
434 if onu_device.admin_state != AdminState.DISABLED:
435 onu_device.admin_state = AdminState.DISABLED
436 self.adapter_agent.update(onu_device)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000437 self.log.debug('putting-onu-in-disabled-state',
438 onu_serial_number=onu_device.serial_number)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400439
Shad Ansarif9d2d102018-06-13 02:15:26 +0000440 # Port and logical port update is taken care of by oper state block
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400441
442 elif onu_indication.admin_state == 'up':
443 if onu_device.admin_state != AdminState.ENABLED:
444 onu_device.admin_state = AdminState.ENABLED
445 self.adapter_agent.update(onu_device)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000446 self.log.debug('putting-onu-in-enabled-state',
447 onu_serial_number=onu_device.serial_number)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400448
449 else:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000450 self.log.warn('Invalid-or-not-implemented-admin-state',
451 received_admin_state=onu_indication.admin_state)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400452
453 self.log.debug('admin-state-dealt-with')
454
Shad Ansarif9d2d102018-06-13 02:15:26 +0000455 # Operating state
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400456 if onu_indication.oper_state == 'down':
Shad Ansarif9d2d102018-06-13 02:15:26 +0000457 # Move to discovered state
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400458 self.log.debug('onu-oper-state-is-down')
459
460 if onu_device.oper_status != OperStatus.DISCOVERED:
461 onu_device.oper_status = OperStatus.DISCOVERED
462 self.adapter_agent.update_device(onu_device)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000463 # Set port oper state to Discovered
464 self.onu_ports_down(onu_device, uni_no, uni_name,
465 OperStatus.DISCOVERED)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400466
467 elif onu_indication.oper_state == 'up':
468
469 if onu_device.oper_status != OperStatus.DISCOVERED:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000470 self.log.debug("ignore onu indication",
471 intf_id=onu_indication.intf_id,
472 onu_id=onu_indication.onu_id,
473 state=onu_device.oper_status,
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400474 msg_oper_state=onu_indication.oper_state)
475 return
476
Shad Ansarif9d2d102018-06-13 02:15:26 +0000477 # Device was in Discovered state, setting it to active
478 onu_adapter_agent = \
479 registry('adapter_loader').get_agent(onu_device.adapter)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400480 if onu_adapter_agent is None:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000481 self.log.error('onu_adapter_agent-could-not-be-retrieved',
482 onu_device=onu_device)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400483 return
484
Shad Ansarif9d2d102018-06-13 02:15:26 +0000485 # Prepare onu configuration
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400486
487 # onu initialization, base configuration (bridge setup ...)
488 def onu_initialization():
489
Shad Ansarif9d2d102018-06-13 02:15:26 +0000490 # FIXME: that's definitely cheating
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400491 if onu_device.adapter == 'broadcom_onu':
Shad Ansarif9d2d102018-06-13 02:15:26 +0000492 onu_adapter_agent.adapter.devices_handlers[onu_device.id] \
493 .message_exchange()
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400494 self.log.debug('broadcom-message-exchange-started')
495
496 # tcont creation (onu)
497 tcont = TcontsConfigData()
498 tcont.alloc_id = platform.mk_alloc_id(onu_indication.onu_id)
499
500 # gem port creation
501 gem_port = GemportsConfigData()
502 gem_port.gemport_id = platform.mk_gemport_id(onu_indication.onu_id)
503
Shad Ansarif9d2d102018-06-13 02:15:26 +0000504 # ports creation/update
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400505 def port_config():
506
507 # "v_enet" creation (olt)
508
Shad Ansarif9d2d102018-06-13 02:15:26 +0000509 # add_port update port when it exists
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400510 self.adapter_agent.add_port(
511 self.device_id,
512 Port(
513 port_no=uni_no,
514 label=uni_name,
515 type=Port.ETHERNET_UNI,
516 admin_state=AdminState.ENABLED,
517 oper_status=OperStatus.ACTIVE))
518
519 # v_enet creation (onu)
520
521 venet = VEnetConfig(name=uni_name)
522 venet.interface.name = uni_name
523 onu_adapter_agent.create_interface(onu_device, venet)
524
525 # ONU device status update in the datastore
526 def onu_update_oper_status():
527 onu_device.oper_status = OperStatus.ACTIVE
528 onu_device.connect_status = ConnectStatus.REACHABLE
529 self.adapter_agent.update_device(onu_device)
530
531 # FIXME : the asynchronicity has to be taken care of properly
532 onu_initialization()
Shad Ansarif9d2d102018-06-13 02:15:26 +0000533 reactor.callLater(10, onu_adapter_agent.create_tcont,
534 device=onu_device, tcont_data=tcont,
535 traffic_descriptor_data=None)
536 reactor.callLater(11, onu_adapter_agent.create_gemport, onu_device,
537 gem_port)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400538 reactor.callLater(12, port_config)
539 reactor.callLater(12, onu_update_oper_status)
540
541 else:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000542 self.log.warn('Not-implemented-or-invalid-value-of-oper-state',
543 oper_state=onu_indication.oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000544
nick47b74372018-05-25 18:22:49 -0400545 def onu_ports_down(self, onu_device, uni_no, uni_name, oper_state):
546 # Set port oper state to Discovered
547 # add port will update port if it exists
548 self.adapter_agent.add_port(
549 self.device_id,
550 Port(
551 port_no=uni_no,
552 label=uni_name,
553 type=Port.ETHERNET_UNI,
554 admin_state=onu_device.admin_state,
555 oper_status=oper_state))
556
557 # Disable logical port
nick47b74372018-05-25 18:22:49 -0400558 onu_ports = self.proxy.get('devices/{}/ports'.format(onu_device.id))
559 onu_port_id = None
560 for onu_port in onu_ports:
561 if onu_port.port_no == uni_no:
562 onu_port_id = onu_port.label
563 if onu_port_id is None:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000564 self.log.error('matching-onu-port-label-not-found',
565 onu_id=onu_device.id, olt_id=self.device_id,
nick47b74372018-05-25 18:22:49 -0400566 onu_ports=onu_ports)
567 return
568 try:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000569 onu_logical_port = self.adapter_agent.get_logical_port(
570 logical_device_id=self.logical_device_id, port_id=onu_port_id)
nick47b74372018-05-25 18:22:49 -0400571 onu_logical_port.ofp_port.state = OFPPS_LINK_DOWN
Shad Ansarif9d2d102018-06-13 02:15:26 +0000572 self.adapter_agent.update_logical_port(
573 logical_device_id=self.logical_device_id,
574 port=onu_logical_port)
nick47b74372018-05-25 18:22:49 -0400575 self.log.debug('cascading-oper-state-to-port-and-logical-port')
576 except KeyError as e:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000577 self.log.error('matching-onu-port-label-invalid',
578 onu_id=onu_device.id, olt_id=self.device_id,
579 onu_ports=onu_ports, onu_port_id=onu_port_id,
580 error=e)
nick47b74372018-05-25 18:22:49 -0400581
Shad Ansari2825d012018-02-22 23:57:46 +0000582 def omci_indication(self, omci_indication):
583
584 self.log.debug("omci indication", intf_id=omci_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000585 onu_id=omci_indication.onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000586
Shad Ansarif9d2d102018-06-13 02:15:26 +0000587 onu_device = self.adapter_agent.get_child_device(
588 self.device_id, onu_id=omci_indication.onu_id)
Shad Ansari0efa6512018-04-28 06:42:54 +0000589
590 self.adapter_agent.receive_proxied_message(onu_device.proxy_address,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000591 omci_indication.pkt)
Shad Ansari2825d012018-02-22 23:57:46 +0000592
Shad Ansari42db7342018-04-25 21:39:46 +0000593 def packet_indication(self, pkt_indication):
594
595 self.log.debug("packet indication", intf_id=pkt_indication.intf_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000596 gemport_id=pkt_indication.gemport_id,
597 flow_id=pkt_indication.flow_id)
Shad Ansari42db7342018-04-25 21:39:46 +0000598
Shad Ansari22920932018-05-17 00:33:34 +0000599 onu_id = platform.onu_id_from_gemport_id(pkt_indication.gemport_id)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000600 logical_port_num = platform.mk_uni_port_num(pkt_indication.intf_id,
601 onu_id)
Shad Ansari42db7342018-04-25 21:39:46 +0000602
603 pkt = Ether(pkt_indication.pkt)
Shad Ansari0efa6512018-04-28 06:42:54 +0000604 kw = dict(logical_device_id=self.logical_device_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000605 logical_port_no=logical_port_num)
Shad Ansari42db7342018-04-25 21:39:46 +0000606 self.adapter_agent.send_packet_in(packet=str(pkt), **kw)
607
nick47b74372018-05-25 18:22:49 -0400608 def olt_reachable(self):
609 device = self.adapter_agent.get_device(self.device_id)
610 device.connect_status = ConnectStatus.REACHABLE
611 self.adapter_agent.update_device(device)
612 # Not changing its child devices state, we cannot guaranty that
613
614 def heartbeat(self):
615
Shad Ansarif9d2d102018-06-13 02:15:26 +0000616 # block till gRPC connection is complete
617 self.channel_ready_future.result()
nick369a5062018-05-29 17:11:06 -0400618
nick47b74372018-05-25 18:22:49 -0400619 while self.heartbeat_thread_active:
620
621 try:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000622 heartbeat = self.stub.HeartbeatCheck(openolt_pb2.Empty(),
623 timeout=GRPC_TIMEOUT)
nick47b74372018-05-25 18:22:49 -0400624 except Exception as e:
625 self.heartbeat_miss += 1
Shad Ansarif9d2d102018-06-13 02:15:26 +0000626 self.log.warn('heartbeat-miss',
627 missed_heartbeat=self.heartbeat_miss, error=e)
nick47b74372018-05-25 18:22:49 -0400628 if self.heartbeat_miss == MAX_HEARTBEAT_MISS:
629 self.log.error('lost-connectivity-to-olt')
Shad Ansarif9d2d102018-06-13 02:15:26 +0000630 # TODO : send alarm/notify monitoring system
nick47b74372018-05-25 18:22:49 -0400631 # Using reactor to synchronize update
632 # flagging it as unreachable and in unknow state
Shad Ansarif9d2d102018-06-13 02:15:26 +0000633 reactor.callFromThread(
634 self.olt_down,
635 oper_state=OperStatus.UNKNOWN,
636 connect_state=ConnectStatus.UNREACHABLE)
nick47b74372018-05-25 18:22:49 -0400637
638 else:
639 # heartbeat received
640 if self.heartbeat_signature is None:
641 # Initialize heartbeat signature
642 self.heartbeat_signature = heartbeat.heartbeat_signature
Shad Ansarif9d2d102018-06-13 02:15:26 +0000643 self.log.debug(
644 'heartbeat-signature',
645 device_id=self.device_id,
646 heartbeat_signature=self.heartbeat_signature)
nick47b74372018-05-25 18:22:49 -0400647 # Check if signature is different
648 if self.heartbeat_signature != heartbeat.heartbeat_signature:
649 # OLT has rebooted
650 self.log.warn('OLT-was-rebooted', device_id=self.device_id)
Shad Ansarif9d2d102018-06-13 02:15:26 +0000651 # TODO: notify monitoring system
nick47b74372018-05-25 18:22:49 -0400652 self.heartbeat_signature = heartbeat.heartbeat_signature
653
654 else:
655 self.log.debug('valid-heartbeat-received')
656
657 if self.heartbeat_miss > MAX_HEARTBEAT_MISS:
658 self.log.info('OLT-connection-restored')
Shad Ansarif9d2d102018-06-13 02:15:26 +0000659 # TODO : suppress alarm/notify monitoring system
nick47b74372018-05-25 18:22:49 -0400660 # flagging it as reachable again
nick369a5062018-05-29 17:11:06 -0400661 reactor.callFromThread(self.olt_reachable)
nick47b74372018-05-25 18:22:49 -0400662
663 if not self.indications_thread_active:
nick369a5062018-05-29 17:11:06 -0400664 self.log.info('(re)starting-indications-thread')
nick47b74372018-05-25 18:22:49 -0400665 # reset indications thread
Shad Ansarif9d2d102018-06-13 02:15:26 +0000666 self.indications_thread = threading.Thread(
667 target=self.process_indications)
nick47b74372018-05-25 18:22:49 -0400668 self.indications_thread.setDaemon(True)
669 self.indications_thread_active = True
670 self.indications_thread.start()
671
672 self.heartbeat_miss = 0
673
674 time.sleep(HEARTBEAT_PERIOD)
675
676 self.log.debug('stopping-heartbeat-thread', device_id=self.device_id)
677
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400678 def port_statistics_indication(self, port_stats):
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400679 self.log.info('port-stats-collected', stats=port_stats)
Nicolas Palpacuere7359fc2018-06-15 14:10:48 -0400680 self.ports_statistics_kpis(port_stats)
681 #FIXME : only the first uplink is a logical port
682 if port_stats.intf_id == 128:
683 # ONOS update
684 self.update_logical_port_stats(port_stats)
685 # FIXME: Discard other uplinks, they do not exist as an object
686 if port_stats.intf_id in [129, 130, 131]:
687 self.log.debug('those uplinks are not created')
688 return
689 # update port object stats
690 port = self.adapter_agent.get_port(self.device_id,
691 port_no=port_stats.intf_id)
692
693 port.rx_packets = port_stats.rx_packets
694 port.rx_bytes = port_stats.rx_bytes
695 port.rx_errors = port_stats.rx_error_packets
696 port.tx_packets = port_stats.tx_packets
697 port.tx_bytes = port_stats.tx_bytes
698 port.tx_errors = port_stats.tx_error_packets
699
700 # Add port does an update if port exists
701 self.adapter_agent.add_port(self.device_id, port)
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400702
703 def flow_statistics_indication(self, flow_stats):
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400704 self.log.info('flow-stats-collected', stats=flow_stats)
Nicolas Palpacuere7359fc2018-06-15 14:10:48 -0400705 # TODO: send to kafka ?
706 # UNTESTED : the openolt driver does not yet provide flow stats
707 self.adapter_agent.update_flow_stats(self.logical_device_id,
708 flow_id=flow_stats.flow_id, packet_count=flow_stats.tx_packets,
709 byte_count=flow_stats.tx_bytes)
710
711 def ports_statistics_kpis(self, port_stats):
712 pm_data = {}
713 pm_data["rx_bytes"] = port_stats.rx_bytes
714 pm_data["rx_packets"] = port_stats.rx_packets
715 pm_data["rx_ucast_packets"] = port_stats.rx_ucast_packets
716 pm_data["rx_mcast_packets"] = port_stats.rx_mcast_packets
717 pm_data["rx_bcast_packets"] = port_stats.rx_bcast_packets
718 pm_data["rx_error_packets"] = port_stats.rx_error_packets
719 pm_data["tx_bytes"] = port_stats.tx_bytes
720 pm_data["tx_packets"] = port_stats.tx_packets
721 pm_data["tx_ucast_packets"] = port_stats.tx_ucast_packets
722 pm_data["tx_mcast_packets"] = port_stats.tx_mcast_packets
723 pm_data["tx_bcast_packets"] = port_stats.tx_bcast_packets
724 pm_data["tx_error_packets"] = port_stats.tx_error_packets
725 pm_data["rx_crc_errors"] = port_stats.rx_crc_errors
726 pm_data["bip_errors"] = port_stats.bip_errors
727
728
729 prefix = 'voltha.openolt.{}'.format(self.device_id)
730 # FIXME
731 if port_stats.intf_id < 132:
732 prefixes = {
733 prefix + '{}.nni'.format(port_stats.intf_id): MetricValuePairs(
734 metrics=pm_data)
735 }
736 else:
737 prefixes = {
738 prefix + '.pon.{}'.format(platform.intf_id_from_pon_port_no(
739 port_stats.intf_id)): MetricValuePairs(
740 metrics=pm_data)
741 }
742
743 kpi_event = KpiEvent(
744 type=KpiEventType.slice,
745 ts=port_stats.timestamp,
746 prefixes=prefixes)
747 self.adapter_agent.submit_kpis(kpi_event)
748
749 def update_logical_port_stats(self, port_stats):
750 # FIXME
751 label = 'nni-{}'.format(port_stats.intf_id)
752 logical_port = self.adapter_agent.get_logical_port(
753 self.logical_device_id, label)
754
755 if logical_port is None:
756 self.log.error('logical-port-is-None',
757 logical_device_id=self.logical_device_id, label=label,
758 port_stats=port_stats)
759 return
760
761 self.log.debug('before', port=logical_port)
762
763 logical_port.ofp_port_stats.rx_packets = port_stats.rx_packets
764 logical_port.ofp_port_stats.rx_bytes = port_stats.rx_bytes
765 logical_port.ofp_port_stats.tx_packets = port_stats.tx_packets
766 logical_port.ofp_port_stats.tx_bytes = port_stats.tx_bytes
767 logical_port.ofp_port_stats.rx_errors = port_stats.rx_error_packets
768 logical_port.ofp_port_stats.tx_errors = port_stats.tx_error_packets
769 logical_port.ofp_port_stats.rx_crc_err = port_stats.rx_crc_errors
770
771 self.log.debug('after', port=logical_port)
772
773 self.adapter_agent.update_logical_port(self.logical_device_id,
774 logical_port)
Nicolas Palpacuer33f1a822018-06-13 12:36:36 -0400775
Shad Ansari42db7342018-04-25 21:39:46 +0000776 def packet_out(self, egress_port, msg):
Shad Ansari0346f0d2018-04-26 06:54:09 +0000777 pkt = Ether(msg)
778 self.log.info('packet out', egress_port=egress_port,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000779 packet=str(pkt).encode("HEX"))
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400780
781 # Find port type
782 egress_port_type = self.port_type(egress_port)
783
784 if egress_port_type == Port.ETHERNET_UNI:
785
786 if pkt.haslayer(Dot1Q):
787 outer_shim = pkt.getlayer(Dot1Q)
788 if isinstance(outer_shim.payload, Dot1Q):
789 # If double tag, remove the outer tag
790 payload = (
791 Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
792 outer_shim.payload
793 )
794 else:
795 payload = pkt
Shad Ansari0346f0d2018-04-26 06:54:09 +0000796 else:
797 payload = pkt
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400798
799 send_pkt = binascii.unhexlify(str(payload).encode("HEX"))
800
Shad Ansarif9d2d102018-06-13 02:15:26 +0000801 self.log.info(
802 'sending-packet-to-ONU', egress_port=egress_port,
803 intf_id=platform.intf_id_from_pon_port_no(egress_port),
804 onu_id=platform.onu_id_from_port_num(egress_port),
805 packet=str(payload).encode("HEX"))
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400806
Shad Ansarif9d2d102018-06-13 02:15:26 +0000807 onu_pkt = openolt_pb2.OnuPacket(
808 intf_id=platform.intf_id_from_pon_port_no(egress_port),
809 onu_id=platform.onu_id_from_port_num(egress_port),
810 pkt=send_pkt)
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400811
812 self.stub.OnuPacketOut(onu_pkt)
813
814 elif egress_port_type == Port.ETHERNET_NNI:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000815 self.log.info('sending-packet-to-uplink', egress_port=egress_port,
816 packet=str(pkt).encode("HEX"))
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400817
818 send_pkt = binascii.unhexlify(str(pkt).encode("HEX"))
819
Shad Ansarif9d2d102018-06-13 02:15:26 +0000820 uplink_pkt = openolt_pb2.UplinkPacket(
821 intf_id=platform.intf_id_from_nni_port_num(egress_port),
822 pkt=send_pkt)
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400823
824 self.stub.UplinkPacketOut(uplink_pkt)
825
Shad Ansari0346f0d2018-04-26 06:54:09 +0000826 else:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000827 self.log.warn('Packet-out-to-this-interface-type-not-implemented',
828 egress_port=egress_port,
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400829 port_type=egress_port_type)
Shad Ansari42db7342018-04-25 21:39:46 +0000830
Shad Ansari2825d012018-02-22 23:57:46 +0000831 def send_proxied_message(self, proxy_address, msg):
Shad Ansarif9d2d102018-06-13 02:15:26 +0000832 omci = openolt_pb2.OmciMsg(intf_id=proxy_address.channel_id,
833 onu_id=proxy_address.onu_id, pkt=str(msg))
Shad Ansari2825d012018-02-22 23:57:46 +0000834 self.stub.OmciMsgOut(omci)
835
836 def add_onu_device(self, intf_id, port_no, onu_id, serial_number):
Shad Ansari2825d012018-02-22 23:57:46 +0000837 self.log.info("Adding ONU", port_no=port_no, onu_id=onu_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000838 serial_number=serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000839
840 # NOTE - channel_id of onu is set to intf_id
Shad Ansari0efa6512018-04-28 06:42:54 +0000841 proxy_address = Device.ProxyAddress(device_id=self.device_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000842 channel_id=intf_id, onu_id=onu_id,
843 onu_session_id=onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000844
845 self.log.info("Adding ONU", proxy_address=proxy_address)
846
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400847 serial_number_str = self.stringify_serial_number(serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000848
Shad Ansarif9d2d102018-06-13 02:15:26 +0000849 self.adapter_agent.add_onu_device(
850 parent_device_id=self.device_id, parent_port_no=port_no,
851 vendor_id=serial_number.vendor_id, proxy_address=proxy_address,
852 root=True, serial_number=serial_number_str,
853 admin_state=AdminState.ENABLED)
Shad Ansari2825d012018-02-22 23:57:46 +0000854
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000855 def port_name(self, port_no, port_type, intf_id=None, serial_number=None):
Shad Ansari2825d012018-02-22 23:57:46 +0000856 if port_type is Port.ETHERNET_NNI:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400857 return "nni-" + str(port_no)
Shad Ansari2825d012018-02-22 23:57:46 +0000858 elif port_type is Port.PON_OLT:
Shad Ansari4a232ca2018-05-05 05:24:17 +0000859 return "pon" + str(intf_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000860 elif port_type is Port.ETHERNET_UNI:
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400861 if serial_number is not None:
862 return serial_number
863 else:
864 return "uni-{}".format(port_no)
Shad Ansari2825d012018-02-22 23:57:46 +0000865
Nicolas Palpacuer7d902812018-06-07 16:17:09 -0400866 def port_type(self, port_no):
867 ports = self.adapter_agent.get_ports(self.device_id)
868 for port in ports:
869 if port.port_no == port_no:
870 return port.type
871 return None
872
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400873 def add_logical_port(self, port_no, intf_id, oper_state):
Shad Ansari2825d012018-02-22 23:57:46 +0000874 self.log.info('adding-logical-port', port_no=port_no)
875
876 label = self.port_name(port_no, Port.ETHERNET_NNI)
877
878 cap = OFPPF_1GB_FD | OFPPF_FIBER
879 curr_speed = OFPPF_1GB_FD
880 max_speed = OFPPF_1GB_FD
881
Nicolas Palpacuercf735ac2018-06-06 11:12:53 -0400882 if oper_state == OperStatus.ACTIVE:
883 of_oper_state = OFPPS_LIVE
884 else:
885 of_oper_state = OFPPS_LINK_DOWN
886
Shad Ansarif9d2d102018-06-13 02:15:26 +0000887 ofp = ofp_port(
888 port_no=port_no,
889 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
890 name=label, config=0, state=of_oper_state, curr=cap,
891 advertised=cap, peer=cap, curr_speed=curr_speed,
892 max_speed=max_speed)
Shad Ansari2825d012018-02-22 23:57:46 +0000893
Nicolas Palpacuere7359fc2018-06-15 14:10:48 -0400894 ofp_stats = ofp_port_stats(port_no=port_no)
895
Shad Ansarif9d2d102018-06-13 02:15:26 +0000896 logical_port = LogicalPort(
897 id=label, ofp_port=ofp, device_id=self.device_id,
Nicolas Palpacuere7359fc2018-06-15 14:10:48 -0400898 device_port_no=port_no, root_port=True,
899 ofp_port_stats=ofp_stats)
Shad Ansari2825d012018-02-22 23:57:46 +0000900
Shad Ansarif9d2d102018-06-13 02:15:26 +0000901 self.adapter_agent.add_logical_port(self.logical_device_id,
902 logical_port)
Shad Ansari2825d012018-02-22 23:57:46 +0000903
904 def add_port(self, intf_id, port_type, oper_status):
Shad Ansari22920932018-05-17 00:33:34 +0000905 port_no = platform.intf_id_to_port_no(intf_id, port_type)
Shad Ansari2825d012018-02-22 23:57:46 +0000906
Shad Ansari4a232ca2018-05-05 05:24:17 +0000907 label = self.port_name(port_no, port_type, intf_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000908
Shad Ansari0efa6512018-04-28 06:42:54 +0000909 self.log.info('adding-port', port_no=port_no, label=label,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000910 port_type=port_type)
Shad Ansari0efa6512018-04-28 06:42:54 +0000911
912 port = Port(port_no=port_no, label=label, type=port_type,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000913 admin_state=AdminState.ENABLED, oper_status=oper_status)
Shad Ansari0efa6512018-04-28 06:42:54 +0000914
Shad Ansari2825d012018-02-22 23:57:46 +0000915 self.adapter_agent.add_port(self.device_id, port)
Shad Ansari0efa6512018-04-28 06:42:54 +0000916
Shad Ansari2825d012018-02-22 23:57:46 +0000917 return port_no, label
918
Shad Ansari2825d012018-02-22 23:57:46 +0000919 def new_onu_id(self, intf_id):
920 onu_id = None
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400921 onu_devices = self.adapter_agent.get_child_devices(self.device_id)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000922 for i in range(1, 512):
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400923 id_not_taken = True
924 for child_device in onu_devices:
925 if child_device.proxy_address.onu_id == i:
926 id_not_taken = False
927 break
928 if id_not_taken:
Shad Ansari2825d012018-02-22 23:57:46 +0000929 onu_id = i
930 break
931 return onu_id
932
933 def stringify_vendor_specific(self, vendor_specific):
934 return ''.join(str(i) for i in [
Shad Ansarif9d2d102018-06-13 02:15:26 +0000935 hex(ord(vendor_specific[0]) >> 4 & 0x0f)[2:],
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000936 hex(ord(vendor_specific[0]) & 0x0f)[2:],
Shad Ansarif9d2d102018-06-13 02:15:26 +0000937 hex(ord(vendor_specific[1]) >> 4 & 0x0f)[2:],
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000938 hex(ord(vendor_specific[1]) & 0x0f)[2:],
Shad Ansarif9d2d102018-06-13 02:15:26 +0000939 hex(ord(vendor_specific[2]) >> 4 & 0x0f)[2:],
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000940 hex(ord(vendor_specific[2]) & 0x0f)[2:],
Shad Ansarif9d2d102018-06-13 02:15:26 +0000941 hex(ord(vendor_specific[3]) >> 4 & 0x0f)[2:],
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000942 hex(ord(vendor_specific[3]) & 0x0f)[2:]])
Shad Ansari2825d012018-02-22 23:57:46 +0000943
Shad Ansari2825d012018-02-22 23:57:46 +0000944 def update_flow_table(self, flows):
945 device = self.adapter_agent.get_device(self.device_id)
Shad Ansaricd2e8ff2018-05-11 20:26:22 +0000946 self.log.debug('update flow table')
Shad Ansari2dda4f32018-05-17 07:16:07 +0000947 in_port = None
Shad Ansari2825d012018-02-22 23:57:46 +0000948
949 for flow in flows:
Shad Ansari2825d012018-02-22 23:57:46 +0000950 is_down_stream = None
Shad Ansari2dda4f32018-05-17 07:16:07 +0000951 in_port = fd.get_in_port(flow)
952 assert in_port is not None
Shad Ansarif9d2d102018-06-13 02:15:26 +0000953 # Right now there is only one NNI port. Get the NNI PORT and
954 # compare with IN_PUT port number. Need to find better way.
Shad Ansari2dda4f32018-05-17 07:16:07 +0000955 ports = self.adapter_agent.get_ports(device.id, Port.ETHERNET_NNI)
Shad Ansari2825d012018-02-22 23:57:46 +0000956
Shad Ansari2dda4f32018-05-17 07:16:07 +0000957 for port in ports:
958 if (port.port_no == in_port):
959 self.log.info('downstream-flow')
960 is_down_stream = True
961 break
962 if is_down_stream is None:
963 is_down_stream = False
964 self.log.info('upstream-flow')
Shad Ansari2825d012018-02-22 23:57:46 +0000965
Shad Ansari2dda4f32018-05-17 07:16:07 +0000966 for flow in flows:
967 try:
968 self.flow_mgr.add_flow(flow, is_down_stream)
969 except Exception as e:
Shad Ansarif9d2d102018-06-13 02:15:26 +0000970 self.log.exception('failed-to-install-flow', e=e,
971 flow=flow)
Shad Ansari89b09d52018-05-21 07:28:14 +0000972
973 # There has to be a better way to do this
974 def ip_hex(self, ip):
975 octets = ip.split(".")
976 hex_ip = []
977 for octet in octets:
978 octet_hex = hex(int(octet))
979 octet_hex = octet_hex.split('0x')[1]
980 octet_hex = octet_hex.rjust(2, '0')
981 hex_ip.append(octet_hex)
982 return ":".join(hex_ip)
Nicolas Palpacuer65de6a42018-05-22 17:28:29 -0400983
984 def stringify_serial_number(self, serial_number):
985 return ''.join([serial_number.vendor_id,
Shad Ansarif9d2d102018-06-13 02:15:26 +0000986 self.stringify_vendor_specific(
987 serial_number.vendor_specific)])
Jonathan Davis0f917a22018-05-30 14:39:45 -0400988
989 def disable(self):
Shad Ansarif9d2d102018-06-13 02:15:26 +0000990 self.log.info('sending-deactivate-olt-message',
991 device_id=self.device_id)
Jonathan Davis0f917a22018-05-30 14:39:45 -0400992
993 # Send grpc call
Shad Ansarif9d2d102018-06-13 02:15:26 +0000994 # self.stub.DeactivateOlt(openolt_pb2.Empty())
Jonathan Davis0f917a22018-05-30 14:39:45 -0400995
Shad Ansarif9d2d102018-06-13 02:15:26 +0000996 # Soft deactivate. Turning down hardware should remove flows,
997 # but we are not doing that presently
Jonathan Davis0f917a22018-05-30 14:39:45 -0400998
999 # Bring OLT down
Shad Ansarif9d2d102018-06-13 02:15:26 +00001000 self.olt_down(oper_state=OperStatus.UNKNOWN,
1001 admin_state=AdminState.DISABLED,
1002 connect_state=ConnectStatus.UNREACHABLE)
Jonathan Davis0f917a22018-05-30 14:39:45 -04001003
1004 def delete(self):
1005 self.log.info('delete-olt', device_id=self.device_id)
1006
1007 # Stop the grpc communication threads
1008 self.log.info('stopping-grpc-threads', device_id=self.device_id)
1009 self.indications_thread_active = False
1010 self.heartbeat_thread_active = False
1011
1012 # Close the grpc channel
1013 # self.log.info('unsubscribing-grpc-channel', device_id=self.device_id)
1014 # self.channel.unsubscribe()
1015
1016 self.log.info('successfully-deleted-olt', device_id=self.device_id)
1017
1018 def reenable(self):
1019 self.log.info('reenable-olt', device_id=self.device_id)
1020
1021 # Bring up OLT
1022 self.olt_up()
1023
1024 # Enable all child devices
1025 self.log.info('enabling-child-devices', device_id=self.device_id)
1026 self.log.info('enabling-child-devices', olt_device_id=self.device_id)
Shad Ansarif9d2d102018-06-13 02:15:26 +00001027 self.adapter_agent.update_child_devices_state(
1028 parent_device_id=self.device_id,
1029 admin_state=AdminState.ENABLED)
Jonathan Davis0f917a22018-05-30 14:39:45 -04001030
1031 # Set all ports to enabled
1032 self.log.info('enabling-all-ports', device_id=self.device_id)
Shad Ansaria0b37892018-06-12 21:34:30 +00001033 self.adapter_agent.enable_all_ports(self.device_id)