blob: 4551b35761777879d142006988363cb53810d74f [file] [log] [blame]
Zsolt Harasztied091602016-12-08 13:36:38 -08001#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08002# Copyright 2017 the original author or authors.
Zsolt Harasztied091602016-12-08 13:36:38 -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"""
18Tibit OLT device adapter
19"""
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080020import json
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080021from uuid import uuid4
22
Zsolt Harasztic5f740b2017-01-18 09:53:17 -080023import arrow
Zsolt Haraszti80175202016-12-24 00:17:51 -080024import structlog
25from scapy.fields import StrField
Zsolt Haraszti348d1932016-12-10 01:10:07 -080026from scapy.layers.l2 import Ether, Dot1Q
Zsolt Haraszti80175202016-12-24 00:17:51 -080027from scapy.packet import Packet, bind_layers
Zsolt Haraszti89a27302016-12-08 16:53:06 -080028from twisted.internet import reactor
Zsolt Haraszti80175202016-12-24 00:17:51 -080029from twisted.internet.defer import DeferredQueue, inlineCallbacks
Zsolt Harasztic5f740b2017-01-18 09:53:17 -080030from twisted.internet.task import LoopingCall
Zsolt Harasztied091602016-12-08 13:36:38 -080031from zope.interface import implementer
32
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080033from common.frameio.frameio import BpfProgramFilter, hexify
Zsolt Harasztied091602016-12-08 13:36:38 -080034from voltha.adapters.interface import IAdapterInterface
Nathan Knuth31c36962016-12-27 10:04:49 -080035from voltha.extensions.eoam.EOAM import EOAMPayload, DPoEOpcode_SetRequest
36from voltha.extensions.eoam.EOAM_TLV import DOLTObject, \
Nathan Knuthd8285e62017-01-11 14:18:43 -060037 NetworkToNetworkPortObject, OLTUnicastLogicalLink, \
38 PortIngressRuleClauseMatchLength01, AddStaticMacAddress, \
39 PortIngressRuleClauseMatchLength02, PortIngressRuleResultForward, \
40 PortIngressRuleResultSet, PortIngressRuleResultInsert, \
41 PortIngressRuleResultCopy, PortIngressRuleResultReplace, \
42 PortIngressRuleResultDelete, PortIngressRuleResultOLTQueue, \
Nathan Knuth05f859e2017-02-23 13:22:26 -080043 PortIngressRuleResultOLTBroadcastQueue, \
Nathan Knuthd8285e62017-01-11 14:18:43 -060044 PortIngressRuleTerminator, AddPortIngressRule, CablelabsOUI, PonPortObject
Nathan Knuth31c36962016-12-27 10:04:49 -080045from voltha.extensions.eoam.EOAM_TLV import PortIngressRuleHeader
Nathan Knuthd390ceb2017-01-07 15:38:58 -080046from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
47from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
Nathan Knuth09c23102017-02-10 04:43:30 -080048from voltha.extensions.eoam.EOAM import EOAMPayload, CablelabsOUI
Zsolt Haraszti80175202016-12-24 00:17:51 -080049from voltha.core.flow_decomposer import *
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080050from voltha.core.logical_device_agent import mac_str_to_tuple
Zsolt Harasztied091602016-12-08 13:36:38 -080051from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
Zsolt Haraszti80175202016-12-24 00:17:51 -080052from voltha.protos.common_pb2 import LogLevel, ConnectStatus
53from voltha.protos.common_pb2 import OperStatus, AdminState
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080054from voltha.protos.device_pb2 import Device, Port
Zsolt Harasztied091602016-12-08 13:36:38 -080055from voltha.protos.device_pb2 import DeviceType, DeviceTypes
Zsolt Harasztic5f740b2017-01-18 09:53:17 -080056from voltha.protos.events_pb2 import KpiEvent, MetricValuePairs
57from voltha.protos.events_pb2 import KpiEventType
Zsolt Harasztied091602016-12-08 13:36:38 -080058from voltha.protos.health_pb2 import HealthStatus
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080059from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
60from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_10GB_FD, \
Nathan Knuthd8285e62017-01-11 14:18:43 -060061 OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
62 OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
Zsolt Haraszti80175202016-12-24 00:17:51 -080063from voltha.registry import registry
Zsolt Haraszti348d1932016-12-10 01:10:07 -080064log = structlog.get_logger()
Zsolt Harasztied091602016-12-08 13:36:38 -080065
Nathan Knuth388eff32017-01-18 18:31:22 -060066TIBIT_ONU_LINK_INDEX = 2
67
Nathan Knuth6e57f332016-12-22 15:49:20 -080068# Match on the MGMT VLAN, Priority 7
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080069TIBIT_MGMT_VLAN = 4090
70TIBIT_MGMT_PRIORITY = 7
71frame_match_case1 = 'ether[14:2] = 0x{:01x}{:03x}'.format(
72 TIBIT_MGMT_PRIORITY << 1, TIBIT_MGMT_VLAN)
73
74TIBIT_PACKET_IN_VLAN = 4000
75frame_match_case2 = '(ether[14:2] & 0xfff) = 0x{:03x}'.format(
76 TIBIT_PACKET_IN_VLAN)
77
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080078TIBIT_PACKET_OUT_VLAN = 4000
79
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080080is_tibit_frame = BpfProgramFilter('{} or {}'.format(
81 frame_match_case1, frame_match_case2))
82
Nathan Knuth05f859e2017-02-23 13:22:26 -080083
84# TODO: This information should be conveyed to the adapter
85# from a higher level.
86MULTICAST_VLAN = 140
87
Zsolt Haraszti89a27302016-12-08 16:53:06 -080088
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080089# Extract OLT MAC address: This is a good
90# example of getting the OLT mac address
91
92#for mac, device in self.device_ids.iteritems():
93# if device == dev_id:
94# olt_mac_address = mac
95# log.info('packet-out', olt_mac_address=olt_mac_address)
Zsolt Haraszti85f12852016-12-24 08:30:58 -080096
Zsolt Haraszti348d1932016-12-10 01:10:07 -080097# To be removed in favor of OAM
Zsolt Haraszti89a27302016-12-08 16:53:06 -080098class TBJSON(Packet):
99 """ TBJSON 'packet' layer. """
100 name = "TBJSON"
101 fields_desc = [StrField("data", default="")]
102
Nathan Knuth6e57f332016-12-22 15:49:20 -0800103bind_layers(Ether, TBJSON, type=0x9001)
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800104
Nathan Knuthd8285e62017-01-11 14:18:43 -0600105SUMITOMO_ELECTRIC_INDUSTRIES_OUI=u"0025DC"
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800106
Zsolt Harasztied091602016-12-08 13:36:38 -0800107@implementer(IAdapterInterface)
108class TibitOltAdapter(object):
109
110 name = 'tibit_olt'
111
112 supported_device_types = [
113 DeviceType(
114 id='tibit_olt',
115 adapter=name,
116 accepts_bulk_flow_update=True
117 )
118 ]
119
120 def __init__(self, adapter_agent, config):
121 self.adapter_agent = adapter_agent
122 self.config = config
123 self.descriptor = Adapter(
124 id=self.name,
125 vendor='Tibit Communications Inc.',
126 version='0.1',
127 config=AdapterConfig(log_level=LogLevel.INFO)
128 )
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800129 self.interface = registry('main').get_args().interface
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800130 self.io_port = None
Nathan Knuth6e57f332016-12-22 15:49:20 -0800131 self.incoming_queues = {} # OLT mac_address -> DeferredQueue()
132 self.device_ids = {} # OLT mac_address -> device_id
Nathan Knuth96531582017-02-13 05:27:37 -0800133 self.vlan_to_device_ids = {} # c-vid -> (device_id, logical_device_id, mac_address)
Zsolt Harasztied091602016-12-08 13:36:38 -0800134
135 def start(self):
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800136 log.debug('starting', interface=self.interface)
137 log.info('started', interface=self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800138
139 def stop(self):
140 log.debug('stopping')
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800141 if self.io_port is not None:
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800142 registry('frameio').close_port(self.io_port)
Zsolt Harasztied091602016-12-08 13:36:38 -0800143 log.info('stopped')
144
145 def adapter_descriptor(self):
146 return self.descriptor
147
148 def device_types(self):
149 return DeviceTypes(items=self.supported_device_types)
150
151 def health(self):
152 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
153
154 def change_master_state(self, master):
155 raise NotImplementedError()
156
157 def adopt_device(self, device):
158 log.info('adopt-device', device=device)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800159 self._activate_io_port()
160 reactor.callLater(0, self._launch_device_activation, device)
Zsolt Harasztied091602016-12-08 13:36:38 -0800161
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800162 def _activate_io_port(self):
163 if self.io_port is None:
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800164 self.io_port = registry('frameio').open_port(
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800165 self.interface, self._rcv_io, is_tibit_frame)
166
167 @inlineCallbacks
168 def _launch_device_activation(self, device):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800169 try:
170 log.debug('launch_dev_activation')
171 # prepare receive queue
172 self.incoming_queues[device.mac_address] = DeferredQueue(size=100)
173
Nathan Knuth6e57f332016-12-22 15:49:20 -0800174 # add mac_address to device_ids table
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800175 olt_mac = device.mac_address
Nathan Knuth6e57f332016-12-22 15:49:20 -0800176 self.device_ids[olt_mac] = device.id
177
178 # send out ping to OLT device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800179 ping_frame = self._make_ping_frame(mac_address=olt_mac)
180 self.io_port.send(ping_frame)
181
182 # wait till we receive a response
Nathan Knuth6e57f332016-12-22 15:49:20 -0800183 ## TODO add timeout mechanism so we can signal if we cannot reach
184 ##device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800185 while True:
186 response = yield self.incoming_queues[olt_mac].get()
187 # verify response and if not the expected response
188 if 1: # TODO check if it is really what we expect, and wait if not
189 break
190
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800191 except Exception as e:
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800192 log.exception('launch device failed', e=e)
193
194 # if we got response, we can fill out the device info, mark the device
195 # reachable
Zsolt Haraszti80175202016-12-24 00:17:51 -0800196 jdev = json.loads(response.payload.payload.body.load)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800197 device.root = True
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800198 device.vendor = 'Tibit Communications, Inc.'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800199 device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800200 device.hardware_version = jdev['results']['datecode']
201 device.firmware_version = jdev['results']['firmware']
202 device.software_version = jdev['results']['modelversion']
203 device.serial_number = jdev['results']['manufacturer']
Nathan Knuth6e57f332016-12-22 15:49:20 -0800204
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800205 device.connect_status = ConnectStatus.REACHABLE
206 self.adapter_agent.update_device(device)
207
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800208 # then shortly after we create some ports for the device
209 log.info('create-port')
210 nni_port = Port(
211 port_no=2,
212 label='NNI facing Ethernet port',
213 type=Port.ETHERNET_NNI,
214 admin_state=AdminState.ENABLED,
215 oper_status=OperStatus.ACTIVE
216 )
217 self.adapter_agent.add_port(device.id, nni_port)
218 self.adapter_agent.add_port(device.id, Port(
219 port_no=1,
220 label='PON port',
221 type=Port.PON_OLT,
222 admin_state=AdminState.ENABLED,
223 oper_status=OperStatus.ACTIVE
224 ))
225
226 log.info('create-logical-device')
227 # then shortly after we create the logical device with one port
228 # that will correspond to the NNI port
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800229 ld = LogicalDevice(
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800230 desc=ofp_desc(
231 mfr_desc=device.vendor,
232 hw_desc=jdev['results']['device'],
233 sw_desc=jdev['results']['firmware'],
234 serial_num=uuid4().hex,
235 dp_desc='n/a'
236 ),
237 switch_features=ofp_switch_features(
238 n_buffers=256, # TODO fake for now
239 n_tables=2, # TODO ditto
240 capabilities=( # TODO and ditto
241 OFPC_FLOW_STATS
242 | OFPC_TABLE_STATS
243 | OFPC_PORT_STATS
244 | OFPC_GROUP_STATS
245 )
246 ),
247 root_device_id=device.id
248 )
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800249 ld_initialized = self.adapter_agent.create_logical_device(ld)
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800250 cap = OFPPF_10GB_FD | OFPPF_FIBER
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800251 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800252 id='nni',
253 ofp_port=ofp_port(
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800254 port_no=0,
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800255 hw_addr=mac_str_to_tuple(device.mac_address),
256 name='nni',
257 config=0,
258 state=OFPPS_LIVE,
259 curr=cap,
260 advertised=cap,
261 peer=cap,
262 curr_speed=OFPPF_10GB_FD,
263 max_speed=OFPPF_10GB_FD
264 ),
265 device_id=device.id,
266 device_port_no=nni_port.port_no,
267 root_port=True
268 ))
269
270 # and finally update to active
271 device = self.adapter_agent.get_device(device.id)
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800272 device.parent_id = ld_initialized.id
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800273 device.oper_status = OperStatus.ACTIVE
274 self.adapter_agent.update_device(device)
275
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800276 # Just transitioned to ACTIVE, wait a tenth of second
277 # before checking for ONUs
278 reactor.callLater(0.1, self._detect_onus, device)
279
280 @inlineCallbacks
281 def _detect_onus(self, device):
282 # send out get 'links' to the OLT device
283 olt_mac = device.mac_address
284 links_frame = self._make_links_frame(mac_address=olt_mac)
285 self.io_port.send(links_frame)
286 while True:
287 response = yield self.incoming_queues[olt_mac].get()
288 # verify response and if not the expected response
289 if 1: # TODO check if it is really what we expect, and wait if not
290 break
291
Zsolt Haraszti80175202016-12-24 00:17:51 -0800292 jdev = json.loads(response.payload.payload.body.load)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600293 onu_mac = ''
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800294 for macid in jdev['results']:
295 if macid['macid'] is None:
296 log.info('MAC ID is NONE %s' % str(macid['macid']))
Nathan Knuthd8285e62017-01-11 14:18:43 -0600297 elif macid['macid'][:6].upper() == SUMITOMO_ELECTRIC_INDUSTRIES_OUI:
298 onu_mac = macid['macid']
299 log.info('SUMITOMO mac address %s' % str(macid['macid']))
300 log.info('activate-olt-for-onu-%s' % onu_mac)
301 # Convert from string to colon separated form
302 onu_mac = ':'.join(s.encode('hex') for s in onu_mac.decode('hex'))
303 vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
304 self.adapter_agent.child_device_detected(
305 parent_device_id=device.id,
306 parent_port_no=1,
307 child_device_type='dpoe_onu',
308 mac_address = onu_mac,
309 proxy_address=Device.ProxyAddress(
310 device_id=device.id,
311 channel_id=vlan_id
312 ),
313 vlan=vlan_id
314 )
315
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800316 else:
Nathan Knuth09c23102017-02-10 04:43:30 -0800317 onu_mac_string = '000c' + macid.get('macid', 'e2000000')[4:]
Nathan Knuthd8285e62017-01-11 14:18:43 -0600318 log.info('activate-olt-for-onu-%s' % onu_mac)
319 # Convert from string to colon separated form
Nathan Knuth09c23102017-02-10 04:43:30 -0800320 onu_mac = ':'.join(s.encode('hex') for s in onu_mac_string.decode('hex'))
321 serial_num = int(macid['macid'][-4:-2], 16)
322 vlan_id = self._olt_side_onu_activation(serial_num)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600323 self.adapter_agent.child_device_detected(
324 parent_device_id=device.id,
325 parent_port_no=1,
326 child_device_type='tibit_onu',
327 mac_address = onu_mac,
328 proxy_address=Device.ProxyAddress(
329 device_id=device.id,
330 channel_id=vlan_id
331 ),
332 vlan=vlan_id
333 )
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800334
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800335 ## Automatically setup default downstream control frames flow (in this case VLAN 4000)
336 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
337 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
338 packet_out_rule = (
339 Ether(dst=device.mac_address) /
340 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
341 EOAMPayload(
342 body=CablelabsOUI() / DPoEOpcode_SetRequest() /
343 NetworkToNetworkPortObject()/
344 PortIngressRuleHeader(precedence=13)/
345 PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
346 operator=Operator['=='],
347 match=TIBIT_PACKET_OUT_VLAN)/
348 PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
349 operator=Operator['=='], match=vlan_id)/
350 PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=int(onu_mac_string[4:], 16))/
351 PortIngressRuleResultForward()/
352 PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
353 PortIngressRuleTerminator()/
354 AddPortIngressRule()))
Nathan Knuth09c23102017-02-10 04:43:30 -0800355
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800356 self.io_port.send(str(packet_out_rule))
357 while True:
358 response = yield self.incoming_queues[olt_mac].get()
359 # verify response and if not the expected response
360 if 1: # TODO check if it is really what we expect, and wait if not
361 break
Nathan Knuth09c23102017-02-10 04:43:30 -0800362
Nathan Knuth388eff32017-01-18 18:31:22 -0600363 # also record the vlan_id -> (device_id, logical_device_id, linkid) for
364 # later use. The linkid is the macid returned.
365 self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id, macid.get('macid', 0))
366
Nathan Knuth09c23102017-02-10 04:43:30 -0800367 ### KPI Metrics - Work in progress feature - Disabling for now
Nathan Knuthab966e52017-01-30 07:48:13 -0800368 ### Give the ONUs a chance to arrive before starting metric collection
369 ### reactor.callLater(5.0, self.start_kpi_collection, device.id)
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800370
Nathan Knuth6e57f332016-12-22 15:49:20 -0800371 def _olt_side_onu_activation(self, serial):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800372 """
373 This is where if this was a real OLT, the OLT-side activation for
374 the new ONU should be performed. By the time we return, the OLT shall
375 be able to provide tunneled (proxy) communication to the given ONU,
376 using the returned information.
377 """
Nathan Knuth6e57f332016-12-22 15:49:20 -0800378 vlan_id = serial + 200
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800379 return vlan_id
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800380
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800381 def _rcv_io(self, port, frame):
382
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800383 log.info('frame-received', frame=hexify(frame))
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800384
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800385 # make into frame to extract source mac
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800386 response = Ether(frame)
387
Nathan Knuth6e57f332016-12-22 15:49:20 -0800388 if response.haslayer(Dot1Q):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800389
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800390 # All OAM responses from the OLT should have a TIBIT_MGMT_VLAN.
391 # Responses from the ONUs should have a TIBIT_MGMT_VLAN followed by a ONU CTAG
392 # All packet-in frames will have the TIBIT_PACKET_IN_VLAN.
393 if response.getlayer(Dot1Q).type == 0x8100:
394
395 if response.getlayer(Dot1Q).vlan == TIBIT_PACKET_IN_VLAN:
396
397 inner_tag_and_rest = response.payload.payload
398
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800399 if isinstance(inner_tag_and_rest, Dot1Q):
400
401 cvid = inner_tag_and_rest.vlan
402
403 frame = Ether(src=response.src,
404 dst=response.dst,
405 type=inner_tag_and_rest.type) /\
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800406 inner_tag_and_rest.payload
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800407
Nathan Knuth6818b3b2017-02-10 03:28:03 -0800408 _, logical_device_id, _ = self.vlan_to_device_ids.get(cvid)
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800409 if logical_device_id is None:
410 log.error('invalid-cvid', cvid=cvid)
411 else:
412 self.adapter_agent.send_packet_in(
413 logical_device_id=logical_device_id,
414 logical_port_no=cvid, # C-VID encodes port no
415 packet=str(frame))
416
417 else:
418 log.error('packet-in-single-tagged',
419 frame=hexify(response))
420
421 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800422 ## Mgmt responses received from the ONU
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800423 ## Since the type of the first layer is 0x8100,
424 ## then the frame must have an inner tag layer
425 olt_mac = response.src
426 device_id = self.device_ids[olt_mac]
427 channel_id = response[Dot1Q:2].vlan
428 log.info('received_channel_id', channel_id=channel_id,
429 device_id=device_id)
430
431 proxy_address=Device.ProxyAddress(
432 device_id=device_id,
433 channel_id=channel_id
434 )
435 # pop dot1q header(s)
436 msg = response.payload.payload
437 self.adapter_agent.receive_proxied_message(proxy_address, msg)
438
Nathan Knuth6e57f332016-12-22 15:49:20 -0800439 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800440 ## Mgmt responses received from the OLT
Nathan Knuth6e57f332016-12-22 15:49:20 -0800441 ## enqueue incoming parsed frame to right device
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800442 log.info('received-dot1q-not-8100')
Nathan Knuth6e57f332016-12-22 15:49:20 -0800443 self.incoming_queues[response.src].put(response)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800444
445 def _make_ping_frame(self, mac_address):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800446 # Create a json packet
447 json_operation_str = '{\"operation\":\"version\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800448 frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800449 return str(frame)
450
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800451 def _make_links_frame(self, mac_address):
452 # Create a json packet
453 json_operation_str = '{\"operation\":\"links\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800454 frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800455 return str(frame)
456
Nathan Knuth388eff32017-01-18 18:31:22 -0600457 def _make_stats_frame(self, mac_address, itype, link):
458 # Create a json packet
459 json_operation_str = ('{\"operation\":\"stats\",\"parameters\":{\"itype\":\"%s\",\"iinst\",\"0\",\"macid\":\"%s\"}}' % (itype, link))
460 frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
461 return str(frame)
462
Zsolt Harasztied091602016-12-08 13:36:38 -0800463 def abandon_device(self, device):
464 raise NotImplementedError(0
465 )
466 def deactivate_device(self, device):
467 raise NotImplementedError()
468
469 def update_flows_bulk(self, device, flows, groups):
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800470 log.info('########################################')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800471 log.info('bulk-flow-update', device_id=device.id,
472 flows=flows, groups=groups)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800473 assert len(groups.items) == 0, "Cannot yet deal with groups"
474
Nathan Knuthf840dfb2017-01-12 18:15:14 -0800475 # extract ONU VID
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800476 # vid_from_device_id = {v[0]: k for k,v in self.vlan_to_device_ids.iteritems()}
477 # ONU_VID = vid_from_device_id[device.id]
Nathan Knuth05f859e2017-02-23 13:22:26 -0800478 _inner_vid = None
Nathan Knuth5f4163e2017-01-11 18:21:10 -0600479
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800480 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
481 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800482
Zsolt Haraszti80175202016-12-24 00:17:51 -0800483 for flow in flows.items:
Zsolt Haraszti80175202016-12-24 00:17:51 -0800484
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800485 try:
486 in_port = get_in_port(flow)
487 assert in_port is not None
Zsolt Haraszti80175202016-12-24 00:17:51 -0800488
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800489 precedence = 255 - min(flow.priority / 256, 255)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800490
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800491 if in_port == 2:
492 log.info('#### Downstream Rule ####')
493 dn_req = NetworkToNetworkPortObject()
494 dn_req /= PortIngressRuleHeader(precedence=precedence)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800495
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800496 for field in get_ofb_fields(flow):
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800497
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800498 if field.type == ETH_TYPE:
499 _type = field.eth_type
500 log.info('#### field.type == ETH_TYPE ####')
501 dn_req /= PortIngressRuleClauseMatchLength02(
502 fieldcode=Clause['L2 Type/Len'],
503 operator=Operator['=='],
504 match=_type)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800505
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800506 elif field.type == IP_PROTO:
507 _proto = field.ip_proto
508 log.info('#### field.type == IP_PROTO ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800509
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800510 elif field.type == IN_PORT:
511 _port = field.port
512 log.info('#### field.type == IN_PORT ####', port=_port)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800513
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800514 elif field.type == VLAN_VID:
515 _vlan_vid = field.vlan_vid & 0xfff
516 log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800517 _outer_vid = _vlan_vid
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800518
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800519 elif field.type == VLAN_PCP:
520 _vlan_pcp = field.vlan_pcp
521 log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800522
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800523 elif field.type == UDP_DST:
524 _udp_dst = field.udp_dst
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800525 log.info('#### field.type == UDP_DST ####', udp_dst=_udp_dst)
Zsolt Haraszti6a5107c2017-01-09 23:42:41 -0800526
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800527 elif field.type == UDP_SRC:
528 _udp_src = field.udp_src
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800529 log.info('#### field.type == UDP_SRC ####', udp_src=_udp_src)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800530
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800531 elif field.type == IPV4_DST:
532 _ipv4_dst = field.ipv4_dst
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800533 log.info('#### field.type == IPV4_DST ####', ipv4_dst=_ipv4_dst)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800534
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800535 elif field.type == METADATA:
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800536 _metadata = field.table_metadata
537 log.info('#### field.type == METADATA ####', metadata=_metadata)
538 _inner_vid = _metadata
Zsolt Haraszti80175202016-12-24 00:17:51 -0800539
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800540 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800541 raise NotImplementedError('field.type={}'.format(
542 field.type))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800543
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800544 for action in get_actions(flow):
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800545
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800546 if action.type == OUTPUT:
547 log.info('#### action.type == OUTPUT ####')
548 dn_req /= PortIngressRuleResultForward()
Nathan Knuth05f859e2017-02-23 13:22:26 -0800549 if _outer_vid == MULTICAST_VLAN:
550 dn_req /= PortIngressRuleResultOLTBroadcastQueue()
551 else:
552 serial = _inner_vid - 200
553 link = (0xe222 << 16) | (serial << 8)
554 dn_req /= PortIngressRuleResultOLTQueue(unicastvssn="TBIT",
555 unicastlink=link)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800556
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800557 elif action.type == POP_VLAN:
558 log.info('#### action.type == POP_VLAN ####')
Nathan Knuth05f859e2017-02-23 13:22:26 -0800559 if _outer_vid == MULTICAST_VLAN:
560 dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])
561 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
562 operator=Operator['=='], match=_outer_vid)
563 else:
564 dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['S-VLAN Tag'])
565 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
566 operator=Operator['=='], match=_outer_vid)
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800567 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
568 operator=Operator['=='], match=_inner_vid)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800569
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800570 elif action.type == PUSH_VLAN:
571 log.info('#### action.type == PUSH_VLAN ####')
572 if action.push.ethertype != 0x8100:
573 log.error('unhandled-tpid',
574 ethertype=action.push.ethertype)
575 dn_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
Nathan Knuthd8285e62017-01-11 14:18:43 -0600576
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800577 elif action.type == SET_FIELD:
578 log.info('#### action.type == SET_FIELD ####')
579 assert (action.set_field.field.oxm_class ==
580 ofp.OFPXMC_OPENFLOW_BASIC)
581 field = action.set_field.field.ofb_field
582 if field.type == VLAN_VID:
583 dn_req /= PortIngressRuleResultSet(
584 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
585 else:
586 log.error('unsupported-action-set-field-type',
587 field_type=field.type)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600588 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800589 log.error('UNSUPPORTED-ACTION-TYPE',
590 action_type=action.type)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800591
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800592 dn_req /= PortIngressRuleTerminator()
593 dn_req /= AddPortIngressRule()
594
595 msg = (
596 Ether(dst=device.mac_address) /
597 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
598 EOAMPayload(
599 body=CablelabsOUI() / DPoEOpcode_SetRequest() / dn_req)
600 )
601
602 self.io_port.send(str(msg))
603
604 elif in_port == 1:
605 # Upstream rule
606 log.info('#### Upstream Rule ####')
607
608 field_match_vlan_upstream_with_link = False
609 up_req_link = PortIngressRuleHeader(precedence=precedence)
610
611 up_req_pon = PonPortObject()
612 up_req_pon /= PortIngressRuleHeader(precedence=precedence)
613
614 for field in get_ofb_fields(flow):
615
616 if field.type == ETH_TYPE:
617 _type = field.eth_type
618 log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
619 match=_type)
620 up_req_pon /= PortIngressRuleClauseMatchLength02(
621 fieldcode=Clause['L2 Type/Len'],
622 operator=Operator['=='],
623 match=_type)
624
625 up_req_link /= PortIngressRuleClauseMatchLength02(
626 fieldcode=Clause['L2 Type/Len'],
627 operator=Operator['=='],
628 match=_type)
629
630 elif field.type == IP_PROTO:
631 _proto = field.ip_proto
632 log.info('#### field.type == IP_PROTO ####', in_port=in_port,
633 ip_proto=_proto)
634
635 up_req_pon /= PortIngressRuleClauseMatchLength01(
636 fieldcode=Clause['IPv4/IPv6 Protocol Type'],
637 operator=Operator['=='], match=_proto)
638
639 up_req_link /= PortIngressRuleClauseMatchLength01(
640 fieldcode=Clause['IPv4/IPv6 Protocol Type'],
641 operator=Operator['=='], match=_proto)
642
643 elif field.type == IN_PORT:
644 _port = field.port
645 log.info('#### field.type == IN_PORT ####')
646
647 elif field.type == VLAN_VID:
648 _vlan_vid = field.vlan_vid & 0xfff
649 log.info('#### field.type == VLAN_VID ####')
650 up_req_pon /= PortIngressRuleClauseMatchLength02(
651 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
652 operator=Operator['=='], match=_vlan_vid)
653
654 serial = _vlan_vid - 200
655 link = (0xe222 << 16) | (serial << 8)
656 up_req_link /= OLTUnicastLogicalLink(unicastvssn='TBIT', unicastlink=link)
657
658 up_req_link /= PortIngressRuleClauseMatchLength02(
659 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
660 operator=Operator['=='], match=_vlan_vid)
661 field_match_vlan_upstream_with_link = True
662
663
664 elif field.type == VLAN_PCP:
665 _vlan_pcp = field.vlan_pcp
666 log.info('#### field.type == VLAN_PCP ####')
667
668 elif field.type == UDP_DST:
669 _udp_dst = field.udp_dst
670 log.info('#### field.type == UDP_DST ####')
671 up_req_pon /= (PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],
672 operator=Operator['=='], match=0x0044)/
673 PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],
674 operator=Operator['=='], match=0x0043))
675
676 elif field.type == UDP_SRC:
677 _udp_src = field.udp_src
678 log.info('#### field.type == UDP_SRC ####')
679
680 else:
681 raise NotImplementedError('field.type={}'.format(
682 field.type))
683
684 for action in get_actions(flow):
685
686 if action.type == OUTPUT:
687 log.info('#### action.type == OUTPUT ####')
688 up_req_pon /= PortIngressRuleResultForward()
689 up_req_link /= PortIngressRuleResultForward()
690
691 elif action.type == POP_VLAN:
692 log.info('#### action.type == POP_VLAN ####')
693
694 elif action.type == PUSH_VLAN:
695 log.info('#### action.type == PUSH_VLAN ####')
696 if action.push.ethertype != 0x8100:
697 log.error('unhandled-ether-type',
698 ethertype=action.push.ethertype)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600699 if field_match_vlan_upstream_with_link == True:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800700 up_req_link /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
701 fieldinstance=1)
702 else:
703 up_req_pon /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
704 fieldinstance=0)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600705
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800706 elif action.type == SET_FIELD:
707 log.info('#### action.type == SET_FIELD ####')
708 assert (action.set_field.field.oxm_class ==
709 ofp.OFPXMC_OPENFLOW_BASIC)
710 field = action.set_field.field.ofb_field
711 if field.type == VLAN_VID:
712 if field_match_vlan_upstream_with_link == True:
713 up_req_link /=(PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/
714 PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag']))
715
716 up_req_pon /= PortIngressRuleResultSet(
717 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
718 up_req_link /= PortIngressRuleResultSet(
719 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
720 else:
721 log.error('unsupported-action-set-field-type',
722 field_type=field.type)
723
Zsolt Haraszti80175202016-12-24 00:17:51 -0800724 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800725 log.error('UNSUPPORTED-ACTION-TYPE',
726 action_type=action.type)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800727
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800728 if (field_match_vlan_upstream_with_link == True):
729 up_req = up_req_link
Zsolt Haraszti80175202016-12-24 00:17:51 -0800730 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800731 up_req = up_req_pon
Zsolt Haraszti80175202016-12-24 00:17:51 -0800732
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800733 up_req /= PortIngressRuleTerminator()
734 up_req /= AddPortIngressRule()
735
736 msg = (
737 Ether(dst=device.mac_address) /
738 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
739 EOAMPayload(
740 body=CablelabsOUI() / DPoEOpcode_SetRequest() / up_req)
741 )
742
743 self.io_port.send(str(msg))
744
Nathan Knuthd8285e62017-01-11 14:18:43 -0600745 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800746 raise Exception('Port should be 1 or 2 by our convention')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600747
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800748 except Exception, e:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800749 log.exception('failed-to-install-flow', e=e, flow=flow)
Zsolt Harasztied091602016-12-08 13:36:38 -0800750
751 def update_flows_incrementally(self, device, flow_changes, group_changes):
752 raise NotImplementedError()
753
754 def send_proxied_message(self, proxy_address, msg):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800755 log.info('send-proxied-message', proxy_address=proxy_address)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800756 device = self.adapter_agent.get_device(proxy_address.device_id)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800757 frame = Ether(dst=device.mac_address) / \
Nathan Knuth6e57f332016-12-22 15:49:20 -0800758 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
759 Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800760 msg
Nathan Knuth6e57f332016-12-22 15:49:20 -0800761
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800762 self.io_port.send(str(frame))
Zsolt Harasztied091602016-12-08 13:36:38 -0800763
764 def receive_proxied_message(self, proxy_address, msg):
765 raise NotImplementedError()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800766
767 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
768 log.info('packet-out', logical_device_id=logical_device_id,
769 egress_port_no=egress_port_no, msg_len=len(msg))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800770
Nathan Knuth96531582017-02-13 05:27:37 -0800771 _, logical_dev_id, _ = self.vlan_to_device_ids[egress_port_no]
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800772 if logical_dev_id != logical_device_id:
773 raise Exception('Internal table mismatch')
774
775 tmp = Ether(msg)
776
777 frame = Ether(dst=tmp.dst, src=tmp.src) / \
778 Dot1Q(vlan=TIBIT_PACKET_OUT_VLAN) / \
779 Dot1Q(vlan=egress_port_no) / \
780 tmp.payload
781
782 self.io_port.send(str(frame))
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800783
784 def start_kpi_collection(self, device_id):
Nathan Knuthc99552d2017-01-19 11:23:32 -0600785 """ Periodic KPI metric collection from the device """
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800786 import random
787
Nathan Knuthc99552d2017-01-19 11:23:32 -0600788 # This is setup (for now) to be called from the adapter. Push
789 # architectures should be explored in the near future.
790 @inlineCallbacks
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800791 def _collect(device_id, prefix):
792
Nathan Knuth388eff32017-01-18 18:31:22 -0600793 pon_port_metrics = {}
794 links = []
795 olt_mac = next((mac for mac, device in self.device_ids.iteritems() if device == device_id), None)
Nathan Knuth96531582017-02-13 05:27:37 -0800796 links = [v[TIBIT_ONU_LINK_INDEX] for _,v,_ in self.vlan_to_device_ids.iteritems()]
Nathan Knuth388eff32017-01-18 18:31:22 -0600797
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800798 try:
Nathan Knuth388eff32017-01-18 18:31:22 -0600799 # Step 1: gather metrics from device
800 log.info('link stats frame', links=links)
801 for link in links:
802 stats_frame = self._make_stats_frame(mac_address=olt_mac, itype='olt', link=link)
803 self.io_port.send(stats_frame)
804
805 ## Add timeout mechanism so we can signal if we cannot reach
806 ## device
807 while True:
808 response = yield self.incoming_queues[olt_mac].get()
809 jdict = json.loads(response.payload.payload.body.load)
810 pon_port_metrics[link] = {k: int(v,16) for k,v in jdict['results'].iteritems()}
811 # verify response and if not the expected response
812 if 1: # TODO check if it is really what we expect, and wait if not
813 break
814
815 log.info('nni stats frame')
816 olt_nni_link = ''.join(l for l in olt_mac.split(':'))
817 stats_frame = self._make_stats_frame(mac_address=olt_mac, itype='eth', link=olt_nni_link)
818 self.io_port.send(stats_frame)
819
820 ## Add timeout mechanism so we can signal if we cannot reach
821 ## device
822 while True:
823 response = yield self.incoming_queues[olt_mac].get()
824 jdict = json.loads(response.payload.payload.body.load)
825 nni_port_metrics = {k: int(v,16) for k,v in jdict['results'].iteritems()}
826 # verify response and if not the expected response
827 if 1: # TODO check if it is really what we expect, and wait if not
828 break
829
Nathan Knuthc99552d2017-01-19 11:23:32 -0600830 olt_metrics = dict(
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800831 cpu_util=20 + 5 * random.random(),
832 buffer_util=10 + 10 * random.random()
833 )
834
835 # Step 2: prepare the KpiEvent for submission
836 # we can time-stamp them here (or could use time derived from OLT
837 ts = arrow.utcnow().timestamp
Nathan Knuthc99552d2017-01-19 11:23:32 -0600838 prefixes = {
839 # CPU Metrics (example)
840 prefix: MetricValuePairs(metrics=olt_metrics),
841 # OLT NNI port
842 prefix + '.nni': MetricValuePairs(metrics=nni_port_metrics)
843 }
844
845 for link in links:
846 # PON link ports
847 prefixes[prefix + '.pon.{}'.format(link)] = MetricValuePairs(metrics=pon_port_metrics[link])
848
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800849 kpi_event = KpiEvent(
850 type=KpiEventType.slice,
851 ts=ts,
Nathan Knuthc99552d2017-01-19 11:23:32 -0600852 prefixes=prefixes
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800853 )
854
855 # Step 3: submit
856 self.adapter_agent.submit_kpis(kpi_event)
857
858 except Exception as e:
859 log.exception('failed-to-submit-kpis', e=e)
860
861 prefix = 'voltha.{}.{}'.format(self.name, device_id)
862 lc = LoopingCall(_collect, device_id, prefix)
863 lc.start(interval=15) # TODO make this configurable
864