blob: 2c329046f2a4346e5e39a8263ab43877612ea290 [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 Bavierf365ea32019-05-30 16:40:50 -070029import hashlib
Andy Bavier904efcf2019-04-01 16:50:34 -070030from scapy.layers.l2 import Ether, Dot1Q, Dot1AD
Gamze Abaka53cc0a22019-01-31 12:06:11 +000031from scapy.layers.inet import IP, Raw
Stephane Barbarie35595062018-02-08 08:34:39 -050032from twisted.internet import reactor
Khen Nursimulud068d812017-03-06 11:44:18 -050033from twisted.internet.defer import inlineCallbacks
Stephane Barbarie35595062018-02-08 08:34:39 -050034from grpc._channel import _Rendezvous
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080035
36from common.frameio.frameio import BpfProgramFilter, hexify
Khen Nursimulud068d812017-03-06 11:44:18 -050037from common.utils.asleep import asleep
Sergio Slobodrian98eff412017-03-15 14:46:30 -040038from twisted.internet.task import LoopingCall
Shad Ansarid1aa9e72017-06-23 21:34:25 -070039from voltha.adapters.iadapter import OltAdapter
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080040from voltha.core.logical_device_agent import mac_str_to_tuple
41from voltha.protos import third_party
Jeff55a2f132018-08-05 21:10:41 -070042from voltha.protos import openflow_13_pb2 as ofp
Scott Bakerd865fa22018-11-07 11:45:28 -080043from voltha.protos import ponsim_pb2, ponsim_pb2_grpc
Shad Ansari14bcd992017-06-13 14:27:20 -070044from voltha.protos.common_pb2 import OperStatus, ConnectStatus, AdminState
Scott Baker50873cc2018-09-21 18:14:09 -070045from voltha.protos.common_pb2 import OperationResp
Shad Ansari14bcd992017-06-13 14:27:20 -070046from voltha.protos.device_pb2 import Port, Device, PmConfig, PmConfigs
Sergio Slobodrian98eff412017-03-15 14:46:30 -040047from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080048from google.protobuf.empty_pb2 import Empty
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080049from voltha.protos.logical_device_pb2 import LogicalPort, LogicalDevice
Stephane Barbarie5253c652017-03-22 16:29:46 -040050from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
51 OFPPF_1GB_FD, \
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080052 OFPC_GROUP_STATS, OFPC_PORT_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS, \
53 ofp_switch_features, ofp_desc
54from voltha.protos.openflow_13_pb2 import ofp_port
Scott Bakerb5be94d2018-10-09 16:13:32 -070055from voltha.protos.ponsim_pb2 import FlowTable, PonSimFrame, PonSimMetricsRequest
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080056from voltha.registry import registry
57
Nikolay Titov89004ec2017-06-19 18:22:42 -040058from voltha.protos.bbf_fiber_base_pb2 import \
khenaidoof3593a82018-06-01 16:41:31 -040059 ChannelgroupConfig, ChannelpartitionConfig, ChannelpairConfig, \
Nikolay Titov176f1db2017-08-10 12:38:43 -040060 ChannelterminationConfig, OntaniConfig, VOntaniConfig, VEnetConfig
61from voltha.protos.bbf_fiber_traffic_descriptor_profile_body_pb2 import \
62 TrafficDescriptorProfileData
63from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
64from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
65from voltha.protos.bbf_fiber_multicast_gemport_body_pb2 import \
66 MulticastGemportsConfigData
Stephane Barbarie35595062018-02-08 08:34:39 -050067
Nikolay Titov176f1db2017-08-10 12:38:43 -040068from voltha.protos.bbf_fiber_multicast_distribution_set_body_pb2 import \
69 MulticastDistributionSetData
Nikolay Titov89004ec2017-06-19 18:22:42 -040070
Nikolay Titov176f1db2017-08-10 12:38:43 -040071from voltha.protos.ponsim_pb2 import InterfaceConfig, TcontInterfaceConfig
Nikolay Titov89004ec2017-06-19 18:22:42 -040072
Scott Baker50873cc2018-09-21 18:14:09 -070073from voltha.extensions.alarms.adapter_alarms import AdapterAlarms as VolthaAdapterAlarms
74from voltha.extensions.alarms.simulator.simulate_alarms import AdapterAlarmSimulator
75
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080076_ = third_party
77log = structlog.get_logger()
78
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080079PACKET_IN_VLAN = 4000
80is_inband_frame = BpfProgramFilter('(ether[14:2] & 0xfff) = 0x{:03x}'.format(
81 PACKET_IN_VLAN))
82
Andy Bavier97566512018-11-14 16:17:41 -070083EAP_ETH_TYPE = 0x888e
84
85# Classifier
86ETH_TYPE = 'eth_type'
87TPID = 'tpid'
88IP_PROTO = 'ip_proto'
89IN_PORT = 'in_port'
90VLAN_VID = 'vlan_vid'
91VLAN_PCP = 'vlan_pcp'
92UDP_DST = 'udp_dst'
93UDP_SRC = 'udp_src'
94IPV4_DST = 'ipv4_dst'
95IPV4_SRC = 'ipv4_src'
96METADATA = 'metadata'
97OUTPUT = 'output'
Stephane Barbarie5253c652017-03-22 16:29:46 -040098
Sergio Slobodrian98eff412017-03-15 14:46:30 -040099class AdapterPmMetrics:
Stephane Barbarie5253c652017-03-22 16:29:46 -0400100 def __init__(self, device):
Sergio Slobodrianec6e3912017-04-02 11:46:55 -0400101 self.pm_names = {'tx_64_pkts', 'tx_65_127_pkts', 'tx_128_255_pkts',
102 'tx_256_511_pkts', 'tx_512_1023_pkts',
103 'tx_1024_1518_pkts', 'tx_1519_9k_pkts',
104 'rx_64_pkts', 'rx_65_127_pkts',
105 'rx_128_255_pkts', 'rx_256_511_pkts',
106 'rx_512_1023_pkts', 'rx_1024_1518_pkts',
107 'rx_1519_9k_pkts'}
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400108 self.device = device
109 self.id = device.id
110 self.name = 'ponsim_olt'
Stephane Barbarie5253c652017-03-22 16:29:46 -0400111 # self.id = "abc"
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400112 self.default_freq = 150
113 self.grouped = False
114 self.freq_override = False
115 self.pon_metrics_config = dict()
116 self.nni_metrics_config = dict()
117 self.lc = None
118 for m in self.pm_names:
119 self.pon_metrics_config[m] = PmConfig(name=m,
120 type=PmConfig.COUNTER,
121 enabled=True)
122 self.nni_metrics_config[m] = PmConfig(name=m,
123 type=PmConfig.COUNTER,
124 enabled=True)
125
126 def update(self, pm_config):
127 if self.default_freq != pm_config.default_freq:
128 # Update the callback to the new frequency.
129 self.default_freq = pm_config.default_freq
130 self.lc.stop()
Stephane Barbarie5253c652017-03-22 16:29:46 -0400131 self.lc.start(interval=self.default_freq / 10)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400132 for m in pm_config.metrics:
133 self.pon_metrics_config[m.name].enabled = m.enabled
134 self.nni_metrics_config[m.name].enabled = m.enabled
135
136 def make_proto(self):
137 pm_config = PmConfigs(
138 id=self.id,
139 default_freq=self.default_freq,
Stephane Barbarie5253c652017-03-22 16:29:46 -0400140 grouped=False,
141 freq_override=False)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400142 for m in sorted(self.pon_metrics_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400143 pm = self.pon_metrics_config[m] # Either will do they're the same
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400144 pm_config.metrics.extend([PmConfig(name=pm.name,
145 type=pm.type,
146 enabled=pm.enabled)])
147 return pm_config
148
149 def collect_port_metrics(self, channel):
150 rtrn_port_metrics = dict()
Scott Bakerd865fa22018-11-07 11:45:28 -0800151 stub = ponsim_pb2_grpc.PonSimStub(channel)
Scott Bakerb5be94d2018-10-09 16:13:32 -0700152 stats = stub.GetStats(ponsim_pb2.PonSimMetricsRequest(port=0))
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400153 rtrn_port_metrics['pon'] = self.extract_pon_metrics(stats)
154 rtrn_port_metrics['nni'] = self.extract_nni_metrics(stats)
155 return rtrn_port_metrics
156
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400157 def extract_pon_metrics(self, stats):
158 rtrn_pon_metrics = dict()
159 for m in stats.metrics:
160 if m.port_name == "pon":
161 for p in m.packets:
162 if self.pon_metrics_config[p.name].enabled:
163 rtrn_pon_metrics[p.name] = p.value
164 return rtrn_pon_metrics
165
166 def extract_nni_metrics(self, stats):
167 rtrn_pon_metrics = dict()
168 for m in stats.metrics:
169 if m.port_name == "nni":
170 for p in m.packets:
171 if self.pon_metrics_config[p.name].enabled:
172 rtrn_pon_metrics[p.name] = p.value
173 return rtrn_pon_metrics
174
175 def start_collector(self, callback):
176 log.info("starting-pm-collection", device_name=self.name,
177 device_id=self.device.id)
178 prefix = 'voltha.{}.{}'.format(self.name, self.device.id)
179 self.lc = LoopingCall(callback, self.device.id, prefix)
Stephane Barbarie5253c652017-03-22 16:29:46 -0400180 self.lc.start(interval=self.default_freq / 10)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400181
Stephane Barbarie35595062018-02-08 08:34:39 -0500182 def stop_collector(self):
183 log.info("stopping-pm-collection", device_name=self.name,
184 device_id=self.device.id)
185 self.lc.stop()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800186
khenaidoof3593a82018-06-01 16:41:31 -0400187
Stephane Barbarie4475a252017-03-31 13:49:20 -0400188class AdapterAlarms:
189 def __init__(self, adapter, device):
190 self.adapter = adapter
191 self.device = device
192 self.lc = None
193
194 def send_alarm(self, context_data, alarm_data):
195 try:
196 current_context = {}
197 for key, value in context_data.__dict__.items():
198 current_context[key] = str(value)
199
200 alarm_event = self.adapter.adapter_agent.create_alarm(
201 resource_id=self.device.id,
khenaidoo032d3302017-06-09 14:50:04 -0400202 description="{}.{} - {}".format(self.adapter.name,
203 self.device.id,
204 alarm_data[
205 'description']) if 'description' in alarm_data else None,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400206 type=alarm_data['type'] if 'type' in alarm_data else None,
khenaidoo032d3302017-06-09 14:50:04 -0400207 category=alarm_data[
208 'category'] if 'category' in alarm_data else None,
209 severity=alarm_data[
210 'severity'] if 'severity' in alarm_data else None,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400211 state=alarm_data['state'] if 'state' in alarm_data else None,
212 raised_ts=alarm_data['ts'] if 'ts' in alarm_data else 0,
213 context=current_context
214 )
215
khenaidoo032d3302017-06-09 14:50:04 -0400216 self.adapter.adapter_agent.submit_alarm(self.device.id,
217 alarm_event)
Stephane Barbarie4475a252017-03-31 13:49:20 -0400218
219 except Exception as e:
220 log.exception('failed-to-send-alarm', e=e)
221
khenaidoof3593a82018-06-01 16:41:31 -0400222
Shad Ansarid1aa9e72017-06-23 21:34:25 -0700223class PonSimOltAdapter(OltAdapter):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800224 def __init__(self, adapter_agent, config):
Shad Ansari14bcd992017-06-13 14:27:20 -0700225 super(PonSimOltAdapter, self).__init__(adapter_agent=adapter_agent,
226 config=config,
Shad Ansari96f817b2017-06-18 23:17:44 -0700227 device_handler_class=PonSimOltHandler,
Shad Ansari14bcd992017-06-13 14:27:20 -0700228 name='ponsim_olt',
229 vendor='Voltha project',
Nikolay Titov89004ec2017-06-19 18:22:42 -0400230 version='0.4',
khenaidoof3593a82018-06-01 16:41:31 -0400231 device_type='ponsim_olt',
232 accepts_bulk_flow_update=True,
233 accepts_add_remove_flow_updates=False)
Shad Ansari96f817b2017-06-18 23:17:44 -0700234
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400235 def update_pm_config(self, device, pm_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400236 log.info("adapter-update-pm-config", device=device,
237 pm_config=pm_config)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400238 handler = self.devices_handlers[device.id]
239 handler.update_pm_config(device, pm_config)
Sergio Slobodrianec864c62017-03-09 11:41:43 -0500240
Nikolay Titov89004ec2017-06-19 18:22:42 -0400241 def create_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400242 if super(PonSimOltAdapter, self)._get_handler(device):
243 log.info('create-interface', device_id=device.id)
244 self.devices_handlers[device.id].create_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400245
246 def update_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400247 if super(PonSimOltAdapter, self)._get_handler(device):
248 log.info('update-interface', device_id=device.id)
249 self.devices_handlers[device.id].update_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400250
251 def remove_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400252 if super(PonSimOltAdapter, self)._get_handler(device):
253 log.info('remove-interface', device_id=device.id)
254 self.devices_handlers[device.id].remove_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400255
Nikolay Titov176f1db2017-08-10 12:38:43 -0400256 def create_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400257 if super(PonSimOltAdapter, self)._get_handler(device):
258 log.info('create-tcont', device_id=device.id)
259 self.devices_handlers[device.id].create_tcont(
260 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400261
262 def update_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400263 if super(PonSimOltAdapter, self)._get_handler(device):
264 log.info('update-tcont', device_id=device.id)
265 self.devices_handlers[device.id].update_tcont(
266 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400267
268 def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400269 if super(PonSimOltAdapter, self)._get_handler(device):
270 log.info('remove-tcont', device_id=device.id)
271 self.devices_handlers[device.id].remove_tcont(
272 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400273
274 def create_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400275 if super(PonSimOltAdapter, self)._get_handler(device):
276 log.info('create-gemport', device_id=device.id)
277 self.devices_handlers[device.id].create_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400278
279 def update_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400280 if super(PonSimOltAdapter, self)._get_handler(device):
281 log.info('update-gemport', device_id=device.id)
282 self.devices_handlers[device.id].update_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400283
284 def remove_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400285 if super(PonSimOltAdapter, self)._get_handler(device):
286 log.info('remove-gemport', device_id=device.id)
287 self.devices_handlers[device.id].remove_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400288
289 def create_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400290 if super(PonSimOltAdapter, self)._get_handler(device):
291 log.info('create-multicast-gemport', device_id=device.id)
292 self.devices_handlers[device.id].create_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400293
294 def update_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400295 if super(PonSimOltAdapter, self)._get_handler(device):
296 log.info('update-multicast-gemport', device_id=device.id)
297 self.devices_handlers[device.id].update_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400298
299 def remove_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400300 if super(PonSimOltAdapter, self)._get_handler(device):
301 log.info('remove-multicast-gemport', device_id=device.id)
302 self.devices_handlers[device.id].remove_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400303
304 def create_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400305 if super(PonSimOltAdapter, self)._get_handler(device):
306 log.info('create-multicast-distribution-set', device_id=device.id)
307 self.devices_handlers[device.id].create_multicast_distribution_set(
308 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400309
310 def update_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400311 if super(PonSimOltAdapter, self)._get_handler(device):
312 log.info('update-multicast-distribution-set', device_id=device.id)
313 self.devices_handlers[device.id].update_multicast_distribution_set(
314 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400315
316 def remove_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400317 if super(PonSimOltAdapter, self)._get_handler(device):
318 log.info('remove-multicast-distribution-set', device_id=device.id)
319 self.devices_handlers[device.id].remove_multicast_distribution_set(
320 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400321
Scott Baker50873cc2018-09-21 18:14:09 -0700322 def simulate_alarm(self, device, alarm):
323 handler = self.devices_handlers[device.id]
324 handler.simulate_alarm(alarm)
325 return OperationResp(code=OperationResp.OPERATION_SUCCESS)
khenaidoof3593a82018-06-01 16:41:31 -0400326
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800327class PonSimOltHandler(object):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400328 xpon_ponsim_olt_itfs = {
329 'create_interface': {
330 'method_name': 'CreateInterface',
331 'log': 'create-interface'},
332 'update_interface': {
333 'method_name': 'UpdateInterface',
334 'log': 'update-interface'},
335 'remove_interface': {
336 'method_name': 'RemoveInterface',
337 'log': 'remove-interface'},
338 'create_tcont': {
339 'method_name': 'CreateTcont',
340 'log': 'create-tconts-config-data'},
341 'update_tcont': {
342 'method_name': 'UpdateTcont',
343 'log': 'update-tconts-config-data'},
344 'remove_tcont': {
345 'method_name': 'RemoveTcont',
346 'log': 'remove-tconts-config-data'},
347 'create_gemport': {
348 'method_name': 'CreateGemport',
349 'log': 'create-gemports-config-data'},
350 'update_gemport': {
351 'method_name': 'UpdateGemport',
352 'log': 'update-gemports-config-data'},
353 'remove_gemport': {
354 'method_name': 'RemoveGemport',
355 'log': 'remove-gemports-config-data'},
356 'create_multicast_gemport': {
357 'method_name': 'CreateMulticastGemport',
358 'log': 'create-multicast-gemports-config-data'},
359 'update_multicast_gemport': {
360 'method_name': 'UpdateMulticastGemport',
361 'log': 'update-multicast-gemports-config-data'},
362 'remove_multicast_gemport': {
363 'method_name': 'RemoveMulticastGemport',
364 'log': 'remove-multicast-gemports-config-data'},
365 'create_multicast_distribution_set': {
366 'method_name': 'CreateMulticastDistributionSet',
367 'log': 'create-multicast-distribution-set-data'},
368 'update_multicast_distribution_set': {
369 'method_name': 'UpdateMulticastDistributionSet',
370 'log': 'update-multicast-distribution-set-data'},
371 'remove_multicast_distribution_set': {
372 'method_name': 'RemoveMulticastDistributionSet',
373 'log': 'remove-multicast-distribution-set-data'},
khenaidoof3593a82018-06-01 16:41:31 -0400374 }
Nikolay Titov176f1db2017-08-10 12:38:43 -0400375
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800376 def __init__(self, adapter, device_id):
377 self.adapter = adapter
378 self.adapter_agent = adapter.adapter_agent
379 self.device_id = device_id
380 self.log = structlog.get_logger(device_id=device_id)
381 self.channel = None
382 self.io_port = None
383 self.logical_device_id = None
Khen Nursimulud068d812017-03-06 11:44:18 -0500384 self.nni_port = None
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400385 self.ofp_port_no = None
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800386 self.interface = registry('main').get_args().interface
Stephane Barbarie35595062018-02-08 08:34:39 -0500387 self.ponsim_comm = registry('main').get_args().ponsim_comm
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400388 self.pm_metrics = None
Stephane Barbarie4475a252017-03-31 13:49:20 -0400389 self.alarms = None
Stephane Barbarie35595062018-02-08 08:34:39 -0500390 self.frames = None
Andy Bavier97566512018-11-14 16:17:41 -0700391 self.uni_ports = []
392 self.ctag_map = {}
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800393
394 def __del__(self):
395 if self.io_port is not None:
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800396 registry('frameio').close_port(self.io_port)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800397
398 def get_channel(self):
399 if self.channel is None:
400 device = self.adapter_agent.get_device(self.device_id)
schowdhury9e247752017-07-14 06:56:20 -0700401
Jeff70e8b2d2018-07-24 13:37:29 -0700402 self.channel = grpc.insecure_channel(device.host_and_port)
schowdhury9e247752017-07-14 06:56:20 -0700403
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800404 return self.channel
405
Stephane Barbarie35595062018-02-08 08:34:39 -0500406 def close_channel(self):
407 if self.channel is None:
408 self.log.info('grpc-channel-already-closed')
409 return
410 else:
411 if self.frames is not None:
412 self.frames.cancel()
413 self.frames = None
414 self.log.info('cancelled-grpc-frame-stream')
415
416 self.channel.unsubscribe(lambda *args: None)
417 self.channel = None
418
419 self.log.info('grpc-channel-closed')
420
khenaidoo032d3302017-06-09 14:50:04 -0400421 def _get_nni_port(self):
422 ports = self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_NNI)
423 if ports:
424 # For now, we use on one NNI port
425 return ports[0]
426
Andy Bavierf365ea32019-05-30 16:40:50 -0700427 # Generate a MAC address based on OLT serial_number (i.e., host_and_port)
428 # An example of calculating the same value in the shell:
429 # $ echo -ne olt0.voltha.svc:50060 | md5sum | cut -c -12
430 def get_mac_address(self, device):
431 hexdig = hashlib.md5(device.serial_number).hexdigest()
432 mac_address = "%s:%s:%s:%s:%s:%s" % (hexdig[0:2], hexdig[2:4], hexdig[4:6], hexdig[6:8], hexdig[8:10], hexdig[10:12])
433 log.info("generated-mac-address", mac_address=mac_address, serial_number=device.serial_number)
434 return mac_address
435
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800436 def activate(self, device):
437 self.log.info('activating')
438
439 if not device.host_and_port:
440 device.oper_status = OperStatus.FAILED
441 device.reason = 'No host_and_port field provided'
442 self.adapter_agent.update_device(device)
443 return
444
Scott Bakerd865fa22018-11-07 11:45:28 -0800445 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800446 info = stub.GetDeviceInfo(Empty())
447 log.info('got-info', info=info)
448
449 device.root = True
450 device.vendor = 'ponsim'
Stephane Barbarie5253c652017-03-22 16:29:46 -0400451 device.model = 'n/a'
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800452 device.serial_number = device.host_and_port
453 device.connect_status = ConnectStatus.REACHABLE
454 self.adapter_agent.update_device(device)
455
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400456 # Now set the initial PM configuration for this device
Stephane Barbarie5253c652017-03-22 16:29:46 -0400457 self.pm_metrics = AdapterPmMetrics(device)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400458 pm_config = self.pm_metrics.make_proto()
459 log.info("initial-pm-config", pm_config=pm_config)
Stephane Barbarie5253c652017-03-22 16:29:46 -0400460 self.adapter_agent.update_device_pm_config(pm_config, init=True)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400461
Stephane Barbarie4475a252017-03-31 13:49:20 -0400462 # Setup alarm handler
463 self.alarms = AdapterAlarms(self.adapter, device)
464
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800465 nni_port = Port(
Jonathan Hart32fe8812018-08-21 17:10:12 -0700466 port_no=info.nni_port,
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800467 label='NNI facing Ethernet port',
468 type=Port.ETHERNET_NNI,
469 admin_state=AdminState.ENABLED,
470 oper_status=OperStatus.ACTIVE
471 )
Khen Nursimulud068d812017-03-06 11:44:18 -0500472 self.nni_port = nni_port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800473 self.adapter_agent.add_port(device.id, nni_port)
474 self.adapter_agent.add_port(device.id, Port(
475 port_no=1,
476 label='PON port',
477 type=Port.PON_OLT,
478 admin_state=AdminState.ENABLED,
479 oper_status=OperStatus.ACTIVE
480 ))
481
482 ld = LogicalDevice(
khenaidoo507d9222017-10-10 16:23:49 -0400483 # not setting id and datapath_id. Adapter agent will pick the id
484 # and will pick the datapath_id is it is not provided
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800485 desc=ofp_desc(
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800486 hw_desc='simualted pon',
487 sw_desc='simualted pon',
khenaidoof3593a82018-06-01 16:41:31 -0400488 # serial_num=uuid4().hex,
Jonathan Hart32fe8812018-08-21 17:10:12 -0700489 serial_num=device.serial_number,
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800490 dp_desc='n/a'
491 ),
492 switch_features=ofp_switch_features(
493 n_buffers=256, # TODO fake for now
494 n_tables=2, # TODO ditto
495 capabilities=( # TODO and ditto
khenaidoof3593a82018-06-01 16:41:31 -0400496 OFPC_FLOW_STATS
497 | OFPC_TABLE_STATS
498 | OFPC_PORT_STATS
499 | OFPC_GROUP_STATS
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800500 )
501 ),
502 root_device_id=device.id
503 )
Andy Bavierf365ea32019-05-30 16:40:50 -0700504
505 mac_address = self.get_mac_address(device)
khenaidoo507d9222017-10-10 16:23:49 -0400506 ld_initialized = self.adapter_agent.create_logical_device(ld,
507 dpid=mac_address)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800508 cap = OFPPF_1GB_FD | OFPPF_FIBER
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400509 self.ofp_port_no = info.nni_port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800510 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
511 id='nni',
512 ofp_port=ofp_port(
513 port_no=info.nni_port,
Stephane Barbarie5253c652017-03-22 16:29:46 -0400514 hw_addr=mac_str_to_tuple(
515 '00:00:00:00:00:%02x' % info.nni_port),
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800516 name='nni',
517 config=0,
518 state=OFPPS_LIVE,
519 curr=cap,
520 advertised=cap,
521 peer=cap,
522 curr_speed=OFPPF_1GB_FD,
523 max_speed=OFPPF_1GB_FD
524 ),
525 device_id=device.id,
526 device_port_no=nni_port.port_no,
527 root_port=True
528 ))
529
530 device = self.adapter_agent.get_device(device.id)
531 device.parent_id = ld_initialized.id
532 device.oper_status = OperStatus.ACTIVE
533 self.adapter_agent.update_device(device)
534 self.logical_device_id = ld_initialized.id
535
Andy Bavierea82b462018-07-27 16:48:13 -0700536 # register ONUS
537 for onu in info.onus:
538 vlan_id = onu.uni_port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800539 self.adapter_agent.child_device_detected(
540 parent_device_id=device.id,
541 parent_port_no=1,
Niren R Chidrawarefcebcd2017-07-19 20:03:39 -0400542 child_device_type='ponsim_onu',
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800543 proxy_address=Device.ProxyAddress(
544 device_id=device.id,
545 channel_id=vlan_id
546 ),
Nikolay Titov89004ec2017-06-19 18:22:42 -0400547 admin_state=AdminState.ENABLED,
Andy Bavierea82b462018-07-27 16:48:13 -0700548 vlan=vlan_id,
549 serial_number=onu.serial_number
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800550 )
Andy Bavier97566512018-11-14 16:17:41 -0700551 self.uni_ports.append(int(onu.uni_port))
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800552
Stephane Barbarie35595062018-02-08 08:34:39 -0500553 if self.ponsim_comm == 'grpc':
554 self.log.info('starting-frame-grpc-stream')
555 reactor.callInThread(self.rcv_grpc)
556 self.log.info('started-frame-grpc-stream')
557 else:
558 # finally, open the frameio port to receive in-band packet_in messages
559 self.log.info('registering-frameio')
560 self.io_port = registry('frameio').open_port(
561 self.interface, self.rcv_io, is_inband_frame)
562 self.log.info('registered-frameio')
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800563
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400564 # Start collecting stats from the device after a brief pause
565 self.start_kpi_collection(device.id)
566
khenaidoo032d3302017-06-09 14:50:04 -0400567 def reconcile(self, device):
568 self.log.info('reconciling-OLT-device-starts')
569
570 if not device.host_and_port:
571 device.oper_status = OperStatus.FAILED
572 device.reason = 'No host_and_port field provided'
573 self.adapter_agent.update_device(device)
574 return
575
576 try:
Scott Bakerd865fa22018-11-07 11:45:28 -0800577 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
khenaidoo032d3302017-06-09 14:50:04 -0400578 info = stub.GetDeviceInfo(Empty())
579 log.info('got-info', info=info)
580 # TODO: Verify we are connected to the same device we are
581 # reconciling - not much data in ponsim to differentiate at the
582 # time
583 device.oper_status = OperStatus.ACTIVE
584 self.adapter_agent.update_device(device)
585 self.ofp_port_no = info.nni_port
586 self.nni_port = self._get_nni_port()
587 except Exception, e:
588 log.exception('device-unreachable', e=e)
589 device.connect_status = ConnectStatus.UNREACHABLE
590 device.oper_status = OperStatus.UNKNOWN
591 self.adapter_agent.update_device(device)
592 return
593
594 # Now set the initial PM configuration for this device
595 self.pm_metrics = AdapterPmMetrics(device)
596 pm_config = self.pm_metrics.make_proto()
597 log.info("initial-pm-config", pm_config=pm_config)
598 self.adapter_agent.update_device_pm_config(pm_config, init=True)
599
600 # Setup alarm handler
601 self.alarms = AdapterAlarms(self.adapter, device)
602
603 # TODO: Is there anything required to verify nni and PON ports
604
605 # Set the logical device id
606 device = self.adapter_agent.get_device(device.id)
607 if device.parent_id:
608 self.logical_device_id = device.parent_id
609 self.adapter_agent.reconcile_logical_device(device.parent_id)
610 else:
611 self.log.info('no-logical-device-set')
612
613 # Reconcile child devices
614 self.adapter_agent.reconcile_child_devices(device.id)
615
Stephane Barbarie35595062018-02-08 08:34:39 -0500616 if self.ponsim_comm == 'grpc':
617 reactor.callInThread(self.rcv_grpc)
618 else:
619 # finally, open the frameio port to receive in-band packet_in messages
620 self.io_port = registry('frameio').open_port(
621 self.interface, self.rcv_io, is_inband_frame)
khenaidoo032d3302017-06-09 14:50:04 -0400622
623 # Start collecting stats from the device after a brief pause
624 self.start_kpi_collection(device.id)
625
626 self.log.info('reconciling-OLT-device-ends')
627
Stephane Barbarie35595062018-02-08 08:34:39 -0500628 def _rcv_frame(self, frame):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800629 pkt = Ether(frame)
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000630 self.log.info('received packet', pkt=pkt)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800631 if pkt.haslayer(Dot1Q):
Andy Bavier904efcf2019-04-01 16:50:34 -0700632 if pkt.haslayer(Dot1AD):
633 outer_shim = pkt.getlayer(Dot1AD)
634 else:
635 outer_shim = pkt.getlayer(Dot1Q)
Stephane Barbarie35595062018-02-08 08:34:39 -0500636
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000637 if pkt.haslayer(IP) or outer_shim.type == EAP_ETH_TYPE:
Andy Bavier904efcf2019-04-01 16:50:34 -0700638 # We don't have any context about the packet at this point.
639 # Assume that only downstream traffic is double-tagged.
640 if isinstance(outer_shim.payload, Dot1Q):
641 logical_port = int(self.nni_port.port_no)
642 else:
643 cvid = outer_shim.vlan
644 logical_port = self.get_subscriber_uni_port(cvid)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800645 popped_frame = (
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000646 Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
647 outer_shim.payload
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800648 )
649 kw = dict(
650 logical_device_id=self.logical_device_id,
651 logical_port_no=logical_port,
652 )
653 self.log.info('sending-packet-in', **kw)
654 self.adapter_agent.send_packet_in(
655 packet=str(popped_frame), **kw)
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000656
Stephane Barbarie4475a252017-03-31 13:49:20 -0400657 elif pkt.haslayer(Raw):
658 raw_data = json.loads(pkt.getlayer(Raw).load)
659 self.alarms.send_alarm(self, raw_data)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800660
Stephane Barbarie35595062018-02-08 08:34:39 -0500661 @inlineCallbacks
662 def rcv_grpc(self):
663 """
664 This call establishes a GRPC stream to receive frames.
665 """
Scott Bakerd865fa22018-11-07 11:45:28 -0800666 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Stephane Barbarie35595062018-02-08 08:34:39 -0500667
668 # Attempt to establish a grpc stream with the remote ponsim service
669 self.frames = stub.ReceiveFrames(Empty())
670
671 self.log.info('start-receiving-grpc-frames')
672
673 try:
674 for frame in self.frames:
khenaidoof3593a82018-06-01 16:41:31 -0400675 self.log.info('received-grpc-frame',
676 frame_len=len(frame.payload))
Stephane Barbarie35595062018-02-08 08:34:39 -0500677 self._rcv_frame(frame.payload)
678
679 except _Rendezvous, e:
khenaidoof3593a82018-06-01 16:41:31 -0400680 log.warn('grpc-connection-lost', message=e.message)
Stephane Barbarie35595062018-02-08 08:34:39 -0500681
682 self.log.info('stopped-receiving-grpc-frames')
683
684 def rcv_io(self, port, frame):
685 self.log.info('received-io-frame', iface_name=port.iface_name,
686 frame_len=len(frame))
687 self._rcv_frame(frame)
688
Andy Bavier97566512018-11-14 16:17:41 -0700689 def to_controller(self, flow):
690 for action in fd.get_actions(flow):
691 if action.type == ofp.OFPAT_OUTPUT:
692 action.output.port = ofp.OFPP_CONTROLLER
693 self.log.info('sending flow to controller')
694
695 # Lookup subscriber ctag for a particular PON port
696 def get_subscriber_ctag(self, flows, port):
697 self.log.debug('looking from subscriber flow for port', port=port)
698
699 for flow in flows:
700 in_port = fd.get_in_port(flow)
701 out_port = fd.get_out_port(flow)
702 if in_port == port and out_port == self.nni_port.port_no:
703 fields = fd.get_ofb_fields(flow)
704 self.log.debug('subscriber flow found', fields=fields)
705 for field in fields:
706 if field.type == fd.VLAN_VID:
707 self.log.debug('subscriber ctag found',
708 vlan_id=field.vlan_vid)
709 return field.vlan_vid & 0x0fff
710 self.log.debug('No subscriber flow found', port=port)
711 return None
712
713 # Lookup UNI port for a particular subscriber ctag
714 def get_subscriber_uni_port(self, ctag):
715 self.log.debug('get_subscriber_uni_port', ctag=ctag, ctag_map=self.ctag_map)
716 c = int(ctag)
717 if c in self.ctag_map:
718 return self.ctag_map[c]
Gamze Abaka53cc0a22019-01-31 12:06:11 +0000719 # return None
720 # HACK: temporarily pass atest
721 return int(128)
Andy Bavier97566512018-11-14 16:17:41 -0700722
723 def clear_ctag_map(self):
724 self.ctag_map = {}
725
726 def update_ctag_map(self, ctag, uni_port):
727 c = int(ctag)
728 u = int(uni_port)
729 if not self.is_uni_port(u):
730 self.log.warning('update_ctag_map: unknown UNI port', uni_port=u)
731 if c in self.ctag_map and self.ctag_map[c] != u:
732 self.log.warning('update_ctag_map: changing UNI port for ctag',
733 ctag=c, old=self.ctag_map[c], new=u)
734 self.ctag_map[c] = u
735
736 # Create a new flow that's a copy of the old flow but change the vlan_vid
737 # Used to create per-subscriber DHCP and EAPOL flows
738 def create_secondary_flow(self, flow, vlan_id):
739 secondary_flow = copy.deepcopy(flow)
740 for field in fd.get_ofb_fields(secondary_flow):
741 if field.type == fd.VLAN_VID:
742 field.vlan_vid = vlan_id | 0x1000
743 return secondary_flow
744
745 def is_uni_port(self, vlan_id):
746 return int(vlan_id) in self.uni_ports
747
748 def create_secondary_flows(self, trapflows, allflows, type):
749 secondary_flows = []
750 for vlan_vid, flow in trapflows.iteritems():
751 if self.is_uni_port(vlan_vid):
752 self.update_ctag_map(vlan_vid, vlan_vid)
753 ctag = self.get_subscriber_ctag(allflows, fd.get_in_port(flow))
754 if ctag is not None:
755 self.update_ctag_map(ctag, vlan_vid)
756 if ctag not in trapflows:
757 self.log.info('add secondary %s flow' % type, ctag=ctag)
758 secondary_flows.append(self.create_secondary_flow(flow, ctag))
759 return secondary_flows
760
Jeff55a2f132018-08-05 21:10:41 -0700761 # VOLTHA's flow decomposition removes the information about which flows
762 # are trap flows where traffic should be forwarded to the controller.
763 # We'll go through the flows and change the output port of flows that we
764 # know to be trap flows to the OF CONTROLLER port.
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800765 def update_flow_table(self, flows):
Scott Bakerd865fa22018-11-07 11:45:28 -0800766 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800767 self.log.info('pushing-olt-flow-table')
Andy Bavier97566512018-11-14 16:17:41 -0700768
769 self.clear_ctag_map()
770 dhcp_upstream_flows = {}
771 eapol_flows = {}
772 secondary_flows = []
Andy Bavier4df0eb42019-04-23 15:54:17 -0700773 eapol_flow_without_vlan = False
Andy Bavier97566512018-11-14 16:17:41 -0700774
Jeff55a2f132018-08-05 21:10:41 -0700775 for flow in flows:
776 classifier_info = {}
777 for field in fd.get_ofb_fields(flow):
778 if field.type == fd.ETH_TYPE:
Andy Bavier97566512018-11-14 16:17:41 -0700779 classifier_info[ETH_TYPE] = field.eth_type
Jeff55a2f132018-08-05 21:10:41 -0700780 elif field.type == fd.IP_PROTO:
Andy Bavier97566512018-11-14 16:17:41 -0700781 classifier_info[IP_PROTO] = field.ip_proto
782 elif field.type == fd.IN_PORT:
783 classifier_info[IN_PORT] = field.port
784 elif field.type == fd.VLAN_VID:
785 classifier_info[VLAN_VID] = field.vlan_vid & 0xfff
786 elif field.type == fd.VLAN_PCP:
787 classifier_info[VLAN_PCP] = field.vlan_pcp
788 elif field.type == fd.UDP_DST:
789 classifier_info[UDP_DST] = field.udp_dst
790 elif field.type == fd.UDP_SRC:
791 classifier_info[UDP_SRC] = field.udp_src
792 elif field.type == fd.IPV4_DST:
793 classifier_info[IPV4_DST] = field.ipv4_dst
794 elif field.type == fd.IPV4_SRC:
795 classifier_info[IPV4_SRC] = field.ipv4_src
796 elif field.type == fd.METADATA:
797 classifier_info[METADATA] = field.table_metadata
798 else:
799 self.log.debug('field-type-unhandled field.type={}'.format(
800 field.type))
801
802 self.log.debug('classifier_info', classifier_info=classifier_info)
803
804 if IP_PROTO in classifier_info:
805 if classifier_info[IP_PROTO] == 17:
806 if UDP_SRC in classifier_info:
807 if classifier_info[UDP_SRC] == 68:
808 self.log.info('dhcp upstream flow add')
809 if VLAN_VID in classifier_info:
810 dhcp_upstream_flows[classifier_info[VLAN_VID]] = flow
811 elif classifier_info[UDP_SRC] == 67:
812 self.log.info('dhcp downstream flow add')
813 self.to_controller(flow)
814 elif classifier_info[IP_PROTO] == 2:
815 self.log.info('igmp flow add')
816 self.to_controller(flow)
817 else:
818 self.log.warn("Invalid-Classifier-to-handle",
819 classifier_info=classifier_info)
820 elif ETH_TYPE in classifier_info:
821 if classifier_info[ETH_TYPE] == EAP_ETH_TYPE:
822 self.log.info('eapol flow add')
823 self.to_controller(flow)
824 if VLAN_VID in classifier_info:
825 eapol_flows[classifier_info[VLAN_VID]] = flow
Andy Bavier4df0eb42019-04-23 15:54:17 -0700826 else:
827 eapol_flow_without_vlan = True
Andy Bavier97566512018-11-14 16:17:41 -0700828
Jeff55a2f132018-08-05 21:10:41 -0700829 self.log.info('out_port', out_port=fd.get_out_port(flow))
830
Andy Bavier97566512018-11-14 16:17:41 -0700831 flows.extend(self.create_secondary_flows(dhcp_upstream_flows, flows, "DHCP"))
832 flows.extend(self.create_secondary_flows(eapol_flows, flows, "EAPOL"))
833
Andy Bavier4df0eb42019-04-23 15:54:17 -0700834 # The OLT app is now adding EAPOL flows with VLAN_VID=4091 but Ponsim can't
835 # properly handle this because it uses VLAN_VID to encode the UNI port ID.
836 # Add an EAPOL trap flow with no VLAN_VID match if we see the 4091 match.
837 if 4091 in eapol_flows and not eapol_flow_without_vlan:
838 new_eapol_flow = [
839 fd.mk_flow_stat(
840 priority=10000,
841 match_fields=[fd.in_port(1), fd.eth_type(EAP_ETH_TYPE)],
842 actions=[fd.output(ofp.OFPP_CONTROLLER)]
843 )
844 ]
845 flows.extend(new_eapol_flow)
846 self.log.info('add eapol flow with no VLAN_VID match')
847
Andy Bavier97566512018-11-14 16:17:41 -0700848 self.log.debug('ctag_map', ctag_map=self.ctag_map)
849
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800850 stub.UpdateFlowTable(FlowTable(
851 port=0,
852 flows=flows
853 ))
854 self.log.info('success')
855
khenaidoof3593a82018-06-01 16:41:31 -0400856 def remove_from_flow_table(self, flows):
857 self.log.debug('remove-from-flow-table', flows=flows)
858 # TODO: Update PONSIM code to accept incremental flow changes
859 # Once completed, the accepts_add_remove_flow_updates for this
860 # device type can be set to True
861
862 def add_to_flow_table(self, flows):
863 self.log.debug('add-to-flow-table', flows=flows)
864 # TODO: Update PONSIM code to accept incremental flow changes
865 # Once completed, the accepts_add_remove_flow_updates for this
866 # device type can be set to True
867
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400868 def update_pm_config(self, device, pm_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400869 log.info("handler-update-pm-config", device=device,
870 pm_config=pm_config)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400871 self.pm_metrics.update(pm_config)
872
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800873 def send_proxied_message(self, proxy_address, msg):
Zack Williams18357ed2018-11-14 10:41:08 -0700874 self.log.debug('sending-proxied-message')
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800875 if isinstance(msg, FlowTable):
Scott Bakerd865fa22018-11-07 11:45:28 -0800876 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800877 self.log.info('pushing-onu-flow-table', port=msg.port)
878 res = stub.UpdateFlowTable(msg)
879 self.adapter_agent.receive_proxied_message(proxy_address, res)
Scott Bakerb5be94d2018-10-09 16:13:32 -0700880 elif isinstance(msg, PonSimMetricsRequest):
Scott Bakerd865fa22018-11-07 11:45:28 -0800881 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Zack Williams18357ed2018-11-14 10:41:08 -0700882 self.log.debug('proxying onu stats request', port=msg.port)
Scott Bakerb5be94d2018-10-09 16:13:32 -0700883 res = stub.GetStats(msg)
884 self.adapter_agent.receive_proxied_message(proxy_address, res)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800885
886 def packet_out(self, egress_port, msg):
Zack Williams18357ed2018-11-14 10:41:08 -0700887 self.log.debug('sending-packet-out', egress_port=egress_port,
888 msg_hex=hexify(msg))
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800889 pkt = Ether(msg)
Jonathan Hart32fe8812018-08-21 17:10:12 -0700890 out_pkt = pkt
Andy Bavier97566512018-11-14 16:17:41 -0700891 self.log.debug("packet_out: incoming: %s" % pkt.summary())
Jonathan Hart32fe8812018-08-21 17:10:12 -0700892 if egress_port != self.nni_port.port_no:
893 # don't do the vlan manipulation for the NNI port, vlans are already correct
Andy Bavier97566512018-11-14 16:17:41 -0700894 if pkt.haslayer(Dot1Q):
Andy Bavier904efcf2019-04-01 16:50:34 -0700895 if pkt.haslayer(Dot1AD):
896 outer_shim = pkt.getlayer(Dot1AD)
897 else:
898 outer_shim = pkt.getlayer(Dot1Q)
899 if isinstance(outer_shim.payload, Dot1Q):
900 # If double tag, remove the outer tag
901 out_pkt = (
902 Ether(src=pkt.src, dst=pkt.dst,
903 type=outer_shim.type) /
904 outer_shim.payload
905 )
906 else:
907 out_pkt = pkt
Andy Bavier97566512018-11-14 16:17:41 -0700908 else:
909 # Add egress port as VLAN tag
910 out_pkt = (
Jonathan Hart32fe8812018-08-21 17:10:12 -0700911 Ether(src=pkt.src, dst=pkt.dst) /
912 Dot1Q(vlan=egress_port, type=pkt.type) /
913 pkt.payload
Andy Bavier97566512018-11-14 16:17:41 -0700914 )
915 self.log.debug("packet_out: outgoing: %s" % out_pkt.summary())
Jonathan Hart32fe8812018-08-21 17:10:12 -0700916
917 # TODO need better way of mapping logical ports to PON ports
918 out_port = self.nni_port.port_no if egress_port == self.nni_port.port_no else 1
Stephane Barbarie35595062018-02-08 08:34:39 -0500919
920 if self.ponsim_comm == 'grpc':
921 # send over grpc stream
Scott Bakerd865fa22018-11-07 11:45:28 -0800922 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
Jonathan Hart32fe8812018-08-21 17:10:12 -0700923 frame = PonSimFrame(id=self.device_id, payload=str(out_pkt), out_port=out_port)
Stephane Barbarie35595062018-02-08 08:34:39 -0500924 stub.SendFrame(frame)
925 else:
926 # send over frameio
927 self.io_port.send(str(out_pkt))
928
Khen Nursimulud068d812017-03-06 11:44:18 -0500929 @inlineCallbacks
930 def reboot(self):
931 self.log.info('rebooting', device_id=self.device_id)
932
933 # Update the operational status to ACTIVATING and connect status to
934 # UNREACHABLE
935 device = self.adapter_agent.get_device(self.device_id)
936 previous_oper_status = device.oper_status
937 previous_conn_status = device.connect_status
938 device.oper_status = OperStatus.ACTIVATING
939 device.connect_status = ConnectStatus.UNREACHABLE
940 self.adapter_agent.update_device(device)
941
khenaidoo71d0a6c2017-03-22 21:46:04 -0400942 # Update the child devices connect state to UNREACHABLE
khenaidoo2d7af132017-03-23 15:45:51 -0400943 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400944 connect_status=ConnectStatus.UNREACHABLE)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400945
Khen Nursimulud068d812017-03-06 11:44:18 -0500946 # Sleep 10 secs, simulating a reboot
Stephane Barbarie5253c652017-03-22 16:29:46 -0400947 # TODO: send alert and clear alert after the reboot
Khen Nursimulud068d812017-03-06 11:44:18 -0500948 yield asleep(10)
949
950 # Change the operational status back to its previous state. With a
951 # real OLT the operational state should be the state the device is
952 # after a reboot.
953 # Get the latest device reference
954 device = self.adapter_agent.get_device(self.device_id)
955 device.oper_status = previous_oper_status
956 device.connect_status = previous_conn_status
957 self.adapter_agent.update_device(device)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400958
959 # Update the child devices connect state to REACHABLE
khenaidoo2d7af132017-03-23 15:45:51 -0400960 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400961 connect_status=ConnectStatus.REACHABLE)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400962
Khen Nursimulud068d812017-03-06 11:44:18 -0500963 self.log.info('rebooted', device_id=self.device_id)
964
sathishg5ae86222017-06-28 15:16:29 +0530965 def self_test_device(self, device):
966 """
967 This is called to Self a device based on a NBI call.
968 :param device: A Voltha.Device object.
969 :return: Will return result of self test
970 """
971 log.info('self-test-device', device=device.id)
972 raise NotImplementedError()
973
Khen Nursimulud068d812017-03-06 11:44:18 -0500974 def disable(self):
975 self.log.info('disabling', device_id=self.device_id)
976
Stephane Barbarie35595062018-02-08 08:34:39 -0500977 self.stop_kpi_collection()
978
Khen Nursimulud068d812017-03-06 11:44:18 -0500979 # Get the latest device reference
980 device = self.adapter_agent.get_device(self.device_id)
981
982 # Update the operational status to UNKNOWN
983 device.oper_status = OperStatus.UNKNOWN
984 device.connect_status = ConnectStatus.UNREACHABLE
985 self.adapter_agent.update_device(device)
986
987 # Remove the logical device
988 logical_device = self.adapter_agent.get_logical_device(
Stephane Barbarie5253c652017-03-22 16:29:46 -0400989 self.logical_device_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500990 self.adapter_agent.delete_logical_device(logical_device)
991
992 # Disable all child devices first
khenaidoo2d7af132017-03-23 15:45:51 -0400993 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400994 admin_state=AdminState.DISABLED)
Khen Nursimulud068d812017-03-06 11:44:18 -0500995
Khen Nursimulud068d812017-03-06 11:44:18 -0500996 # Remove the peer references from this device
997 self.adapter_agent.delete_all_peer_references(self.device_id)
998
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400999 # Set all ports to disabled
1000 self.adapter_agent.disable_all_ports(self.device_id)
1001
Stephane Barbarie35595062018-02-08 08:34:39 -05001002 self.close_channel()
1003 self.log.info('disabled-grpc-channel')
1004
1005 if self.ponsim_comm == 'frameio':
1006 # close the frameio port
1007 registry('frameio').close_port(self.io_port)
1008 self.log.info('disabled-frameio-port')
Khen Nursimulud068d812017-03-06 11:44:18 -05001009
khenaidoo032d3302017-06-09 14:50:04 -04001010 # Update the logice device mapping
1011 if self.logical_device_id in \
1012 self.adapter.logical_device_id_to_root_device_id:
1013 del self.adapter.logical_device_id_to_root_device_id[
1014 self.logical_device_id]
1015
Khen Nursimulud068d812017-03-06 11:44:18 -05001016 # TODO:
1017 # 1) Remove all flows from the device
1018 # 2) Remove the device from ponsim
1019
1020 self.log.info('disabled', device_id=device.id)
1021
Khen Nursimulud068d812017-03-06 11:44:18 -05001022 def reenable(self):
1023 self.log.info('re-enabling', device_id=self.device_id)
1024
1025 # Get the latest device reference
1026 device = self.adapter_agent.get_device(self.device_id)
1027
khenaidoo032d3302017-06-09 14:50:04 -04001028 # Set the ofp_port_no and nni_port in case we bypassed the reconcile
1029 # process if the device was in DISABLED state on voltha restart
1030 if not self.ofp_port_no and not self.nni_port:
Scott Bakerd865fa22018-11-07 11:45:28 -08001031 stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
khenaidoo032d3302017-06-09 14:50:04 -04001032 info = stub.GetDeviceInfo(Empty())
1033 log.info('got-info', info=info)
1034 self.ofp_port_no = info.nni_port
1035 self.nni_port = self._get_nni_port()
1036
Khen Nursimulud068d812017-03-06 11:44:18 -05001037 # Update the connect status to REACHABLE
1038 device.connect_status = ConnectStatus.REACHABLE
1039 self.adapter_agent.update_device(device)
1040
Khen Nursimuluc60afa12017-03-13 14:33:50 -04001041 # Set all ports to enabled
1042 self.adapter_agent.enable_all_ports(self.device_id)
1043
Khen Nursimulud068d812017-03-06 11:44:18 -05001044 ld = LogicalDevice(
1045 # not setting id and datapth_id will let the adapter agent pick id
1046 desc=ofp_desc(
Khen Nursimulud068d812017-03-06 11:44:18 -05001047 hw_desc='simulated pon',
1048 sw_desc='simulated pon',
1049 serial_num=uuid4().hex,
1050 dp_desc='n/a'
1051 ),
1052 switch_features=ofp_switch_features(
1053 n_buffers=256, # TODO fake for now
1054 n_tables=2, # TODO ditto
1055 capabilities=( # TODO and ditto
khenaidoof3593a82018-06-01 16:41:31 -04001056 OFPC_FLOW_STATS
1057 | OFPC_TABLE_STATS
1058 | OFPC_PORT_STATS
1059 | OFPC_GROUP_STATS
Khen Nursimulud068d812017-03-06 11:44:18 -05001060 )
1061 ),
1062 root_device_id=device.id
1063 )
Andy Bavierf365ea32019-05-30 16:40:50 -07001064
1065 mac_address = self.get_mac_address(device)
khenaidoo507d9222017-10-10 16:23:49 -04001066 ld_initialized = self.adapter_agent.create_logical_device(ld,
1067 dpid=mac_address)
Khen Nursimulud068d812017-03-06 11:44:18 -05001068 cap = OFPPF_1GB_FD | OFPPF_FIBER
1069 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
1070 id='nni',
1071 ofp_port=ofp_port(
Khen Nursimuluc60afa12017-03-13 14:33:50 -04001072 port_no=self.ofp_port_no,
Khen Nursimulud068d812017-03-06 11:44:18 -05001073 hw_addr=mac_str_to_tuple(
Khen Nursimuluc60afa12017-03-13 14:33:50 -04001074 '00:00:00:00:00:%02x' % self.ofp_port_no),
Khen Nursimulud068d812017-03-06 11:44:18 -05001075 name='nni',
1076 config=0,
1077 state=OFPPS_LIVE,
1078 curr=cap,
1079 advertised=cap,
1080 peer=cap,
1081 curr_speed=OFPPF_1GB_FD,
1082 max_speed=OFPPF_1GB_FD
1083 ),
1084 device_id=device.id,
1085 device_port_no=self.nni_port.port_no,
1086 root_port=True
1087 ))
1088
1089 device = self.adapter_agent.get_device(device.id)
1090 device.parent_id = ld_initialized.id
1091 device.oper_status = OperStatus.ACTIVE
1092 self.adapter_agent.update_device(device)
1093 self.logical_device_id = ld_initialized.id
1094
1095 # Reenable all child devices
khenaidoo2d7af132017-03-23 15:45:51 -04001096 self.adapter_agent.update_child_devices_state(device.id,
Stephane Barbarie4475a252017-03-31 13:49:20 -04001097 admin_state=AdminState.ENABLED)
Khen Nursimulud068d812017-03-06 11:44:18 -05001098
Stephane Barbarie35595062018-02-08 08:34:39 -05001099 if self.ponsim_comm == 'grpc':
1100 # establish frame grpc-stream
1101 reactor.callInThread(self.rcv_grpc)
1102 else:
1103 # finally, open the frameio port to receive in-band packet_in messages
1104 self.io_port = registry('frameio').open_port(
1105 self.interface, self.rcv_io, is_inband_frame)
1106
1107 self.start_kpi_collection(device.id)
Khen Nursimulud068d812017-03-06 11:44:18 -05001108
1109 self.log.info('re-enabled', device_id=device.id)
1110
Khen Nursimulud068d812017-03-06 11:44:18 -05001111 def delete(self):
1112 self.log.info('deleting', device_id=self.device_id)
1113
1114 # Remove all child devices
1115 self.adapter_agent.delete_all_child_devices(self.device_id)
1116
Stephane Barbarie35595062018-02-08 08:34:39 -05001117 self.close_channel()
1118 self.log.info('disabled-grpc-channel')
1119
1120 if self.ponsim_comm == 'frameio':
1121 # close the frameio port
1122 registry('frameio').close_port(self.io_port)
1123 self.log.info('disabled-frameio-port')
1124
Khen Nursimulud068d812017-03-06 11:44:18 -05001125 # TODO:
1126 # 1) Remove all flows from the device
1127 # 2) Remove the device from ponsim
1128
1129 self.log.info('deleted', device_id=self.device_id)
Sergio Slobodrian98eff412017-03-15 14:46:30 -04001130
1131 def start_kpi_collection(self, device_id):
1132
1133 def _collect(device_id, prefix):
1134
1135 try:
1136 # Step 1: gather metrics from device
1137 port_metrics = \
Stephane Barbarie5253c652017-03-22 16:29:46 -04001138 self.pm_metrics.collect_port_metrics(self.get_channel())
Sergio Slobodrian98eff412017-03-15 14:46:30 -04001139
1140 # Step 2: prepare the KpiEvent for submission
1141 # we can time-stamp them here (or could use time derived from OLT
1142 ts = arrow.utcnow().timestamp
1143 kpi_event = KpiEvent(
1144 type=KpiEventType.slice,
1145 ts=ts,
1146 prefixes={
1147 # OLT NNI port
1148 prefix + '.nni': MetricValuePairs(
1149 metrics=port_metrics['nni']),
1150 # OLT PON port
1151 prefix + '.pon': MetricValuePairs(
1152 metrics=port_metrics['pon'])
1153 }
1154 )
1155
1156 # Step 3: submit
1157 self.adapter_agent.submit_kpis(kpi_event)
1158
1159 except Exception as e:
1160 log.exception('failed-to-submit-kpis', e=e)
Stephane Barbarie5253c652017-03-22 16:29:46 -04001161
Sergio Slobodrian98eff412017-03-15 14:46:30 -04001162 self.pm_metrics.start_collector(_collect)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001163
Stephane Barbarie35595062018-02-08 08:34:39 -05001164 def stop_kpi_collection(self):
1165 self.pm_metrics.stop_collector()
1166
Nikolay Titov89004ec2017-06-19 18:22:42 -04001167 def get_interface_config(self, data):
1168 interfaceConfig = InterfaceConfig()
1169 if isinstance(data, ChannelgroupConfig):
1170 interfaceConfig.channel_group_config.CopyFrom(data)
1171 elif isinstance(data, ChannelpartitionConfig):
1172 interfaceConfig.channel_partition_config.CopyFrom(data)
1173 elif isinstance(data, ChannelpairConfig):
1174 interfaceConfig.channel_pair_config.CopyFrom(data)
1175 elif isinstance(data, ChannelterminationConfig):
1176 interfaceConfig.channel_termination_config.CopyFrom(data)
1177 elif isinstance(data, OntaniConfig):
1178 interfaceConfig.ont_ani_config.CopyFrom(data)
1179 elif isinstance(data, VOntaniConfig):
1180 interfaceConfig.vont_ani_config.CopyFrom(data)
1181 elif isinstance(data, VEnetConfig):
1182 interfaceConfig.venet_config.CopyFrom(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -04001183 elif isinstance(data, TrafficDescriptorProfileData):
1184 interfaceConfig.traffic_descriptor_profile_config_data.CopyFrom(
1185 data)
1186 elif isinstance(data, TcontsConfigData):
1187 interfaceConfig.tconts_config_data.CopyFrom(data)
1188 elif isinstance(data, GemportsConfigData):
1189 interfaceConfig.gemports_config_data.CopyFrom(data)
1190 elif isinstance(data, MulticastGemportsConfigData):
1191 interfaceConfig.multicast_gemports_config_data.CopyFrom(data)
1192 elif isinstance(data, MulticastDistributionSetData):
1193 interfaceConfig.multicast_distribution_set_data.CopyFrom(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001194 else:
1195 return None
1196 return interfaceConfig
1197
Nikolay Titov176f1db2017-08-10 12:38:43 -04001198 def xpon_ponsim_olt_interface(self, method_name, data, data2=None):
Nikolay Titov89004ec2017-06-19 18:22:42 -04001199 interfaceConfig = self.get_interface_config(data)
1200 if interfaceConfig is not None:
Nikolay Titov176f1db2017-08-10 12:38:43 -04001201 self.log.info(
1202 'forwarding-{}-request-to-olt-for-interface-type'
khenaidoof3593a82018-06-01 16:41:31 -04001203 .format(self.xpon_ponsim_olt_itfs[method_name]['log']),
Nikolay Titov176f1db2017-08-10 12:38:43 -04001204 interface_type=type(data))
Scott Bakerd865fa22018-11-07 11:45:28 -08001205 stub = ponsim_pb2_grpc.XPonSimStub(self.get_channel())
Nikolay Titov176f1db2017-08-10 12:38:43 -04001206 _method = getattr(
1207 stub, self.xpon_ponsim_olt_itfs[method_name]['method_name'])
1208 if isinstance(data, TcontsConfigData):
1209 tcont_config = TcontInterfaceConfig()
1210 tcont_config.tconts_config_data.CopyFrom(data)
1211 tcont_config.traffic_descriptor_profile_config_data.CopyFrom(
1212 data2)
1213 _method(tcont_config)
1214 else:
1215 _method(interfaceConfig)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001216 self.log.info('success')
1217
Nikolay Titov176f1db2017-08-10 12:38:43 -04001218 def create_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001219 _method_name = sys._getframe().f_code.co_name
1220 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001221
Nikolay Titov89004ec2017-06-19 18:22:42 -04001222 def update_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001223 _method_name = sys._getframe().f_code.co_name
1224 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov89004ec2017-06-19 18:22:42 -04001225
1226 def remove_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001227 _method_name = sys._getframe().f_code.co_name
1228 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001229
1230 def create_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001231 _method_name = sys._getframe().f_code.co_name
1232 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1233 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001234
1235 def update_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001236 _method_name = sys._getframe().f_code.co_name
1237 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1238 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001239
1240 def remove_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001241 _method_name = sys._getframe().f_code.co_name
1242 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1243 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001244
1245 def create_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001246 _method_name = sys._getframe().f_code.co_name
1247 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001248
1249 def update_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001250 _method_name = sys._getframe().f_code.co_name
1251 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001252
1253 def remove_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001254 _method_name = sys._getframe().f_code.co_name
1255 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001256
1257 def create_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001258 _method_name = sys._getframe().f_code.co_name
1259 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001260
1261 def update_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001262 _method_name = sys._getframe().f_code.co_name
1263 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001264
1265 def remove_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001266 _method_name = sys._getframe().f_code.co_name
1267 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001268
1269 def create_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001270 _method_name = sys._getframe().f_code.co_name
1271 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001272
1273 def update_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001274 _method_name = sys._getframe().f_code.co_name
1275 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001276
1277 def remove_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001278 _method_name = sys._getframe().f_code.co_name
1279 self.xpon_ponsim_olt_interface(_method_name, data);
Scott Baker50873cc2018-09-21 18:14:09 -07001280
1281 def simulate_alarm(self, alarm):
1282 # Ponsim_olt implements its own AdapterAlarms class, rather than using the Voltha alarm extension. Until that
1283 # has been reconciled, temporarily instantiate the Voltha alarm extension's AdapterAlarms here, for the
1284 # purpose of sending simulated alarms.
1285 alarms = VolthaAdapterAlarms(self.adapter_agent, self.device_id, self.logical_device_id)
1286 simulator = AdapterAlarmSimulator(alarms)
1287 simulator.simulate_alarm(alarm)