blob: 391f62b41cef0c50e6efd9d54f0d5dc7fad66357 [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
Sergio Slobodrianec864c62017-03-09 11:41:43 -0500148 def update_pm_config(self, device, pm_configs):
149 raise NotImplementedError()
150
Zsolt Harasztied091602016-12-08 13:36:38 -0800151 def device_types(self):
152 return DeviceTypes(items=self.supported_device_types)
153
154 def health(self):
155 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
156
157 def change_master_state(self, master):
158 raise NotImplementedError()
159
160 def adopt_device(self, device):
161 log.info('adopt-device', device=device)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800162 self._activate_io_port()
163 reactor.callLater(0, self._launch_device_activation, device)
Zsolt Harasztied091602016-12-08 13:36:38 -0800164
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800165 def _activate_io_port(self):
166 if self.io_port is None:
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800167 self.io_port = registry('frameio').open_port(
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800168 self.interface, self._rcv_io, is_tibit_frame)
169
170 @inlineCallbacks
171 def _launch_device_activation(self, device):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800172 try:
173 log.debug('launch_dev_activation')
174 # prepare receive queue
175 self.incoming_queues[device.mac_address] = DeferredQueue(size=100)
176
Nathan Knuth6e57f332016-12-22 15:49:20 -0800177 # add mac_address to device_ids table
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800178 olt_mac = device.mac_address
Nathan Knuth6e57f332016-12-22 15:49:20 -0800179 self.device_ids[olt_mac] = device.id
180
181 # send out ping to OLT device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800182 ping_frame = self._make_ping_frame(mac_address=olt_mac)
183 self.io_port.send(ping_frame)
184
185 # wait till we receive a response
Nathan Knuth6e57f332016-12-22 15:49:20 -0800186 ## TODO add timeout mechanism so we can signal if we cannot reach
187 ##device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800188 while True:
189 response = yield self.incoming_queues[olt_mac].get()
190 # verify response and if not the expected response
191 if 1: # TODO check if it is really what we expect, and wait if not
192 break
193
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800194 except Exception as e:
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800195 log.exception('launch device failed', e=e)
196
197 # if we got response, we can fill out the device info, mark the device
198 # reachable
Zsolt Haraszti80175202016-12-24 00:17:51 -0800199 jdev = json.loads(response.payload.payload.body.load)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800200 device.root = True
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800201 device.vendor = 'Tibit Communications, Inc.'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800202 device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800203 device.hardware_version = jdev['results']['datecode']
204 device.firmware_version = jdev['results']['firmware']
205 device.software_version = jdev['results']['modelversion']
206 device.serial_number = jdev['results']['manufacturer']
Nathan Knuth6e57f332016-12-22 15:49:20 -0800207
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800208 device.connect_status = ConnectStatus.REACHABLE
209 self.adapter_agent.update_device(device)
210
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800211 # then shortly after we create some ports for the device
212 log.info('create-port')
213 nni_port = Port(
214 port_no=2,
215 label='NNI facing Ethernet port',
216 type=Port.ETHERNET_NNI,
217 admin_state=AdminState.ENABLED,
218 oper_status=OperStatus.ACTIVE
219 )
220 self.adapter_agent.add_port(device.id, nni_port)
221 self.adapter_agent.add_port(device.id, Port(
222 port_no=1,
223 label='PON port',
224 type=Port.PON_OLT,
225 admin_state=AdminState.ENABLED,
226 oper_status=OperStatus.ACTIVE
227 ))
228
229 log.info('create-logical-device')
230 # then shortly after we create the logical device with one port
231 # that will correspond to the NNI port
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800232 ld = LogicalDevice(
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800233 desc=ofp_desc(
234 mfr_desc=device.vendor,
235 hw_desc=jdev['results']['device'],
236 sw_desc=jdev['results']['firmware'],
237 serial_num=uuid4().hex,
238 dp_desc='n/a'
239 ),
240 switch_features=ofp_switch_features(
241 n_buffers=256, # TODO fake for now
242 n_tables=2, # TODO ditto
243 capabilities=( # TODO and ditto
244 OFPC_FLOW_STATS
245 | OFPC_TABLE_STATS
246 | OFPC_PORT_STATS
247 | OFPC_GROUP_STATS
248 )
249 ),
250 root_device_id=device.id
251 )
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800252 ld_initialized = self.adapter_agent.create_logical_device(ld)
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800253 cap = OFPPF_10GB_FD | OFPPF_FIBER
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800254 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800255 id='nni',
256 ofp_port=ofp_port(
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800257 port_no=0,
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800258 hw_addr=mac_str_to_tuple(device.mac_address),
259 name='nni',
260 config=0,
261 state=OFPPS_LIVE,
262 curr=cap,
263 advertised=cap,
264 peer=cap,
265 curr_speed=OFPPF_10GB_FD,
266 max_speed=OFPPF_10GB_FD
267 ),
268 device_id=device.id,
269 device_port_no=nni_port.port_no,
270 root_port=True
271 ))
272
273 # and finally update to active
274 device = self.adapter_agent.get_device(device.id)
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800275 device.parent_id = ld_initialized.id
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800276 device.oper_status = OperStatus.ACTIVE
277 self.adapter_agent.update_device(device)
278
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800279 # Just transitioned to ACTIVE, wait a tenth of second
280 # before checking for ONUs
281 reactor.callLater(0.1, self._detect_onus, device)
282
283 @inlineCallbacks
284 def _detect_onus(self, device):
285 # send out get 'links' to the OLT device
286 olt_mac = device.mac_address
287 links_frame = self._make_links_frame(mac_address=olt_mac)
288 self.io_port.send(links_frame)
289 while True:
290 response = yield self.incoming_queues[olt_mac].get()
291 # verify response and if not the expected response
292 if 1: # TODO check if it is really what we expect, and wait if not
293 break
294
Zsolt Haraszti80175202016-12-24 00:17:51 -0800295 jdev = json.loads(response.payload.payload.body.load)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600296 onu_mac = ''
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800297 for macid in jdev['results']:
298 if macid['macid'] is None:
299 log.info('MAC ID is NONE %s' % str(macid['macid']))
Nathan Knuthd8285e62017-01-11 14:18:43 -0600300 elif macid['macid'][:6].upper() == SUMITOMO_ELECTRIC_INDUSTRIES_OUI:
301 onu_mac = macid['macid']
302 log.info('SUMITOMO mac address %s' % str(macid['macid']))
303 log.info('activate-olt-for-onu-%s' % onu_mac)
304 # Convert from string to colon separated form
305 onu_mac = ':'.join(s.encode('hex') for s in onu_mac.decode('hex'))
306 vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
307 self.adapter_agent.child_device_detected(
308 parent_device_id=device.id,
309 parent_port_no=1,
310 child_device_type='dpoe_onu',
311 mac_address = onu_mac,
312 proxy_address=Device.ProxyAddress(
313 device_id=device.id,
314 channel_id=vlan_id
315 ),
316 vlan=vlan_id
317 )
318
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800319 else:
Nathan Knuth09c23102017-02-10 04:43:30 -0800320 onu_mac_string = '000c' + macid.get('macid', 'e2000000')[4:]
Nathan Knuthd8285e62017-01-11 14:18:43 -0600321 log.info('activate-olt-for-onu-%s' % onu_mac)
322 # Convert from string to colon separated form
Nathan Knuth09c23102017-02-10 04:43:30 -0800323 onu_mac = ':'.join(s.encode('hex') for s in onu_mac_string.decode('hex'))
324 serial_num = int(macid['macid'][-4:-2], 16)
325 vlan_id = self._olt_side_onu_activation(serial_num)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600326 self.adapter_agent.child_device_detected(
327 parent_device_id=device.id,
328 parent_port_no=1,
329 child_device_type='tibit_onu',
330 mac_address = onu_mac,
331 proxy_address=Device.ProxyAddress(
332 device_id=device.id,
333 channel_id=vlan_id
334 ),
335 vlan=vlan_id
336 )
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800337
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800338 ## Automatically setup default downstream control frames flow (in this case VLAN 4000)
339 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
340 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
341 packet_out_rule = (
342 Ether(dst=device.mac_address) /
343 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
344 EOAMPayload(
345 body=CablelabsOUI() / DPoEOpcode_SetRequest() /
346 NetworkToNetworkPortObject()/
347 PortIngressRuleHeader(precedence=13)/
348 PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
349 operator=Operator['=='],
350 match=TIBIT_PACKET_OUT_VLAN)/
351 PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
352 operator=Operator['=='], match=vlan_id)/
353 PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=int(onu_mac_string[4:], 16))/
354 PortIngressRuleResultForward()/
355 PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
356 PortIngressRuleTerminator()/
357 AddPortIngressRule()))
Nathan Knuth09c23102017-02-10 04:43:30 -0800358
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800359 self.io_port.send(str(packet_out_rule))
360 while True:
361 response = yield self.incoming_queues[olt_mac].get()
362 # verify response and if not the expected response
363 if 1: # TODO check if it is really what we expect, and wait if not
364 break
Nathan Knuth09c23102017-02-10 04:43:30 -0800365
Nathan Knuth388eff32017-01-18 18:31:22 -0600366 # also record the vlan_id -> (device_id, logical_device_id, linkid) for
367 # later use. The linkid is the macid returned.
368 self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id, macid.get('macid', 0))
369
Nathan Knuth09c23102017-02-10 04:43:30 -0800370 ### KPI Metrics - Work in progress feature - Disabling for now
Nathan Knuthab966e52017-01-30 07:48:13 -0800371 ### Give the ONUs a chance to arrive before starting metric collection
372 ### reactor.callLater(5.0, self.start_kpi_collection, device.id)
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800373
Nathan Knuth6e57f332016-12-22 15:49:20 -0800374 def _olt_side_onu_activation(self, serial):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800375 """
376 This is where if this was a real OLT, the OLT-side activation for
377 the new ONU should be performed. By the time we return, the OLT shall
378 be able to provide tunneled (proxy) communication to the given ONU,
379 using the returned information.
380 """
Nathan Knuth6e57f332016-12-22 15:49:20 -0800381 vlan_id = serial + 200
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800382 return vlan_id
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800383
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800384 def _rcv_io(self, port, frame):
385
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800386 log.info('frame-received', frame=hexify(frame))
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800387
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800388 # make into frame to extract source mac
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800389 response = Ether(frame)
390
Nathan Knuth6e57f332016-12-22 15:49:20 -0800391 if response.haslayer(Dot1Q):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800392
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800393 # All OAM responses from the OLT should have a TIBIT_MGMT_VLAN.
394 # Responses from the ONUs should have a TIBIT_MGMT_VLAN followed by a ONU CTAG
395 # All packet-in frames will have the TIBIT_PACKET_IN_VLAN.
396 if response.getlayer(Dot1Q).type == 0x8100:
397
398 if response.getlayer(Dot1Q).vlan == TIBIT_PACKET_IN_VLAN:
399
400 inner_tag_and_rest = response.payload.payload
401
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800402 if isinstance(inner_tag_and_rest, Dot1Q):
403
404 cvid = inner_tag_and_rest.vlan
405
406 frame = Ether(src=response.src,
407 dst=response.dst,
408 type=inner_tag_and_rest.type) /\
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800409 inner_tag_and_rest.payload
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800410
Nathan Knuth6818b3b2017-02-10 03:28:03 -0800411 _, logical_device_id, _ = self.vlan_to_device_ids.get(cvid)
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800412 if logical_device_id is None:
413 log.error('invalid-cvid', cvid=cvid)
414 else:
415 self.adapter_agent.send_packet_in(
416 logical_device_id=logical_device_id,
417 logical_port_no=cvid, # C-VID encodes port no
418 packet=str(frame))
419
420 else:
421 log.error('packet-in-single-tagged',
422 frame=hexify(response))
423
424 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800425 ## Mgmt responses received from the ONU
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800426 ## Since the type of the first layer is 0x8100,
427 ## then the frame must have an inner tag layer
428 olt_mac = response.src
429 device_id = self.device_ids[olt_mac]
430 channel_id = response[Dot1Q:2].vlan
431 log.info('received_channel_id', channel_id=channel_id,
432 device_id=device_id)
433
434 proxy_address=Device.ProxyAddress(
435 device_id=device_id,
436 channel_id=channel_id
437 )
438 # pop dot1q header(s)
439 msg = response.payload.payload
440 self.adapter_agent.receive_proxied_message(proxy_address, msg)
441
Nathan Knuth6e57f332016-12-22 15:49:20 -0800442 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800443 ## Mgmt responses received from the OLT
Nathan Knuth6e57f332016-12-22 15:49:20 -0800444 ## enqueue incoming parsed frame to right device
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800445 log.info('received-dot1q-not-8100')
Nathan Knuth6e57f332016-12-22 15:49:20 -0800446 self.incoming_queues[response.src].put(response)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800447
448 def _make_ping_frame(self, mac_address):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800449 # Create a json packet
450 json_operation_str = '{\"operation\":\"version\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800451 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 -0800452 return str(frame)
453
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800454 def _make_links_frame(self, mac_address):
455 # Create a json packet
456 json_operation_str = '{\"operation\":\"links\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800457 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 -0800458 return str(frame)
459
Nathan Knuth388eff32017-01-18 18:31:22 -0600460 def _make_stats_frame(self, mac_address, itype, link):
461 # Create a json packet
462 json_operation_str = ('{\"operation\":\"stats\",\"parameters\":{\"itype\":\"%s\",\"iinst\",\"0\",\"macid\":\"%s\"}}' % (itype, link))
463 frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
464 return str(frame)
465
Zsolt Harasztied091602016-12-08 13:36:38 -0800466 def abandon_device(self, device):
467 raise NotImplementedError(0
468 )
Khen Nursimulud068d812017-03-06 11:44:18 -0500469 def disable_device(self, device):
470 raise NotImplementedError()
471
472 def reenable_device(self, device):
473 raise NotImplementedError()
474
475 def reboot_device(self, device):
476 raise NotImplementedError()
477
478 def delete_device(self, device):
479 raise NotImplementedError()
480
481 def get_device_details(self, device):
Zsolt Harasztied091602016-12-08 13:36:38 -0800482 raise NotImplementedError()
483
484 def update_flows_bulk(self, device, flows, groups):
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800485 log.info('########################################')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800486 log.info('bulk-flow-update', device_id=device.id,
487 flows=flows, groups=groups)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800488 assert len(groups.items) == 0, "Cannot yet deal with groups"
489
Nathan Knuthf840dfb2017-01-12 18:15:14 -0800490 # extract ONU VID
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800491 # vid_from_device_id = {v[0]: k for k,v in self.vlan_to_device_ids.iteritems()}
492 # ONU_VID = vid_from_device_id[device.id]
Nathan Knuth05f859e2017-02-23 13:22:26 -0800493 _inner_vid = None
Nathan Knuth5f4163e2017-01-11 18:21:10 -0600494
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800495 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
496 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800497
Zsolt Haraszti80175202016-12-24 00:17:51 -0800498 for flow in flows.items:
Zsolt Haraszti80175202016-12-24 00:17:51 -0800499
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800500 try:
501 in_port = get_in_port(flow)
502 assert in_port is not None
Zsolt Haraszti80175202016-12-24 00:17:51 -0800503
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800504 precedence = 255 - min(flow.priority / 256, 255)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800505
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800506 if in_port == 2:
507 log.info('#### Downstream Rule ####')
508 dn_req = NetworkToNetworkPortObject()
509 dn_req /= PortIngressRuleHeader(precedence=precedence)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800510
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800511 for field in get_ofb_fields(flow):
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800512
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800513 if field.type == ETH_TYPE:
514 _type = field.eth_type
515 log.info('#### field.type == ETH_TYPE ####')
516 dn_req /= PortIngressRuleClauseMatchLength02(
517 fieldcode=Clause['L2 Type/Len'],
518 operator=Operator['=='],
519 match=_type)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800520
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800521 elif field.type == IP_PROTO:
522 _proto = field.ip_proto
523 log.info('#### field.type == IP_PROTO ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800524
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800525 elif field.type == IN_PORT:
526 _port = field.port
527 log.info('#### field.type == IN_PORT ####', port=_port)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800528
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800529 elif field.type == VLAN_VID:
530 _vlan_vid = field.vlan_vid & 0xfff
531 log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800532 _outer_vid = _vlan_vid
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800533
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800534 elif field.type == VLAN_PCP:
535 _vlan_pcp = field.vlan_pcp
536 log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800537
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800538 elif field.type == UDP_DST:
539 _udp_dst = field.udp_dst
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800540 log.info('#### field.type == UDP_DST ####', udp_dst=_udp_dst)
Zsolt Haraszti6a5107c2017-01-09 23:42:41 -0800541
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800542 elif field.type == UDP_SRC:
543 _udp_src = field.udp_src
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800544 log.info('#### field.type == UDP_SRC ####', udp_src=_udp_src)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800545
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800546 elif field.type == IPV4_DST:
547 _ipv4_dst = field.ipv4_dst
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800548 log.info('#### field.type == IPV4_DST ####', ipv4_dst=_ipv4_dst)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800549
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800550 elif field.type == METADATA:
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800551 _metadata = field.table_metadata
552 log.info('#### field.type == METADATA ####', metadata=_metadata)
553 _inner_vid = _metadata
Zsolt Haraszti80175202016-12-24 00:17:51 -0800554
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800555 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800556 raise NotImplementedError('field.type={}'.format(
557 field.type))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800558
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800559 for action in get_actions(flow):
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800560
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800561 if action.type == OUTPUT:
562 log.info('#### action.type == OUTPUT ####')
563 dn_req /= PortIngressRuleResultForward()
Nathan Knuth05f859e2017-02-23 13:22:26 -0800564 if _outer_vid == MULTICAST_VLAN:
565 dn_req /= PortIngressRuleResultOLTBroadcastQueue()
566 else:
567 serial = _inner_vid - 200
568 link = (0xe222 << 16) | (serial << 8)
569 dn_req /= PortIngressRuleResultOLTQueue(unicastvssn="TBIT",
570 unicastlink=link)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800571
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800572 elif action.type == POP_VLAN:
573 log.info('#### action.type == POP_VLAN ####')
Nathan Knuth05f859e2017-02-23 13:22:26 -0800574 if _outer_vid == MULTICAST_VLAN:
575 dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])
576 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
577 operator=Operator['=='], match=_outer_vid)
578 else:
579 dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['S-VLAN Tag'])
580 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
581 operator=Operator['=='], match=_outer_vid)
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800582 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
583 operator=Operator['=='], match=_inner_vid)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800584
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800585 elif action.type == PUSH_VLAN:
586 log.info('#### action.type == PUSH_VLAN ####')
587 if action.push.ethertype != 0x8100:
588 log.error('unhandled-tpid',
589 ethertype=action.push.ethertype)
590 dn_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
Nathan Knuthd8285e62017-01-11 14:18:43 -0600591
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800592 elif action.type == SET_FIELD:
593 log.info('#### action.type == SET_FIELD ####')
594 assert (action.set_field.field.oxm_class ==
595 ofp.OFPXMC_OPENFLOW_BASIC)
596 field = action.set_field.field.ofb_field
597 if field.type == VLAN_VID:
598 dn_req /= PortIngressRuleResultSet(
599 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
600 else:
601 log.error('unsupported-action-set-field-type',
602 field_type=field.type)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600603 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800604 log.error('UNSUPPORTED-ACTION-TYPE',
605 action_type=action.type)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800606
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800607 dn_req /= PortIngressRuleTerminator()
608 dn_req /= AddPortIngressRule()
609
610 msg = (
611 Ether(dst=device.mac_address) /
612 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
613 EOAMPayload(
614 body=CablelabsOUI() / DPoEOpcode_SetRequest() / dn_req)
615 )
616
617 self.io_port.send(str(msg))
618
619 elif in_port == 1:
620 # Upstream rule
621 log.info('#### Upstream Rule ####')
622
623 field_match_vlan_upstream_with_link = False
624 up_req_link = PortIngressRuleHeader(precedence=precedence)
625
626 up_req_pon = PonPortObject()
627 up_req_pon /= PortIngressRuleHeader(precedence=precedence)
628
629 for field in get_ofb_fields(flow):
630
631 if field.type == ETH_TYPE:
632 _type = field.eth_type
633 log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
634 match=_type)
635 up_req_pon /= PortIngressRuleClauseMatchLength02(
636 fieldcode=Clause['L2 Type/Len'],
637 operator=Operator['=='],
638 match=_type)
639
640 up_req_link /= PortIngressRuleClauseMatchLength02(
641 fieldcode=Clause['L2 Type/Len'],
642 operator=Operator['=='],
643 match=_type)
644
645 elif field.type == IP_PROTO:
646 _proto = field.ip_proto
647 log.info('#### field.type == IP_PROTO ####', in_port=in_port,
648 ip_proto=_proto)
649
650 up_req_pon /= PortIngressRuleClauseMatchLength01(
651 fieldcode=Clause['IPv4/IPv6 Protocol Type'],
652 operator=Operator['=='], match=_proto)
653
654 up_req_link /= PortIngressRuleClauseMatchLength01(
655 fieldcode=Clause['IPv4/IPv6 Protocol Type'],
656 operator=Operator['=='], match=_proto)
657
658 elif field.type == IN_PORT:
659 _port = field.port
660 log.info('#### field.type == IN_PORT ####')
661
662 elif field.type == VLAN_VID:
663 _vlan_vid = field.vlan_vid & 0xfff
664 log.info('#### field.type == VLAN_VID ####')
665 up_req_pon /= PortIngressRuleClauseMatchLength02(
666 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
667 operator=Operator['=='], match=_vlan_vid)
668
669 serial = _vlan_vid - 200
670 link = (0xe222 << 16) | (serial << 8)
671 up_req_link /= OLTUnicastLogicalLink(unicastvssn='TBIT', unicastlink=link)
672
673 up_req_link /= PortIngressRuleClauseMatchLength02(
674 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
675 operator=Operator['=='], match=_vlan_vid)
676 field_match_vlan_upstream_with_link = True
677
678
679 elif field.type == VLAN_PCP:
680 _vlan_pcp = field.vlan_pcp
681 log.info('#### field.type == VLAN_PCP ####')
682
683 elif field.type == UDP_DST:
684 _udp_dst = field.udp_dst
685 log.info('#### field.type == UDP_DST ####')
686 up_req_pon /= (PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],
687 operator=Operator['=='], match=0x0044)/
688 PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],
689 operator=Operator['=='], match=0x0043))
690
691 elif field.type == UDP_SRC:
692 _udp_src = field.udp_src
693 log.info('#### field.type == UDP_SRC ####')
694
695 else:
696 raise NotImplementedError('field.type={}'.format(
697 field.type))
698
699 for action in get_actions(flow):
700
701 if action.type == OUTPUT:
702 log.info('#### action.type == OUTPUT ####')
703 up_req_pon /= PortIngressRuleResultForward()
704 up_req_link /= PortIngressRuleResultForward()
705
706 elif action.type == POP_VLAN:
707 log.info('#### action.type == POP_VLAN ####')
708
709 elif action.type == PUSH_VLAN:
710 log.info('#### action.type == PUSH_VLAN ####')
711 if action.push.ethertype != 0x8100:
712 log.error('unhandled-ether-type',
713 ethertype=action.push.ethertype)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600714 if field_match_vlan_upstream_with_link == True:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800715 up_req_link /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
716 fieldinstance=1)
717 else:
718 up_req_pon /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
719 fieldinstance=0)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600720
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800721 elif action.type == SET_FIELD:
722 log.info('#### action.type == SET_FIELD ####')
723 assert (action.set_field.field.oxm_class ==
724 ofp.OFPXMC_OPENFLOW_BASIC)
725 field = action.set_field.field.ofb_field
726 if field.type == VLAN_VID:
727 if field_match_vlan_upstream_with_link == True:
728 up_req_link /=(PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/
729 PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag']))
730
731 up_req_pon /= PortIngressRuleResultSet(
732 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
733 up_req_link /= PortIngressRuleResultSet(
734 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
735 else:
736 log.error('unsupported-action-set-field-type',
737 field_type=field.type)
738
Zsolt Haraszti80175202016-12-24 00:17:51 -0800739 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800740 log.error('UNSUPPORTED-ACTION-TYPE',
741 action_type=action.type)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800742
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800743 if (field_match_vlan_upstream_with_link == True):
744 up_req = up_req_link
Zsolt Haraszti80175202016-12-24 00:17:51 -0800745 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800746 up_req = up_req_pon
Zsolt Haraszti80175202016-12-24 00:17:51 -0800747
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800748 up_req /= PortIngressRuleTerminator()
749 up_req /= AddPortIngressRule()
750
751 msg = (
752 Ether(dst=device.mac_address) /
753 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
754 EOAMPayload(
755 body=CablelabsOUI() / DPoEOpcode_SetRequest() / up_req)
756 )
757
758 self.io_port.send(str(msg))
759
Nathan Knuthd8285e62017-01-11 14:18:43 -0600760 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800761 raise Exception('Port should be 1 or 2 by our convention')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600762
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800763 except Exception, e:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800764 log.exception('failed-to-install-flow', e=e, flow=flow)
Zsolt Harasztied091602016-12-08 13:36:38 -0800765
766 def update_flows_incrementally(self, device, flow_changes, group_changes):
767 raise NotImplementedError()
768
769 def send_proxied_message(self, proxy_address, msg):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800770 log.info('send-proxied-message', proxy_address=proxy_address)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800771 device = self.adapter_agent.get_device(proxy_address.device_id)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800772 frame = Ether(dst=device.mac_address) / \
Nathan Knuth6e57f332016-12-22 15:49:20 -0800773 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
774 Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800775 msg
Nathan Knuth6e57f332016-12-22 15:49:20 -0800776
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800777 self.io_port.send(str(frame))
Zsolt Harasztied091602016-12-08 13:36:38 -0800778
779 def receive_proxied_message(self, proxy_address, msg):
780 raise NotImplementedError()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800781
782 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
783 log.info('packet-out', logical_device_id=logical_device_id,
784 egress_port_no=egress_port_no, msg_len=len(msg))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800785
Nathan Knuth96531582017-02-13 05:27:37 -0800786 _, logical_dev_id, _ = self.vlan_to_device_ids[egress_port_no]
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800787 if logical_dev_id != logical_device_id:
788 raise Exception('Internal table mismatch')
789
790 tmp = Ether(msg)
791
792 frame = Ether(dst=tmp.dst, src=tmp.src) / \
793 Dot1Q(vlan=TIBIT_PACKET_OUT_VLAN) / \
794 Dot1Q(vlan=egress_port_no) / \
795 tmp.payload
796
797 self.io_port.send(str(frame))
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800798
799 def start_kpi_collection(self, device_id):
Nathan Knuthc99552d2017-01-19 11:23:32 -0600800 """ Periodic KPI metric collection from the device """
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800801 import random
802
Nathan Knuthc99552d2017-01-19 11:23:32 -0600803 # This is setup (for now) to be called from the adapter. Push
804 # architectures should be explored in the near future.
805 @inlineCallbacks
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800806 def _collect(device_id, prefix):
807
Nathan Knuth388eff32017-01-18 18:31:22 -0600808 pon_port_metrics = {}
809 links = []
810 olt_mac = next((mac for mac, device in self.device_ids.iteritems() if device == device_id), None)
Nathan Knuth96531582017-02-13 05:27:37 -0800811 links = [v[TIBIT_ONU_LINK_INDEX] for _,v,_ in self.vlan_to_device_ids.iteritems()]
Nathan Knuth388eff32017-01-18 18:31:22 -0600812
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800813 try:
Nathan Knuth388eff32017-01-18 18:31:22 -0600814 # Step 1: gather metrics from device
815 log.info('link stats frame', links=links)
816 for link in links:
817 stats_frame = self._make_stats_frame(mac_address=olt_mac, itype='olt', link=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 pon_port_metrics[link] = {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
830 log.info('nni stats frame')
831 olt_nni_link = ''.join(l for l in olt_mac.split(':'))
832 stats_frame = self._make_stats_frame(mac_address=olt_mac, itype='eth', link=olt_nni_link)
833 self.io_port.send(stats_frame)
834
835 ## Add timeout mechanism so we can signal if we cannot reach
836 ## device
837 while True:
838 response = yield self.incoming_queues[olt_mac].get()
839 jdict = json.loads(response.payload.payload.body.load)
840 nni_port_metrics = {k: int(v,16) for k,v in jdict['results'].iteritems()}
841 # verify response and if not the expected response
842 if 1: # TODO check if it is really what we expect, and wait if not
843 break
844
Nathan Knuthc99552d2017-01-19 11:23:32 -0600845 olt_metrics = dict(
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800846 cpu_util=20 + 5 * random.random(),
847 buffer_util=10 + 10 * random.random()
848 )
849
850 # Step 2: prepare the KpiEvent for submission
851 # we can time-stamp them here (or could use time derived from OLT
852 ts = arrow.utcnow().timestamp
Nathan Knuthc99552d2017-01-19 11:23:32 -0600853 prefixes = {
854 # CPU Metrics (example)
855 prefix: MetricValuePairs(metrics=olt_metrics),
856 # OLT NNI port
857 prefix + '.nni': MetricValuePairs(metrics=nni_port_metrics)
858 }
859
860 for link in links:
861 # PON link ports
862 prefixes[prefix + '.pon.{}'.format(link)] = MetricValuePairs(metrics=pon_port_metrics[link])
863
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800864 kpi_event = KpiEvent(
865 type=KpiEventType.slice,
866 ts=ts,
Nathan Knuthc99552d2017-01-19 11:23:32 -0600867 prefixes=prefixes
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800868 )
869
870 # Step 3: submit
871 self.adapter_agent.submit_kpis(kpi_event)
872
873 except Exception as e:
874 log.exception('failed-to-submit-kpis', e=e)
875
876 prefix = 'voltha.{}.{}'.format(self.name, device_id)
877 lc = LoopingCall(_collect, device_id, prefix)
878 lc.start(interval=15) # TODO make this configurable
879