blob: 36ab71de3fac34f3d77490e1c27feb138936b2af [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 Knuthb396f472017-03-28 17:18:51 -070044 PortIngressRuleTerminator, AddPortIngressRule, CablelabsOUI, \
45 ItuOUI, PonPortObject
Nathan Knuth31c36962016-12-27 10:04:49 -080046from voltha.extensions.eoam.EOAM_TLV import PortIngressRuleHeader
Nathan Knuthd390ceb2017-01-07 15:38:58 -080047from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
48from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
Nathan Knuth09c23102017-02-10 04:43:30 -080049from voltha.extensions.eoam.EOAM import EOAMPayload, CablelabsOUI
Zsolt Haraszti80175202016-12-24 00:17:51 -080050from voltha.core.flow_decomposer import *
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080051from voltha.core.logical_device_agent import mac_str_to_tuple
Zsolt Harasztied091602016-12-08 13:36:38 -080052from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
Zsolt Haraszti80175202016-12-24 00:17:51 -080053from voltha.protos.common_pb2 import LogLevel, ConnectStatus
54from voltha.protos.common_pb2 import OperStatus, AdminState
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080055from voltha.protos.device_pb2 import Device, Port
Zsolt Harasztied091602016-12-08 13:36:38 -080056from voltha.protos.device_pb2 import DeviceType, DeviceTypes
Zsolt Harasztic5f740b2017-01-18 09:53:17 -080057from voltha.protos.events_pb2 import KpiEvent, MetricValuePairs
58from voltha.protos.events_pb2 import KpiEventType
Zsolt Harasztied091602016-12-08 13:36:38 -080059from voltha.protos.health_pb2 import HealthStatus
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080060from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
61from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_10GB_FD, \
Nathan Knuthd8285e62017-01-11 14:18:43 -060062 OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
63 OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
Zsolt Haraszti80175202016-12-24 00:17:51 -080064from voltha.registry import registry
Zsolt Haraszti348d1932016-12-10 01:10:07 -080065log = structlog.get_logger()
Zsolt Harasztied091602016-12-08 13:36:38 -080066
Nathan Knuth388eff32017-01-18 18:31:22 -060067TIBIT_ONU_LINK_INDEX = 2
68
Nathan Knuth6e57f332016-12-22 15:49:20 -080069# Match on the MGMT VLAN, Priority 7
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080070TIBIT_MGMT_VLAN = 4090
71TIBIT_MGMT_PRIORITY = 7
72frame_match_case1 = 'ether[14:2] = 0x{:01x}{:03x}'.format(
73 TIBIT_MGMT_PRIORITY << 1, TIBIT_MGMT_VLAN)
74
75TIBIT_PACKET_IN_VLAN = 4000
76frame_match_case2 = '(ether[14:2] & 0xfff) = 0x{:03x}'.format(
77 TIBIT_PACKET_IN_VLAN)
78
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080079TIBIT_PACKET_OUT_VLAN = 4000
80
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080081is_tibit_frame = BpfProgramFilter('{} or {}'.format(
82 frame_match_case1, frame_match_case2))
83
Nathan Knuth05f859e2017-02-23 13:22:26 -080084
85# TODO: This information should be conveyed to the adapter
86# from a higher level.
87MULTICAST_VLAN = 140
88
Zsolt Haraszti89a27302016-12-08 16:53:06 -080089
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080090# Extract OLT MAC address: This is a good
91# example of getting the OLT mac address
92
93#for mac, device in self.device_ids.iteritems():
94# if device == dev_id:
95# olt_mac_address = mac
96# log.info('packet-out', olt_mac_address=olt_mac_address)
Zsolt Haraszti85f12852016-12-24 08:30:58 -080097
Zsolt Haraszti348d1932016-12-10 01:10:07 -080098# To be removed in favor of OAM
Zsolt Haraszti89a27302016-12-08 16:53:06 -080099class TBJSON(Packet):
100 """ TBJSON 'packet' layer. """
101 name = "TBJSON"
102 fields_desc = [StrField("data", default="")]
103
Paul Graya107c4d2017-03-16 13:57:58 -0400104bind_layers(Ether, TBJSON, type=0xA8C8)
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800105
Nathan Knuthb396f472017-03-28 17:18:51 -0700106TIBIT_COMMUNICATIONS_OUI=u'000CE2'
107SUMITOMO_ELECTRIC_INDUSTRIES_OUI=u'0025DC'
108
109ADTRAN_SHORTENED_VSSN=u'4144' # 'AD'
110TIBIT_SHORTENED_VSSN=u'5442' # 'TB'
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800111
Zsolt Harasztied091602016-12-08 13:36:38 -0800112@implementer(IAdapterInterface)
113class TibitOltAdapter(object):
114
115 name = 'tibit_olt'
116
117 supported_device_types = [
118 DeviceType(
119 id='tibit_olt',
120 adapter=name,
121 accepts_bulk_flow_update=True
122 )
123 ]
124
125 def __init__(self, adapter_agent, config):
126 self.adapter_agent = adapter_agent
127 self.config = config
128 self.descriptor = Adapter(
129 id=self.name,
130 vendor='Tibit Communications Inc.',
131 version='0.1',
132 config=AdapterConfig(log_level=LogLevel.INFO)
133 )
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800134 self.interface = registry('main').get_args().interface
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800135 self.io_port = None
Nathan Knuth6e57f332016-12-22 15:49:20 -0800136 self.incoming_queues = {} # OLT mac_address -> DeferredQueue()
137 self.device_ids = {} # OLT mac_address -> device_id
Nathan Knuth96531582017-02-13 05:27:37 -0800138 self.vlan_to_device_ids = {} # c-vid -> (device_id, logical_device_id, mac_address)
Zsolt Harasztied091602016-12-08 13:36:38 -0800139
140 def start(self):
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800141 log.debug('starting', interface=self.interface)
142 log.info('started', interface=self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800143
144 def stop(self):
145 log.debug('stopping')
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800146 if self.io_port is not None:
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800147 registry('frameio').close_port(self.io_port)
Zsolt Harasztied091602016-12-08 13:36:38 -0800148 log.info('stopped')
149
150 def adapter_descriptor(self):
151 return self.descriptor
152
Sergio Slobodrianec864c62017-03-09 11:41:43 -0500153 def update_pm_config(self, device, pm_configs):
154 raise NotImplementedError()
155
Zsolt Harasztied091602016-12-08 13:36:38 -0800156 def device_types(self):
157 return DeviceTypes(items=self.supported_device_types)
158
159 def health(self):
160 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
161
162 def change_master_state(self, master):
163 raise NotImplementedError()
164
165 def adopt_device(self, device):
166 log.info('adopt-device', device=device)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800167 self._activate_io_port()
168 reactor.callLater(0, self._launch_device_activation, device)
Zsolt Harasztied091602016-12-08 13:36:38 -0800169
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800170 def _activate_io_port(self):
171 if self.io_port is None:
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800172 self.io_port = registry('frameio').open_port(
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800173 self.interface, self._rcv_io, is_tibit_frame)
174
175 @inlineCallbacks
176 def _launch_device_activation(self, device):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800177 try:
178 log.debug('launch_dev_activation')
179 # prepare receive queue
180 self.incoming_queues[device.mac_address] = DeferredQueue(size=100)
181
Nathan Knuth6e57f332016-12-22 15:49:20 -0800182 # add mac_address to device_ids table
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800183 olt_mac = device.mac_address
Nathan Knuth6e57f332016-12-22 15:49:20 -0800184 self.device_ids[olt_mac] = device.id
185
186 # send out ping to OLT device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800187 ping_frame = self._make_ping_frame(mac_address=olt_mac)
188 self.io_port.send(ping_frame)
189
190 # wait till we receive a response
Nathan Knuth6e57f332016-12-22 15:49:20 -0800191 ## TODO add timeout mechanism so we can signal if we cannot reach
192 ##device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800193 while True:
194 response = yield self.incoming_queues[olt_mac].get()
195 # verify response and if not the expected response
196 if 1: # TODO check if it is really what we expect, and wait if not
197 break
198
Zsolt Haraszti3e6f0892017-01-19 11:51:40 -0800199 except Exception as e:
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800200 log.exception('launch device failed', e=e)
201
202 # if we got response, we can fill out the device info, mark the device
203 # reachable
Zsolt Haraszti80175202016-12-24 00:17:51 -0800204 jdev = json.loads(response.payload.payload.body.load)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800205 device.root = True
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800206 device.vendor = 'Tibit Communications, Inc.'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800207 device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800208 device.hardware_version = jdev['results']['datecode']
209 device.firmware_version = jdev['results']['firmware']
210 device.software_version = jdev['results']['modelversion']
211 device.serial_number = jdev['results']['manufacturer']
Nathan Knuth6e57f332016-12-22 15:49:20 -0800212
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800213 device.connect_status = ConnectStatus.REACHABLE
214 self.adapter_agent.update_device(device)
215
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800216 # then shortly after we create some ports for the device
217 log.info('create-port')
218 nni_port = Port(
219 port_no=2,
220 label='NNI facing Ethernet port',
221 type=Port.ETHERNET_NNI,
222 admin_state=AdminState.ENABLED,
223 oper_status=OperStatus.ACTIVE
224 )
225 self.adapter_agent.add_port(device.id, nni_port)
226 self.adapter_agent.add_port(device.id, Port(
227 port_no=1,
228 label='PON port',
229 type=Port.PON_OLT,
230 admin_state=AdminState.ENABLED,
231 oper_status=OperStatus.ACTIVE
232 ))
233
234 log.info('create-logical-device')
235 # then shortly after we create the logical device with one port
236 # that will correspond to the NNI port
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800237 ld = LogicalDevice(
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800238 desc=ofp_desc(
239 mfr_desc=device.vendor,
240 hw_desc=jdev['results']['device'],
241 sw_desc=jdev['results']['firmware'],
242 serial_num=uuid4().hex,
243 dp_desc='n/a'
244 ),
245 switch_features=ofp_switch_features(
246 n_buffers=256, # TODO fake for now
247 n_tables=2, # TODO ditto
248 capabilities=( # TODO and ditto
249 OFPC_FLOW_STATS
250 | OFPC_TABLE_STATS
251 | OFPC_PORT_STATS
252 | OFPC_GROUP_STATS
253 )
254 ),
255 root_device_id=device.id
256 )
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800257 ld_initialized = self.adapter_agent.create_logical_device(ld)
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800258 cap = OFPPF_10GB_FD | OFPPF_FIBER
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800259 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800260 id='nni',
261 ofp_port=ofp_port(
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800262 port_no=0,
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800263 hw_addr=mac_str_to_tuple(device.mac_address),
264 name='nni',
265 config=0,
266 state=OFPPS_LIVE,
267 curr=cap,
268 advertised=cap,
269 peer=cap,
270 curr_speed=OFPPF_10GB_FD,
271 max_speed=OFPPF_10GB_FD
272 ),
273 device_id=device.id,
274 device_port_no=nni_port.port_no,
275 root_port=True
276 ))
277
278 # and finally update to active
279 device = self.adapter_agent.get_device(device.id)
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800280 device.parent_id = ld_initialized.id
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800281 device.oper_status = OperStatus.ACTIVE
282 self.adapter_agent.update_device(device)
283
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800284 # Just transitioned to ACTIVE, wait a tenth of second
285 # before checking for ONUs
286 reactor.callLater(0.1, self._detect_onus, device)
287
288 @inlineCallbacks
289 def _detect_onus(self, device):
290 # send out get 'links' to the OLT device
291 olt_mac = device.mac_address
292 links_frame = self._make_links_frame(mac_address=olt_mac)
293 self.io_port.send(links_frame)
294 while True:
295 response = yield self.incoming_queues[olt_mac].get()
296 # verify response and if not the expected response
297 if 1: # TODO check if it is really what we expect, and wait if not
298 break
299
Zsolt Haraszti80175202016-12-24 00:17:51 -0800300 jdev = json.loads(response.payload.payload.body.load)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600301 onu_mac = ''
Nathan Knuthb396f472017-03-28 17:18:51 -0700302 child_device_name = ''
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800303 for macid in jdev['results']:
304 if macid['macid'] is None:
305 log.info('MAC ID is NONE %s' % str(macid['macid']))
Nathan Knuthd8285e62017-01-11 14:18:43 -0600306 elif macid['macid'][:6].upper() == SUMITOMO_ELECTRIC_INDUSTRIES_OUI:
Nathan Knuthb396f472017-03-28 17:18:51 -0700307 onu_mac_string = macid['macid']
Nathan Knuthd8285e62017-01-11 14:18:43 -0600308 log.info('SUMITOMO mac address %s' % str(macid['macid']))
Nathan Knuthb396f472017-03-28 17:18:51 -0700309 child_device_name = 'dpoe_onu'
310
311 elif macid['macid'][:4].upper() == ADTRAN_SHORTENED_VSSN:
312 onu_mac_string = macid['macid']
313 log.info('ADTRAN mac address %s' % str(macid['macid']))
314 child_device_name = 'adtran_onu'
Nathan Knuthd8285e62017-01-11 14:18:43 -0600315
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 Knuthb396f472017-03-28 17:18:51 -0700318 log.info('TIBIT mac address %s' % onu_mac)
319 child_device_name = 'tibit_onu'
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800320
Nathan Knuthb396f472017-03-28 17:18:51 -0700321 # Convert from string to colon separated form
322 onu_mac = ':'.join(s.encode('hex') for s in onu_mac_string.decode('hex'))
323 log.info('activate-olt-for-onu-%s' % onu_mac)
324 mac_octet_4 = int(macid['macid'][-4:-2], 16)
325 vlan_id = self._olt_side_onu_activation(mac_octet_4)
326 self.adapter_agent.child_device_detected(
327 parent_device_id=device.id,
328 parent_port_no=1,
329 child_device_type=child_device_name,
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 )
Nathan Knuth09c23102017-02-10 04:43:30 -0800337
Nathan Knuthb396f472017-03-28 17:18:51 -0700338 ## Automatically setup default downstream control frames flow (in this case VLAN 4000)
339 ## on the OLT for the new ONU/ONT device
340 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
341 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
342 packet_out_rule = (
343 Ether(dst=device.mac_address) /
344 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
345 EOAMPayload(
346 body=CablelabsOUI() / DPoEOpcode_SetRequest() /
347 NetworkToNetworkPortObject()/
348 PortIngressRuleHeader(precedence=13)/
349 PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
350 operator=Operator['=='],
351 match=TIBIT_PACKET_OUT_VLAN)/
352 PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
353 operator=Operator['=='], match=vlan_id)/
354 PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=int(onu_mac_string[4:], 16))/
355 PortIngressRuleResultForward()/
356 PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])/
357 PortIngressRuleTerminator()/
358 AddPortIngressRule()))
359
360 self.io_port.send(str(packet_out_rule))
361 while True:
362 response = yield self.incoming_queues[olt_mac].get()
363 # verify response and if not the expected response
364 if 1: # TODO check if it is really what we expect, and wait if not
365 break
Nathan Knuth09c23102017-02-10 04:43:30 -0800366
Nathan Knuth388eff32017-01-18 18:31:22 -0600367 # also record the vlan_id -> (device_id, logical_device_id, linkid) for
368 # later use. The linkid is the macid returned.
369 self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id, macid.get('macid', 0))
370
Nathan Knuth09c23102017-02-10 04:43:30 -0800371 ### KPI Metrics - Work in progress feature - Disabling for now
Nathan Knuthab966e52017-01-30 07:48:13 -0800372 ### Give the ONUs a chance to arrive before starting metric collection
373 ### reactor.callLater(5.0, self.start_kpi_collection, device.id)
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800374
Nathan Knuth6e57f332016-12-22 15:49:20 -0800375 def _olt_side_onu_activation(self, serial):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800376 """
377 This is where if this was a real OLT, the OLT-side activation for
378 the new ONU should be performed. By the time we return, the OLT shall
379 be able to provide tunneled (proxy) communication to the given ONU,
380 using the returned information.
381 """
Nathan Knuth6e57f332016-12-22 15:49:20 -0800382 vlan_id = serial + 200
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800383 return vlan_id
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800384
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800385 def _rcv_io(self, port, frame):
386
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800387 log.info('frame-received', frame=hexify(frame))
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800388
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800389 # make into frame to extract source mac
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800390 response = Ether(frame)
391
Nathan Knuth6e57f332016-12-22 15:49:20 -0800392 if response.haslayer(Dot1Q):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800393
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800394 # All OAM responses from the OLT should have a TIBIT_MGMT_VLAN.
395 # Responses from the ONUs should have a TIBIT_MGMT_VLAN followed by a ONU CTAG
396 # All packet-in frames will have the TIBIT_PACKET_IN_VLAN.
397 if response.getlayer(Dot1Q).type == 0x8100:
398
399 if response.getlayer(Dot1Q).vlan == TIBIT_PACKET_IN_VLAN:
400
401 inner_tag_and_rest = response.payload.payload
402
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800403 if isinstance(inner_tag_and_rest, Dot1Q):
404
405 cvid = inner_tag_and_rest.vlan
406
407 frame = Ether(src=response.src,
408 dst=response.dst,
409 type=inner_tag_and_rest.type) /\
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800410 inner_tag_and_rest.payload
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800411
Nathan Knuth6818b3b2017-02-10 03:28:03 -0800412 _, logical_device_id, _ = self.vlan_to_device_ids.get(cvid)
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800413 if logical_device_id is None:
414 log.error('invalid-cvid', cvid=cvid)
415 else:
416 self.adapter_agent.send_packet_in(
417 logical_device_id=logical_device_id,
418 logical_port_no=cvid, # C-VID encodes port no
419 packet=str(frame))
420
421 else:
422 log.error('packet-in-single-tagged',
423 frame=hexify(response))
424
425 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800426 ## Mgmt responses received from the ONU
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800427 ## Since the type of the first layer is 0x8100,
428 ## then the frame must have an inner tag layer
429 olt_mac = response.src
430 device_id = self.device_ids[olt_mac]
431 channel_id = response[Dot1Q:2].vlan
432 log.info('received_channel_id', channel_id=channel_id,
433 device_id=device_id)
434
435 proxy_address=Device.ProxyAddress(
436 device_id=device_id,
437 channel_id=channel_id
438 )
439 # pop dot1q header(s)
440 msg = response.payload.payload
441 self.adapter_agent.receive_proxied_message(proxy_address, msg)
442
Nathan Knuth6e57f332016-12-22 15:49:20 -0800443 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800444 ## Mgmt responses received from the OLT
Nathan Knuth6e57f332016-12-22 15:49:20 -0800445 ## enqueue incoming parsed frame to right device
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800446 log.info('received-dot1q-not-8100')
Nathan Knuth6e57f332016-12-22 15:49:20 -0800447 self.incoming_queues[response.src].put(response)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800448
449 def _make_ping_frame(self, mac_address):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800450 # Create a json packet
451 json_operation_str = '{\"operation\":\"version\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800452 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 -0800453 return str(frame)
454
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800455 def _make_links_frame(self, mac_address):
456 # Create a json packet
457 json_operation_str = '{\"operation\":\"links\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800458 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 -0800459 return str(frame)
460
Nathan Knuth388eff32017-01-18 18:31:22 -0600461 def _make_stats_frame(self, mac_address, itype, link):
462 # Create a json packet
463 json_operation_str = ('{\"operation\":\"stats\",\"parameters\":{\"itype\":\"%s\",\"iinst\",\"0\",\"macid\":\"%s\"}}' % (itype, link))
464 frame = Ether(dst=mac_address)/Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY)/TBJSON(data='json %s' % json_operation_str)
465 return str(frame)
466
Zsolt Harasztied091602016-12-08 13:36:38 -0800467 def abandon_device(self, device):
468 raise NotImplementedError(0
469 )
Khen Nursimulud068d812017-03-06 11:44:18 -0500470 def disable_device(self, device):
471 raise NotImplementedError()
472
473 def reenable_device(self, device):
474 raise NotImplementedError()
475
476 def reboot_device(self, device):
477 raise NotImplementedError()
478
479 def delete_device(self, device):
480 raise NotImplementedError()
481
482 def get_device_details(self, device):
Zsolt Harasztied091602016-12-08 13:36:38 -0800483 raise NotImplementedError()
484
485 def update_flows_bulk(self, device, flows, groups):
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800486 log.info('########################################')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800487 log.info('bulk-flow-update', device_id=device.id,
488 flows=flows, groups=groups)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800489 assert len(groups.items) == 0, "Cannot yet deal with groups"
490
Nathan Knuthf840dfb2017-01-12 18:15:14 -0800491 # extract ONU VID
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800492 # vid_from_device_id = {v[0]: k for k,v in self.vlan_to_device_ids.iteritems()}
493 # ONU_VID = vid_from_device_id[device.id]
Nathan Knuth05f859e2017-02-23 13:22:26 -0800494 _inner_vid = None
Nathan Knuth5f4163e2017-01-11 18:21:10 -0600495
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800496 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
497 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800498
Zsolt Haraszti80175202016-12-24 00:17:51 -0800499 for flow in flows.items:
Zsolt Haraszti80175202016-12-24 00:17:51 -0800500
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800501 try:
502 in_port = get_in_port(flow)
503 assert in_port is not None
Zsolt Haraszti80175202016-12-24 00:17:51 -0800504
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800505 precedence = 255 - min(flow.priority / 256, 255)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800506
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800507 if in_port == 2:
508 log.info('#### Downstream Rule ####')
509 dn_req = NetworkToNetworkPortObject()
510 dn_req /= PortIngressRuleHeader(precedence=precedence)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800511
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800512 for field in get_ofb_fields(flow):
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800513
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800514 if field.type == ETH_TYPE:
515 _type = field.eth_type
516 log.info('#### field.type == ETH_TYPE ####')
517 dn_req /= PortIngressRuleClauseMatchLength02(
518 fieldcode=Clause['L2 Type/Len'],
519 operator=Operator['=='],
520 match=_type)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800521
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800522 elif field.type == IP_PROTO:
523 _proto = field.ip_proto
524 log.info('#### field.type == IP_PROTO ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800525
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800526 elif field.type == IN_PORT:
527 _port = field.port
528 log.info('#### field.type == IN_PORT ####', port=_port)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800529
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800530 elif field.type == VLAN_VID:
531 _vlan_vid = field.vlan_vid & 0xfff
532 log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800533 _outer_vid = _vlan_vid
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800534
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800535 elif field.type == VLAN_PCP:
536 _vlan_pcp = field.vlan_pcp
537 log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800538
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800539 elif field.type == UDP_DST:
540 _udp_dst = field.udp_dst
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800541 log.info('#### field.type == UDP_DST ####', udp_dst=_udp_dst)
Zsolt Haraszti6a5107c2017-01-09 23:42:41 -0800542
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800543 elif field.type == UDP_SRC:
544 _udp_src = field.udp_src
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800545 log.info('#### field.type == UDP_SRC ####', udp_src=_udp_src)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800546
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800547 elif field.type == IPV4_DST:
548 _ipv4_dst = field.ipv4_dst
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800549 log.info('#### field.type == IPV4_DST ####', ipv4_dst=_ipv4_dst)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800550
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800551 elif field.type == METADATA:
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800552 _metadata = field.table_metadata
553 log.info('#### field.type == METADATA ####', metadata=_metadata)
554 _inner_vid = _metadata
Zsolt Haraszti80175202016-12-24 00:17:51 -0800555
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800556 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800557 raise NotImplementedError('field.type={}'.format(
558 field.type))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800559
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800560 for action in get_actions(flow):
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800561
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800562 if action.type == OUTPUT:
563 log.info('#### action.type == OUTPUT ####')
564 dn_req /= PortIngressRuleResultForward()
Nathan Knuth05f859e2017-02-23 13:22:26 -0800565 if _outer_vid == MULTICAST_VLAN:
566 dn_req /= PortIngressRuleResultOLTBroadcastQueue()
Nathan Knuthb396f472017-03-28 17:18:51 -0700567 elif _inner_vid is not None:
Nathan Knuth05f859e2017-02-23 13:22:26 -0800568 serial = _inner_vid - 200
569 link = (0xe222 << 16) | (serial << 8)
570 dn_req /= PortIngressRuleResultOLTQueue(unicastvssn="TBIT",
571 unicastlink=link)
Nathan Knuthb396f472017-03-28 17:18:51 -0700572 elif _inner_vid is None:
573 log.info('#### action.type == OUTPUT INNER VID is NONE ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800574
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800575 elif action.type == POP_VLAN:
576 log.info('#### action.type == POP_VLAN ####')
Nathan Knuth05f859e2017-02-23 13:22:26 -0800577 if _outer_vid == MULTICAST_VLAN:
578 dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['C-VLAN Tag'])
579 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
580 operator=Operator['=='], match=_outer_vid)
581 else:
582 dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['S-VLAN Tag'])
583 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
584 operator=Operator['=='], match=_outer_vid)
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800585 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
586 operator=Operator['=='], match=_inner_vid)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800587
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800588 elif action.type == PUSH_VLAN:
589 log.info('#### action.type == PUSH_VLAN ####')
590 if action.push.ethertype != 0x8100:
591 log.error('unhandled-tpid',
592 ethertype=action.push.ethertype)
593 dn_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
Nathan Knuthd8285e62017-01-11 14:18:43 -0600594
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800595 elif action.type == SET_FIELD:
596 log.info('#### action.type == SET_FIELD ####')
597 assert (action.set_field.field.oxm_class ==
598 ofp.OFPXMC_OPENFLOW_BASIC)
599 field = action.set_field.field.ofb_field
600 if field.type == VLAN_VID:
601 dn_req /= PortIngressRuleResultSet(
602 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
603 else:
604 log.error('unsupported-action-set-field-type',
605 field_type=field.type)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600606 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800607 log.error('UNSUPPORTED-ACTION-TYPE',
608 action_type=action.type)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800609
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800610 dn_req /= PortIngressRuleTerminator()
611 dn_req /= AddPortIngressRule()
612
613 msg = (
614 Ether(dst=device.mac_address) /
615 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
616 EOAMPayload(
617 body=CablelabsOUI() / DPoEOpcode_SetRequest() / dn_req)
618 )
619
620 self.io_port.send(str(msg))
621
622 elif in_port == 1:
623 # Upstream rule
624 log.info('#### Upstream Rule ####')
625
626 field_match_vlan_upstream_with_link = False
627 up_req_link = PortIngressRuleHeader(precedence=precedence)
628
629 up_req_pon = PonPortObject()
630 up_req_pon /= PortIngressRuleHeader(precedence=precedence)
631
632 for field in get_ofb_fields(flow):
633
634 if field.type == ETH_TYPE:
635 _type = field.eth_type
636 log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
637 match=_type)
638 up_req_pon /= PortIngressRuleClauseMatchLength02(
639 fieldcode=Clause['L2 Type/Len'],
640 operator=Operator['=='],
641 match=_type)
642
643 up_req_link /= PortIngressRuleClauseMatchLength02(
644 fieldcode=Clause['L2 Type/Len'],
645 operator=Operator['=='],
646 match=_type)
647
648 elif field.type == IP_PROTO:
649 _proto = field.ip_proto
650 log.info('#### field.type == IP_PROTO ####', in_port=in_port,
651 ip_proto=_proto)
652
653 up_req_pon /= PortIngressRuleClauseMatchLength01(
654 fieldcode=Clause['IPv4/IPv6 Protocol Type'],
655 operator=Operator['=='], match=_proto)
656
657 up_req_link /= PortIngressRuleClauseMatchLength01(
658 fieldcode=Clause['IPv4/IPv6 Protocol Type'],
659 operator=Operator['=='], match=_proto)
660
661 elif field.type == IN_PORT:
662 _port = field.port
663 log.info('#### field.type == IN_PORT ####')
664
665 elif field.type == VLAN_VID:
666 _vlan_vid = field.vlan_vid & 0xfff
667 log.info('#### field.type == VLAN_VID ####')
668 up_req_pon /= PortIngressRuleClauseMatchLength02(
669 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
670 operator=Operator['=='], match=_vlan_vid)
671
672 serial = _vlan_vid - 200
673 link = (0xe222 << 16) | (serial << 8)
674 up_req_link /= OLTUnicastLogicalLink(unicastvssn='TBIT', unicastlink=link)
675
676 up_req_link /= PortIngressRuleClauseMatchLength02(
677 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
678 operator=Operator['=='], match=_vlan_vid)
679 field_match_vlan_upstream_with_link = True
680
681
682 elif field.type == VLAN_PCP:
683 _vlan_pcp = field.vlan_pcp
684 log.info('#### field.type == VLAN_PCP ####')
685
686 elif field.type == UDP_DST:
687 _udp_dst = field.udp_dst
688 log.info('#### field.type == UDP_DST ####')
689 up_req_pon /= (PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],
690 operator=Operator['=='], match=0x0044)/
691 PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],
692 operator=Operator['=='], match=0x0043))
693
694 elif field.type == UDP_SRC:
695 _udp_src = field.udp_src
696 log.info('#### field.type == UDP_SRC ####')
697
698 else:
699 raise NotImplementedError('field.type={}'.format(
700 field.type))
701
702 for action in get_actions(flow):
703
704 if action.type == OUTPUT:
705 log.info('#### action.type == OUTPUT ####')
706 up_req_pon /= PortIngressRuleResultForward()
707 up_req_link /= PortIngressRuleResultForward()
708
709 elif action.type == POP_VLAN:
710 log.info('#### action.type == POP_VLAN ####')
711
712 elif action.type == PUSH_VLAN:
713 log.info('#### action.type == PUSH_VLAN ####')
714 if action.push.ethertype != 0x8100:
715 log.error('unhandled-ether-type',
716 ethertype=action.push.ethertype)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600717 if field_match_vlan_upstream_with_link == True:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800718 up_req_link /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
719 fieldinstance=1)
720 else:
721 up_req_pon /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
722 fieldinstance=0)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600723
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800724 elif action.type == SET_FIELD:
725 log.info('#### action.type == SET_FIELD ####')
726 assert (action.set_field.field.oxm_class ==
727 ofp.OFPXMC_OPENFLOW_BASIC)
728 field = action.set_field.field.ofb_field
729 if field.type == VLAN_VID:
730 if field_match_vlan_upstream_with_link == True:
731 up_req_link /=(PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/
732 PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag']))
733
734 up_req_pon /= PortIngressRuleResultSet(
735 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
736 up_req_link /= PortIngressRuleResultSet(
737 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
738 else:
739 log.error('unsupported-action-set-field-type',
740 field_type=field.type)
741
Zsolt Haraszti80175202016-12-24 00:17:51 -0800742 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800743 log.error('UNSUPPORTED-ACTION-TYPE',
744 action_type=action.type)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800745
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800746 if (field_match_vlan_upstream_with_link == True):
747 up_req = up_req_link
Zsolt Haraszti80175202016-12-24 00:17:51 -0800748 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800749 up_req = up_req_pon
Zsolt Haraszti80175202016-12-24 00:17:51 -0800750
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800751 up_req /= PortIngressRuleTerminator()
752 up_req /= AddPortIngressRule()
753
754 msg = (
755 Ether(dst=device.mac_address) /
756 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
757 EOAMPayload(
758 body=CablelabsOUI() / DPoEOpcode_SetRequest() / up_req)
759 )
760
761 self.io_port.send(str(msg))
762
Nathan Knuthd8285e62017-01-11 14:18:43 -0600763 else:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800764 raise Exception('Port should be 1 or 2 by our convention')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600765
Nathan Knuth6b7b6ff2017-02-12 03:30:48 -0800766 except Exception, e:
Nathan Knuth2976a3f2017-01-11 22:47:26 -0800767 log.exception('failed-to-install-flow', e=e, flow=flow)
Zsolt Harasztied091602016-12-08 13:36:38 -0800768
769 def update_flows_incrementally(self, device, flow_changes, group_changes):
770 raise NotImplementedError()
771
772 def send_proxied_message(self, proxy_address, msg):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800773 log.info('send-proxied-message', proxy_address=proxy_address)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800774 device = self.adapter_agent.get_device(proxy_address.device_id)
Nathan Knuthb396f472017-03-28 17:18:51 -0700775
776 mac_address = self.vlan_to_device_ids[proxy_address.channel_id][2].upper()
777
778 if mac_address.startswith(TIBIT_SHORTENED_VSSN):
779 # Send straight OAM
780 frame = Ether(dst=device.mac_address) / \
781 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
782 Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
783 msg
784 else:
785 # Use the standard to send OMCI over OAM
786 encapsulated_omci = EOAMPayload(body=ItuOUI()/msg)
787
788 frame = Ether(dst=device.mac_address) / \
789 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
790 Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
791 encapsulated_omci
Nathan Knuth6e57f332016-12-22 15:49:20 -0800792
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800793 self.io_port.send(str(frame))
Zsolt Harasztied091602016-12-08 13:36:38 -0800794
795 def receive_proxied_message(self, proxy_address, msg):
796 raise NotImplementedError()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800797
798 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
799 log.info('packet-out', logical_device_id=logical_device_id,
800 egress_port_no=egress_port_no, msg_len=len(msg))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800801
Nathan Knuth96531582017-02-13 05:27:37 -0800802 _, logical_dev_id, _ = self.vlan_to_device_ids[egress_port_no]
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800803 if logical_dev_id != logical_device_id:
804 raise Exception('Internal table mismatch')
805
806 tmp = Ether(msg)
807
808 frame = Ether(dst=tmp.dst, src=tmp.src) / \
809 Dot1Q(vlan=TIBIT_PACKET_OUT_VLAN) / \
810 Dot1Q(vlan=egress_port_no) / \
811 tmp.payload
812
813 self.io_port.send(str(frame))
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800814
815 def start_kpi_collection(self, device_id):
Nathan Knuthc99552d2017-01-19 11:23:32 -0600816 """ Periodic KPI metric collection from the device """
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800817 import random
818
Nathan Knuthc99552d2017-01-19 11:23:32 -0600819 # This is setup (for now) to be called from the adapter. Push
820 # architectures should be explored in the near future.
821 @inlineCallbacks
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800822 def _collect(device_id, prefix):
823
Nathan Knuth388eff32017-01-18 18:31:22 -0600824 pon_port_metrics = {}
825 links = []
826 olt_mac = next((mac for mac, device in self.device_ids.iteritems() if device == device_id), None)
Nathan Knuth96531582017-02-13 05:27:37 -0800827 links = [v[TIBIT_ONU_LINK_INDEX] for _,v,_ in self.vlan_to_device_ids.iteritems()]
Nathan Knuth388eff32017-01-18 18:31:22 -0600828
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800829 try:
Nathan Knuth388eff32017-01-18 18:31:22 -0600830 # Step 1: gather metrics from device
831 log.info('link stats frame', links=links)
832 for link in links:
833 stats_frame = self._make_stats_frame(mac_address=olt_mac, itype='olt', link=link)
834 self.io_port.send(stats_frame)
835
836 ## Add timeout mechanism so we can signal if we cannot reach
837 ## device
838 while True:
839 response = yield self.incoming_queues[olt_mac].get()
840 jdict = json.loads(response.payload.payload.body.load)
841 pon_port_metrics[link] = {k: int(v,16) for k,v in jdict['results'].iteritems()}
842 # verify response and if not the expected response
843 if 1: # TODO check if it is really what we expect, and wait if not
844 break
845
846 log.info('nni stats frame')
847 olt_nni_link = ''.join(l for l in olt_mac.split(':'))
848 stats_frame = self._make_stats_frame(mac_address=olt_mac, itype='eth', link=olt_nni_link)
849 self.io_port.send(stats_frame)
850
851 ## Add timeout mechanism so we can signal if we cannot reach
852 ## device
853 while True:
854 response = yield self.incoming_queues[olt_mac].get()
855 jdict = json.loads(response.payload.payload.body.load)
856 nni_port_metrics = {k: int(v,16) for k,v in jdict['results'].iteritems()}
857 # verify response and if not the expected response
858 if 1: # TODO check if it is really what we expect, and wait if not
859 break
860
Nathan Knuthc99552d2017-01-19 11:23:32 -0600861 olt_metrics = dict(
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800862 cpu_util=20 + 5 * random.random(),
863 buffer_util=10 + 10 * random.random()
864 )
865
866 # Step 2: prepare the KpiEvent for submission
867 # we can time-stamp them here (or could use time derived from OLT
868 ts = arrow.utcnow().timestamp
Nathan Knuthc99552d2017-01-19 11:23:32 -0600869 prefixes = {
870 # CPU Metrics (example)
871 prefix: MetricValuePairs(metrics=olt_metrics),
872 # OLT NNI port
873 prefix + '.nni': MetricValuePairs(metrics=nni_port_metrics)
874 }
875
876 for link in links:
877 # PON link ports
878 prefixes[prefix + '.pon.{}'.format(link)] = MetricValuePairs(metrics=pon_port_metrics[link])
879
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800880 kpi_event = KpiEvent(
881 type=KpiEventType.slice,
882 ts=ts,
Nathan Knuthc99552d2017-01-19 11:23:32 -0600883 prefixes=prefixes
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800884 )
885
886 # Step 3: submit
887 self.adapter_agent.submit_kpis(kpi_event)
888
889 except Exception as e:
890 log.exception('failed-to-submit-kpis', e=e)
891
892 prefix = 'voltha.{}.{}'.format(self.name, device_id)
893 lc = LoopingCall(_collect, device_id, prefix)
894 lc.start(interval=15) # TODO make this configurable