blob: 3901885b31087df166a0d382c3072979283536fa [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 Haraszti80175202016-12-24 00:17:51 -080023import structlog
24from scapy.fields import StrField
Zsolt Haraszti348d1932016-12-10 01:10:07 -080025from scapy.layers.l2 import Ether, Dot1Q
Zsolt Haraszti80175202016-12-24 00:17:51 -080026from scapy.packet import Packet, bind_layers
Zsolt Haraszti89a27302016-12-08 16:53:06 -080027from twisted.internet import reactor
Zsolt Haraszti80175202016-12-24 00:17:51 -080028from twisted.internet.defer import DeferredQueue, inlineCallbacks
Zsolt Harasztied091602016-12-08 13:36:38 -080029from zope.interface import implementer
30
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080031from common.frameio.frameio import BpfProgramFilter, hexify
Zsolt Harasztied091602016-12-08 13:36:38 -080032from voltha.adapters.interface import IAdapterInterface
Nathan Knuth31c36962016-12-27 10:04:49 -080033from voltha.extensions.eoam.EOAM import EOAMPayload, DPoEOpcode_SetRequest
34from voltha.extensions.eoam.EOAM_TLV import DOLTObject, \
Nathan Knuthd8285e62017-01-11 14:18:43 -060035 NetworkToNetworkPortObject, OLTUnicastLogicalLink, \
36 PortIngressRuleClauseMatchLength01, AddStaticMacAddress, \
37 PortIngressRuleClauseMatchLength02, PortIngressRuleResultForward, \
38 PortIngressRuleResultSet, PortIngressRuleResultInsert, \
39 PortIngressRuleResultCopy, PortIngressRuleResultReplace, \
40 PortIngressRuleResultDelete, PortIngressRuleResultOLTQueue, \
41 PortIngressRuleTerminator, AddPortIngressRule, CablelabsOUI, PonPortObject
Nathan Knuth31c36962016-12-27 10:04:49 -080042from voltha.extensions.eoam.EOAM_TLV import PortIngressRuleHeader
Nathan Knuthd390ceb2017-01-07 15:38:58 -080043from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
44from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
Zsolt Haraszti80175202016-12-24 00:17:51 -080045from voltha.core.flow_decomposer import *
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080046from voltha.core.logical_device_agent import mac_str_to_tuple
Zsolt Harasztied091602016-12-08 13:36:38 -080047from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
Zsolt Haraszti80175202016-12-24 00:17:51 -080048from voltha.protos.common_pb2 import LogLevel, ConnectStatus
49from voltha.protos.common_pb2 import OperStatus, AdminState
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080050from voltha.protos.device_pb2 import Device, Port
Zsolt Harasztied091602016-12-08 13:36:38 -080051from voltha.protos.device_pb2 import DeviceType, DeviceTypes
52from voltha.protos.health_pb2 import HealthStatus
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080053from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
54from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_10GB_FD, \
Nathan Knuthd8285e62017-01-11 14:18:43 -060055 OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
56 OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
Zsolt Haraszti80175202016-12-24 00:17:51 -080057from voltha.registry import registry
Zsolt Haraszti348d1932016-12-10 01:10:07 -080058log = structlog.get_logger()
Zsolt Harasztied091602016-12-08 13:36:38 -080059
Nathan Knuth6e57f332016-12-22 15:49:20 -080060# Match on the MGMT VLAN, Priority 7
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080061TIBIT_MGMT_VLAN = 4090
62TIBIT_MGMT_PRIORITY = 7
63frame_match_case1 = 'ether[14:2] = 0x{:01x}{:03x}'.format(
64 TIBIT_MGMT_PRIORITY << 1, TIBIT_MGMT_VLAN)
65
66TIBIT_PACKET_IN_VLAN = 4000
67frame_match_case2 = '(ether[14:2] & 0xfff) = 0x{:03x}'.format(
68 TIBIT_PACKET_IN_VLAN)
69
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080070TIBIT_PACKET_OUT_VLAN = 4000
71
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080072is_tibit_frame = BpfProgramFilter('{} or {}'.format(
73 frame_match_case1, frame_match_case2))
74
Nathan Knuth6e57f332016-12-22 15:49:20 -080075#is_tibit_frame = lambda x: True
Zsolt Haraszti89a27302016-12-08 16:53:06 -080076
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080077# Extract OLT MAC address: This is a good
78# example of getting the OLT mac address
79
80#for mac, device in self.device_ids.iteritems():
81# if device == dev_id:
82# olt_mac_address = mac
83# log.info('packet-out', olt_mac_address=olt_mac_address)
Zsolt Haraszti85f12852016-12-24 08:30:58 -080084
Zsolt Haraszti348d1932016-12-10 01:10:07 -080085# To be removed in favor of OAM
Zsolt Haraszti89a27302016-12-08 16:53:06 -080086class TBJSON(Packet):
87 """ TBJSON 'packet' layer. """
88 name = "TBJSON"
89 fields_desc = [StrField("data", default="")]
90
Nathan Knuth6e57f332016-12-22 15:49:20 -080091bind_layers(Ether, TBJSON, type=0x9001)
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080092
Nathan Knuthd8285e62017-01-11 14:18:43 -060093SUMITOMO_ELECTRIC_INDUSTRIES_OUI=u"0025DC"
Zsolt Haraszti85f12852016-12-24 08:30:58 -080094
Zsolt Harasztied091602016-12-08 13:36:38 -080095@implementer(IAdapterInterface)
96class TibitOltAdapter(object):
97
98 name = 'tibit_olt'
99
100 supported_device_types = [
101 DeviceType(
102 id='tibit_olt',
103 adapter=name,
104 accepts_bulk_flow_update=True
105 )
106 ]
107
108 def __init__(self, adapter_agent, config):
109 self.adapter_agent = adapter_agent
110 self.config = config
111 self.descriptor = Adapter(
112 id=self.name,
113 vendor='Tibit Communications Inc.',
114 version='0.1',
115 config=AdapterConfig(log_level=LogLevel.INFO)
116 )
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800117 self.interface = registry('main').get_args().interface
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800118 self.io_port = None
Nathan Knuth6e57f332016-12-22 15:49:20 -0800119 self.incoming_queues = {} # OLT mac_address -> DeferredQueue()
120 self.device_ids = {} # OLT mac_address -> device_id
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800121 self.vlan_to_device_ids = {} # c-vid -> (device_id, logical_device_id)
Zsolt Harasztied091602016-12-08 13:36:38 -0800122
123 def start(self):
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800124 log.debug('starting', interface=self.interface)
125 log.info('started', interface=self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800126
127 def stop(self):
128 log.debug('stopping')
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800129 if self.io_port is not None:
130 registry('frameio').del_interface(self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800131 log.info('stopped')
132
133 def adapter_descriptor(self):
134 return self.descriptor
135
136 def device_types(self):
137 return DeviceTypes(items=self.supported_device_types)
138
139 def health(self):
140 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
141
142 def change_master_state(self, master):
143 raise NotImplementedError()
144
145 def adopt_device(self, device):
146 log.info('adopt-device', device=device)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800147 self._activate_io_port()
148 reactor.callLater(0, self._launch_device_activation, device)
Zsolt Harasztied091602016-12-08 13:36:38 -0800149
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800150 def _activate_io_port(self):
151 if self.io_port is None:
152 self.io_port = registry('frameio').add_interface(
153 self.interface, self._rcv_io, is_tibit_frame)
154
155 @inlineCallbacks
156 def _launch_device_activation(self, device):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800157 try:
158 log.debug('launch_dev_activation')
159 # prepare receive queue
160 self.incoming_queues[device.mac_address] = DeferredQueue(size=100)
161
Nathan Knuth6e57f332016-12-22 15:49:20 -0800162 # add mac_address to device_ids table
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800163 olt_mac = device.mac_address
Nathan Knuth6e57f332016-12-22 15:49:20 -0800164 self.device_ids[olt_mac] = device.id
165
166 # send out ping to OLT device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800167 ping_frame = self._make_ping_frame(mac_address=olt_mac)
168 self.io_port.send(ping_frame)
169
170 # wait till we receive a response
Nathan Knuth6e57f332016-12-22 15:49:20 -0800171 ## TODO add timeout mechanism so we can signal if we cannot reach
172 ##device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800173 while True:
174 response = yield self.incoming_queues[olt_mac].get()
175 # verify response and if not the expected response
176 if 1: # TODO check if it is really what we expect, and wait if not
177 break
178
179 except Exception, e:
180 log.exception('launch device failed', e=e)
181
182 # if we got response, we can fill out the device info, mark the device
183 # reachable
Zsolt Haraszti80175202016-12-24 00:17:51 -0800184 # jdev = json.loads(response.data[5:])
185 jdev = json.loads(response.payload.payload.body.load)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800186 device.root = True
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800187 device.vendor = 'Tibit Communications, Inc.'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800188 device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800189 device.hardware_version = jdev['results']['datecode']
190 device.firmware_version = jdev['results']['firmware']
191 device.software_version = jdev['results']['modelversion']
192 device.serial_number = jdev['results']['manufacturer']
Nathan Knuth6e57f332016-12-22 15:49:20 -0800193
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800194 device.connect_status = ConnectStatus.REACHABLE
195 self.adapter_agent.update_device(device)
196
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800197 # then shortly after we create some ports for the device
198 log.info('create-port')
199 nni_port = Port(
200 port_no=2,
201 label='NNI facing Ethernet port',
202 type=Port.ETHERNET_NNI,
203 admin_state=AdminState.ENABLED,
204 oper_status=OperStatus.ACTIVE
205 )
206 self.adapter_agent.add_port(device.id, nni_port)
207 self.adapter_agent.add_port(device.id, Port(
208 port_no=1,
209 label='PON port',
210 type=Port.PON_OLT,
211 admin_state=AdminState.ENABLED,
212 oper_status=OperStatus.ACTIVE
213 ))
214
215 log.info('create-logical-device')
216 # then shortly after we create the logical device with one port
217 # that will correspond to the NNI port
218 logical_device_id = uuid4().hex[:12]
219 ld = LogicalDevice(
220 id=logical_device_id,
221 datapath_id=int('0x' + logical_device_id[:8], 16), # from id
222 desc=ofp_desc(
223 mfr_desc=device.vendor,
224 hw_desc=jdev['results']['device'],
225 sw_desc=jdev['results']['firmware'],
226 serial_num=uuid4().hex,
227 dp_desc='n/a'
228 ),
229 switch_features=ofp_switch_features(
230 n_buffers=256, # TODO fake for now
231 n_tables=2, # TODO ditto
232 capabilities=( # TODO and ditto
233 OFPC_FLOW_STATS
234 | OFPC_TABLE_STATS
235 | OFPC_PORT_STATS
236 | OFPC_GROUP_STATS
237 )
238 ),
239 root_device_id=device.id
240 )
241 self.adapter_agent.create_logical_device(ld)
242 cap = OFPPF_10GB_FD | OFPPF_FIBER
243 self.adapter_agent.add_logical_port(ld.id, LogicalPort(
244 id='nni',
245 ofp_port=ofp_port(
246 port_no=129,
247 hw_addr=mac_str_to_tuple(device.mac_address),
248 name='nni',
249 config=0,
250 state=OFPPS_LIVE,
251 curr=cap,
252 advertised=cap,
253 peer=cap,
254 curr_speed=OFPPF_10GB_FD,
255 max_speed=OFPPF_10GB_FD
256 ),
257 device_id=device.id,
258 device_port_no=nni_port.port_no,
259 root_port=True
260 ))
261
262 # and finally update to active
263 device = self.adapter_agent.get_device(device.id)
264 device.parent_id = ld.id
265 device.oper_status = OperStatus.ACTIVE
266 self.adapter_agent.update_device(device)
267
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800268 # Just transitioned to ACTIVE, wait a tenth of second
269 # before checking for ONUs
270 reactor.callLater(0.1, self._detect_onus, device)
271
272 @inlineCallbacks
273 def _detect_onus(self, device):
274 # send out get 'links' to the OLT device
275 olt_mac = device.mac_address
276 links_frame = self._make_links_frame(mac_address=olt_mac)
277 self.io_port.send(links_frame)
278 while True:
279 response = yield self.incoming_queues[olt_mac].get()
280 # verify response and if not the expected response
281 if 1: # TODO check if it is really what we expect, and wait if not
282 break
283
Zsolt Haraszti80175202016-12-24 00:17:51 -0800284 jdev = json.loads(response.payload.payload.body.load)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600285 onu_mac = ''
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800286 for macid in jdev['results']:
287 if macid['macid'] is None:
288 log.info('MAC ID is NONE %s' % str(macid['macid']))
Nathan Knuthd8285e62017-01-11 14:18:43 -0600289 elif macid['macid'][:6].upper() == SUMITOMO_ELECTRIC_INDUSTRIES_OUI:
290 onu_mac = macid['macid']
291 log.info('SUMITOMO mac address %s' % str(macid['macid']))
292 log.info('activate-olt-for-onu-%s' % onu_mac)
293 # Convert from string to colon separated form
294 onu_mac = ':'.join(s.encode('hex') for s in onu_mac.decode('hex'))
295 vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
296 self.adapter_agent.child_device_detected(
297 parent_device_id=device.id,
298 parent_port_no=1,
299 child_device_type='dpoe_onu',
300 mac_address = onu_mac,
301 proxy_address=Device.ProxyAddress(
302 device_id=device.id,
303 channel_id=vlan_id
304 ),
305 vlan=vlan_id
306 )
307
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800308 else:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600309 onu_mac = '000c' + macid.get('macid', 'e2000000')[4:]
310 log.info('activate-olt-for-onu-%s' % onu_mac)
311 # Convert from string to colon separated form
312 onu_mac = ':'.join(s.encode('hex') for s in onu_mac.decode('hex'))
313 vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
314 self.adapter_agent.child_device_detected(
315 parent_device_id=device.id,
316 parent_port_no=1,
317 child_device_type='tibit_onu',
318 mac_address = onu_mac,
319 proxy_address=Device.ProxyAddress(
320 device_id=device.id,
321 channel_id=vlan_id
322 ),
323 vlan=vlan_id
324 )
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800325
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800326 # also record the vlan_id -> (device_id, logical_device_id) for
327 # later use
328 self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id)
329
Nathan Knuth6e57f332016-12-22 15:49:20 -0800330 def _olt_side_onu_activation(self, serial):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800331 """
332 This is where if this was a real OLT, the OLT-side activation for
333 the new ONU should be performed. By the time we return, the OLT shall
334 be able to provide tunneled (proxy) communication to the given ONU,
335 using the returned information.
336 """
Nathan Knuth6e57f332016-12-22 15:49:20 -0800337 vlan_id = serial + 200
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800338 return vlan_id
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800339
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800340 def _rcv_io(self, port, frame):
341
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800342 log.info('frame-received', frame=hexify(frame))
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800343
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800344 # make into frame to extract source mac
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800345 response = Ether(frame)
346
Nathan Knuth6e57f332016-12-22 15:49:20 -0800347 if response.haslayer(Dot1Q):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800348
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800349 # All OAM responses from the OLT should have a TIBIT_MGMT_VLAN.
350 # Responses from the ONUs should have a TIBIT_MGMT_VLAN followed by a ONU CTAG
351 # All packet-in frames will have the TIBIT_PACKET_IN_VLAN.
352 if response.getlayer(Dot1Q).type == 0x8100:
353
354 if response.getlayer(Dot1Q).vlan == TIBIT_PACKET_IN_VLAN:
355
356 inner_tag_and_rest = response.payload.payload
357
358 inner_tag_and_rest.show() # TODO remove this soon
359
360 if isinstance(inner_tag_and_rest, Dot1Q):
361
362 cvid = inner_tag_and_rest.vlan
363
364 frame = Ether(src=response.src,
365 dst=response.dst,
366 type=inner_tag_and_rest.type) /\
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800367 inner_tag_and_rest.payload
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800368
369 _, logical_device_id = self.vlan_to_device_ids.get(cvid)
370 if logical_device_id is None:
371 log.error('invalid-cvid', cvid=cvid)
372 else:
373 self.adapter_agent.send_packet_in(
374 logical_device_id=logical_device_id,
375 logical_port_no=cvid, # C-VID encodes port no
376 packet=str(frame))
377
378 else:
379 log.error('packet-in-single-tagged',
380 frame=hexify(response))
381
382 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800383 ## Mgmt responses received from the ONU
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800384 ## Since the type of the first layer is 0x8100,
385 ## then the frame must have an inner tag layer
386 olt_mac = response.src
387 device_id = self.device_ids[olt_mac]
388 channel_id = response[Dot1Q:2].vlan
389 log.info('received_channel_id', channel_id=channel_id,
390 device_id=device_id)
391
392 proxy_address=Device.ProxyAddress(
393 device_id=device_id,
394 channel_id=channel_id
395 )
396 # pop dot1q header(s)
397 msg = response.payload.payload
398 self.adapter_agent.receive_proxied_message(proxy_address, msg)
399
Nathan Knuth6e57f332016-12-22 15:49:20 -0800400 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800401 ## Mgmt responses received from the OLT
Nathan Knuth6e57f332016-12-22 15:49:20 -0800402 ## enqueue incoming parsed frame to right device
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800403 log.info('received-dot1q-not-8100')
Nathan Knuth6e57f332016-12-22 15:49:20 -0800404 self.incoming_queues[response.src].put(response)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800405
406 def _make_ping_frame(self, mac_address):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800407 # Create a json packet
408 json_operation_str = '{\"operation\":\"version\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800409 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 -0800410 return str(frame)
411
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800412 def _make_links_frame(self, mac_address):
413 # Create a json packet
414 json_operation_str = '{\"operation\":\"links\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800415 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 -0800416 return str(frame)
417
Zsolt Harasztied091602016-12-08 13:36:38 -0800418 def abandon_device(self, device):
419 raise NotImplementedError(0
420 )
421 def deactivate_device(self, device):
422 raise NotImplementedError()
423
424 def update_flows_bulk(self, device, flows, groups):
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800425 log.info('########################################')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800426 log.info('bulk-flow-update', device_id=device.id,
427 flows=flows, groups=groups)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800428 assert len(groups.items) == 0, "Cannot yet deal with groups"
429
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800430 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
431 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800432
Zsolt Haraszti80175202016-12-24 00:17:51 -0800433 for flow in flows.items:
434 in_port = get_in_port(flow)
435 assert in_port is not None
436
437 precedence = 255 - min(flow.priority / 256, 255)
438
439 if in_port == 2:
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800440 log.info('#### Downstream Rule ####')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600441 dn_req = NetworkToNetworkPortObject()
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800442 dn_req /= PortIngressRuleHeader(precedence=precedence)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800443
444 for field in get_ofb_fields(flow):
445
446 if field.type == ETH_TYPE:
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800447 _type = field.eth_type
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800448 log.info('#### field.type == ETH_TYPE ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800449 dn_req /= PortIngressRuleClauseMatchLength02(
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800450 fieldcode=Clause['L2 Type/Len'],
451 operator=Operator['=='],
452 match=_type)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800453
Zsolt Haraszti80175202016-12-24 00:17:51 -0800454 elif field.type == IP_PROTO:
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800455 _proto = field.ip_proto
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800456 log.info('#### field.type == IP_PROTO ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800457 pass # construct ip_proto based condition here
458
459 elif field.type == IN_PORT:
460 _port = field.port
Nathan Knuthd8285e62017-01-11 14:18:43 -0600461 log.info('#### field.type == IN_PORT ####', port=_port)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800462 pass # construct in_port based condition here
463
464 elif field.type == VLAN_VID:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600465 _vlan_vid = field.vlan_vid & 0xfff
466 log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)
467 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
468 operator=Operator['=='], match=_vlan_vid)
469 if (_vlan_vid != 140):
470 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=1,
471 operator=Operator['=='], match=0x00f1)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800472
473 elif field.type == VLAN_PCP:
474 _vlan_pcp = field.vlan_pcp
Nathan Knuthd8285e62017-01-11 14:18:43 -0600475 log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800476 pass # construct VLAN PCP based filter condition here
477
478 elif field.type == UDP_DST:
479 _udp_dst = field.udp_dst
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800480 log.info('#### field.type == UDP_DST ####')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600481 pass # construct UDP SDT based filter here
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800482
Nathan Knuthd8285e62017-01-11 14:18:43 -0600483 elif field.type == IPV4_DST:
484 _udp_dst = field.ipv4_dst
485 log.info('#### field.type == IPV4_DST ####')
486 import pdb
487 pdb.set_trace()
488 pass # construct UDP SDT based filter here
Zsolt Haraszti6a5107c2017-01-09 23:42:41 -0800489
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800490 else:
491 raise NotImplementedError('field.type={}'.format(
492 field.type))
Zsolt Haraszti80175202016-12-24 00:17:51 -0800493
494 for action in get_actions(flow):
495
496 if action.type == OUTPUT:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600497 log.info('#### action.type == OUTPUT ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800498 dn_req /= PortIngressRuleResultForward()
Nathan Knuthd8285e62017-01-11 14:18:43 -0600499 dn_req /= PortIngressRuleResultOLTQueue(unicastvssn="TBIT", unicastlink=0xe2222900)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800500
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800501 elif action.type == POP_VLAN:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600502 log.info('#### action.type == POP_VLAN ####')
503 dn_req /= PortIngressRuleResultDelete(fieldcode=Clause['S-VLAN Tag'])
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800504 pass # construct vlan pop command here
505
Zsolt Haraszti80175202016-12-24 00:17:51 -0800506 elif action.type == PUSH_VLAN:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600507 log.info('#### action.type == PUSH_VLAN ####')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800508 if action.push.ethertype != 0x8100:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600509 log.error('unhandled-tpid',
Zsolt Haraszti80175202016-12-24 00:17:51 -0800510 ethertype=action.push.ethertype)
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800511 dn_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
Zsolt Haraszti80175202016-12-24 00:17:51 -0800512
513 elif action.type == SET_FIELD:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600514 log.info('#### action.type == SET_FIELD ####')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800515 assert (action.set_field.field.oxm_class ==
516 ofp.OFPXMC_OPENFLOW_BASIC)
517 field = action.set_field.field.ofb_field
518 if field.type == VLAN_VID:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800519 dn_req /= PortIngressRuleResultSet(
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800520 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800521 else:
522 log.error('unsupported-action-set-field-type',
523 field_type=field.type)
524 else:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600525 log.error('UNSUPPORTED-ACTION-TYPE',
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800526 action_type=action.type)
527
Nathan Knuthd8285e62017-01-11 14:18:43 -0600528 dn_req /= PortIngressRuleTerminator()
529 dn_req /= AddPortIngressRule()
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800530
Nathan Knuthd8285e62017-01-11 14:18:43 -0600531 msg = (
532 Ether(dst=device.mac_address) /
533 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
534 EOAMPayload(
535 body=CablelabsOUI() / DPoEOpcode_SetRequest() / dn_req)
536 )
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800537
Nathan Knuthd8285e62017-01-11 14:18:43 -0600538 self.io_port.send(str(msg))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800539
540 elif in_port == 1:
541 # Upstream rule
542 log.info('#### Upstream Rule ####')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600543
544 field_match_vlan_upstream_with_link = False
545 up_req_link = PortIngressRuleHeader(precedence=precedence)
546
547 up_req_pon = PonPortObject()
548 up_req_pon /= PortIngressRuleHeader(precedence=precedence)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800549
550 for field in get_ofb_fields(flow):
551
552 if field.type == ETH_TYPE:
553 _type = field.eth_type
Nathan Knuthd8285e62017-01-11 14:18:43 -0600554 log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
555 match=_type)
556 up_req_pon /= PortIngressRuleClauseMatchLength02(
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800557 fieldcode=Clause['L2 Type/Len'],
Nathan Knuthd8285e62017-01-11 14:18:43 -0600558 operator=Operator['=='],
559 match=_type)
560
561 up_req_link /= PortIngressRuleClauseMatchLength02(
562 fieldcode=Clause['L2 Type/Len'],
563 operator=Operator['=='],
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800564 match=_type)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800565
566 elif field.type == IP_PROTO:
567 _proto = field.ip_proto
Nathan Knuthd8285e62017-01-11 14:18:43 -0600568 log.info('#### field.type == IP_PROTO ####', in_port=in_port,
569 ip_proto=ip_proto)
570
571 up_req_pon /= PortIngressRuleClauseMatchLength01(
572 fieldcode=Clause['IPv4/IPv6 Protocol Type'],
573 operator=Operator['=='], match=_proto)
574
575 up_req_link /= PortIngressRuleClauseMatchLength01(
576 fieldcode=Clause['IPv4/IPv6 Protocol Type'],
577 operator=Operator['=='], match=_proto)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800578
579 elif field.type == IN_PORT:
580 _port = field.port
581 log.info('#### field.type == IN_PORT ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800582
583 elif field.type == VLAN_VID:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600584 _vlan_vid = field.vlan_vid & 0xfff
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800585 log.info('#### field.type == VLAN_VID ####')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600586 up_req_pon /= PortIngressRuleClauseMatchLength02(
587 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
588 operator=Operator['=='], match=_vlan_vid)
589
590 serial = _vlan_vid - 200
591 #link = (0xe222 << 16) | (serial << 8)
592 #up_req_link /= OLTUnicastLogicalLink(unicastvssn='TBIT', unicastlink=link)
593
594 up_req_link /=UnicastLogicalLink(unicastlink=link)
595 up_req_link /= PortIngressRuleClauseMatchLength02(
596 fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
597 operator=Operator['=='], match=_vlan_vid)
598 field_match_vlan_upstream_with_link = True
599
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800600
601 elif field.type == VLAN_PCP:
602 _vlan_pcp = field.vlan_pcp
603 log.info('#### field.type == VLAN_PCP ####')
Zsolt Haraszti3578a1c2017-01-10 15:29:02 -0800604
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800605 elif field.type == UDP_DST:
606 _udp_dst = field.udp_dst
607 log.info('#### field.type == UDP_DST ####')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600608 up_req_pon /= (PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP source port'],
609 operator=Operator['=='], match=0x0044)/
610 PortIngressRuleClauseMatchLength02(fieldcode=Clause['TCP/UDP destination port'],
611 operator=Operator['=='], match=0x0043))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800612
613 else:
614 raise NotImplementedError('field.type={}'.format(
615 field.type))
616
617 for action in get_actions(flow):
618
619 if action.type == OUTPUT:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600620 log.info('#### action.type == OUTPUT ####')
621 up_req_pon /= PortIngressRuleResultForward()
622 up_req_link /= PortIngressRuleResultForward()
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800623
624 elif action.type == POP_VLAN:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600625 log.info('#### action.type == POP_VLAN ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800626
627 elif action.type == PUSH_VLAN:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600628 log.info('#### action.type == PUSH_VLAN ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800629 if action.push.ethertype != 0x8100:
630 log.error('unhandled-ether-type',
631 ethertype=action.push.ethertype)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600632 if field_match_vlan_upstream_with_link == True:
633 up_req_link /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
634 fieldinstance=1)
635 else:
636 up_req_pon /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'],
637 fieldinstance=0)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800638
639 elif action.type == SET_FIELD:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600640 log.info('#### action.type == SET_FIELD ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800641 assert (action.set_field.field.oxm_class ==
642 ofp.OFPXMC_OPENFLOW_BASIC)
643 field = action.set_field.field.ofb_field
644 if field.type == VLAN_VID:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600645 if field_match_vlan_upstream_with_link == True:
646 up_req_link /=(PortIngressRuleResultCopy(fieldcode=Clause['C-VLAN Tag'])/
647 PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag']))
648
649 up_req_pon /= PortIngressRuleResultSet(
650 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
651 up_req_link /= PortIngressRuleResultSet(
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800652 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800653 else:
654 log.error('unsupported-action-set-field-type',
655 field_type=field.type)
656
657 else:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600658 log.error('UNSUPPORTED-ACTION-TYPE',
Zsolt Haraszti80175202016-12-24 00:17:51 -0800659 action_type=action.type)
660
Nathan Knuthd8285e62017-01-11 14:18:43 -0600661 if (field_match_vlan_upstream_with_link == True):
662 up_req = up_req_link
663 up_req.show()
664 else:
665 up_req = up_req_pon
666
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800667 up_req /= PortIngressRuleTerminator()
668 up_req /= AddPortIngressRule()
Zsolt Haraszti80175202016-12-24 00:17:51 -0800669
670 msg = (
671 Ether(dst=device.mac_address) /
672 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
673 EOAMPayload(
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800674 body=CablelabsOUI() / DPoEOpcode_SetRequest() / up_req)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800675 )
676
677 self.io_port.send(str(msg))
678
679 else:
680 raise Exception('Port should be 1 or 2 by our convention')
Zsolt Harasztied091602016-12-08 13:36:38 -0800681
682 def update_flows_incrementally(self, device, flow_changes, group_changes):
683 raise NotImplementedError()
684
685 def send_proxied_message(self, proxy_address, msg):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800686 log.info('send-proxied-message', proxy_address=proxy_address)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800687 device = self.adapter_agent.get_device(proxy_address.device_id)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800688 frame = Ether(dst=device.mac_address) / \
Nathan Knuth6e57f332016-12-22 15:49:20 -0800689 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
690 Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800691 msg
Nathan Knuth6e57f332016-12-22 15:49:20 -0800692
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800693 self.io_port.send(str(frame))
Zsolt Harasztied091602016-12-08 13:36:38 -0800694
695 def receive_proxied_message(self, proxy_address, msg):
696 raise NotImplementedError()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800697
698 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
699 log.info('packet-out', logical_device_id=logical_device_id,
700 egress_port_no=egress_port_no, msg_len=len(msg))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800701
702 dev_id, logical_dev_id = self.vlan_to_device_ids[egress_port_no]
703 if logical_dev_id != logical_device_id:
704 raise Exception('Internal table mismatch')
705
706 tmp = Ether(msg)
707
708 frame = Ether(dst=tmp.dst, src=tmp.src) / \
709 Dot1Q(vlan=TIBIT_PACKET_OUT_VLAN) / \
710 Dot1Q(vlan=egress_port_no) / \
711 tmp.payload
712
713 self.io_port.send(str(frame))