blob: 4bbfac51e59138db251930ac2a848e7d1da44117 [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"""
Nikolay Titov176f1db2017-08-10 12:38:43 -040020import sys
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080021from uuid import uuid4
22
Sergio Slobodrian98eff412017-03-15 14:46:30 -040023import arrow
Jeff55a2f132018-08-05 21:10:41 -070024import voltha.core.flow_decomposer as fd
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080025import grpc
Stephane Barbarie4475a252017-03-31 13:49:20 -040026import json
Andy Bavier97566512018-11-14 16:17:41 -070027import copy
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080028import structlog
Andy Bavier904efcf2019-04-01 16:50:34 -070029from scapy.layers.l2 import Ether, Dot1Q, Dot1AD
Gamze Abaka53cc0a22019-01-31 12:06:11 +000030from scapy.layers.inet import IP, Raw
Stephane Barbarie35595062018-02-08 08:34:39 -050031from twisted.internet import reactor
Khen Nursimulud068d812017-03-06 11:44:18 -050032from twisted.internet.defer import inlineCallbacks
Stephane Barbarie35595062018-02-08 08:34:39 -050033from grpc._channel import _Rendezvous
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080034
35from common.frameio.frameio import BpfProgramFilter, hexify
Khen Nursimulud068d812017-03-06 11:44:18 -050036from common.utils.asleep import asleep
Sergio Slobodrian98eff412017-03-15 14:46:30 -040037from twisted.internet.task import LoopingCall
Shad Ansarid1aa9e72017-06-23 21:34:25 -070038from voltha.adapters.iadapter import OltAdapter
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080039from voltha.core.logical_device_agent import mac_str_to_tuple
40from voltha.protos import third_party
Jeff55a2f132018-08-05 21:10:41 -070041from voltha.protos import openflow_13_pb2 as ofp
Scott Bakerd865fa22018-11-07 11:45:28 -080042from voltha.protos import ponsim_pb2, ponsim_pb2_grpc
Shad Ansari14bcd992017-06-13 14:27:20 -070043from voltha.protos.common_pb2 import OperStatus, ConnectStatus, AdminState
Scott Baker50873cc2018-09-21 18:14:09 -070044from voltha.protos.common_pb2 import OperationResp
Shad Ansari14bcd992017-06-13 14:27:20 -070045from voltha.protos.device_pb2 import Port, Device, PmConfig, PmConfigs
Sergio Slobodrian98eff412017-03-15 14:46:30 -040046from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080047from google.protobuf.empty_pb2 import Empty
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080048from voltha.protos.logical_device_pb2 import LogicalPort, LogicalDevice
Stephane Barbarie5253c652017-03-22 16:29:46 -040049from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
50 OFPPF_1GB_FD, \
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080051 OFPC_GROUP_STATS, OFPC_PORT_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS, \
52 ofp_switch_features, ofp_desc
53from voltha.protos.openflow_13_pb2 import ofp_port
Scott Bakerb5be94d2018-10-09 16:13:32 -070054from voltha.protos.ponsim_pb2 import FlowTable, PonSimFrame, PonSimMetricsRequest
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080055from voltha.registry import registry
56
Nikolay Titov89004ec2017-06-19 18:22:42 -040057from voltha.protos.bbf_fiber_base_pb2 import \
khenaidoof3593a82018-06-01 16:41:31 -040058 ChannelgroupConfig, ChannelpartitionConfig, ChannelpairConfig, \
Nikolay Titov176f1db2017-08-10 12:38:43 -040059 ChannelterminationConfig, OntaniConfig, VOntaniConfig, VEnetConfig
60from voltha.protos.bbf_fiber_traffic_descriptor_profile_body_pb2 import \
61 TrafficDescriptorProfileData
62from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
63from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
64from voltha.protos.bbf_fiber_multicast_gemport_body_pb2 import \
65 MulticastGemportsConfigData
Stephane Barbarie35595062018-02-08 08:34:39 -050066
Nikolay Titov176f1db2017-08-10 12:38:43 -040067from voltha.protos.bbf_fiber_multicast_distribution_set_body_pb2 import \
68 MulticastDistributionSetData
Nikolay Titov89004ec2017-06-19 18:22:42 -040069
Nikolay Titov176f1db2017-08-10 12:38:43 -040070from voltha.protos.ponsim_pb2 import InterfaceConfig, TcontInterfaceConfig
Nikolay Titov89004ec2017-06-19 18:22:42 -040071
Scott Baker50873cc2018-09-21 18:14:09 -070072from voltha.extensions.alarms.adapter_alarms import AdapterAlarms as VolthaAdapterAlarms
73from voltha.extensions.alarms.simulator.simulate_alarms import AdapterAlarmSimulator
74
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080075_ = third_party
76log = structlog.get_logger()
77
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080078PACKET_IN_VLAN = 4000
79is_inband_frame = BpfProgramFilter('(ether[14:2] & 0xfff) = 0x{:03x}'.format(
80 PACKET_IN_VLAN))
81
Andy Bavier97566512018-11-14 16:17:41 -070082EAP_ETH_TYPE = 0x888e
83
84# Classifier
85ETH_TYPE = 'eth_type'
86TPID = 'tpid'
87IP_PROTO = 'ip_proto'
88IN_PORT = 'in_port'
89VLAN_VID = 'vlan_vid'
90VLAN_PCP = 'vlan_pcp'
91UDP_DST = 'udp_dst'
92UDP_SRC = 'udp_src'
93IPV4_DST = 'ipv4_dst'
94IPV4_SRC = 'ipv4_src'
95METADATA = 'metadata'
96OUTPUT = 'output'
Stephane Barbarie5253c652017-03-22 16:29:46 -040097
Sergio Slobodrian98eff412017-03-15 14:46:30 -040098class AdapterPmMetrics:
Stephane Barbarie5253c652017-03-22 16:29:46 -040099 def __init__(self, device):
Sergio Slobodrianec6e3912017-04-02 11:46:55 -0400100 self.pm_names = {'tx_64_pkts', 'tx_65_127_pkts', 'tx_128_255_pkts',
101 'tx_256_511_pkts', 'tx_512_1023_pkts',
102 'tx_1024_1518_pkts', 'tx_1519_9k_pkts',
103 'rx_64_pkts', 'rx_65_127_pkts',
104 'rx_128_255_pkts', 'rx_256_511_pkts',
105 'rx_512_1023_pkts', 'rx_1024_1518_pkts',
106 'rx_1519_9k_pkts'}
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400107 self.device = device
108 self.id = device.id
109 self.name = 'ponsim_olt'
Stephane Barbarie5253c652017-03-22 16:29:46 -0400110 # self.id = "abc"
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400111 self.default_freq = 150
112 self.grouped = False
113 self.freq_override = False
114 self.pon_metrics_config = dict()
115 self.nni_metrics_config = dict()
116 self.lc = None
117 for m in self.pm_names:
118 self.pon_metrics_config[m] = PmConfig(name=m,
119 type=PmConfig.COUNTER,
120 enabled=True)
121 self.nni_metrics_config[m] = PmConfig(name=m,
122 type=PmConfig.COUNTER,
123 enabled=True)
124
125 def update(self, pm_config):
126 if self.default_freq != pm_config.default_freq:
127 # Update the callback to the new frequency.
128 self.default_freq = pm_config.default_freq
129 self.lc.stop()
Stephane Barbarie5253c652017-03-22 16:29:46 -0400130 self.lc.start(interval=self.default_freq / 10)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400131 for m in pm_config.metrics:
132 self.pon_metrics_config[m.name].enabled = m.enabled
133 self.nni_metrics_config[m.name].enabled = m.enabled
134
135 def make_proto(self):
136 pm_config = PmConfigs(
137 id=self.id,
138 default_freq=self.default_freq,
Stephane Barbarie5253c652017-03-22 16:29:46 -0400139 grouped=False,
140 freq_override=False)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400141 for m in sorted(self.pon_metrics_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400142 pm = self.pon_metrics_config[m] # Either will do they're the same
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400143 pm_config.metrics.extend([PmConfig(name=pm.name,
144 type=pm.type,
145 enabled=pm.enabled)])
146 return pm_config
147
148 def collect_port_metrics(self, channel):
149 rtrn_port_metrics = dict()
Scott Bakerd865fa22018-11-07 11:45:28 -0800150 stub = ponsim_pb2_grpc.PonSimStub(channel)
Scott Bakerb5be94d2018-10-09 16:13:32 -0700151 stats = stub.GetStats(ponsim_pb2.PonSimMetricsRequest(port=0))
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400152 rtrn_port_metrics['pon'] = self.extract_pon_metrics(stats)
153 rtrn_port_metrics['nni'] = self.extract_nni_metrics(stats)
154 return rtrn_port_metrics
155
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400156 def extract_pon_metrics(self, stats):
157 rtrn_pon_metrics = dict()
158 for m in stats.metrics:
159 if m.port_name == "pon":
160 for p in m.packets:
161 if self.pon_metrics_config[p.name].enabled:
162 rtrn_pon_metrics[p.name] = p.value
163 return rtrn_pon_metrics
164
165 def extract_nni_metrics(self, stats):
166 rtrn_pon_metrics = dict()
167 for m in stats.metrics:
168 if m.port_name == "nni":
169 for p in m.packets:
170 if self.pon_metrics_config[p.name].enabled:
171 rtrn_pon_metrics[p.name] = p.value
172 return rtrn_pon_metrics
173
174 def start_collector(self, callback):
175 log.info("starting-pm-collection", device_name=self.name,
176 device_id=self.device.id)
177 prefix = 'voltha.{}.{}'.format(self.name, self.device.id)
178 self.lc = LoopingCall(callback, self.device.id, prefix)
Stephane Barbarie5253c652017-03-22 16:29:46 -0400179 self.lc.start(interval=self.default_freq / 10)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400180
Stephane Barbarie35595062018-02-08 08:34:39 -0500181 def stop_collector(self):
182 log.info("stopping-pm-collection", device_name=self.name,
183 device_id=self.device.id)
184 self.lc.stop()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800185
khenaidoof3593a82018-06-01 16:41:31 -0400186
Stephane Barbarie4475a252017-03-31 13:49:20 -0400187class AdapterAlarms:
188 def __init__(self, adapter, device):
189 self.adapter = adapter
190 self.device = device
191 self.lc = None
192
193 def send_alarm(self, context_data, alarm_data):
194 try:
195 current_context = {}
196 for key, value in context_data.__dict__.items():
197 current_context[key] = str(value)
198
199 alarm_event = self.adapter.adapter_agent.create_alarm(
200 resource_id=self.device.id,
khenaidoo032d3302017-06-09 14:50:04 -0400201 description="{}.{} - {}".format(self.adapter.name,
202 self.device.id,
203 alarm_data[
204 'description']) if 'description' in alarm_data else None,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400205 type=alarm_data['type'] if 'type' in alarm_data else None,
khenaidoo032d3302017-06-09 14:50:04 -0400206 category=alarm_data[
207 'category'] if 'category' in alarm_data else None,
208 severity=alarm_data[
209 'severity'] if 'severity' in alarm_data else None,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400210 state=alarm_data['state'] if 'state' in alarm_data else None,
211 raised_ts=alarm_data['ts'] if 'ts' in alarm_data else 0,
212 context=current_context
213 )
214
khenaidoo032d3302017-06-09 14:50:04 -0400215 self.adapter.adapter_agent.submit_alarm(self.device.id,
216 alarm_event)
Stephane Barbarie4475a252017-03-31 13:49:20 -0400217
218 except Exception as e:
219 log.exception('failed-to-send-alarm', e=e)
220
khenaidoof3593a82018-06-01 16:41:31 -0400221
Shad Ansarid1aa9e72017-06-23 21:34:25 -0700222class PonSimOltAdapter(OltAdapter):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800223 def __init__(self, adapter_agent, config):
Shad Ansari14bcd992017-06-13 14:27:20 -0700224 super(PonSimOltAdapter, self).__init__(adapter_agent=adapter_agent,
225 config=config,
Shad Ansari96f817b2017-06-18 23:17:44 -0700226 device_handler_class=PonSimOltHandler,
Shad Ansari14bcd992017-06-13 14:27:20 -0700227 name='ponsim_olt',
228 vendor='Voltha project',
Nikolay Titov89004ec2017-06-19 18:22:42 -0400229 version='0.4',
khenaidoof3593a82018-06-01 16:41:31 -0400230 device_type='ponsim_olt',
231 accepts_bulk_flow_update=True,
232 accepts_add_remove_flow_updates=False)
Shad Ansari96f817b2017-06-18 23:17:44 -0700233
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400234 def update_pm_config(self, device, pm_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400235 log.info("adapter-update-pm-config", device=device,
236 pm_config=pm_config)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400237 handler = self.devices_handlers[device.id]
238 handler.update_pm_config(device, pm_config)
Sergio Slobodrianec864c62017-03-09 11:41:43 -0500239
Nikolay Titov89004ec2017-06-19 18:22:42 -0400240 def create_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400241 if super(PonSimOltAdapter, self)._get_handler(device):
242 log.info('create-interface', device_id=device.id)
243 self.devices_handlers[device.id].create_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400244
245 def update_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400246 if super(PonSimOltAdapter, self)._get_handler(device):
247 log.info('update-interface', device_id=device.id)
248 self.devices_handlers[device.id].update_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400249
250 def remove_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400251 if super(PonSimOltAdapter, self)._get_handler(device):
252 log.info('remove-interface', device_id=device.id)
253 self.devices_handlers[device.id].remove_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400254
Nikolay Titov176f1db2017-08-10 12:38:43 -0400255 def create_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400256 if super(PonSimOltAdapter, self)._get_handler(device):
257 log.info('create-tcont', device_id=device.id)
258 self.devices_handlers[device.id].create_tcont(
259 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400260
261 def update_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400262 if super(PonSimOltAdapter, self)._get_handler(device):
263 log.info('update-tcont', device_id=device.id)
264 self.devices_handlers[device.id].update_tcont(
265 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400266
267 def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400268 if super(PonSimOltAdapter, self)._get_handler(device):
269 log.info('remove-tcont', device_id=device.id)
270 self.devices_handlers[device.id].remove_tcont(
271 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400272
273 def create_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400274 if super(PonSimOltAdapter, self)._get_handler(device):
275 log.info('create-gemport', device_id=device.id)
276 self.devices_handlers[device.id].create_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400277
278 def update_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400279 if super(PonSimOltAdapter, self)._get_handler(device):
280 log.info('update-gemport', device_id=device.id)
281 self.devices_handlers[device.id].update_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400282
283 def remove_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400284 if super(PonSimOltAdapter, self)._get_handler(device):
285 log.info('remove-gemport', device_id=device.id)
286 self.devices_handlers[device.id].remove_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400287
288 def create_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400289 if super(PonSimOltAdapter, self)._get_handler(device):
290 log.info('create-multicast-gemport', device_id=device.id)
291 self.devices_handlers[device.id].create_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400292
293 def update_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400294 if super(PonSimOltAdapter, self)._get_handler(device):
295 log.info('update-multicast-gemport', device_id=device.id)
296 self.devices_handlers[device.id].update_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400297
298 def remove_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400299 if super(PonSimOltAdapter, self)._get_handler(device):
300 log.info('remove-multicast-gemport', device_id=device.id)
301 self.devices_handlers[device.id].remove_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400302
303 def create_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400304 if super(PonSimOltAdapter, self)._get_handler(device):
305 log.info('create-multicast-distribution-set', device_id=device.id)
306 self.devices_handlers[device.id].create_multicast_distribution_set(
307 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400308
309 def update_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400310 if super(PonSimOltAdapter, self)._get_handler(device):
311 log.info('update-multicast-distribution-set', device_id=device.id)
312 self.devices_handlers[device.id].update_multicast_distribution_set(
313 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400314
315 def remove_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400316 if super(PonSimOltAdapter, self)._get_handler(device):
317 log.info('remove-multicast-distribution-set', device_id=device.id)
318 self.devices_handlers[device.id].remove_multicast_distribution_set(
319 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400320
Scott Baker50873cc2018-09-21 18:14:09 -0700321 def simulate_alarm(self, device, alarm):
322 handler = self.devices_handlers[device.id]
323 handler.simulate_alarm(alarm)
324 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
khenaidoof3593a82018-06-01 16:41:31 -0400325
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800326class PonSimOltHandler(object):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400327 xpon_ponsim_olt_itfs = {
328 'create_interface': {
329 'method_name': 'CreateInterface',
330 'log': 'create-interface'},
331 'update_interface': {
332 'method_name': 'UpdateInterface',
333 'log': 'update-interface'},
334 'remove_interface': {
335 'method_name': 'RemoveInterface',
336 'log': 'remove-interface'},
337 'create_tcont': {
338 'method_name': 'CreateTcont',
339 'log': 'create-tconts-config-data'},
340 'update_tcont': {
341 'method_name': 'UpdateTcont',
342 'log': 'update-tconts-config-data'},
343 'remove_tcont': {
344 'method_name': 'RemoveTcont',
345 'log': 'remove-tconts-config-data'},
346 'create_gemport': {
347 'method_name': 'CreateGemport',
348 'log': 'create-gemports-config-data'},
349 'update_gemport': {
350 'method_name': 'UpdateGemport',
351 'log': 'update-gemports-config-data'},
352 'remove_gemport': {
353 'method_name': 'RemoveGemport',
354 'log': 'remove-gemports-config-data'},
355 'create_multicast_gemport': {
356 'method_name': 'CreateMulticastGemport',
357 'log': 'create-multicast-gemports-config-data'},
358 'update_multicast_gemport': {
359 'method_name': 'UpdateMulticastGemport',
360 'log': 'update-multicast-gemports-config-data'},
361 'remove_multicast_gemport': {
362 'method_name': 'RemoveMulticastGemport',
363 'log': 'remove-multicast-gemports-config-data'},
364 'create_multicast_distribution_set': {
365 'method_name': 'CreateMulticastDistributionSet',
366 'log': 'create-multicast-distribution-set-data'},
367 'update_multicast_distribution_set': {
368 'method_name': 'UpdateMulticastDistributionSet',
369 'log': 'update-multicast-distribution-set-data'},
370 'remove_multicast_distribution_set': {
371 'method_name': 'RemoveMulticastDistributionSet',
372 'log': 'remove-multicast-distribution-set-data'},
khenaidoof3593a82018-06-01 16:41:31 -0400373 }
Nikolay Titov176f1db2017-08-10 12:38:43 -0400374
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800375 def __init__(self, adapter, device_id):
376 self.adapter = adapter
377 self.adapter_agent = adapter.adapter_agent
378 self.device_id = device_id
379 self.log = structlog.get_logger(device_id=device_id)
380 self.channel = None
381 self.io_port = None
382 self.logical_device_id = None
Khen Nursimulud068d812017-03-06 11:44:18 -0500383 self.nni_port = None
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400384 self.ofp_port_no = None
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800385 self.interface = registry('main').get_args().interface
Stephane Barbarie35595062018-02-08 08:34:39 -0500386 self.ponsim_comm = registry('main').get_args().ponsim_comm
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400387 self.pm_metrics = None
Stephane Barbarie4475a252017-03-31 13:49:20 -0400388 self.alarms = None
Stephane Barbarie35595062018-02-08 08:34:39 -0500389 self.frames = None
Andy Bavier97566512018-11-14 16:17:41 -0700390 self.uni_ports = []
391 self.ctag_map = {}
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800392
393 def __del__(self):
394 if self.io_port is not None:
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800395 registry('frameio').close_port(self.io_port)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800396
397 def get_channel(self):
398 if self.channel is None:
399 device = self.adapter_agent.get_device(self.device_id)
schowdhury9e247752017-07-14 06:56:20 -0700400
Jeff70e8b2d2018-07-24 13:37:29 -0700401 self.channel = grpc.insecure_channel(device.host_and_port)
schowdhury9e247752017-07-14 06:56:20 -0700402
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800403 return self.channel
404
Stephane Barbarie35595062018-02-08 08:34:39 -0500405 def close_channel(self):
406 if self.channel is None:
407 self.log.info('grpc-channel-already-closed')
408 return
409 else:
410 if self.frames is not None:
411 self.frames.cancel()
412 self.frames = None
413 self.log.info('cancelled-grpc-frame-stream')
414
415 self.channel.unsubscribe(lambda *args: None)
416 self.channel = None
417
418 self.log.info('grpc-channel-closed')
419
khenaidoo032d3302017-06-09 14:50:04 -0400420 def _get_nni_port(self):
421 ports = self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_NNI)
422 if ports:
423 # For now, we use on one NNI port
424 return ports[0]
425
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800426 def activate(self, device):
427 self.log.info('activating')
428
429 if not device.host_and_port:
430 device.oper_status = OperStatus.FAILED
431 device.reason = 'No host_and_port field provided'
432 self.adapter_agent.update_device(device)
433 return
434
Scott Bakerd865fa22018-11-07 11:45:28 -0800435 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800436 info = stub.GetDeviceInfo(Empty())
437 log.info('got-info', info=info)
438
439 device.root = True
440 device.vendor = 'ponsim'
Stephane Barbarie5253c652017-03-22 16:29:46 -0400441 device.model = 'n/a'
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800442 device.serial_number = device.host_and_port
443 device.connect_status = ConnectStatus.REACHABLE
444 self.adapter_agent.update_device(device)
445
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400446 # Now set the initial PM configuration for this device
Stephane Barbarie5253c652017-03-22 16:29:46 -0400447 self.pm_metrics = AdapterPmMetrics(device)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400448 pm_config = self.pm_metrics.make_proto()
449 log.info("initial-pm-config", pm_config=pm_config)
Stephane Barbarie5253c652017-03-22 16:29:46 -0400450 self.adapter_agent.update_device_pm_config(pm_config, init=True)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400451
Stephane Barbarie4475a252017-03-31 13:49:20 -0400452 # Setup alarm handler
453 self.alarms = AdapterAlarms(self.adapter, device)
454
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800455 nni_port = Port(
Jonathan Hart32fe8812018-08-21 17:10:12 -0700456 port_no=info.nni_port,
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800457 label='NNI facing Ethernet port',
458 type=Port.ETHERNET_NNI,
459 admin_state=AdminState.ENABLED,
460 oper_status=OperStatus.ACTIVE
461 )
Khen Nursimulud068d812017-03-06 11:44:18 -0500462 self.nni_port = nni_port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800463 self.adapter_agent.add_port(device.id, nni_port)
464 self.adapter_agent.add_port(device.id, Port(
465 port_no=1,
466 label='PON port',
467 type=Port.PON_OLT,
468 admin_state=AdminState.ENABLED,
469 oper_status=OperStatus.ACTIVE
470 ))
471
472 ld = LogicalDevice(
khenaidoo507d9222017-10-10 16:23:49 -0400473 # not setting id and datapath_id. Adapter agent will pick the id
474 # and will pick the datapath_id is it is not provided
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800475 desc=ofp_desc(
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800476 hw_desc='simualted pon',
477 sw_desc='simualted pon',
khenaidoof3593a82018-06-01 16:41:31 -0400478 # serial_num=uuid4().hex,
Jonathan Hart32fe8812018-08-21 17:10:12 -0700479 serial_num=device.serial_number,
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800480 dp_desc='n/a'
481 ),
482 switch_features=ofp_switch_features(
483 n_buffers=256, # TODO fake for now
484 n_tables=2, # TODO ditto
485 capabilities=( # TODO and ditto
khenaidoof3593a82018-06-01 16:41:31 -0400486 OFPC_FLOW_STATS
487 | OFPC_TABLE_STATS
488 | OFPC_PORT_STATS
489 | OFPC_GROUP_STATS
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800490 )
491 ),
492 root_device_id=device.id
493 )
khenaidoo507d9222017-10-10 16:23:49 -0400494 mac_address = "AA:BB:CC:DD:EE:FF"
495 ld_initialized = self.adapter_agent.create_logical_device(ld,
496 dpid=mac_address)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800497 cap = OFPPF_1GB_FD | OFPPF_FIBER
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400498 self.ofp_port_no = info.nni_port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800499 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
500 id='nni',
501 ofp_port=ofp_port(
502 port_no=info.nni_port,
Stephane Barbarie5253c652017-03-22 16:29:46 -0400503 hw_addr=mac_str_to_tuple(
504 '00:00:00:00:00:%02x' % info.nni_port),
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800505 name='nni',
506 config=0,
507 state=OFPPS_LIVE,
508 curr=cap,
509 advertised=cap,
510 peer=cap,
511 curr_speed=OFPPF_1GB_FD,
512 max_speed=OFPPF_1GB_FD
513 ),
514 device_id=device.id,
515 device_port_no=nni_port.port_no,
516 root_port=True
517 ))
518
519 device = self.adapter_agent.get_device(device.id)
520 device.parent_id = ld_initialized.id
521 device.oper_status = OperStatus.ACTIVE
522 self.adapter_agent.update_device(device)
523 self.logical_device_id = ld_initialized.id
524
Andy Bavierea82b462018-07-27 16:48:13 -0700525 # register ONUS
526 for onu in info.onus:
527 vlan_id = onu.uni_port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800528 self.adapter_agent.child_device_detected(
529 parent_device_id=device.id,
530 parent_port_no=1,
Niren R Chidrawarefcebcd2017-07-19 20:03:39 -0400531 child_device_type='ponsim_onu',
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800532 proxy_address=Device.ProxyAddress(
533 device_id=device.id,
534 channel_id=vlan_id
535 ),
Nikolay Titov89004ec2017-06-19 18:22:42 -0400536 admin_state=AdminState.ENABLED,
Andy Bavierea82b462018-07-27 16:48:13 -0700537 vlan=vlan_id,
538 serial_number=onu.serial_number
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800539 )
Andy Bavier97566512018-11-14 16:17:41 -0700540 self.uni_ports.append(int(onu.uni_port))
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800541
Stephane Barbarie35595062018-02-08 08:34:39 -0500542 if self.ponsim_comm == 'grpc':
543 self.log.info('starting-frame-grpc-stream')
544 reactor.callInThread(self.rcv_grpc)
545 self.log.info('started-frame-grpc-stream')
546 else:
547 # finally, open the frameio port to receive in-band packet_in messages
548 self.log.info('registering-frameio')
549 self.io_port = registry('frameio').open_port(
550 self.interface, self.rcv_io, is_inband_frame)
551 self.log.info('registered-frameio')
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800552
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400553 # Start collecting stats from the device after a brief pause
554 self.start_kpi_collection(device.id)
555
khenaidoo032d3302017-06-09 14:50:04 -0400556 def reconcile(self, device):
557 self.log.info('reconciling-OLT-device-starts')
558
559 if not device.host_and_port:
560 device.oper_status = OperStatus.FAILED
561 device.reason = 'No host_and_port field provided'
562 self.adapter_agent.update_device(device)
563 return
564
565 try:
Scott Bakerd865fa22018-11-07 11:45:28 -0800566 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
khenaidoo032d3302017-06-09 14:50:04 -0400567 info = stub.GetDeviceInfo(Empty())
568 log.info('got-info', info=info)
569 # TODO: Verify we are connected to the same device we are
570 # reconciling - not much data in ponsim to differentiate at the
571 # time
572 device.oper_status = OperStatus.ACTIVE
573 self.adapter_agent.update_device(device)
574 self.ofp_port_no = info.nni_port
575 self.nni_port = self._get_nni_port()
576 except Exception, e:
577 log.exception('device-unreachable', e=e)
578 device.connect_status = ConnectStatus.UNREACHABLE
579 device.oper_status = OperStatus.UNKNOWN
580 self.adapter_agent.update_device(device)
581 return
582
583 # Now set the initial PM configuration for this device
584 self.pm_metrics = AdapterPmMetrics(device)
585 pm_config = self.pm_metrics.make_proto()
586 log.info("initial-pm-config", pm_config=pm_config)
587 self.adapter_agent.update_device_pm_config(pm_config, init=True)
588
589 # Setup alarm handler
590 self.alarms = AdapterAlarms(self.adapter, device)
591
592 # TODO: Is there anything required to verify nni and PON ports
593
594 # Set the logical device id
595 device = self.adapter_agent.get_device(device.id)
596 if device.parent_id:
597 self.logical_device_id = device.parent_id
598 self.adapter_agent.reconcile_logical_device(device.parent_id)
599 else:
600 self.log.info('no-logical-device-set')
601
602 # Reconcile child devices
603 self.adapter_agent.reconcile_child_devices(device.id)
604
Stephane Barbarie35595062018-02-08 08:34:39 -0500605 if self.ponsim_comm == 'grpc':
606 reactor.callInThread(self.rcv_grpc)
607 else:
608 # finally, open the frameio port to receive in-band packet_in messages
609 self.io_port = registry('frameio').open_port(
610 self.interface, self.rcv_io, is_inband_frame)
khenaidoo032d3302017-06-09 14:50:04 -0400611
612 # Start collecting stats from the device after a brief pause
613 self.start_kpi_collection(device.id)
614
615 self.log.info('reconciling-OLT-device-ends')
616
Stephane Barbarie35595062018-02-08 08:34:39 -0500617 def _rcv_frame(self, frame):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800618 pkt = Ether(frame)
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000619 self.log.info('received packet', pkt=pkt)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800620 if pkt.haslayer(Dot1Q):
Andy Bavier904efcf2019-04-01 16:50:34 -0700621 if pkt.haslayer(Dot1AD):
622 outer_shim = pkt.getlayer(Dot1AD)
623 else:
624 outer_shim = pkt.getlayer(Dot1Q)
Stephane Barbarie35595062018-02-08 08:34:39 -0500625
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000626 if pkt.haslayer(IP) or outer_shim.type == EAP_ETH_TYPE:
Andy Bavier904efcf2019-04-01 16:50:34 -0700627 # We don't have any context about the packet at this point.
628 # Assume that only downstream traffic is double-tagged.
629 if isinstance(outer_shim.payload, Dot1Q):
630 logical_port = int(self.nni_port.port_no)
631 else:
632 cvid = outer_shim.vlan
633 logical_port = self.get_subscriber_uni_port(cvid)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800634 popped_frame = (
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000635 Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
636 outer_shim.payload
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800637 )
638 kw = dict(
639 logical_device_id=self.logical_device_id,
640 logical_port_no=logical_port,
641 )
642 self.log.info('sending-packet-in', **kw)
643 self.adapter_agent.send_packet_in(
644 packet=str(popped_frame), **kw)
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000645
Stephane Barbarie4475a252017-03-31 13:49:20 -0400646 elif pkt.haslayer(Raw):
647 raw_data = json.loads(pkt.getlayer(Raw).load)
648 self.alarms.send_alarm(self, raw_data)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800649
Stephane Barbarie35595062018-02-08 08:34:39 -0500650 @inlineCallbacks
651 def rcv_grpc(self):
652 """
653 This call establishes a GRPC stream to receive frames.
654 """
Scott Bakerd865fa22018-11-07 11:45:28 -0800655 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Stephane Barbarie35595062018-02-08 08:34:39 -0500656
657 # Attempt to establish a grpc stream with the remote ponsim service
658 self.frames = stub.ReceiveFrames(Empty())
659
660 self.log.info('start-receiving-grpc-frames')
661
662 try:
663 for frame in self.frames:
khenaidoof3593a82018-06-01 16:41:31 -0400664 self.log.info('received-grpc-frame',
665 frame_len=len(frame.payload))
Stephane Barbarie35595062018-02-08 08:34:39 -0500666 self._rcv_frame(frame.payload)
667
668 except _Rendezvous, e:
khenaidoof3593a82018-06-01 16:41:31 -0400669 log.warn('grpc-connection-lost', message=e.message)
Stephane Barbarie35595062018-02-08 08:34:39 -0500670
671 self.log.info('stopped-receiving-grpc-frames')
672
673 def rcv_io(self, port, frame):
674 self.log.info('received-io-frame', iface_name=port.iface_name,
675 frame_len=len(frame))
676 self._rcv_frame(frame)
677
Andy Bavier97566512018-11-14 16:17:41 -0700678 def to_controller(self, flow):
679 for action in fd.get_actions(flow):
680 if action.type == ofp.OFPAT_OUTPUT:
681 action.output.port = ofp.OFPP_CONTROLLER
682 self.log.info('sending flow to controller')
683
684 # Lookup subscriber ctag for a particular PON port
685 def get_subscriber_ctag(self, flows, port):
686 self.log.debug('looking from subscriber flow for port', port=port)
687
688 for flow in flows:
689 in_port = fd.get_in_port(flow)
690 out_port = fd.get_out_port(flow)
691 if in_port == port and out_port == self.nni_port.port_no:
692 fields = fd.get_ofb_fields(flow)
693 self.log.debug('subscriber flow found', fields=fields)
694 for field in fields:
695 if field.type == fd.VLAN_VID:
696 self.log.debug('subscriber ctag found',
697 vlan_id=field.vlan_vid)
698 return field.vlan_vid & 0x0fff
699 self.log.debug('No subscriber flow found', port=port)
700 return None
701
702 # Lookup UNI port for a particular subscriber ctag
703 def get_subscriber_uni_port(self, ctag):
704 self.log.debug('get_subscriber_uni_port', ctag=ctag, ctag_map=self.ctag_map)
705 c = int(ctag)
706 if c in self.ctag_map:
707 return self.ctag_map[c]
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000708 # return None
709 # HACK: temporarily pass atest
710 return int(128)
Andy Bavier97566512018-11-14 16:17:41 -0700711
712 def clear_ctag_map(self):
713 self.ctag_map = {}
714
715 def update_ctag_map(self, ctag, uni_port):
716 c = int(ctag)
717 u = int(uni_port)
718 if not self.is_uni_port(u):
719 self.log.warning('update_ctag_map: unknown UNI port', uni_port=u)
720 if c in self.ctag_map and self.ctag_map[c] != u:
721 self.log.warning('update_ctag_map: changing UNI port for ctag',
722 ctag=c, old=self.ctag_map[c], new=u)
723 self.ctag_map[c] = u
724
725 # Create a new flow that's a copy of the old flow but change the vlan_vid
726 # Used to create per-subscriber DHCP and EAPOL flows
727 def create_secondary_flow(self, flow, vlan_id):
728 secondary_flow = copy.deepcopy(flow)
729 for field in fd.get_ofb_fields(secondary_flow):
730 if field.type == fd.VLAN_VID:
731 field.vlan_vid = vlan_id | 0x1000
732 return secondary_flow
733
734 def is_uni_port(self, vlan_id):
735 return int(vlan_id) in self.uni_ports
736
737 def create_secondary_flows(self, trapflows, allflows, type):
738 secondary_flows = []
739 for vlan_vid, flow in trapflows.iteritems():
740 if self.is_uni_port(vlan_vid):
741 self.update_ctag_map(vlan_vid, vlan_vid)
742 ctag = self.get_subscriber_ctag(allflows, fd.get_in_port(flow))
743 if ctag is not None:
744 self.update_ctag_map(ctag, vlan_vid)
745 if ctag not in trapflows:
746 self.log.info('add secondary %s flow' % type, ctag=ctag)
747 secondary_flows.append(self.create_secondary_flow(flow, ctag))
748 return secondary_flows
749
Jeff55a2f132018-08-05 21:10:41 -0700750 # VOLTHA's flow decomposition removes the information about which flows
751 # are trap flows where traffic should be forwarded to the controller.
752 # We'll go through the flows and change the output port of flows that we
753 # know to be trap flows to the OF CONTROLLER port.
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800754 def update_flow_table(self, flows):
Scott Bakerd865fa22018-11-07 11:45:28 -0800755 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800756 self.log.info('pushing-olt-flow-table')
Andy Bavier97566512018-11-14 16:17:41 -0700757
758 self.clear_ctag_map()
759 dhcp_upstream_flows = {}
760 eapol_flows = {}
761 secondary_flows = []
762
Jeff55a2f132018-08-05 21:10:41 -0700763 for flow in flows:
764 classifier_info = {}
765 for field in fd.get_ofb_fields(flow):
766 if field.type == fd.ETH_TYPE:
Andy Bavier97566512018-11-14 16:17:41 -0700767 classifier_info[ETH_TYPE] = field.eth_type
Jeff55a2f132018-08-05 21:10:41 -0700768 elif field.type == fd.IP_PROTO:
Andy Bavier97566512018-11-14 16:17:41 -0700769 classifier_info[IP_PROTO] = field.ip_proto
770 elif field.type == fd.IN_PORT:
771 classifier_info[IN_PORT] = field.port
772 elif field.type == fd.VLAN_VID:
773 classifier_info[VLAN_VID] = field.vlan_vid & 0xfff
774 elif field.type == fd.VLAN_PCP:
775 classifier_info[VLAN_PCP] = field.vlan_pcp
776 elif field.type == fd.UDP_DST:
777 classifier_info[UDP_DST] = field.udp_dst
778 elif field.type == fd.UDP_SRC:
779 classifier_info[UDP_SRC] = field.udp_src
780 elif field.type == fd.IPV4_DST:
781 classifier_info[IPV4_DST] = field.ipv4_dst
782 elif field.type == fd.IPV4_SRC:
783 classifier_info[IPV4_SRC] = field.ipv4_src
784 elif field.type == fd.METADATA:
785 classifier_info[METADATA] = field.table_metadata
786 else:
787 self.log.debug('field-type-unhandled field.type={}'.format(
788 field.type))
789
790 self.log.debug('classifier_info', classifier_info=classifier_info)
791
792 if IP_PROTO in classifier_info:
793 if classifier_info[IP_PROTO] == 17:
794 if UDP_SRC in classifier_info:
795 if classifier_info[UDP_SRC] == 68:
796 self.log.info('dhcp upstream flow add')
797 if VLAN_VID in classifier_info:
798 dhcp_upstream_flows[classifier_info[VLAN_VID]] = flow
799 elif classifier_info[UDP_SRC] == 67:
800 self.log.info('dhcp downstream flow add')
801 self.to_controller(flow)
802 elif classifier_info[IP_PROTO] == 2:
803 self.log.info('igmp flow add')
804 self.to_controller(flow)
805 else:
806 self.log.warn("Invalid-Classifier-to-handle",
807 classifier_info=classifier_info)
808 elif ETH_TYPE in classifier_info:
809 if classifier_info[ETH_TYPE] == EAP_ETH_TYPE:
810 self.log.info('eapol flow add')
811 self.to_controller(flow)
812 if VLAN_VID in classifier_info:
813 eapol_flows[classifier_info[VLAN_VID]] = flow
814
Jeff55a2f132018-08-05 21:10:41 -0700815 self.log.info('out_port', out_port=fd.get_out_port(flow))
816
Andy Bavier97566512018-11-14 16:17:41 -0700817 flows.extend(self.create_secondary_flows(dhcp_upstream_flows, flows, "DHCP"))
818 flows.extend(self.create_secondary_flows(eapol_flows, flows, "EAPOL"))
819
820 self.log.debug('ctag_map', ctag_map=self.ctag_map)
821
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800822 stub.UpdateFlowTable(FlowTable(
823 port=0,
824 flows=flows
825 ))
826 self.log.info('success')
827
khenaidoof3593a82018-06-01 16:41:31 -0400828 def remove_from_flow_table(self, flows):
829 self.log.debug('remove-from-flow-table', flows=flows)
830 # TODO: Update PONSIM code to accept incremental flow changes
831 # Once completed, the accepts_add_remove_flow_updates for this
832 # device type can be set to True
833
834 def add_to_flow_table(self, flows):
835 self.log.debug('add-to-flow-table', flows=flows)
836 # TODO: Update PONSIM code to accept incremental flow changes
837 # Once completed, the accepts_add_remove_flow_updates for this
838 # device type can be set to True
839
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400840 def update_pm_config(self, device, pm_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400841 log.info("handler-update-pm-config", device=device,
842 pm_config=pm_config)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400843 self.pm_metrics.update(pm_config)
844
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800845 def send_proxied_message(self, proxy_address, msg):
Zack Williams18357ed2018-11-14 10:41:08 -0700846 self.log.debug('sending-proxied-message')
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800847 if isinstance(msg, FlowTable):
Scott Bakerd865fa22018-11-07 11:45:28 -0800848 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800849 self.log.info('pushing-onu-flow-table', port=msg.port)
850 res = stub.UpdateFlowTable(msg)
851 self.adapter_agent.receive_proxied_message(proxy_address, res)
Scott Bakerb5be94d2018-10-09 16:13:32 -0700852 elif isinstance(msg, PonSimMetricsRequest):
Scott Bakerd865fa22018-11-07 11:45:28 -0800853 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Zack Williams18357ed2018-11-14 10:41:08 -0700854 self.log.debug('proxying onu stats request', port=msg.port)
Scott Bakerb5be94d2018-10-09 16:13:32 -0700855 res = stub.GetStats(msg)
856 self.adapter_agent.receive_proxied_message(proxy_address, res)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800857
858 def packet_out(self, egress_port, msg):
Zack Williams18357ed2018-11-14 10:41:08 -0700859 self.log.debug('sending-packet-out', egress_port=egress_port,
860 msg_hex=hexify(msg))
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800861 pkt = Ether(msg)
Jonathan Hart32fe8812018-08-21 17:10:12 -0700862 out_pkt = pkt
Andy Bavier97566512018-11-14 16:17:41 -0700863 self.log.debug("packet_out: incoming: %s" % pkt.summary())
Jonathan Hart32fe8812018-08-21 17:10:12 -0700864 if egress_port != self.nni_port.port_no:
865 # don't do the vlan manipulation for the NNI port, vlans are already correct
Andy Bavier97566512018-11-14 16:17:41 -0700866 if pkt.haslayer(Dot1Q):
Andy Bavier904efcf2019-04-01 16:50:34 -0700867 if pkt.haslayer(Dot1AD):
868 outer_shim = pkt.getlayer(Dot1AD)
869 else:
870 outer_shim = pkt.getlayer(Dot1Q)
871 if isinstance(outer_shim.payload, Dot1Q):
872 # If double tag, remove the outer tag
873 out_pkt = (
874 Ether(src=pkt.src, dst=pkt.dst,
875 type=outer_shim.type) /
876 outer_shim.payload
877 )
878 else:
879 out_pkt = pkt
Andy Bavier97566512018-11-14 16:17:41 -0700880 else:
881 # Add egress port as VLAN tag
882 out_pkt = (
Jonathan Hart32fe8812018-08-21 17:10:12 -0700883 Ether(src=pkt.src, dst=pkt.dst) /
884 Dot1Q(vlan=egress_port, type=pkt.type) /
885 pkt.payload
Andy Bavier97566512018-11-14 16:17:41 -0700886 )
887 self.log.debug("packet_out: outgoing: %s" % out_pkt.summary())
Jonathan Hart32fe8812018-08-21 17:10:12 -0700888
889 # TODO need better way of mapping logical ports to PON ports
890 out_port = self.nni_port.port_no if egress_port == self.nni_port.port_no else 1
Stephane Barbarie35595062018-02-08 08:34:39 -0500891
892 if self.ponsim_comm == 'grpc':
893 # send over grpc stream
Scott Bakerd865fa22018-11-07 11:45:28 -0800894 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Jonathan Hart32fe8812018-08-21 17:10:12 -0700895 frame = PonSimFrame(id=self.device_id, payload=str(out_pkt), out_port=out_port)
Stephane Barbarie35595062018-02-08 08:34:39 -0500896 stub.SendFrame(frame)
897 else:
898 # send over frameio
899 self.io_port.send(str(out_pkt))
900
Khen Nursimulud068d812017-03-06 11:44:18 -0500901 @inlineCallbacks
902 def reboot(self):
903 self.log.info('rebooting', device_id=self.device_id)
904
905 # Update the operational status to ACTIVATING and connect status to
906 # UNREACHABLE
907 device = self.adapter_agent.get_device(self.device_id)
908 previous_oper_status = device.oper_status
909 previous_conn_status = device.connect_status
910 device.oper_status = OperStatus.ACTIVATING
911 device.connect_status = ConnectStatus.UNREACHABLE
912 self.adapter_agent.update_device(device)
913
khenaidoo71d0a6c2017-03-22 21:46:04 -0400914 # Update the child devices connect state to UNREACHABLE
khenaidoo2d7af132017-03-23 15:45:51 -0400915 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400916 connect_status=ConnectStatus.UNREACHABLE)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400917
Khen Nursimulud068d812017-03-06 11:44:18 -0500918 # Sleep 10 secs, simulating a reboot
Stephane Barbarie5253c652017-03-22 16:29:46 -0400919 # TODO: send alert and clear alert after the reboot
Khen Nursimulud068d812017-03-06 11:44:18 -0500920 yield asleep(10)
921
922 # Change the operational status back to its previous state. With a
923 # real OLT the operational state should be the state the device is
924 # after a reboot.
925 # Get the latest device reference
926 device = self.adapter_agent.get_device(self.device_id)
927 device.oper_status = previous_oper_status
928 device.connect_status = previous_conn_status
929 self.adapter_agent.update_device(device)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400930
931 # Update the child devices connect state to REACHABLE
khenaidoo2d7af132017-03-23 15:45:51 -0400932 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400933 connect_status=ConnectStatus.REACHABLE)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400934
Khen Nursimulud068d812017-03-06 11:44:18 -0500935 self.log.info('rebooted', device_id=self.device_id)
936
sathishg5ae86222017-06-28 15:16:29 +0530937 def self_test_device(self, device):
938 """
939 This is called to Self a device based on a NBI call.
940 :param device: A Voltha.Device object.
941 :return: Will return result of self test
942 """
943 log.info('self-test-device', device=device.id)
944 raise NotImplementedError()
945
Khen Nursimulud068d812017-03-06 11:44:18 -0500946 def disable(self):
947 self.log.info('disabling', device_id=self.device_id)
948
Stephane Barbarie35595062018-02-08 08:34:39 -0500949 self.stop_kpi_collection()
950
Khen Nursimulud068d812017-03-06 11:44:18 -0500951 # Get the latest device reference
952 device = self.adapter_agent.get_device(self.device_id)
953
954 # Update the operational status to UNKNOWN
955 device.oper_status = OperStatus.UNKNOWN
956 device.connect_status = ConnectStatus.UNREACHABLE
957 self.adapter_agent.update_device(device)
958
959 # Remove the logical device
960 logical_device = self.adapter_agent.get_logical_device(
Stephane Barbarie5253c652017-03-22 16:29:46 -0400961 self.logical_device_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500962 self.adapter_agent.delete_logical_device(logical_device)
963
964 # Disable all child devices first
khenaidoo2d7af132017-03-23 15:45:51 -0400965 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400966 admin_state=AdminState.DISABLED)
Khen Nursimulud068d812017-03-06 11:44:18 -0500967
Khen Nursimulud068d812017-03-06 11:44:18 -0500968 # Remove the peer references from this device
969 self.adapter_agent.delete_all_peer_references(self.device_id)
970
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400971 # Set all ports to disabled
972 self.adapter_agent.disable_all_ports(self.device_id)
973
Stephane Barbarie35595062018-02-08 08:34:39 -0500974 self.close_channel()
975 self.log.info('disabled-grpc-channel')
976
977 if self.ponsim_comm == 'frameio':
978 # close the frameio port
979 registry('frameio').close_port(self.io_port)
980 self.log.info('disabled-frameio-port')
Khen Nursimulud068d812017-03-06 11:44:18 -0500981
khenaidoo032d3302017-06-09 14:50:04 -0400982 # Update the logice device mapping
983 if self.logical_device_id in \
984 self.adapter.logical_device_id_to_root_device_id:
985 del self.adapter.logical_device_id_to_root_device_id[
986 self.logical_device_id]
987
Khen Nursimulud068d812017-03-06 11:44:18 -0500988 # TODO:
989 # 1) Remove all flows from the device
990 # 2) Remove the device from ponsim
991
992 self.log.info('disabled', device_id=device.id)
993
Khen Nursimulud068d812017-03-06 11:44:18 -0500994 def reenable(self):
995 self.log.info('re-enabling', device_id=self.device_id)
996
997 # Get the latest device reference
998 device = self.adapter_agent.get_device(self.device_id)
999
khenaidoo032d3302017-06-09 14:50:04 -04001000 # Set the ofp_port_no and nni_port in case we bypassed the reconcile
1001 # process if the device was in DISABLED state on voltha restart
1002 if not self.ofp_port_no and not self.nni_port:
Scott Bakerd865fa22018-11-07 11:45:28 -08001003 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
khenaidoo032d3302017-06-09 14:50:04 -04001004 info = stub.GetDeviceInfo(Empty())
1005 log.info('got-info', info=info)
1006 self.ofp_port_no = info.nni_port
1007 self.nni_port = self._get_nni_port()
1008
Khen Nursimulud068d812017-03-06 11:44:18 -05001009 # Update the connect status to REACHABLE
1010 device.connect_status = ConnectStatus.REACHABLE
1011 self.adapter_agent.update_device(device)
1012
Khen Nursimuluc60afa12017-03-13 14:33:50 -04001013 # Set all ports to enabled
1014 self.adapter_agent.enable_all_ports(self.device_id)
1015
Khen Nursimulud068d812017-03-06 11:44:18 -05001016 ld = LogicalDevice(
1017 # not setting id and datapth_id will let the adapter agent pick id
1018 desc=ofp_desc(
Khen Nursimulud068d812017-03-06 11:44:18 -05001019 hw_desc='simulated pon',
1020 sw_desc='simulated pon',
1021 serial_num=uuid4().hex,
1022 dp_desc='n/a'
1023 ),
1024 switch_features=ofp_switch_features(
1025 n_buffers=256, # TODO fake for now
1026 n_tables=2, # TODO ditto
1027 capabilities=( # TODO and ditto
khenaidoof3593a82018-06-01 16:41:31 -04001028 OFPC_FLOW_STATS
1029 | OFPC_TABLE_STATS
1030 | OFPC_PORT_STATS
1031 | OFPC_GROUP_STATS
Khen Nursimulud068d812017-03-06 11:44:18 -05001032 )
1033 ),
1034 root_device_id=device.id
1035 )
khenaidoo507d9222017-10-10 16:23:49 -04001036 mac_address = "AA:BB:CC:DD:EE:FF"
1037 ld_initialized = self.adapter_agent.create_logical_device(ld,
1038 dpid=mac_address)
Khen Nursimulud068d812017-03-06 11:44:18 -05001039 cap = OFPPF_1GB_FD | OFPPF_FIBER
1040 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
1041 id='nni',
1042 ofp_port=ofp_port(
Khen Nursimuluc60afa12017-03-13 14:33:50 -04001043 port_no=self.ofp_port_no,
Khen Nursimulud068d812017-03-06 11:44:18 -05001044 hw_addr=mac_str_to_tuple(
Khen Nursimuluc60afa12017-03-13 14:33:50 -04001045 '00:00:00:00:00:%02x' % self.ofp_port_no),
Khen Nursimulud068d812017-03-06 11:44:18 -05001046 name='nni',
1047 config=0,
1048 state=OFPPS_LIVE,
1049 curr=cap,
1050 advertised=cap,
1051 peer=cap,
1052 curr_speed=OFPPF_1GB_FD,
1053 max_speed=OFPPF_1GB_FD
1054 ),
1055 device_id=device.id,
1056 device_port_no=self.nni_port.port_no,
1057 root_port=True
1058 ))
1059
1060 device = self.adapter_agent.get_device(device.id)
1061 device.parent_id = ld_initialized.id
1062 device.oper_status = OperStatus.ACTIVE
1063 self.adapter_agent.update_device(device)
1064 self.logical_device_id = ld_initialized.id
1065
1066 # Reenable all child devices
khenaidoo2d7af132017-03-23 15:45:51 -04001067 self.adapter_agent.update_child_devices_state(device.id,
Stephane Barbarie4475a252017-03-31 13:49:20 -04001068 admin_state=AdminState.ENABLED)
Khen Nursimulud068d812017-03-06 11:44:18 -05001069
Stephane Barbarie35595062018-02-08 08:34:39 -05001070 if self.ponsim_comm == 'grpc':
1071 # establish frame grpc-stream
1072 reactor.callInThread(self.rcv_grpc)
1073 else:
1074 # finally, open the frameio port to receive in-band packet_in messages
1075 self.io_port = registry('frameio').open_port(
1076 self.interface, self.rcv_io, is_inband_frame)
1077
1078 self.start_kpi_collection(device.id)
Khen Nursimulud068d812017-03-06 11:44:18 -05001079
1080 self.log.info('re-enabled', device_id=device.id)
1081
Khen Nursimulud068d812017-03-06 11:44:18 -05001082 def delete(self):
1083 self.log.info('deleting', device_id=self.device_id)
1084
1085 # Remove all child devices
1086 self.adapter_agent.delete_all_child_devices(self.device_id)
1087
Stephane Barbarie35595062018-02-08 08:34:39 -05001088 self.close_channel()
1089 self.log.info('disabled-grpc-channel')
1090
1091 if self.ponsim_comm == 'frameio':
1092 # close the frameio port
1093 registry('frameio').close_port(self.io_port)
1094 self.log.info('disabled-frameio-port')
1095
Khen Nursimulud068d812017-03-06 11:44:18 -05001096 # TODO:
1097 # 1) Remove all flows from the device
1098 # 2) Remove the device from ponsim
1099
1100 self.log.info('deleted', device_id=self.device_id)
Sergio Slobodrian98eff412017-03-15 14:46:30 -04001101
1102 def start_kpi_collection(self, device_id):
1103
1104 def _collect(device_id, prefix):
1105
1106 try:
1107 # Step 1: gather metrics from device
1108 port_metrics = \
Stephane Barbarie5253c652017-03-22 16:29:46 -04001109 self.pm_metrics.collect_port_metrics(self.get_channel())
Sergio Slobodrian98eff412017-03-15 14:46:30 -04001110
1111 # Step 2: prepare the KpiEvent for submission
1112 # we can time-stamp them here (or could use time derived from OLT
1113 ts = arrow.utcnow().timestamp
1114 kpi_event = KpiEvent(
1115 type=KpiEventType.slice,
1116 ts=ts,
1117 prefixes={
1118 # OLT NNI port
1119 prefix + '.nni': MetricValuePairs(
1120 metrics=port_metrics['nni']),
1121 # OLT PON port
1122 prefix + '.pon': MetricValuePairs(
1123 metrics=port_metrics['pon'])
1124 }
1125 )
1126
1127 # Step 3: submit
1128 self.adapter_agent.submit_kpis(kpi_event)
1129
1130 except Exception as e:
1131 log.exception('failed-to-submit-kpis', e=e)
Stephane Barbarie5253c652017-03-22 16:29:46 -04001132
Sergio Slobodrian98eff412017-03-15 14:46:30 -04001133 self.pm_metrics.start_collector(_collect)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001134
Stephane Barbarie35595062018-02-08 08:34:39 -05001135 def stop_kpi_collection(self):
1136 self.pm_metrics.stop_collector()
1137
Nikolay Titov89004ec2017-06-19 18:22:42 -04001138 def get_interface_config(self, data):
1139 interfaceConfig = InterfaceConfig()
1140 if isinstance(data, ChannelgroupConfig):
1141 interfaceConfig.channel_group_config.CopyFrom(data)
1142 elif isinstance(data, ChannelpartitionConfig):
1143 interfaceConfig.channel_partition_config.CopyFrom(data)
1144 elif isinstance(data, ChannelpairConfig):
1145 interfaceConfig.channel_pair_config.CopyFrom(data)
1146 elif isinstance(data, ChannelterminationConfig):
1147 interfaceConfig.channel_termination_config.CopyFrom(data)
1148 elif isinstance(data, OntaniConfig):
1149 interfaceConfig.ont_ani_config.CopyFrom(data)
1150 elif isinstance(data, VOntaniConfig):
1151 interfaceConfig.vont_ani_config.CopyFrom(data)
1152 elif isinstance(data, VEnetConfig):
1153 interfaceConfig.venet_config.CopyFrom(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001154 elif isinstance(data, TrafficDescriptorProfileData):
1155 interfaceConfig.traffic_descriptor_profile_config_data.CopyFrom(
1156 data)
1157 elif isinstance(data, TcontsConfigData):
1158 interfaceConfig.tconts_config_data.CopyFrom(data)
1159 elif isinstance(data, GemportsConfigData):
1160 interfaceConfig.gemports_config_data.CopyFrom(data)
1161 elif isinstance(data, MulticastGemportsConfigData):
1162 interfaceConfig.multicast_gemports_config_data.CopyFrom(data)
1163 elif isinstance(data, MulticastDistributionSetData):
1164 interfaceConfig.multicast_distribution_set_data.CopyFrom(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001165 else:
1166 return None
1167 return interfaceConfig
1168
Nikolay Titov176f1db2017-08-10 12:38:43 -04001169 def xpon_ponsim_olt_interface(self, method_name, data, data2=None):
Nikolay Titov89004ec2017-06-19 18:22:42 -04001170 interfaceConfig = self.get_interface_config(data)
1171 if interfaceConfig is not None:
Nikolay Titov176f1db2017-08-10 12:38:43 -04001172 self.log.info(
1173 'forwarding-{}-request-to-olt-for-interface-type'
khenaidoof3593a82018-06-01 16:41:31 -04001174 .format(self.xpon_ponsim_olt_itfs[method_name]['log']),
Nikolay Titov176f1db2017-08-10 12:38:43 -04001175 interface_type=type(data))
Scott Bakerd865fa22018-11-07 11:45:28 -08001176 stub = ponsim_pb2_grpc.XPonSimStub(self.get_channel())
Nikolay Titov176f1db2017-08-10 12:38:43 -04001177 _method = getattr(
1178 stub, self.xpon_ponsim_olt_itfs[method_name]['method_name'])
1179 if isinstance(data, TcontsConfigData):
1180 tcont_config = TcontInterfaceConfig()
1181 tcont_config.tconts_config_data.CopyFrom(data)
1182 tcont_config.traffic_descriptor_profile_config_data.CopyFrom(
1183 data2)
1184 _method(tcont_config)
1185 else:
1186 _method(interfaceConfig)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001187 self.log.info('success')
1188
Nikolay Titov176f1db2017-08-10 12:38:43 -04001189 def create_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001190 _method_name = sys._getframe().f_code.co_name
1191 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001192
Nikolay Titov89004ec2017-06-19 18:22:42 -04001193 def update_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001194 _method_name = sys._getframe().f_code.co_name
1195 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov89004ec2017-06-19 18:22:42 -04001196
1197 def remove_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001198 _method_name = sys._getframe().f_code.co_name
1199 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001200
1201 def create_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001202 _method_name = sys._getframe().f_code.co_name
1203 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1204 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001205
1206 def update_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001207 _method_name = sys._getframe().f_code.co_name
1208 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1209 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001210
1211 def remove_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001212 _method_name = sys._getframe().f_code.co_name
1213 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1214 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001215
1216 def create_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001217 _method_name = sys._getframe().f_code.co_name
1218 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001219
1220 def update_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001221 _method_name = sys._getframe().f_code.co_name
1222 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001223
1224 def remove_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001225 _method_name = sys._getframe().f_code.co_name
1226 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001227
1228 def create_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001229 _method_name = sys._getframe().f_code.co_name
1230 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001231
1232 def update_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001233 _method_name = sys._getframe().f_code.co_name
1234 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001235
1236 def remove_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001237 _method_name = sys._getframe().f_code.co_name
1238 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001239
1240 def create_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001241 _method_name = sys._getframe().f_code.co_name
1242 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001243
1244 def update_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001245 _method_name = sys._getframe().f_code.co_name
1246 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001247
1248 def remove_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001249 _method_name = sys._getframe().f_code.co_name
1250 self.xpon_ponsim_olt_interface(_method_name, data);
Scott Baker50873cc2018-09-21 18:14:09 -07001251
1252 def simulate_alarm(self, alarm):
1253 # Ponsim_olt implements its own AdapterAlarms class, rather than using the Voltha alarm extension. Until that
1254 # has been reconciled, temporarily instantiate the Voltha alarm extension's AdapterAlarms here, for the
1255 # purpose of sending simulated alarms.
1256 alarms = VolthaAdapterAlarms(self.adapter_agent, self.device_id, self.logical_device_id)
1257 simulator = AdapterAlarmSimulator(alarms)
1258 simulator.simulate_alarm(alarm)