blob: dc6b297300e8fa346071c6d470eeddda849c65a5 [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
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080024import grpc
Stephane Barbarie4475a252017-03-31 13:49:20 -040025import json
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080026import structlog
27from scapy.layers.l2 import Ether, Dot1Q
Stephane Barbarie4475a252017-03-31 13:49:20 -040028from scapy.layers.inet import Raw
Stephane Barbarie35595062018-02-08 08:34:39 -050029from twisted.internet import reactor
Khen Nursimulud068d812017-03-06 11:44:18 -050030from twisted.internet.defer import inlineCallbacks
Stephane Barbarie35595062018-02-08 08:34:39 -050031from grpc._channel import _Rendezvous
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080032
33from common.frameio.frameio import BpfProgramFilter, hexify
Khen Nursimulud068d812017-03-06 11:44:18 -050034from common.utils.asleep import asleep
Sergio Slobodrian98eff412017-03-15 14:46:30 -040035from twisted.internet.task import LoopingCall
Shad Ansarid1aa9e72017-06-23 21:34:25 -070036from voltha.adapters.iadapter import OltAdapter
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080037from voltha.core.logical_device_agent import mac_str_to_tuple
38from voltha.protos import third_party
39from voltha.protos import ponsim_pb2
Shad Ansari14bcd992017-06-13 14:27:20 -070040from voltha.protos.common_pb2 import OperStatus, ConnectStatus, AdminState
41from voltha.protos.device_pb2 import Port, Device, PmConfig, PmConfigs
Sergio Slobodrian98eff412017-03-15 14:46:30 -040042from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080043from google.protobuf.empty_pb2 import Empty
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080044from voltha.protos.logical_device_pb2 import LogicalPort, LogicalDevice
Stephane Barbarie5253c652017-03-22 16:29:46 -040045from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
46 OFPPF_1GB_FD, \
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080047 OFPC_GROUP_STATS, OFPC_PORT_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS, \
48 ofp_switch_features, ofp_desc
49from voltha.protos.openflow_13_pb2 import ofp_port
Stephane Barbarie35595062018-02-08 08:34:39 -050050from voltha.protos.ponsim_pb2 import FlowTable, PonSimFrame
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080051from voltha.registry import registry
52
Nikolay Titov89004ec2017-06-19 18:22:42 -040053from voltha.protos.bbf_fiber_base_pb2 import \
khenaidoof3593a82018-06-01 16:41:31 -040054 ChannelgroupConfig, ChannelpartitionConfig, ChannelpairConfig, \
Nikolay Titov176f1db2017-08-10 12:38:43 -040055 ChannelterminationConfig, OntaniConfig, VOntaniConfig, VEnetConfig
56from voltha.protos.bbf_fiber_traffic_descriptor_profile_body_pb2 import \
57 TrafficDescriptorProfileData
58from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
59from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
60from voltha.protos.bbf_fiber_multicast_gemport_body_pb2 import \
61 MulticastGemportsConfigData
Stephane Barbarie35595062018-02-08 08:34:39 -050062
Nikolay Titov176f1db2017-08-10 12:38:43 -040063from voltha.protos.bbf_fiber_multicast_distribution_set_body_pb2 import \
64 MulticastDistributionSetData
Nikolay Titov89004ec2017-06-19 18:22:42 -040065
Nikolay Titov176f1db2017-08-10 12:38:43 -040066from voltha.protos.ponsim_pb2 import InterfaceConfig, TcontInterfaceConfig
Nikolay Titov89004ec2017-06-19 18:22:42 -040067
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080068_ = third_party
69log = structlog.get_logger()
70
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080071PACKET_IN_VLAN = 4000
72is_inband_frame = BpfProgramFilter('(ether[14:2] & 0xfff) = 0x{:03x}'.format(
73 PACKET_IN_VLAN))
74
Stephane Barbarie5253c652017-03-22 16:29:46 -040075
Sergio Slobodrian98eff412017-03-15 14:46:30 -040076class AdapterPmMetrics:
Stephane Barbarie5253c652017-03-22 16:29:46 -040077 def __init__(self, device):
Sergio Slobodrianec6e3912017-04-02 11:46:55 -040078 self.pm_names = {'tx_64_pkts', 'tx_65_127_pkts', 'tx_128_255_pkts',
79 'tx_256_511_pkts', 'tx_512_1023_pkts',
80 'tx_1024_1518_pkts', 'tx_1519_9k_pkts',
81 'rx_64_pkts', 'rx_65_127_pkts',
82 'rx_128_255_pkts', 'rx_256_511_pkts',
83 'rx_512_1023_pkts', 'rx_1024_1518_pkts',
84 'rx_1519_9k_pkts'}
Sergio Slobodrian98eff412017-03-15 14:46:30 -040085 self.device = device
86 self.id = device.id
87 self.name = 'ponsim_olt'
Stephane Barbarie5253c652017-03-22 16:29:46 -040088 # self.id = "abc"
Sergio Slobodrian98eff412017-03-15 14:46:30 -040089 self.default_freq = 150
90 self.grouped = False
91 self.freq_override = False
92 self.pon_metrics_config = dict()
93 self.nni_metrics_config = dict()
94 self.lc = None
95 for m in self.pm_names:
96 self.pon_metrics_config[m] = PmConfig(name=m,
97 type=PmConfig.COUNTER,
98 enabled=True)
99 self.nni_metrics_config[m] = PmConfig(name=m,
100 type=PmConfig.COUNTER,
101 enabled=True)
102
103 def update(self, pm_config):
104 if self.default_freq != pm_config.default_freq:
105 # Update the callback to the new frequency.
106 self.default_freq = pm_config.default_freq
107 self.lc.stop()
Stephane Barbarie5253c652017-03-22 16:29:46 -0400108 self.lc.start(interval=self.default_freq / 10)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400109 for m in pm_config.metrics:
110 self.pon_metrics_config[m.name].enabled = m.enabled
111 self.nni_metrics_config[m.name].enabled = m.enabled
112
113 def make_proto(self):
114 pm_config = PmConfigs(
115 id=self.id,
116 default_freq=self.default_freq,
Stephane Barbarie5253c652017-03-22 16:29:46 -0400117 grouped=False,
118 freq_override=False)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400119 for m in sorted(self.pon_metrics_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400120 pm = self.pon_metrics_config[m] # Either will do they're the same
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400121 pm_config.metrics.extend([PmConfig(name=pm.name,
122 type=pm.type,
123 enabled=pm.enabled)])
124 return pm_config
125
126 def collect_port_metrics(self, channel):
127 rtrn_port_metrics = dict()
128 stub = ponsim_pb2.PonSimStub(channel)
129 stats = stub.GetStats(Empty())
130 rtrn_port_metrics['pon'] = self.extract_pon_metrics(stats)
131 rtrn_port_metrics['nni'] = self.extract_nni_metrics(stats)
132 return rtrn_port_metrics
133
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400134 def extract_pon_metrics(self, stats):
135 rtrn_pon_metrics = dict()
136 for m in stats.metrics:
137 if m.port_name == "pon":
138 for p in m.packets:
139 if self.pon_metrics_config[p.name].enabled:
140 rtrn_pon_metrics[p.name] = p.value
141 return rtrn_pon_metrics
142
143 def extract_nni_metrics(self, stats):
144 rtrn_pon_metrics = dict()
145 for m in stats.metrics:
146 if m.port_name == "nni":
147 for p in m.packets:
148 if self.pon_metrics_config[p.name].enabled:
149 rtrn_pon_metrics[p.name] = p.value
150 return rtrn_pon_metrics
151
152 def start_collector(self, callback):
153 log.info("starting-pm-collection", device_name=self.name,
154 device_id=self.device.id)
155 prefix = 'voltha.{}.{}'.format(self.name, self.device.id)
156 self.lc = LoopingCall(callback, self.device.id, prefix)
Stephane Barbarie5253c652017-03-22 16:29:46 -0400157 self.lc.start(interval=self.default_freq / 10)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400158
Stephane Barbarie35595062018-02-08 08:34:39 -0500159 def stop_collector(self):
160 log.info("stopping-pm-collection", device_name=self.name,
161 device_id=self.device.id)
162 self.lc.stop()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800163
khenaidoof3593a82018-06-01 16:41:31 -0400164
Stephane Barbarie4475a252017-03-31 13:49:20 -0400165class AdapterAlarms:
166 def __init__(self, adapter, device):
167 self.adapter = adapter
168 self.device = device
169 self.lc = None
170
171 def send_alarm(self, context_data, alarm_data):
172 try:
173 current_context = {}
174 for key, value in context_data.__dict__.items():
175 current_context[key] = str(value)
176
177 alarm_event = self.adapter.adapter_agent.create_alarm(
178 resource_id=self.device.id,
khenaidoo032d3302017-06-09 14:50:04 -0400179 description="{}.{} - {}".format(self.adapter.name,
180 self.device.id,
181 alarm_data[
182 'description']) if 'description' in alarm_data else None,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400183 type=alarm_data['type'] if 'type' in alarm_data else None,
khenaidoo032d3302017-06-09 14:50:04 -0400184 category=alarm_data[
185 'category'] if 'category' in alarm_data else None,
186 severity=alarm_data[
187 'severity'] if 'severity' in alarm_data else None,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400188 state=alarm_data['state'] if 'state' in alarm_data else None,
189 raised_ts=alarm_data['ts'] if 'ts' in alarm_data else 0,
190 context=current_context
191 )
192
khenaidoo032d3302017-06-09 14:50:04 -0400193 self.adapter.adapter_agent.submit_alarm(self.device.id,
194 alarm_event)
Stephane Barbarie4475a252017-03-31 13:49:20 -0400195
196 except Exception as e:
197 log.exception('failed-to-send-alarm', e=e)
198
khenaidoof3593a82018-06-01 16:41:31 -0400199
Shad Ansarid1aa9e72017-06-23 21:34:25 -0700200class PonSimOltAdapter(OltAdapter):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800201 def __init__(self, adapter_agent, config):
Shad Ansari14bcd992017-06-13 14:27:20 -0700202 super(PonSimOltAdapter, self).__init__(adapter_agent=adapter_agent,
203 config=config,
Shad Ansari96f817b2017-06-18 23:17:44 -0700204 device_handler_class=PonSimOltHandler,
Shad Ansari14bcd992017-06-13 14:27:20 -0700205 name='ponsim_olt',
206 vendor='Voltha project',
Nikolay Titov89004ec2017-06-19 18:22:42 -0400207 version='0.4',
khenaidoof3593a82018-06-01 16:41:31 -0400208 device_type='ponsim_olt',
209 accepts_bulk_flow_update=True,
210 accepts_add_remove_flow_updates=False)
Shad Ansari96f817b2017-06-18 23:17:44 -0700211
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400212 def update_pm_config(self, device, pm_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400213 log.info("adapter-update-pm-config", device=device,
214 pm_config=pm_config)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400215 handler = self.devices_handlers[device.id]
216 handler.update_pm_config(device, pm_config)
Sergio Slobodrianec864c62017-03-09 11:41:43 -0500217
Nikolay Titov89004ec2017-06-19 18:22:42 -0400218 def create_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400219 if super(PonSimOltAdapter, self)._get_handler(device):
220 log.info('create-interface', device_id=device.id)
221 self.devices_handlers[device.id].create_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400222
223 def update_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400224 if super(PonSimOltAdapter, self)._get_handler(device):
225 log.info('update-interface', device_id=device.id)
226 self.devices_handlers[device.id].update_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400227
228 def remove_interface(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400229 if super(PonSimOltAdapter, self)._get_handler(device):
230 log.info('remove-interface', device_id=device.id)
231 self.devices_handlers[device.id].remove_interface(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400232
Nikolay Titov176f1db2017-08-10 12:38:43 -0400233 def create_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400234 if super(PonSimOltAdapter, self)._get_handler(device):
235 log.info('create-tcont', device_id=device.id)
236 self.devices_handlers[device.id].create_tcont(
237 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400238
239 def update_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400240 if super(PonSimOltAdapter, self)._get_handler(device):
241 log.info('update-tcont', device_id=device.id)
242 self.devices_handlers[device.id].update_tcont(
243 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400244
245 def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400246 if super(PonSimOltAdapter, self)._get_handler(device):
247 log.info('remove-tcont', device_id=device.id)
248 self.devices_handlers[device.id].remove_tcont(
249 tcont_data, traffic_descriptor_data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400250
251 def create_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400252 if super(PonSimOltAdapter, self)._get_handler(device):
253 log.info('create-gemport', device_id=device.id)
254 self.devices_handlers[device.id].create_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400255
256 def update_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400257 if super(PonSimOltAdapter, self)._get_handler(device):
258 log.info('update-gemport', device_id=device.id)
259 self.devices_handlers[device.id].update_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400260
261 def remove_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400262 if super(PonSimOltAdapter, self)._get_handler(device):
263 log.info('remove-gemport', device_id=device.id)
264 self.devices_handlers[device.id].remove_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400265
266 def create_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400267 if super(PonSimOltAdapter, self)._get_handler(device):
268 log.info('create-multicast-gemport', device_id=device.id)
269 self.devices_handlers[device.id].create_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400270
271 def update_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400272 if super(PonSimOltAdapter, self)._get_handler(device):
273 log.info('update-multicast-gemport', device_id=device.id)
274 self.devices_handlers[device.id].update_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400275
276 def remove_multicast_gemport(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400277 if super(PonSimOltAdapter, self)._get_handler(device):
278 log.info('remove-multicast-gemport', device_id=device.id)
279 self.devices_handlers[device.id].remove_multicast_gemport(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400280
281 def create_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400282 if super(PonSimOltAdapter, self)._get_handler(device):
283 log.info('create-multicast-distribution-set', device_id=device.id)
284 self.devices_handlers[device.id].create_multicast_distribution_set(
285 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400286
287 def update_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400288 if super(PonSimOltAdapter, self)._get_handler(device):
289 log.info('update-multicast-distribution-set', device_id=device.id)
290 self.devices_handlers[device.id].update_multicast_distribution_set(
291 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400292
293 def remove_multicast_distribution_set(self, device, data):
Nikolay Titov4e1c3702017-08-23 12:41:57 -0400294 if super(PonSimOltAdapter, self)._get_handler(device):
295 log.info('remove-multicast-distribution-set', device_id=device.id)
296 self.devices_handlers[device.id].remove_multicast_distribution_set(
297 data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400298
khenaidoof3593a82018-06-01 16:41:31 -0400299
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800300class PonSimOltHandler(object):
Nikolay Titov176f1db2017-08-10 12:38:43 -0400301 xpon_ponsim_olt_itfs = {
302 'create_interface': {
303 'method_name': 'CreateInterface',
304 'log': 'create-interface'},
305 'update_interface': {
306 'method_name': 'UpdateInterface',
307 'log': 'update-interface'},
308 'remove_interface': {
309 'method_name': 'RemoveInterface',
310 'log': 'remove-interface'},
311 'create_tcont': {
312 'method_name': 'CreateTcont',
313 'log': 'create-tconts-config-data'},
314 'update_tcont': {
315 'method_name': 'UpdateTcont',
316 'log': 'update-tconts-config-data'},
317 'remove_tcont': {
318 'method_name': 'RemoveTcont',
319 'log': 'remove-tconts-config-data'},
320 'create_gemport': {
321 'method_name': 'CreateGemport',
322 'log': 'create-gemports-config-data'},
323 'update_gemport': {
324 'method_name': 'UpdateGemport',
325 'log': 'update-gemports-config-data'},
326 'remove_gemport': {
327 'method_name': 'RemoveGemport',
328 'log': 'remove-gemports-config-data'},
329 'create_multicast_gemport': {
330 'method_name': 'CreateMulticastGemport',
331 'log': 'create-multicast-gemports-config-data'},
332 'update_multicast_gemport': {
333 'method_name': 'UpdateMulticastGemport',
334 'log': 'update-multicast-gemports-config-data'},
335 'remove_multicast_gemport': {
336 'method_name': 'RemoveMulticastGemport',
337 'log': 'remove-multicast-gemports-config-data'},
338 'create_multicast_distribution_set': {
339 'method_name': 'CreateMulticastDistributionSet',
340 'log': 'create-multicast-distribution-set-data'},
341 'update_multicast_distribution_set': {
342 'method_name': 'UpdateMulticastDistributionSet',
343 'log': 'update-multicast-distribution-set-data'},
344 'remove_multicast_distribution_set': {
345 'method_name': 'RemoveMulticastDistributionSet',
346 'log': 'remove-multicast-distribution-set-data'},
khenaidoof3593a82018-06-01 16:41:31 -0400347 }
Nikolay Titov176f1db2017-08-10 12:38:43 -0400348
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800349 def __init__(self, adapter, device_id):
350 self.adapter = adapter
351 self.adapter_agent = adapter.adapter_agent
352 self.device_id = device_id
353 self.log = structlog.get_logger(device_id=device_id)
354 self.channel = None
355 self.io_port = None
356 self.logical_device_id = None
Khen Nursimulud068d812017-03-06 11:44:18 -0500357 self.nni_port = None
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400358 self.ofp_port_no = None
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800359 self.interface = registry('main').get_args().interface
Stephane Barbarie35595062018-02-08 08:34:39 -0500360 self.ponsim_comm = registry('main').get_args().ponsim_comm
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400361 self.pm_metrics = None
Stephane Barbarie4475a252017-03-31 13:49:20 -0400362 self.alarms = None
Stephane Barbarie35595062018-02-08 08:34:39 -0500363 self.frames = None
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800364
365 def __del__(self):
366 if self.io_port is not None:
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800367 registry('frameio').close_port(self.io_port)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800368
369 def get_channel(self):
370 if self.channel is None:
371 device = self.adapter_agent.get_device(self.device_id)
schowdhury9e247752017-07-14 06:56:20 -0700372
373 # read in certificate
374 try:
khenaidoof3593a82018-06-01 16:41:31 -0400375 with open('/voltha/pki/voltha-CA.pem') as f:
376 trusted_certs = f.read()
schowdhury9e247752017-07-14 06:56:20 -0700377
khenaidoof3593a82018-06-01 16:41:31 -0400378 with open('/voltha/pki/voltha.crt') as f:
379 client_cert = f.read()
schowdhury9e247752017-07-14 06:56:20 -0700380
khenaidoof3593a82018-06-01 16:41:31 -0400381 with open('/voltha/pki/voltha.key') as f:
382 client_key = f.read()
schowdhury9e247752017-07-14 06:56:20 -0700383 except Exception as e:
khenaidoof3593a82018-06-01 16:41:31 -0400384 log.error('failed-to-read-cert-keys', reason=e)
schowdhury9e247752017-07-14 06:56:20 -0700385
386 # create credentials
khenaidoof3593a82018-06-01 16:41:31 -0400387 credentials = grpc.ssl_channel_credentials(
388 root_certificates=trusted_certs, private_key=client_key,
389 certificate_chain=client_cert)
schowdhury9e247752017-07-14 06:56:20 -0700390
391 # create channel using ssl credentials
khenaidoof3593a82018-06-01 16:41:31 -0400392 my_server_host_override_string = "ABCD" # Server's CN Name, Ugly but no other Choice.
393 self.channel = grpc.secure_channel(device.host_and_port,
394 credentials, options=((
395 'grpc.ssl_target_name_override',
396 my_server_host_override_string,),))
schowdhury9e247752017-07-14 06:56:20 -0700397
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800398 return self.channel
399
Stephane Barbarie35595062018-02-08 08:34:39 -0500400 def close_channel(self):
401 if self.channel is None:
402 self.log.info('grpc-channel-already-closed')
403 return
404 else:
405 if self.frames is not None:
406 self.frames.cancel()
407 self.frames = None
408 self.log.info('cancelled-grpc-frame-stream')
409
410 self.channel.unsubscribe(lambda *args: None)
411 self.channel = None
412
413 self.log.info('grpc-channel-closed')
414
khenaidoo032d3302017-06-09 14:50:04 -0400415 def _get_nni_port(self):
416 ports = self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_NNI)
417 if ports:
418 # For now, we use on one NNI port
419 return ports[0]
420
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800421 def activate(self, device):
422 self.log.info('activating')
423
424 if not device.host_and_port:
425 device.oper_status = OperStatus.FAILED
426 device.reason = 'No host_and_port field provided'
427 self.adapter_agent.update_device(device)
428 return
429
430 stub = ponsim_pb2.PonSimStub(self.get_channel())
431 info = stub.GetDeviceInfo(Empty())
432 log.info('got-info', info=info)
433
434 device.root = True
435 device.vendor = 'ponsim'
Stephane Barbarie5253c652017-03-22 16:29:46 -0400436 device.model = 'n/a'
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800437 device.serial_number = device.host_and_port
438 device.connect_status = ConnectStatus.REACHABLE
439 self.adapter_agent.update_device(device)
440
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400441 # Now set the initial PM configuration for this device
Stephane Barbarie5253c652017-03-22 16:29:46 -0400442 self.pm_metrics = AdapterPmMetrics(device)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400443 pm_config = self.pm_metrics.make_proto()
444 log.info("initial-pm-config", pm_config=pm_config)
Stephane Barbarie5253c652017-03-22 16:29:46 -0400445 self.adapter_agent.update_device_pm_config(pm_config, init=True)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400446
Stephane Barbarie4475a252017-03-31 13:49:20 -0400447 # Setup alarm handler
448 self.alarms = AdapterAlarms(self.adapter, device)
449
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800450 nni_port = Port(
451 port_no=2,
452 label='NNI facing Ethernet port',
453 type=Port.ETHERNET_NNI,
454 admin_state=AdminState.ENABLED,
455 oper_status=OperStatus.ACTIVE
456 )
Khen Nursimulud068d812017-03-06 11:44:18 -0500457 self.nni_port = nni_port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800458 self.adapter_agent.add_port(device.id, nni_port)
459 self.adapter_agent.add_port(device.id, Port(
460 port_no=1,
461 label='PON port',
462 type=Port.PON_OLT,
463 admin_state=AdminState.ENABLED,
464 oper_status=OperStatus.ACTIVE
465 ))
466
467 ld = LogicalDevice(
khenaidoo507d9222017-10-10 16:23:49 -0400468 # not setting id and datapath_id. Adapter agent will pick the id
469 # and will pick the datapath_id is it is not provided
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800470 desc=ofp_desc(
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800471 hw_desc='simualted pon',
472 sw_desc='simualted pon',
khenaidoof3593a82018-06-01 16:41:31 -0400473 # serial_num=uuid4().hex,
474 serial_num="9b7cfd85441b407c87ee3261df7d4818",
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800475 dp_desc='n/a'
476 ),
477 switch_features=ofp_switch_features(
478 n_buffers=256, # TODO fake for now
479 n_tables=2, # TODO ditto
480 capabilities=( # TODO and ditto
khenaidoof3593a82018-06-01 16:41:31 -0400481 OFPC_FLOW_STATS
482 | OFPC_TABLE_STATS
483 | OFPC_PORT_STATS
484 | OFPC_GROUP_STATS
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800485 )
486 ),
487 root_device_id=device.id
488 )
khenaidoo507d9222017-10-10 16:23:49 -0400489 mac_address = "AA:BB:CC:DD:EE:FF"
490 ld_initialized = self.adapter_agent.create_logical_device(ld,
491 dpid=mac_address)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800492 cap = OFPPF_1GB_FD | OFPPF_FIBER
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400493 self.ofp_port_no = info.nni_port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800494 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
495 id='nni',
496 ofp_port=ofp_port(
497 port_no=info.nni_port,
Stephane Barbarie5253c652017-03-22 16:29:46 -0400498 hw_addr=mac_str_to_tuple(
499 '00:00:00:00:00:%02x' % info.nni_port),
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800500 name='nni',
501 config=0,
502 state=OFPPS_LIVE,
503 curr=cap,
504 advertised=cap,
505 peer=cap,
506 curr_speed=OFPPF_1GB_FD,
507 max_speed=OFPPF_1GB_FD
508 ),
509 device_id=device.id,
510 device_port_no=nni_port.port_no,
511 root_port=True
512 ))
513
514 device = self.adapter_agent.get_device(device.id)
515 device.parent_id = ld_initialized.id
516 device.oper_status = OperStatus.ACTIVE
517 self.adapter_agent.update_device(device)
518 self.logical_device_id = ld_initialized.id
519
520 # register ONUS per uni port
521 for port_no in info.uni_ports:
522 vlan_id = port_no
523 self.adapter_agent.child_device_detected(
524 parent_device_id=device.id,
525 parent_port_no=1,
Niren R Chidrawarefcebcd2017-07-19 20:03:39 -0400526 child_device_type='ponsim_onu',
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800527 proxy_address=Device.ProxyAddress(
528 device_id=device.id,
529 channel_id=vlan_id
530 ),
Nikolay Titov89004ec2017-06-19 18:22:42 -0400531 admin_state=AdminState.ENABLED,
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800532 vlan=vlan_id
533 )
534
Stephane Barbarie35595062018-02-08 08:34:39 -0500535 if self.ponsim_comm == 'grpc':
536 self.log.info('starting-frame-grpc-stream')
537 reactor.callInThread(self.rcv_grpc)
538 self.log.info('started-frame-grpc-stream')
539 else:
540 # finally, open the frameio port to receive in-band packet_in messages
541 self.log.info('registering-frameio')
542 self.io_port = registry('frameio').open_port(
543 self.interface, self.rcv_io, is_inband_frame)
544 self.log.info('registered-frameio')
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800545
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400546 # Start collecting stats from the device after a brief pause
547 self.start_kpi_collection(device.id)
548
khenaidoo032d3302017-06-09 14:50:04 -0400549 def reconcile(self, device):
550 self.log.info('reconciling-OLT-device-starts')
551
552 if not device.host_and_port:
553 device.oper_status = OperStatus.FAILED
554 device.reason = 'No host_and_port field provided'
555 self.adapter_agent.update_device(device)
556 return
557
558 try:
559 stub = ponsim_pb2.PonSimStub(self.get_channel())
560 info = stub.GetDeviceInfo(Empty())
561 log.info('got-info', info=info)
562 # TODO: Verify we are connected to the same device we are
563 # reconciling - not much data in ponsim to differentiate at the
564 # time
565 device.oper_status = OperStatus.ACTIVE
566 self.adapter_agent.update_device(device)
567 self.ofp_port_no = info.nni_port
568 self.nni_port = self._get_nni_port()
569 except Exception, e:
570 log.exception('device-unreachable', e=e)
571 device.connect_status = ConnectStatus.UNREACHABLE
572 device.oper_status = OperStatus.UNKNOWN
573 self.adapter_agent.update_device(device)
574 return
575
576 # Now set the initial PM configuration for this device
577 self.pm_metrics = AdapterPmMetrics(device)
578 pm_config = self.pm_metrics.make_proto()
579 log.info("initial-pm-config", pm_config=pm_config)
580 self.adapter_agent.update_device_pm_config(pm_config, init=True)
581
582 # Setup alarm handler
583 self.alarms = AdapterAlarms(self.adapter, device)
584
585 # TODO: Is there anything required to verify nni and PON ports
586
587 # Set the logical device id
588 device = self.adapter_agent.get_device(device.id)
589 if device.parent_id:
590 self.logical_device_id = device.parent_id
591 self.adapter_agent.reconcile_logical_device(device.parent_id)
592 else:
593 self.log.info('no-logical-device-set')
594
595 # Reconcile child devices
596 self.adapter_agent.reconcile_child_devices(device.id)
597
Stephane Barbarie35595062018-02-08 08:34:39 -0500598 if self.ponsim_comm == 'grpc':
599 reactor.callInThread(self.rcv_grpc)
600 else:
601 # finally, open the frameio port to receive in-band packet_in messages
602 self.io_port = registry('frameio').open_port(
603 self.interface, self.rcv_io, is_inband_frame)
khenaidoo032d3302017-06-09 14:50:04 -0400604
605 # Start collecting stats from the device after a brief pause
606 self.start_kpi_collection(device.id)
607
608 self.log.info('reconciling-OLT-device-ends')
609
Stephane Barbarie35595062018-02-08 08:34:39 -0500610 def _rcv_frame(self, frame):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800611 pkt = Ether(frame)
Stephane Barbarie35595062018-02-08 08:34:39 -0500612
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800613 if pkt.haslayer(Dot1Q):
614 outer_shim = pkt.getlayer(Dot1Q)
Stephane Barbarie35595062018-02-08 08:34:39 -0500615
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800616 if isinstance(outer_shim.payload, Dot1Q):
617 inner_shim = outer_shim.payload
618 cvid = inner_shim.vlan
619 logical_port = cvid
620 popped_frame = (
khenaidoof3593a82018-06-01 16:41:31 -0400621 Ether(src=pkt.src, dst=pkt.dst, type=inner_shim.type) /
622 inner_shim.payload
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800623 )
624 kw = dict(
625 logical_device_id=self.logical_device_id,
626 logical_port_no=logical_port,
627 )
628 self.log.info('sending-packet-in', **kw)
629 self.adapter_agent.send_packet_in(
630 packet=str(popped_frame), **kw)
Stephane Barbarie4475a252017-03-31 13:49:20 -0400631 elif pkt.haslayer(Raw):
632 raw_data = json.loads(pkt.getlayer(Raw).load)
633 self.alarms.send_alarm(self, raw_data)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800634
Stephane Barbarie35595062018-02-08 08:34:39 -0500635 @inlineCallbacks
636 def rcv_grpc(self):
637 """
638 This call establishes a GRPC stream to receive frames.
639 """
640 stub = ponsim_pb2.PonSimStub(self.get_channel())
641
642 # Attempt to establish a grpc stream with the remote ponsim service
643 self.frames = stub.ReceiveFrames(Empty())
644
645 self.log.info('start-receiving-grpc-frames')
646
647 try:
648 for frame in self.frames:
khenaidoof3593a82018-06-01 16:41:31 -0400649 self.log.info('received-grpc-frame',
650 frame_len=len(frame.payload))
Stephane Barbarie35595062018-02-08 08:34:39 -0500651 self._rcv_frame(frame.payload)
652
653 except _Rendezvous, e:
khenaidoof3593a82018-06-01 16:41:31 -0400654 log.warn('grpc-connection-lost', message=e.message)
Stephane Barbarie35595062018-02-08 08:34:39 -0500655
656 self.log.info('stopped-receiving-grpc-frames')
657
658 def rcv_io(self, port, frame):
659 self.log.info('received-io-frame', iface_name=port.iface_name,
660 frame_len=len(frame))
661 self._rcv_frame(frame)
662
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800663 def update_flow_table(self, flows):
664 stub = ponsim_pb2.PonSimStub(self.get_channel())
665 self.log.info('pushing-olt-flow-table')
666 stub.UpdateFlowTable(FlowTable(
667 port=0,
668 flows=flows
669 ))
670 self.log.info('success')
671
khenaidoof3593a82018-06-01 16:41:31 -0400672 def remove_from_flow_table(self, flows):
673 self.log.debug('remove-from-flow-table', flows=flows)
674 # TODO: Update PONSIM code to accept incremental flow changes
675 # Once completed, the accepts_add_remove_flow_updates for this
676 # device type can be set to True
677
678 def add_to_flow_table(self, flows):
679 self.log.debug('add-to-flow-table', flows=flows)
680 # TODO: Update PONSIM code to accept incremental flow changes
681 # Once completed, the accepts_add_remove_flow_updates for this
682 # device type can be set to True
683
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400684 def update_pm_config(self, device, pm_config):
Stephane Barbarie5253c652017-03-22 16:29:46 -0400685 log.info("handler-update-pm-config", device=device,
686 pm_config=pm_config)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400687 self.pm_metrics.update(pm_config)
688
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800689 def send_proxied_message(self, proxy_address, msg):
690 self.log.info('sending-proxied-message')
691 if isinstance(msg, FlowTable):
692 stub = ponsim_pb2.PonSimStub(self.get_channel())
693 self.log.info('pushing-onu-flow-table', port=msg.port)
694 res = stub.UpdateFlowTable(msg)
695 self.adapter_agent.receive_proxied_message(proxy_address, res)
696
697 def packet_out(self, egress_port, msg):
698 self.log.info('sending-packet-out', egress_port=egress_port,
699 msg=hexify(msg))
700 pkt = Ether(msg)
701 out_pkt = (
khenaidoof3593a82018-06-01 16:41:31 -0400702 Ether(src=pkt.src, dst=pkt.dst) /
703 Dot1Q(vlan=4000) /
704 Dot1Q(vlan=egress_port, type=pkt.type) /
705 pkt.payload
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800706 )
Stephane Barbarie35595062018-02-08 08:34:39 -0500707
708 if self.ponsim_comm == 'grpc':
709 # send over grpc stream
710 stub = ponsim_pb2.PonSimStub(self.get_channel())
711 frame = PonSimFrame(id=self.device_id, payload=str(out_pkt))
712 stub.SendFrame(frame)
713 else:
714 # send over frameio
715 self.io_port.send(str(out_pkt))
716
Khen Nursimulud068d812017-03-06 11:44:18 -0500717 @inlineCallbacks
718 def reboot(self):
719 self.log.info('rebooting', device_id=self.device_id)
720
721 # Update the operational status to ACTIVATING and connect status to
722 # UNREACHABLE
723 device = self.adapter_agent.get_device(self.device_id)
724 previous_oper_status = device.oper_status
725 previous_conn_status = device.connect_status
726 device.oper_status = OperStatus.ACTIVATING
727 device.connect_status = ConnectStatus.UNREACHABLE
728 self.adapter_agent.update_device(device)
729
khenaidoo71d0a6c2017-03-22 21:46:04 -0400730 # Update the child devices connect state to UNREACHABLE
khenaidoo2d7af132017-03-23 15:45:51 -0400731 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400732 connect_status=ConnectStatus.UNREACHABLE)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400733
Khen Nursimulud068d812017-03-06 11:44:18 -0500734 # Sleep 10 secs, simulating a reboot
Stephane Barbarie5253c652017-03-22 16:29:46 -0400735 # TODO: send alert and clear alert after the reboot
Khen Nursimulud068d812017-03-06 11:44:18 -0500736 yield asleep(10)
737
738 # Change the operational status back to its previous state. With a
739 # real OLT the operational state should be the state the device is
740 # after a reboot.
741 # Get the latest device reference
742 device = self.adapter_agent.get_device(self.device_id)
743 device.oper_status = previous_oper_status
744 device.connect_status = previous_conn_status
745 self.adapter_agent.update_device(device)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400746
747 # Update the child devices connect state to REACHABLE
khenaidoo2d7af132017-03-23 15:45:51 -0400748 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400749 connect_status=ConnectStatus.REACHABLE)
khenaidoo71d0a6c2017-03-22 21:46:04 -0400750
Khen Nursimulud068d812017-03-06 11:44:18 -0500751 self.log.info('rebooted', device_id=self.device_id)
752
sathishg5ae86222017-06-28 15:16:29 +0530753 def self_test_device(self, device):
754 """
755 This is called to Self a device based on a NBI call.
756 :param device: A Voltha.Device object.
757 :return: Will return result of self test
758 """
759 log.info('self-test-device', device=device.id)
760 raise NotImplementedError()
761
Khen Nursimulud068d812017-03-06 11:44:18 -0500762 def disable(self):
763 self.log.info('disabling', device_id=self.device_id)
764
Stephane Barbarie35595062018-02-08 08:34:39 -0500765 self.stop_kpi_collection()
766
Khen Nursimulud068d812017-03-06 11:44:18 -0500767 # Get the latest device reference
768 device = self.adapter_agent.get_device(self.device_id)
769
770 # Update the operational status to UNKNOWN
771 device.oper_status = OperStatus.UNKNOWN
772 device.connect_status = ConnectStatus.UNREACHABLE
773 self.adapter_agent.update_device(device)
774
775 # Remove the logical device
776 logical_device = self.adapter_agent.get_logical_device(
Stephane Barbarie5253c652017-03-22 16:29:46 -0400777 self.logical_device_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500778 self.adapter_agent.delete_logical_device(logical_device)
779
780 # Disable all child devices first
khenaidoo2d7af132017-03-23 15:45:51 -0400781 self.adapter_agent.update_child_devices_state(self.device_id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400782 admin_state=AdminState.DISABLED)
Khen Nursimulud068d812017-03-06 11:44:18 -0500783
Khen Nursimulud068d812017-03-06 11:44:18 -0500784 # Remove the peer references from this device
785 self.adapter_agent.delete_all_peer_references(self.device_id)
786
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400787 # Set all ports to disabled
788 self.adapter_agent.disable_all_ports(self.device_id)
789
Stephane Barbarie35595062018-02-08 08:34:39 -0500790 self.close_channel()
791 self.log.info('disabled-grpc-channel')
792
793 if self.ponsim_comm == 'frameio':
794 # close the frameio port
795 registry('frameio').close_port(self.io_port)
796 self.log.info('disabled-frameio-port')
Khen Nursimulud068d812017-03-06 11:44:18 -0500797
khenaidoo032d3302017-06-09 14:50:04 -0400798 # Update the logice device mapping
799 if self.logical_device_id in \
800 self.adapter.logical_device_id_to_root_device_id:
801 del self.adapter.logical_device_id_to_root_device_id[
802 self.logical_device_id]
803
Khen Nursimulud068d812017-03-06 11:44:18 -0500804 # TODO:
805 # 1) Remove all flows from the device
806 # 2) Remove the device from ponsim
807
808 self.log.info('disabled', device_id=device.id)
809
Khen Nursimulud068d812017-03-06 11:44:18 -0500810 def reenable(self):
811 self.log.info('re-enabling', device_id=self.device_id)
812
813 # Get the latest device reference
814 device = self.adapter_agent.get_device(self.device_id)
815
khenaidoo032d3302017-06-09 14:50:04 -0400816 # Set the ofp_port_no and nni_port in case we bypassed the reconcile
817 # process if the device was in DISABLED state on voltha restart
818 if not self.ofp_port_no and not self.nni_port:
819 stub = ponsim_pb2.PonSimStub(self.get_channel())
820 info = stub.GetDeviceInfo(Empty())
821 log.info('got-info', info=info)
822 self.ofp_port_no = info.nni_port
823 self.nni_port = self._get_nni_port()
824
Khen Nursimulud068d812017-03-06 11:44:18 -0500825 # Update the connect status to REACHABLE
826 device.connect_status = ConnectStatus.REACHABLE
827 self.adapter_agent.update_device(device)
828
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400829 # Set all ports to enabled
830 self.adapter_agent.enable_all_ports(self.device_id)
831
Khen Nursimulud068d812017-03-06 11:44:18 -0500832 ld = LogicalDevice(
833 # not setting id and datapth_id will let the adapter agent pick id
834 desc=ofp_desc(
Khen Nursimulud068d812017-03-06 11:44:18 -0500835 hw_desc='simulated pon',
836 sw_desc='simulated pon',
837 serial_num=uuid4().hex,
838 dp_desc='n/a'
839 ),
840 switch_features=ofp_switch_features(
841 n_buffers=256, # TODO fake for now
842 n_tables=2, # TODO ditto
843 capabilities=( # TODO and ditto
khenaidoof3593a82018-06-01 16:41:31 -0400844 OFPC_FLOW_STATS
845 | OFPC_TABLE_STATS
846 | OFPC_PORT_STATS
847 | OFPC_GROUP_STATS
Khen Nursimulud068d812017-03-06 11:44:18 -0500848 )
849 ),
850 root_device_id=device.id
851 )
khenaidoo507d9222017-10-10 16:23:49 -0400852 mac_address = "AA:BB:CC:DD:EE:FF"
853 ld_initialized = self.adapter_agent.create_logical_device(ld,
854 dpid=mac_address)
Khen Nursimulud068d812017-03-06 11:44:18 -0500855 cap = OFPPF_1GB_FD | OFPPF_FIBER
856 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
857 id='nni',
858 ofp_port=ofp_port(
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400859 port_no=self.ofp_port_no,
Khen Nursimulud068d812017-03-06 11:44:18 -0500860 hw_addr=mac_str_to_tuple(
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400861 '00:00:00:00:00:%02x' % self.ofp_port_no),
Khen Nursimulud068d812017-03-06 11:44:18 -0500862 name='nni',
863 config=0,
864 state=OFPPS_LIVE,
865 curr=cap,
866 advertised=cap,
867 peer=cap,
868 curr_speed=OFPPF_1GB_FD,
869 max_speed=OFPPF_1GB_FD
870 ),
871 device_id=device.id,
872 device_port_no=self.nni_port.port_no,
873 root_port=True
874 ))
875
876 device = self.adapter_agent.get_device(device.id)
877 device.parent_id = ld_initialized.id
878 device.oper_status = OperStatus.ACTIVE
879 self.adapter_agent.update_device(device)
880 self.logical_device_id = ld_initialized.id
881
882 # Reenable all child devices
khenaidoo2d7af132017-03-23 15:45:51 -0400883 self.adapter_agent.update_child_devices_state(device.id,
Stephane Barbarie4475a252017-03-31 13:49:20 -0400884 admin_state=AdminState.ENABLED)
Khen Nursimulud068d812017-03-06 11:44:18 -0500885
Stephane Barbarie35595062018-02-08 08:34:39 -0500886 if self.ponsim_comm == 'grpc':
887 # establish frame grpc-stream
888 reactor.callInThread(self.rcv_grpc)
889 else:
890 # finally, open the frameio port to receive in-band packet_in messages
891 self.io_port = registry('frameio').open_port(
892 self.interface, self.rcv_io, is_inband_frame)
893
894 self.start_kpi_collection(device.id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500895
896 self.log.info('re-enabled', device_id=device.id)
897
Khen Nursimulud068d812017-03-06 11:44:18 -0500898 def delete(self):
899 self.log.info('deleting', device_id=self.device_id)
900
901 # Remove all child devices
902 self.adapter_agent.delete_all_child_devices(self.device_id)
903
Stephane Barbarie35595062018-02-08 08:34:39 -0500904 self.close_channel()
905 self.log.info('disabled-grpc-channel')
906
907 if self.ponsim_comm == 'frameio':
908 # close the frameio port
909 registry('frameio').close_port(self.io_port)
910 self.log.info('disabled-frameio-port')
911
Khen Nursimulud068d812017-03-06 11:44:18 -0500912 # TODO:
913 # 1) Remove all flows from the device
914 # 2) Remove the device from ponsim
915
916 self.log.info('deleted', device_id=self.device_id)
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400917
918 def start_kpi_collection(self, device_id):
919
920 def _collect(device_id, prefix):
921
922 try:
923 # Step 1: gather metrics from device
924 port_metrics = \
Stephane Barbarie5253c652017-03-22 16:29:46 -0400925 self.pm_metrics.collect_port_metrics(self.get_channel())
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400926
927 # Step 2: prepare the KpiEvent for submission
928 # we can time-stamp them here (or could use time derived from OLT
929 ts = arrow.utcnow().timestamp
930 kpi_event = KpiEvent(
931 type=KpiEventType.slice,
932 ts=ts,
933 prefixes={
934 # OLT NNI port
935 prefix + '.nni': MetricValuePairs(
936 metrics=port_metrics['nni']),
937 # OLT PON port
938 prefix + '.pon': MetricValuePairs(
939 metrics=port_metrics['pon'])
940 }
941 )
942
943 # Step 3: submit
944 self.adapter_agent.submit_kpis(kpi_event)
945
946 except Exception as e:
947 log.exception('failed-to-submit-kpis', e=e)
Stephane Barbarie5253c652017-03-22 16:29:46 -0400948
Sergio Slobodrian98eff412017-03-15 14:46:30 -0400949 self.pm_metrics.start_collector(_collect)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400950
Stephane Barbarie35595062018-02-08 08:34:39 -0500951 def stop_kpi_collection(self):
952 self.pm_metrics.stop_collector()
953
Nikolay Titov89004ec2017-06-19 18:22:42 -0400954 def get_interface_config(self, data):
955 interfaceConfig = InterfaceConfig()
956 if isinstance(data, ChannelgroupConfig):
957 interfaceConfig.channel_group_config.CopyFrom(data)
958 elif isinstance(data, ChannelpartitionConfig):
959 interfaceConfig.channel_partition_config.CopyFrom(data)
960 elif isinstance(data, ChannelpairConfig):
961 interfaceConfig.channel_pair_config.CopyFrom(data)
962 elif isinstance(data, ChannelterminationConfig):
963 interfaceConfig.channel_termination_config.CopyFrom(data)
964 elif isinstance(data, OntaniConfig):
965 interfaceConfig.ont_ani_config.CopyFrom(data)
966 elif isinstance(data, VOntaniConfig):
967 interfaceConfig.vont_ani_config.CopyFrom(data)
968 elif isinstance(data, VEnetConfig):
969 interfaceConfig.venet_config.CopyFrom(data)
Nikolay Titov176f1db2017-08-10 12:38:43 -0400970 elif isinstance(data, TrafficDescriptorProfileData):
971 interfaceConfig.traffic_descriptor_profile_config_data.CopyFrom(
972 data)
973 elif isinstance(data, TcontsConfigData):
974 interfaceConfig.tconts_config_data.CopyFrom(data)
975 elif isinstance(data, GemportsConfigData):
976 interfaceConfig.gemports_config_data.CopyFrom(data)
977 elif isinstance(data, MulticastGemportsConfigData):
978 interfaceConfig.multicast_gemports_config_data.CopyFrom(data)
979 elif isinstance(data, MulticastDistributionSetData):
980 interfaceConfig.multicast_distribution_set_data.CopyFrom(data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400981 else:
982 return None
983 return interfaceConfig
984
Nikolay Titov176f1db2017-08-10 12:38:43 -0400985 def xpon_ponsim_olt_interface(self, method_name, data, data2=None):
Nikolay Titov89004ec2017-06-19 18:22:42 -0400986 interfaceConfig = self.get_interface_config(data)
987 if interfaceConfig is not None:
Nikolay Titov176f1db2017-08-10 12:38:43 -0400988 self.log.info(
989 'forwarding-{}-request-to-olt-for-interface-type'
khenaidoof3593a82018-06-01 16:41:31 -0400990 .format(self.xpon_ponsim_olt_itfs[method_name]['log']),
Nikolay Titov176f1db2017-08-10 12:38:43 -0400991 interface_type=type(data))
Nikolay Titov89004ec2017-06-19 18:22:42 -0400992 stub = ponsim_pb2.XPonSimStub(self.get_channel())
Nikolay Titov176f1db2017-08-10 12:38:43 -0400993 _method = getattr(
994 stub, self.xpon_ponsim_olt_itfs[method_name]['method_name'])
995 if isinstance(data, TcontsConfigData):
996 tcont_config = TcontInterfaceConfig()
997 tcont_config.tconts_config_data.CopyFrom(data)
998 tcont_config.traffic_descriptor_profile_config_data.CopyFrom(
999 data2)
1000 _method(tcont_config)
1001 else:
1002 _method(interfaceConfig)
Nikolay Titov89004ec2017-06-19 18:22:42 -04001003 self.log.info('success')
1004
Nikolay Titov176f1db2017-08-10 12:38:43 -04001005 def create_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001006 _method_name = sys._getframe().f_code.co_name
1007 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001008
Nikolay Titov89004ec2017-06-19 18:22:42 -04001009 def update_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001010 _method_name = sys._getframe().f_code.co_name
1011 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov89004ec2017-06-19 18:22:42 -04001012
1013 def remove_interface(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001014 _method_name = sys._getframe().f_code.co_name
1015 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001016
1017 def create_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001018 _method_name = sys._getframe().f_code.co_name
1019 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1020 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001021
1022 def update_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001023 _method_name = sys._getframe().f_code.co_name
1024 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1025 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001026
1027 def remove_tcont(self, tcont_data, traffic_descriptor_data):
khenaidoof3593a82018-06-01 16:41:31 -04001028 _method_name = sys._getframe().f_code.co_name
1029 self.xpon_ponsim_olt_interface(_method_name, tcont_data,
1030 traffic_descriptor_data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001031
1032 def create_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001033 _method_name = sys._getframe().f_code.co_name
1034 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001035
1036 def update_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001037 _method_name = sys._getframe().f_code.co_name
1038 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001039
1040 def remove_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001041 _method_name = sys._getframe().f_code.co_name
1042 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001043
1044 def create_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001045 _method_name = sys._getframe().f_code.co_name
1046 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001047
1048 def update_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001049 _method_name = sys._getframe().f_code.co_name
1050 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001051
1052 def remove_multicast_gemport(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001053 _method_name = sys._getframe().f_code.co_name
1054 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001055
1056 def create_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001057 _method_name = sys._getframe().f_code.co_name
1058 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001059
1060 def update_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001061 _method_name = sys._getframe().f_code.co_name
1062 self.xpon_ponsim_olt_interface(_method_name, data);
Nikolay Titov176f1db2017-08-10 12:38:43 -04001063
1064 def remove_multicast_distribution_set(self, data):
khenaidoof3593a82018-06-01 16:41:31 -04001065 _method_name = sys._getframe().f_code.co_name
1066 self.xpon_ponsim_olt_interface(_method_name, data);