blob: 70dd42fa8ac8d36b8542be1c3b82dc48c1bf1542 [file] [log] [blame]
alshabib22302372016-12-20 13:46:14 -08001#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08002# Copyright 2017 the original author or authors.
alshabib22302372016-12-20 13:46:14 -08003#
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#
alshabib7a1e4b72017-03-03 15:26:58 -080016from struct import pack, unpack
17
alshabib22302372016-12-20 13:46:14 -080018from scapy.automaton import ATMT
alshabib22302372016-12-20 13:46:14 -080019import structlog
alshabib8b7e0ec2017-03-02 15:12:29 -080020from voltha.adapters.microsemi_olt.BaseOltAutomaton import BaseOltAutomaton
21from voltha.adapters.microsemi_olt.PAS5211 import PAS5211EventOnuActivation, PAS5211MsgGetActivationAuthMode, \
alshabib7a1e4b72017-03-03 15:26:58 -080022 PAS5211MsgGetActivationAuthModeResponse, PAS5211MsgSetOnuOmciPortId, \
23 PAS5211MsgSetOnuOmciPortIdResponse, PAS5211MsgSendFrame, PAS5211MsgSendFrameResponse, \
24 PAS5211MsgGetLogicalObjectStatus, PAS5211MsgGetLogicalObjectStatusResponse, PAS5211MsgSetOnuAllocId, \
25 PAS5211MsgGetDbaMode, PAS5211MsgGetDbaModeResponse, PAS5211MsgSendDbaAlgorithmMsg, \
26 PAS5211MsgSendDbaAlgorithmMsgResponse, PAS5211EventDbaAlgorithm, PAS5211MsgSetPortIdConfig, \
27 PAS5211MsgSetPortIdConfigResponse, PAS5211MsgGetOnuIdByPortId, PAS5211MsgGetOnuIdByPortIdResponse, \
28 PAS5211SetVlanUplinkConfiguration, PAS5211SetVlanUplinkConfigurationResponse, PAS5211MsgSetOnuAllocIdResponse
29from voltha.adapters.microsemi_olt.PAS5211_constants import PON_ACTIVATION_AUTH_AUTO, PON_ENABLE, PON_PORT_PON, \
30 PON_LOGICAL_OBJECT_TYPE_ALLOC_ID, PON_LOGICAL_OBJECT_TYPE_ONU_ID_BY_ALLOC_ID, PON_TRUE, \
31 PMC_OFAL_MAX_BI_DIRECTIONAL_FLOW_PER_ONU, PMC_OFAL_START_FLOW_ID_BASE, PON_DBA_MODE_RUNNING, \
32 PYTHAGORAS_UPDATE_AID_SLA, SLA_be_bw_gros, SLA_gr_bw_gros, SLA_gr_bw_fine, SLA_be_bw_fine, PYTHAGORAS_DBA_DATA_COS, \
33 PYTHAGORAS_DBA_STATUS_REPORT_NSR, PYTHAGORAS_SET_SLA_RESP_SIZE, PON_PORT_TYPE_GEM, PON_PORT_DESTINATION_CNI0, \
34 PON_FALSE, PON_DISABLE
alshabib22302372016-12-20 13:46:14 -080035from voltha.extensions.omci.omci_entities import CircuitPack
36from voltha.extensions.omci.omci_frame import OmciFrame
37from voltha.extensions.omci.omci_messages import OmciGet, OmciGetResponse
alshabib22302372016-12-20 13:46:14 -080038
39log = structlog.get_logger()
40_verbose = False
41
alshabib7a1e4b72017-03-03 15:26:58 -080042ALLOC_ID = 1000
43
44def alloc_id(onu_id):
45 for i in range(0, PMC_OFAL_MAX_BI_DIRECTIONAL_FLOW_PER_ONU):
46 alloc_id = PMC_OFAL_START_FLOW_ID_BASE + \
47 (onu_id * PMC_OFAL_MAX_BI_DIRECTIONAL_FLOW_PER_ONU) + i
48 yield alloc_id
49
alshabib22302372016-12-20 13:46:14 -080050def hexstring(string):
51 return ":".join("{:02x}".format(ord(c)) for c in string)
52
53class ActivationManager(BaseOltAutomaton):
54
55 onu_id = None
56 serial_number = None
57 onu_session_id = None
58 port_id = None
59 channel_id = None
alshabib7a1e4b72017-03-03 15:26:58 -080060 alloc_id = None
61 vendor = None
alshabib22302372016-12-20 13:46:14 -080062
63 def parse_args(self, debug=0, store=0, **kwargs):
64 self.onu_id = kwargs.pop('onu_id')
65 self.serial_number = kwargs.pop('serial_number')
66 self.onu_session_id = kwargs.pop('onu_session_id')
67 self.port_id = self.onu_id
68 self.channel_id = kwargs.pop('channel_id')
alshabib7a1e4b72017-03-03 15:26:58 -080069 self.alloc_id = alloc_id(self.onu_id)
alshabib22302372016-12-20 13:46:14 -080070
71 if self.onu_id is None or self.serial_number is None or \
72 self.onu_session_id is None or self.channel_id is None:
73 raise ValueError('ONU is not well defined')
74
75 BaseOltAutomaton.parse_args(self, debug=debug, store=store, **kwargs)
76
77 """
78 States
79 """
80
81 @ATMT.state(initial=1)
82 def got_activation_event(self):
83 pass
84
85 @ATMT.state()
86 def wait_get_auth_mode(self):
87 pass
88
89 @ATMT.state()
90 def got_auth_mode(self):
91 pass
92
93 @ATMT.state()
94 def wait_omci_port_id(self):
95 pass
96
97 @ATMT.state()
98 def got_omci_port_id(self):
99 pass
100
101 @ATMT.state()
102 def wait_send_frame(self):
103 pass
104
105 @ATMT.state()
106 def wait_omci_get(self):
107 pass
108
alshabib7a1e4b72017-03-03 15:26:58 -0800109 @ATMT.state()
110 def wait_logical_object_status(self):
111 pass
112
113 @ATMT.state()
114 def wait_set_alloc_id(self):
115 pass
116
117 @ATMT.state()
118 def wait_dba_mode(self):
119 pass
120
121 @ATMT.state()
122 def wait_send_dba_alg_msg(self):
123 pass
124
125 @ATMT.state()
126 def wait_dba_alg_event(self):
127 pass
128
129 @ATMT.state()
130 def wait_set_port_id_config(self):
131 pass
132
133 @ATMT.state()
134 def wait_get_onu_id_by_port_id(self):
135 pass
136
137 @ATMT.state()
138 def wait_set_vlan_uplink_config(self):
139 pass
140
alshabib22302372016-12-20 13:46:14 -0800141 @ATMT.state(final=1)
142 def end(self):
143 pass
144
145 @ATMT.state(error=1)
alshabib7a1e4b72017-03-03 15:26:58 -0800146 def error(self, msg):
147 log.error(msg)
alshabib22302372016-12-20 13:46:14 -0800148
149 """
150 Utility Methods
151 """
152
alshabib22302372016-12-20 13:46:14 -0800153 def px(self, pkt):
154 return self.p(pkt, channel_id=self.channel_id,
155 onu_id=self.onu_id, onu_session_id=self.onu_session_id)
156
alshabib7a1e4b72017-03-03 15:26:58 -0800157 def detect_onu(self):
158 log.info("Activated {} ONT".format(self.vendor))
alshabib7a1e4b72017-03-03 15:26:58 -0800159 try:
160 self.device.onu_detected(
161 parent_port_no=self.channel_id,
162 child_device_type='%s_onu' % self.vendor.lower(),
163 onu_id=self.onu_id,
alshabib38ba2032017-03-14 11:19:58 +0100164 serial_number=hexstring(self.serial_number),
165 onu_session_id=self.onu_session_id
alshabib7a1e4b72017-03-03 15:26:58 -0800166 )
167 except Exception as e:
168 print e
169
alshabib22302372016-12-20 13:46:14 -0800170 """
171 Transitions
172 """
173
174 # Transition from got_activation_event
175 @ATMT.condition(got_activation_event)
176 def send_get_activation_auth_mode(self):
177 auth_mode = PAS5211MsgGetActivationAuthMode()
178 self.send(self.p(auth_mode))
179 raise self.wait_get_auth_mode()
180
181 # Transitions from wait_get_auth_mode
182 @ATMT.timeout(wait_get_auth_mode, 3)
183 def timeout_get_auth_mode(self):
alshabib7a1e4b72017-03-03 15:26:58 -0800184 raise self.error('Could not get auth mode for OLT {}; dropping activation event for {}'
alshabib22302372016-12-20 13:46:14 -0800185 .format(self.target, hexstring(self.serial_number)))
186
187 @ATMT.receive_condition(wait_get_auth_mode)
188 def wait_for_get_auth_mode(self, pkt):
189 if PAS5211MsgGetActivationAuthModeResponse in pkt:
190 if pkt.mode == PON_ACTIVATION_AUTH_AUTO:
191 raise self.got_auth_mode()
192 else:
193 # TODO There may be something that can be done here.
194 # See line 2497 of PAS_onu_mode_change_thread.c
195 log.error('Got unknown auth mode {}; dropping activation event'.format(pkt.mode))
196 raise self.end()
197
198 # Transitions from got auth_mode
199 @ATMT.condition(got_auth_mode)
200 def send_omci_port_id(self):
201 omci_port_id = PAS5211MsgSetOnuOmciPortId(port_id=self.port_id, activate=PON_ENABLE)
202 self.send(self.px(omci_port_id))
203 raise self.wait_omci_port_id()
204
205 # Transitions from wait_omci_port_id
206 @ATMT.timeout(wait_omci_port_id, 3)
207 def timeout_omci_port_id(self):
alshabib7a1e4b72017-03-03 15:26:58 -0800208 raise self.error('Could not set omci port id for OLT {}; dropping activation event for {}'
alshabib22302372016-12-20 13:46:14 -0800209 .format(self.target, hexstring(self.serial_number)))
210
211 @ATMT.receive_condition(wait_omci_port_id)
212 def wait_for_omci_port_id(self, pkt):
213 if pkt.opcode == PAS5211MsgSetOnuOmciPortIdResponse.opcode and \
214 pkt.onu_id == self.onu_id and pkt.onu_session_id == self.onu_session_id and \
215 pkt.channel_id == self.channel_id:
216 raise self.got_omci_port_id()
217
218 # Transitions from got_omci_port_id
219 @ATMT.condition(got_omci_port_id)
220 def send_omci_identity_frame(self):
221 # attr_mask |= OMCI_ATTR_BIT(OMCI_CIRCUIT_PACK_ATTR_VENDOR_ID);
222 #message.attributes_mask = 2048
223
224 # Entity_id
225 # equip_ind = OMCI_CIRCUIT_PACK_INTEGRATED_EQUIPMENT;
226 # slot_id = 257;
227 # entity_instance = ((equip_ind<<8) | slot_id
228 message = OmciGet(entity_class=CircuitPack.class_id, entity_id = 257,
229 attributes_mask=2048)
230 #TODO fix transaction id
231 frame = OmciFrame(transaction_id=0, message_type=OmciGet.message_id,
232 omci_message=message)
233 omci_frame = PAS5211MsgSendFrame(port_type=PON_PORT_PON, port_id=self.port_id,
234 management_frame=PON_ENABLE, frame=frame)
235
alshabib7a1e4b72017-03-03 15:26:58 -0800236
alshabib22302372016-12-20 13:46:14 -0800237 self.send(self.px(omci_frame))
238
239 raise self.wait_send_frame()
240
241 # Transitions from wait_send_frame
242 @ATMT.timeout(wait_send_frame, 3)
243 def timeout_send_frame(self):
alshabib7a1e4b72017-03-03 15:26:58 -0800244 raise self.error('Could not send omci to OLT {}; dropping activation event for {}'
alshabib22302372016-12-20 13:46:14 -0800245 .format(self.target, hexstring(self.serial_number)))
246
247 @ATMT.receive_condition(wait_send_frame)
248 def wait_for_send_frame(self, pkt):
alshabib8b7e0ec2017-03-02 15:12:29 -0800249 if PAS5211MsgSendFrameResponse in pkt:
alshabib22302372016-12-20 13:46:14 -0800250 raise self.wait_omci_get()
251
252 # Transitions from wait_omci_get
253 @ATMT.timeout(wait_omci_get, 3)
254 def timeout_send_frame(self):
alshabib7a1e4b72017-03-03 15:26:58 -0800255 raise self.error('Did not receive omci get event from OLT {}; dropping activation event for {}'
alshabib22302372016-12-20 13:46:14 -0800256 .format(self.target, hexstring(self.serial_number)))
257
258 @ATMT.receive_condition(wait_omci_get)
259 def wait_for_omci_get(self, pkt):
260 if OmciGetResponse in pkt:
alshabib7a1e4b72017-03-03 15:26:58 -0800261 self.allocId = self.alloc_id.next()
262 self.vendor = pkt['OmciGetResponse'].data['vendor_id']
263 l_obj_status = PAS5211MsgGetLogicalObjectStatus(
264 type=PON_LOGICAL_OBJECT_TYPE_ALLOC_ID,
265 value=self.allocId)
266 self.send(self.px(l_obj_status))
267 raise self.wait_logical_object_status()
alshabib8b7e0ec2017-03-02 15:12:29 -0800268
alshabib7a1e4b72017-03-03 15:26:58 -0800269 # Transitions from wait_logical_object_status
270 @ATMT.timeout(wait_logical_object_status, 3)
271 def timeout_logical_object_status(self):
272 raise self.error('Did not receive info about alloc id status for {}; dropping activation event for {}'
273 .format(self.target, hexstring(self.serial_number)))
274
275 @ATMT.receive_condition(wait_logical_object_status)
276 def wait_for_logical_object_status(self, pkt):
277 if PAS5211MsgGetLogicalObjectStatusResponse in pkt:
278 if pkt.type == PON_LOGICAL_OBJECT_TYPE_ALLOC_ID:
279 if pkt.return_value == 0:
280 # alloc-id not set
281 set_alloc_id = PAS5211MsgSetOnuAllocId(
282 alloc_id=self.allocId,
283 allocate=PON_ENABLE
284 )
285 self.onu_id = -1
286 self.port_id = self.allocId
287 self.send(self.px(set_alloc_id))
288 raise self.wait_set_alloc_id()
289 else:
290 l_obj_status = PAS5211MsgGetLogicalObjectStatus(
291 type=PON_LOGICAL_OBJECT_TYPE_ONU_ID_BY_ALLOC_ID,
292 value=self.allocId)
293 self.send(self.px(l_obj_status))
294 raise self.wait_logical_object_status()
295 elif pkt.type == PON_LOGICAL_OBJECT_TYPE_ONU_ID_BY_ALLOC_ID:
296 # That's your onu id.
297 self.onu_id = pkt.return_value
298 # FIXME Need to iterate to get the port id as
299 # in PMC_OFAL_flow_db.c line 656
300 # UPDATE PORT_ID
301 set_alloc_id = PAS5211MsgSetOnuAllocId(
302 alloc_id=self.allocId,
303 allocate=PON_ENABLE
304 )
305 self.send(self.px(set_alloc_id))
306 raise self.wait_for_set_alloc_id() #FIXME are we done? probably not but check
307
308 # Transitions from wait_set_alloc_id
309 @ATMT.timeout(wait_set_alloc_id, 3)
310 def timeout_set_alloc_id(self):
311 raise self.error('Was not able to set alloc id for {}; dropping activation event for {}'
312 .format(self.target, hexstring(self.serial_number)))
313
314 @ATMT.receive_condition(wait_set_alloc_id)
315 def wait_for_set_alloc_id(self, pkt):
316 if PAS5211MsgSetOnuAllocIdResponse in pkt:
317 self.send(self.px(PAS5211MsgGetDbaMode()))
318 raise self.wait_dba_mode()
319
320 # Transitions from wait for dba mode (See Pythagoras_api.c line 344 & PMC_OFAL.c 2062)
321 @ATMT.timeout(wait_dba_mode, 3)
322 def timeout_wait_dba_mode(self):
323 raise self.error('Did not get DBA mode for {}; dropping activation event for {}'
324 .format(self.target, hexstring(self.serial_number)))
325
326
327 @ATMT.receive_condition(wait_dba_mode)
328 def wait_for_dba_mode(self, pkt):
329 if PAS5211MsgGetDbaModeResponse in pkt:
330 if pkt.dba_mode != PON_DBA_MODE_RUNNING:
331 raise self.error('DBA is not running; dropping activation event for {}'
332 .format(hexstring(self.serial_number)))
333
334 data = pack('<LLHHBBBB', PYTHAGORAS_UPDATE_AID_SLA,
335 self.allocId, SLA_gr_bw_gros, SLA_be_bw_gros,
336 SLA_gr_bw_fine, SLA_be_bw_fine, PYTHAGORAS_DBA_DATA_COS,
337 PYTHAGORAS_DBA_STATUS_REPORT_NSR)
338
339 send_dba_alg = PAS5211MsgSendDbaAlgorithmMsg(data=data)
340 self.send(self.px(send_dba_alg))
341 raise self.wait_send_dba_alg_msg()
342
343 # Transitions from wait_send_dba_alg_msg
344 @ATMT.timeout(wait_send_dba_alg_msg, 3)
345 def timeout_wait_for_send_dba_alg_msg(self):
346 raise self.error('Unable to set dba alg params for {}; dropping activation event for {}'
347 .format(self.target, hexstring(self.serial_number)))
348
349 @ATMT.receive_condition(wait_send_dba_alg_msg)
350 def wait_for_send_dba_alg_msg(self, pkt):
351 if PAS5211MsgSendDbaAlgorithmMsgResponse in pkt:
352 raise self.wait_dba_alg_event()
353
354 # Transitions from wait_dba_alg_event
355 @ATMT.timeout(wait_dba_alg_event, 3)
356 def timeout_wait_for_send_dba_alg_event(self):
357 raise self.error('DBA params ont set for {}; dropping activation event for {}'
358 .format(self.target, hexstring(self.serial_number)))
359
360 @ATMT.receive_condition(wait_dba_alg_event)
361 def wait_for_send_dba_alg_event(self, pkt):
362 if PAS5211EventDbaAlgorithm in pkt:
363 if pkt.size < PYTHAGORAS_SET_SLA_RESP_SIZE:
364 raise self.error('DBA Event message too small for {}, dropping activation event for {}'
365 .format(self.target, hexstring(self.serial_number)))
366
367 (_, aid, _) = unpack('<LLH',pkt.data)
368 if aid == self.allocId:
369 # All is well moving on.
370 # There is some more shit at PYTHAGORAS.c line 395 but fuck it.
371 set_port_id_config = PAS5211MsgSetPortIdConfig(
372 port_id=self.port_id,
373 activate=PON_ENABLE,
374 alloc_id=self.allocId,
375 type=PON_PORT_TYPE_GEM,
376 destination=PON_PORT_DESTINATION_CNI0
377 )
378 self.send(self.px(set_port_id_config))
379 raise self.wait_set_port_id_config()
380
381 # Transitions from wait_set_port_id_config
382 @ATMT.timeout(wait_set_port_id_config, 3)
383 def timeout_wait_set_port_id_config(self):
384 raise self.error('Could not set port id config for {}; dropping activation event for {}'
385 .format(self.target, hexstring(self.serial_number)))
386
387 @ATMT.receive_condition(wait_set_port_id_config)
388 def wait_for_set_port_id_config(self, pkt):
389 if PAS5211MsgSetPortIdConfigResponse in pkt:
390 get_onu_id = PAS5211MsgGetOnuIdByPortId(
391 port_id=self.port_id
alshabib8b7e0ec2017-03-02 15:12:29 -0800392 )
alshabib7a1e4b72017-03-03 15:26:58 -0800393 self.send(self.px(get_onu_id))
394 raise self.wait_get_onu_id_by_port_id()
alshabib8b7e0ec2017-03-02 15:12:29 -0800395
alshabib7a1e4b72017-03-03 15:26:58 -0800396 # Transistions from wait_get_onu_id_by_port_id
397 @ATMT.timeout(wait_get_onu_id_by_port_id, 3)
398 def timeout_wait_get_onu_id_by_port_id(self):
399 raise self.error('Could not get onu id for {}; dropping activation event for {}'
400 .format(self.target, hexstring(self.serial_number)))
401
402 @ATMT.receive_condition(wait_get_onu_id_by_port_id)
403 def wait_for_get_onu_id_by_port_id(self, pkt):
404 if PAS5211MsgGetOnuIdByPortIdResponse in pkt:
405 self.onu_id = pkt['PAS5211MsgGetOnuIdByPortIdResponse'].onu_id
406 # There may be more things to do here. but traces indicate that no.
407 # see PAS.c line 977 and onwards.
408 set_vlan_uplink_config = PAS5211SetVlanUplinkConfiguration(
409 port_id=self.port_id,
410 pvid_config_enabled=PON_FALSE,
411 min_cos=0,
412 max_cos=7,
413 de_bit=PON_DISABLE
414 )
415 self.send(self.px(set_vlan_uplink_config))
416 raise self.wait_set_vlan_uplink_config()
417
418 # Transitions from wait_set_vlan_uplink_config
419 @ATMT.timeout(wait_set_vlan_uplink_config, 3)
420 def timeout_wait_set_vlan_uplink_config(self):
421 raise self.error('Could not set vlan uplink config for {}; dropping activation event for {}'
422 .format(self.target, hexstring(self.serial_number)))
423
424 @ATMT.receive_condition(wait_set_vlan_uplink_config)
425 def wait_for_set_vlan_uplink_config(self, pkt):
426 if PAS5211SetVlanUplinkConfigurationResponse in pkt:
427 # YAY we made it.
alshabib38ba2032017-03-14 11:19:58 +0100428 # TODO update OLT with CNI port
alshabib7a1e4b72017-03-03 15:26:58 -0800429 self.detect_onu()
alshabib22302372016-12-20 13:46:14 -0800430 raise self.end()
431
432
433class ActivationWatcher(BaseOltAutomaton):
434
435 """
436 States
437 """
438
439 @ATMT.state(initial=1)
440 def wait_onu_activation_event(self):
441 pass
442
443 """
444 Transitions
445 """
446
447 # Transitions from wait_onu_activation_event
448 @ATMT.receive_condition(wait_onu_activation_event)
449 def wait_for_onu_activation_event(self, pkt):
450 if PAS5211EventOnuActivation in pkt:
451 log.info('{} activated'.format(hexstring(pkt.serial_number)))
452 onu_activation = ActivationManager(iface=self.iface, target=self.target, comm=self.comm,
453 onu_id=pkt.onu_id, serial_number=pkt.serial_number,
454 onu_session_id=pkt.onu_session_id,
455 channel_id=pkt.channel_id, device=self.device)
456 onu_activation.runbg()
457 raise self.wait_onu_activation_event()