blob: 5eea6f7b3f5a34a4ab872847e229c698fab30a37 [file] [log] [blame]
Zsolt Haraszti656ecc62016-12-28 15:08:23 -08001#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08002# Copyright 2017 the original author or authors.
Zsolt Haraszti656ecc62016-12-28 15:08:23 -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#
16
17"""
18Fully simulated OLT/ONU adapter.
19"""
20
Scott Bakerb5be94d2018-10-09 16:13:32 -070021import arrow
Nikolay Titov176f1db2017-08-10 12:38:43 -040022import sys
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080023import structlog
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080024from twisted.internet.defer import DeferredQueue, inlineCallbacks
Khen Nursimulud068d812017-03-06 11:44:18 -050025from common.utils.asleep import asleep
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080026
Scott Bakerb5be94d2018-10-09 16:13:32 -070027from twisted.internet.task import LoopingCall
Shad Ansarid1aa9e72017-06-23 21:34:25 -070028from voltha.adapters.iadapter import OnuAdapter
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080029from voltha.core.logical_device_agent import mac_str_to_tuple
30from voltha.protos import third_party
Shad Ansari14bcd992017-06-13 14:27:20 -070031from voltha.protos.common_pb2 import OperStatus, ConnectStatus, AdminState
Scott Bakerb5be94d2018-10-09 16:13:32 -070032from voltha.protos.device_pb2 import Port, PmConfig, PmConfigs
33from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080034from voltha.protos.logical_device_pb2 import LogicalPort
Khen Nursimulud068d812017-03-06 11:44:18 -050035from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
Shad Ansari14bcd992017-06-13 14:27:20 -070036 OFPPF_1GB_FD
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080037from voltha.protos.openflow_13_pb2 import ofp_port
Scott Bakerb5be94d2018-10-09 16:13:32 -070038from voltha.protos.ponsim_pb2 import FlowTable, PonSimMetricsRequest, PonSimMetrics
Nikolay Titov0da216c2017-07-27 00:47:44 -040039from voltha.protos.ponsim_pb2 import InterfaceConfig
40from voltha.protos.bbf_fiber_base_pb2 import OntaniConfig, VOntaniConfig, \
41 VEnetConfig
Nikolay Titov176f1db2017-08-10 12:38:43 -040042from voltha.protos.bbf_fiber_traffic_descriptor_profile_body_pb2 import \
43 TrafficDescriptorProfileData
44from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
45from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
46from voltha.protos.bbf_fiber_multicast_gemport_body_pb2 import \
47 MulticastGemportsConfigData
48from voltha.protos.bbf_fiber_multicast_distribution_set_body_pb2 import \
49 MulticastDistributionSetData
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080050
51_ = third_party
52log = structlog.get_logger()
53
Nikolay Titov176f1db2017-08-10 12:38:43 -040054xpon_ponsim_onu_itfs = {
55 'create_interface': {
56 'log': 'create-interface'},
57 'update_interface': {
58 'log': 'update-interface'},
59 'remove_interface': {
60 'log': 'remove-interface'},
61 'create_tcont': {
62 'log': 'create-tconts-config-data'},
63 'update_tcont': {
64 'log': 'update-tconts-config-data'},
65 'remove_tcont': {
66 'log': 'remove-tconts-config-data'},
67 'create_gemport': {
68 'log': 'create-gemports-config-data'},
69 'update_gemport': {
70 'log': 'update-gemports-config-data'},
71 'remove_gemport': {
72 'log': 'remove-gemports-config-data'},
73 'create_multicast_gemport': {
74 'log': 'create-multicast-gemports-config-data'},
75 'update_multicast_gemport': {
76 'log': 'update-multicast-gemports-config-data'},
77 'remove_multicast_gemport': {
78 'log': 'remove-multicast-gemports-config-data'},
79 'create_multicast_distribution_set': {
80 'log': 'create-multicast-distribution-set-data'},
81 'update_multicast_distribution_set': {
82 'log': 'update-multicast-distribution-set-data'},
83 'remove_multicast_distribution_set': {
84 'log': 'remove-multicast-distribution-set-data'},
khenaidoof3593a82018-06-01 16:41:31 -040085}
86
Scott Bakerb5be94d2018-10-09 16:13:32 -070087class AdapterPmMetrics:
88 def __init__(self, device):
89 self.pm_names = {'tx_64_pkts', 'tx_65_127_pkts', 'tx_128_255_pkts',
90 'tx_256_511_pkts', 'tx_512_1023_pkts',
91 'tx_1024_1518_pkts', 'tx_1519_9k_pkts',
92 'rx_64_pkts', 'rx_65_127_pkts',
93 'rx_128_255_pkts', 'rx_256_511_pkts',
94 'rx_512_1023_pkts', 'rx_1024_1518_pkts',
95 'rx_1519_9k_pkts'}
96 self.device = device
97 self.id = device.id
98 self.name = 'ponsim_onu'
99 # self.id = "abc"
100 self.default_freq = 150
101 self.grouped = False
102 self.freq_override = False
103 self.pon_metrics_config = dict()
104 self.uni_metrics_config = dict()
105 self.lc = None
106 for m in self.pm_names:
107 self.pon_metrics_config[m] = PmConfig(name=m,
108 type=PmConfig.COUNTER,
109 enabled=True)
110 self.uni_metrics_config[m] = PmConfig(name=m,
111 type=PmConfig.COUNTER,
112 enabled=True)
113
114 def update(self, pm_config):
115 if self.default_freq != pm_config.default_freq:
116 # Update the callback to the new frequency.
117 self.default_freq = pm_config.default_freq
118 self.lc.stop()
119 self.lc.start(interval=self.default_freq / 10)
120 for m in pm_config.metrics:
121 self.pon_metrics_config[m.name].enabled = m.enabled
122 self.uni_metrics_config[m.name].enabled = m.enabled
123
124 def make_proto(self):
125 pm_config = PmConfigs(
126 id=self.id,
127 default_freq=self.default_freq,
128 grouped=False,
129 freq_override=False)
130 for m in sorted(self.pon_metrics_config):
131 pm = self.pon_metrics_config[m] # Either will do they're the same
132 pm_config.metrics.extend([PmConfig(name=pm.name,
133 type=pm.type,
134 enabled=pm.enabled)])
135 return pm_config
136
137 def extract_metrics(self, stats):
138 rtrn_port_metrics = dict()
139 rtrn_port_metrics['pon'] = self.extract_pon_metrics(stats)
140 rtrn_port_metrics['uni'] = self.extract_uni_metrics(stats)
141 return rtrn_port_metrics
142
143 def extract_pon_metrics(self, stats):
144 rtrn_pon_metrics = dict()
145 for m in stats.metrics:
146 if m.port_name == "pon":
147 for p in m.packets:
148 if self.pon_metrics_config[p.name].enabled:
149 rtrn_pon_metrics[p.name] = p.value
150 return rtrn_pon_metrics
151
152 def extract_uni_metrics(self, stats):
153 rtrn_pon_metrics = dict()
154 for m in stats.metrics:
155 if m.port_name == "uni":
156 for p in m.packets:
157 if self.pon_metrics_config[p.name].enabled:
158 rtrn_pon_metrics[p.name] = p.value
159 return rtrn_pon_metrics
160
161 def start_collector(self, callback):
162 log.info("starting-pm-collection", device_name=self.name,
163 device_id=self.device.id)
164 prefix = 'voltha.{}.{}'.format(self.name, self.device.id)
165 self.lc = LoopingCall(callback, self.device.id, prefix)
166 self.lc.start(interval=self.default_freq / 10)
167
168 def stop_collector(self):
169 log.info("stopping-pm-collection", device_name=self.name,
170 device_id=self.device.id)
171 self.lc.stop()
172
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800173
Shad Ansarid1aa9e72017-06-23 21:34:25 -0700174class PonSimOnuAdapter(OnuAdapter):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800175 def __init__(self, adapter_agent, config):
khenaidoof3593a82018-06-01 16:41:31 -0400176 # DeviceType of ONU should be same as VENDOR ID of ONU Serial Number as specified by standard
177 # requires for identifying correct adapter or ranged ONU
Shad Ansari14bcd992017-06-13 14:27:20 -0700178 super(PonSimOnuAdapter, self).__init__(adapter_agent=adapter_agent,
179 config=config,
khenaidoof3593a82018-06-01 16:41:31 -0400180 device_handler_class=PonSimOnuHandler,
Shad Ansari14bcd992017-06-13 14:27:20 -0700181 name='ponsim_onu',
182 vendor='Voltha project',
Nikolay Titov89004ec2017-06-19 18:22:42 -0400183 version='0.4',
Niren R Chidrawarefcebcd2017-07-19 20:03:39 -0400184 device_type='ponsim_onu',
khenaidoof3593a82018-06-01 16:41:31 -0400185 vendor_id='PSMO',
186 accepts_bulk_flow_update=True,
187 accepts_add_remove_flow_updates=False)
Khen Nursimulud068d812017-03-06 11:44:18 -0500188
Nikolay Titov176f1db2017-08-10 12:38:43 -0400189 def xpon_ponsim_onu_adapter_interface(self, method_name, device, data,
190 data2=None):
191 log.info('{}'.format(xpon_ponsim_onu_itfs[method_name]['log']),
192 device_id=device.id)
Nikolay Titovfae5c912017-08-01 15:09:59 -0400193 if device.id in self.devices_handlers:
194 handler = self.devices_handlers[device.id]
195 if handler is not None:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400196 _method = getattr(handler, method_name)
197 if isinstance(data, TcontsConfigData):
198 _method(data, data2)
199 else:
200 _method(data)
201
Scott Bakerb5be94d2018-10-09 16:13:32 -0700202 def update_pm_config(self, device, pm_config):
203 log.info("adapter-update-pm-config", device=device,
204 pm_config=pm_config)
205 handler = self.devices_handlers[device.id]
206 handler.update_pm_config(device, pm_config)
207
Nikolay Titov176f1db2017-08-10 12:38:43 -0400208 def create_interface(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400209 _method_name = sys._getframe().f_code.co_name
210 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titovfae5c912017-08-01 15:09:59 -0400211
Nikolay Titove44c3d22017-08-03 15:27:37 -0400212 def update_interface(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400213 _method_name = sys._getframe().f_code.co_name
214 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titove44c3d22017-08-03 15:27:37 -0400215
Nikolay Titovfae5c912017-08-01 15:09:59 -0400216 def remove_interface(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400217 _method_name = sys._getframe().f_code.co_name
218 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400219
220 def create_tcont(self, device, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -0400221 _method_name = sys._getframe().f_code.co_name
222 self.xpon_ponsim_onu_adapter_interface(_method_name, device,
223 tcont_data,
224 traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400225
226 def update_tcont(self, device, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -0400227 _method_name = sys._getframe().f_code.co_name
228 self.xpon_ponsim_onu_adapter_interface(_method_name, device,
229 tcont_data,
230 traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400231
232 def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -0400233 _method_name = sys._getframe().f_code.co_name
234 self.xpon_ponsim_onu_adapter_interface(_method_name, device,
235 tcont_data,
236 traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400237
238 def create_gemport(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400239 _method_name = sys._getframe().f_code.co_name
240 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400241
242 def update_gemport(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400243 _method_name = sys._getframe().f_code.co_name
244 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400245
246 def remove_gemport(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400247 _method_name = sys._getframe().f_code.co_name
248 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400249
250 def create_multicast_gemport(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400251 _method_name = sys._getframe().f_code.co_name
252 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400253
254 def update_multicast_gemport(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400255 _method_name = sys._getframe().f_code.co_name
256 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400257
258 def remove_multicast_gemport(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400259 _method_name = sys._getframe().f_code.co_name
260 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400261
262 def create_multicast_distribution_set(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400263 _method_name = sys._getframe().f_code.co_name
264 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400265
266 def update_multicast_distribution_set(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400267 _method_name = sys._getframe().f_code.co_name
268 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400269
270 def remove_multicast_distribution_set(self, device, data):
khenaidoof3593a82018-06-01 16:41:31 -0400271 _method_name = sys._getframe().f_code.co_name
272 self.xpon_ponsim_onu_adapter_interface(_method_name, device, data)
273
Nikolay Titov0da216c2017-07-27 00:47:44 -0400274
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800275class PonSimOnuHandler(object):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800276 def __init__(self, adapter, device_id):
277 self.adapter = adapter
278 self.adapter_agent = adapter.adapter_agent
279 self.device_id = device_id
280 self.log = structlog.get_logger(device_id=device_id)
281 self.incoming_messages = DeferredQueue()
282 self.proxy_address = None
Khen Nursimulud068d812017-03-06 11:44:18 -0500283 # reference of uni_port is required when re-enabling the device if
284 # it was disabled previously
285 self.uni_port = None
286 self.pon_port = None
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800287
288 def receive_message(self, msg):
Scott Bakerb5be94d2018-10-09 16:13:32 -0700289 if isinstance(msg, PonSimMetrics):
290 # Message is a reply to an ONU statistics request. Push it out to Kafka via adapter.submit_kpis().
291 if self.pm_metrics:
Zack Williams18357ed2018-11-14 10:41:08 -0700292 self.log.debug('Handling incoming ONU metrics')
Scott Bakerb5be94d2018-10-09 16:13:32 -0700293 prefix = 'voltha.{}.{}'.format("ponsim_onu", self.device_id)
294 port_metrics = self.pm_metrics.extract_metrics(msg)
295 try:
296 ts = arrow.utcnow().timestamp
297 kpi_event = KpiEvent(
298 type=KpiEventType.slice,
299 ts=ts,
300 prefixes={
301 # OLT NNI port
302 prefix + '.uni': MetricValuePairs(
303 metrics=port_metrics['uni']),
304 # OLT PON port
305 prefix + '.pon': MetricValuePairs(
306 metrics=port_metrics['pon'])
307 }
308 )
309
Zack Williams18357ed2018-11-14 10:41:08 -0700310 self.log.debug('Submitting KPI for incoming ONU metrics')
Scott Bakerb5be94d2018-10-09 16:13:32 -0700311
312 # Step 3: submit
313 self.adapter_agent.submit_kpis(kpi_event)
314 except Exception as e:
315 log.exception('failed-to-submit-kpis', e=e)
316 else:
317 # We received a statistics message, but we don't have pm_metrics set up. This shouldn't happen.
318 self.log.warning('received unexpected PonSimMetrics')
319 else:
320 # The message is probably a reply to a FlowTable update. self.update_flow_table() will pop it off this
321 # queue and return it to its caller.
322 self.incoming_messages.put(msg)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800323
324 def activate(self, device):
325 self.log.info('activating')
326
327 # first we verify that we got parent reference and proxy info
328 assert device.parent_id
329 assert device.proxy_address.device_id
330 assert device.proxy_address.channel_id
331
332 # register for proxied messages right away
333 self.proxy_address = device.proxy_address
334 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
335
336 # populate device info
Andy Bavierea82b462018-07-27 16:48:13 -0700337 device.root = False
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800338 device.vendor = 'ponsim'
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400339 device.model = 'n/a'
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800340 device.connect_status = ConnectStatus.REACHABLE
341 self.adapter_agent.update_device(device)
342
Scott Bakerb5be94d2018-10-09 16:13:32 -0700343 # Now set the initial PM configuration for this device
344 self.pm_metrics = AdapterPmMetrics(device)
345 pm_config = self.pm_metrics.make_proto()
346 log.info("initial-pm-config", pm_config=pm_config)
347 self.adapter_agent.update_device_pm_config(pm_config, init=True)
348
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800349 # register physical ports
Khen Nursimulud068d812017-03-06 11:44:18 -0500350 self.uni_port = Port(
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800351 port_no=2,
352 label='UNI facing Ethernet port',
353 type=Port.ETHERNET_UNI,
354 admin_state=AdminState.ENABLED,
355 oper_status=OperStatus.ACTIVE
356 )
Khen Nursimulud068d812017-03-06 11:44:18 -0500357 self.pon_port = Port(
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800358 port_no=1,
359 label='PON port',
360 type=Port.PON_ONU,
361 admin_state=AdminState.ENABLED,
362 oper_status=OperStatus.ACTIVE,
363 peers=[
364 Port.PeerPort(
365 device_id=device.parent_id,
366 port_no=device.parent_port_no
367 )
368 ]
Khen Nursimulud068d812017-03-06 11:44:18 -0500369 )
370 self.adapter_agent.add_port(device.id, self.uni_port)
371 self.adapter_agent.add_port(device.id, self.pon_port)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800372
373 # add uni port to logical device
374 parent_device = self.adapter_agent.get_device(device.parent_id)
375 logical_device_id = parent_device.parent_id
376 assert logical_device_id
377 port_no = device.proxy_address.channel_id
378 cap = OFPPF_1GB_FD | OFPPF_FIBER
379 self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
380 id='uni-{}'.format(port_no),
381 ofp_port=ofp_port(
382 port_no=port_no,
383 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
Andy Bavierea82b462018-07-27 16:48:13 -0700384 name=device.serial_number,
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800385 config=0,
386 state=OFPPS_LIVE,
387 curr=cap,
388 advertised=cap,
389 peer=cap,
390 curr_speed=OFPPF_1GB_FD,
391 max_speed=OFPPF_1GB_FD
392 ),
393 device_id=device.id,
Khen Nursimulud068d812017-03-06 11:44:18 -0500394 device_port_no=self.uni_port.port_no
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800395 ))
396
397 device = self.adapter_agent.get_device(device.id)
398 device.oper_status = OperStatus.ACTIVE
399 self.adapter_agent.update_device(device)
400
Scott Bakerb5be94d2018-10-09 16:13:32 -0700401 # Start collecting stats from the device after a brief pause
402 self.start_kpi_collection(device.id)
403
khenaidoo032d3302017-06-09 14:50:04 -0400404 def _get_uni_port(self):
405 ports = self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_UNI)
406 if ports:
407 # For now, we use on one uni port
408 return ports[0]
409
410 def _get_pon_port(self):
411 ports = self.adapter_agent.get_ports(self.device_id, Port.PON_ONU)
412 if ports:
413 # For now, we use on one uni port
414 return ports[0]
415
416 def reconcile(self, device):
417 self.log.info('reconciling-ONU-device-starts')
418
419 # first we verify that we got parent reference and proxy info
420 assert device.parent_id
421 assert device.proxy_address.device_id
422 assert device.proxy_address.channel_id
423
424 # register for proxied messages right away
425 self.proxy_address = device.proxy_address
426 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
427
428 # Set the connection status to REACHABLE
429 device.connect_status = ConnectStatus.REACHABLE
430 self.adapter_agent.update_device(device)
431
Scott Bakerb5be94d2018-10-09 16:13:32 -0700432 # Now set the initial PM configuration for this device
433 self.pm_metrics = AdapterPmMetrics(device)
434 pm_config = self.pm_metrics.make_proto()
435 log.info("initial-pm-config", pm_config=pm_config)
436 self.adapter_agent.update_device_pm_config(pm_config, init=True)
437
khenaidoo032d3302017-06-09 14:50:04 -0400438 # TODO: Verify that the uni, pon and logical ports exists
439
440 # Mark the device as REACHABLE and ACTIVE
441 device = self.adapter_agent.get_device(device.id)
442 device.connect_status = ConnectStatus.REACHABLE
443 device.oper_status = OperStatus.ACTIVE
444 self.adapter_agent.update_device(device)
445
Scott Bakerb5be94d2018-10-09 16:13:32 -0700446 # Start collecting stats from the device after a brief pause
447 self.start_kpi_collection(device.id)
448
khenaidoo032d3302017-06-09 14:50:04 -0400449 self.log.info('reconciling-ONU-device-ends')
450
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800451 @inlineCallbacks
452 def update_flow_table(self, flows):
453
454 # we need to proxy through the OLT to get to the ONU
455
456 # reset response queue
457 while self.incoming_messages.pending:
458 yield self.incoming_messages.get()
459
460 msg = FlowTable(
461 port=self.proxy_address.channel_id,
462 flows=flows
463 )
464 self.adapter_agent.send_proxied_message(self.proxy_address, msg)
465
466 yield self.incoming_messages.get()
Khen Nursimulud068d812017-03-06 11:44:18 -0500467
khenaidoof3593a82018-06-01 16:41:31 -0400468 def remove_from_flow_table(self, flows):
469 self.log.debug('remove-from-flow-table', flows=flows)
470 # TODO: Update PONSIM code to accept incremental flow changes.
471 # Once completed, the accepts_add_remove_flow_updates for this
472 # device type can be set to True
473
474 def add_to_flow_table(self, flows):
475 self.log.debug('add-to-flow-table', flows=flows)
476 # TODO: Update PONSIM code to accept incremental flow changes
477 # Once completed, the accepts_add_remove_flow_updates for this
478 # device type can be set to True
479
Scott Bakerb5be94d2018-10-09 16:13:32 -0700480 def update_pm_config(self, device, pm_config):
481 log.info("handler-update-pm-config", device=device,
482 pm_config=pm_config)
483 self.pm_metrics.update(pm_config)
484
Khen Nursimulud068d812017-03-06 11:44:18 -0500485 @inlineCallbacks
486 def reboot(self):
487 self.log.info('rebooting', device_id=self.device_id)
488
489 # Update the operational status to ACTIVATING and connect status to
490 # UNREACHABLE
491 device = self.adapter_agent.get_device(self.device_id)
492 previous_oper_status = device.oper_status
493 previous_conn_status = device.connect_status
494 device.oper_status = OperStatus.ACTIVATING
495 device.connect_status = ConnectStatus.UNREACHABLE
496 self.adapter_agent.update_device(device)
497
498 # Sleep 10 secs, simulating a reboot
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400499 # TODO: send alert and clear alert after the reboot
Khen Nursimulud068d812017-03-06 11:44:18 -0500500 yield asleep(10)
501
502 # Change the operational status back to its previous state. With a
503 # real OLT the operational state should be the state the device is
504 # after a reboot.
505 # Get the latest device reference
506 device = self.adapter_agent.get_device(self.device_id)
507 device.oper_status = previous_oper_status
508 device.connect_status = previous_conn_status
509 self.adapter_agent.update_device(device)
510 self.log.info('rebooted', device_id=self.device_id)
511
sathishg5ae86222017-06-28 15:16:29 +0530512 def self_test_device(self, device):
513 """
514 This is called to Self a device based on a NBI call.
515 :param device: A Voltha.Device object.
516 :return: Will return result of self test
517 """
518 log.info('self-test-device', device=device.id)
519 raise NotImplementedError()
520
Khen Nursimulud068d812017-03-06 11:44:18 -0500521 def disable(self):
522 self.log.info('disabling', device_id=self.device_id)
523
Scott Bakerb5be94d2018-10-09 16:13:32 -0700524 self.stop_kpi_collection()
525
Khen Nursimulud068d812017-03-06 11:44:18 -0500526 # Get the latest device reference
527 device = self.adapter_agent.get_device(self.device_id)
528
529 # Disable all ports on that device
530 self.adapter_agent.disable_all_ports(self.device_id)
531
532 # Update the device operational status to UNKNOWN
533 device.oper_status = OperStatus.UNKNOWN
534 device.connect_status = ConnectStatus.UNREACHABLE
535 self.adapter_agent.update_device(device)
536
537 # Remove the uni logical port from the OLT, if still present
538 parent_device = self.adapter_agent.get_device(device.parent_id)
539 assert parent_device
540 logical_device_id = parent_device.parent_id
541 assert logical_device_id
542 port_no = device.proxy_address.channel_id
543 port_id = 'uni-{}'.format(port_no)
544 try:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400545 port = self.adapter_agent.get_logical_port(logical_device_id,
546 port_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500547 self.adapter_agent.delete_logical_port(logical_device_id, port)
548 except KeyError:
549 self.log.info('logical-port-not-found', device_id=self.device_id,
550 portid=port_id)
551
552 # Remove pon port from parent
khenaidoo032d3302017-06-09 14:50:04 -0400553 self.pon_port = self._get_pon_port()
Khen Nursimulud068d812017-03-06 11:44:18 -0500554 self.adapter_agent.delete_port_reference_from_parent(self.device_id,
555 self.pon_port)
556
557 # Just updating the port status may be an option as well
558 # port.ofp_port.config = OFPPC_NO_RECV
559 # yield self.adapter_agent.update_logical_port(logical_device_id,
560 # port)
561 # Unregister for proxied message
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400562 self.adapter_agent.unregister_for_proxied_messages(
563 device.proxy_address)
Khen Nursimulud068d812017-03-06 11:44:18 -0500564
565 # TODO:
566 # 1) Remove all flows from the device
567 # 2) Remove the device from ponsim
568
569 self.log.info('disabled', device_id=device.id)
570
Khen Nursimulud068d812017-03-06 11:44:18 -0500571 def reenable(self):
572 self.log.info('re-enabling', device_id=self.device_id)
khenaidoo032d3302017-06-09 14:50:04 -0400573 try:
574 # Get the latest device reference
575 device = self.adapter_agent.get_device(self.device_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500576
khenaidoo032d3302017-06-09 14:50:04 -0400577 # First we verify that we got parent reference and proxy info
578 assert device.parent_id
579 assert device.proxy_address.device_id
580 assert device.proxy_address.channel_id
Khen Nursimulud068d812017-03-06 11:44:18 -0500581
khenaidoo032d3302017-06-09 14:50:04 -0400582 # Re-register for proxied messages right away
583 self.proxy_address = device.proxy_address
584 self.adapter_agent.register_for_proxied_messages(
585 device.proxy_address)
Khen Nursimulud068d812017-03-06 11:44:18 -0500586
khenaidoo032d3302017-06-09 14:50:04 -0400587 # Re-enable the ports on that device
588 self.adapter_agent.enable_all_ports(self.device_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500589
khenaidoo032d3302017-06-09 14:50:04 -0400590 # Refresh the port reference
591 self.uni_port = self._get_uni_port()
592 self.pon_port = self._get_pon_port()
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400593
khenaidoo032d3302017-06-09 14:50:04 -0400594 # Add the pon port reference to the parent
595 self.adapter_agent.add_port_reference_to_parent(device.id,
596 self.pon_port)
Khen Nursimulud068d812017-03-06 11:44:18 -0500597
khenaidoo032d3302017-06-09 14:50:04 -0400598 # Update the connect status to REACHABLE
599 device.connect_status = ConnectStatus.REACHABLE
600 self.adapter_agent.update_device(device)
Khen Nursimulud068d812017-03-06 11:44:18 -0500601
khenaidoo032d3302017-06-09 14:50:04 -0400602 # re-add uni port to logical device
603 parent_device = self.adapter_agent.get_device(device.parent_id)
604 logical_device_id = parent_device.parent_id
605 assert logical_device_id
606 port_no = device.proxy_address.channel_id
607 cap = OFPPF_1GB_FD | OFPPF_FIBER
608 self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
609 id='uni-{}'.format(port_no),
610 ofp_port=ofp_port(
611 port_no=port_no,
612 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
Andy Bavierea82b462018-07-27 16:48:13 -0700613 name=device.serial_number,
khenaidoo032d3302017-06-09 14:50:04 -0400614 config=0,
615 state=OFPPS_LIVE,
616 curr=cap,
617 advertised=cap,
618 peer=cap,
619 curr_speed=OFPPF_1GB_FD,
620 max_speed=OFPPF_1GB_FD
621 ),
622 device_id=device.id,
623 device_port_no=self.uni_port.port_no
624 ))
Khen Nursimulud068d812017-03-06 11:44:18 -0500625
khenaidoo032d3302017-06-09 14:50:04 -0400626 device = self.adapter_agent.get_device(device.id)
627 device.oper_status = OperStatus.ACTIVE
628 self.adapter_agent.update_device(device)
Khen Nursimulud068d812017-03-06 11:44:18 -0500629
Scott Bakerb5be94d2018-10-09 16:13:32 -0700630 self.start_kpi_collection(device.id)
631
khenaidoo032d3302017-06-09 14:50:04 -0400632 self.log.info('re-enabled', device_id=device.id)
633 except Exception, e:
634 self.log.exception('error-reenabling', e=e)
Khen Nursimulud068d812017-03-06 11:44:18 -0500635
Khen Nursimulud068d812017-03-06 11:44:18 -0500636 def delete(self):
637 self.log.info('deleting', device_id=self.device_id)
638
639 # A delete request may be received when an OLT is dsiabled
640
641 # TODO:
642 # 1) Remove all flows from the device
643 # 2) Remove the device from ponsim
644
645 self.log.info('deleted', device_id=self.device_id)
Nikolay Titov0da216c2017-07-27 00:47:44 -0400646
Scott Bakerb5be94d2018-10-09 16:13:32 -0700647 def start_kpi_collection(self, device_id):
648 def _collect(device_id, prefix):
649 # Proxy a message to ponsim_olt. The OLT will then query the ONU for statistics. The reply will
650 # arrive proxied back to us in self.receive_message().
651 msg = PonSimMetricsRequest(port=self.proxy_address.channel_id)
652 self.adapter_agent.send_proxied_message(self.proxy_address, msg)
653
654 self.pm_metrics.start_collector(_collect)
655
656 def stop_kpi_collection(self):
657 self.pm_metrics.stop_collector()
658
659
Nikolay Titov0da216c2017-07-27 00:47:44 -0400660 def get_interface_config(self, data):
661 interfaceConfig = InterfaceConfig()
662 if isinstance(data, OntaniConfig):
663 interfaceConfig.ont_ani_config.CopyFrom(data)
664 elif isinstance(data, VOntaniConfig):
665 interfaceConfig.vont_ani_config.CopyFrom(data)
666 elif isinstance(data, VEnetConfig):
667 interfaceConfig.venet_config.CopyFrom(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400668 elif isinstance(data, TrafficDescriptorProfileData):
669 interfaceConfig.traffic_descriptor_profile_config_data.CopyFrom(
670 data)
671 elif isinstance(data, TcontsConfigData):
672 interfaceConfig.tconts_config_data.CopyFrom(data)
673 elif isinstance(data, GemportsConfigData):
674 interfaceConfig.gemports_config_data.CopyFrom(data)
675 elif isinstance(data, MulticastGemportsConfigData):
676 interfaceConfig.multicast_gemports_config_data.CopyFrom(data)
677 elif isinstance(data, MulticastDistributionSetData):
678 interfaceConfig.multicast_distribution_set_data.CopyFrom(data)
Nikolay Titov0da216c2017-07-27 00:47:44 -0400679 else:
680 return None
681 return interfaceConfig
682
khenaidoof3593a82018-06-01 16:41:31 -0400683 def xpon_ponsim_onu_interface(self, method_name, data, data2=None):
Nikolay Titov0da216c2017-07-27 00:47:44 -0400684 interfaceConfig = self.get_interface_config(data)
685 if interfaceConfig is not None:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400686 self.log.info('forwarding-{}-request-to-onu-for-interface-type'
687 .format(xpon_ponsim_onu_itfs[method_name]['log']),
688 interface_type=type(data))
689 if data2 is not None:
690 self.log.info(interface_type=type(data2))
691
692 def create_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400693 _method_name = sys._getframe().f_code.co_name
694 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titovfae5c912017-08-01 15:09:59 -0400695
Nikolay Titove44c3d22017-08-03 15:27:37 -0400696 def update_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400697 _method_name = sys._getframe().f_code.co_name
698 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titove44c3d22017-08-03 15:27:37 -0400699
Nikolay Titovfae5c912017-08-01 15:09:59 -0400700 def remove_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400701 _method_name = sys._getframe().f_code.co_name
702 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400703
704 def create_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -0400705 _method_name = sys._getframe().f_code.co_name
706 self.xpon_ponsim_onu_interface(_method_name, tcont_data,
707 traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400708
709 def update_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -0400710 _method_name = sys._getframe().f_code.co_name
711 self.xpon_ponsim_onu_interface(_method_name, tcont_data,
712 traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400713
714 def remove_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -0400715 _method_name = sys._getframe().f_code.co_name
716 self.xpon_ponsim_onu_interface(_method_name, tcont_data,
717 traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400718
719 def create_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400720 _method_name = sys._getframe().f_code.co_name
721 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400722
723 def update_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400724 _method_name = sys._getframe().f_code.co_name
725 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400726
727 def remove_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400728 _method_name = sys._getframe().f_code.co_name
729 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400730
731 def create_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400732 _method_name = sys._getframe().f_code.co_name
733 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400734
735 def update_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400736 _method_name = sys._getframe().f_code.co_name
737 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400738
739 def remove_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400740 _method_name = sys._getframe().f_code.co_name
741 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400742
743 def create_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400744 _method_name = sys._getframe().f_code.co_name
745 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400746
747 def update_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400748 _method_name = sys._getframe().f_code.co_name
749 self.xpon_ponsim_onu_interface(_method_name, data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400750
751 def remove_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -0400752 _method_name = sys._getframe().f_code.co_name
753 self.xpon_ponsim_onu_interface(_method_name, data)