blob: 850a0c94c0963cc66bdc96249bf399820df2ba41 [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, \
Zsolt Haraszti80175202016-12-24 00:17:51 -080035 PortIngressRuleClauseMatchLength02, PortIngressRuleResultForward, \
36 PortIngressRuleResultSet, PortIngressRuleResultInsert, \
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080037 PortIngressRuleTerminator, AddPortIngressRule, CablelabsOUI, PonPortObject
Nathan Knuth31c36962016-12-27 10:04:49 -080038from voltha.extensions.eoam.EOAM_TLV import PortIngressRuleHeader
Nathan Knuthd390ceb2017-01-07 15:38:58 -080039from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
40from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
Zsolt Haraszti80175202016-12-24 00:17:51 -080041from voltha.core.flow_decomposer import *
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080042from voltha.core.logical_device_agent import mac_str_to_tuple
Zsolt Harasztied091602016-12-08 13:36:38 -080043from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
Zsolt Haraszti80175202016-12-24 00:17:51 -080044from voltha.protos.common_pb2 import LogLevel, ConnectStatus
45from voltha.protos.common_pb2 import OperStatus, AdminState
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080046from voltha.protos.device_pb2 import Device, Port
Zsolt Harasztied091602016-12-08 13:36:38 -080047from voltha.protos.device_pb2 import DeviceType, DeviceTypes
48from voltha.protos.health_pb2 import HealthStatus
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080049from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
50from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_10GB_FD, \
51 OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
52 OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
Zsolt Haraszti80175202016-12-24 00:17:51 -080053from voltha.registry import registry
Zsolt Haraszti348d1932016-12-10 01:10:07 -080054log = structlog.get_logger()
Zsolt Harasztied091602016-12-08 13:36:38 -080055
Nathan Knuth6e57f332016-12-22 15:49:20 -080056# Match on the MGMT VLAN, Priority 7
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080057TIBIT_MGMT_VLAN = 4090
58TIBIT_MGMT_PRIORITY = 7
59frame_match_case1 = 'ether[14:2] = 0x{:01x}{:03x}'.format(
60 TIBIT_MGMT_PRIORITY << 1, TIBIT_MGMT_VLAN)
61
62TIBIT_PACKET_IN_VLAN = 4000
63frame_match_case2 = '(ether[14:2] & 0xfff) = 0x{:03x}'.format(
64 TIBIT_PACKET_IN_VLAN)
65
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080066TIBIT_PACKET_OUT_VLAN = 4000
67
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080068is_tibit_frame = BpfProgramFilter('{} or {}'.format(
69 frame_match_case1, frame_match_case2))
70
Nathan Knuth6e57f332016-12-22 15:49:20 -080071#is_tibit_frame = lambda x: True
Zsolt Haraszti89a27302016-12-08 16:53:06 -080072
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080073# Extract OLT MAC address: This is a good
74# example of getting the OLT mac address
75
76#for mac, device in self.device_ids.iteritems():
77# if device == dev_id:
78# olt_mac_address = mac
79# log.info('packet-out', olt_mac_address=olt_mac_address)
Zsolt Haraszti85f12852016-12-24 08:30:58 -080080
Zsolt Haraszti348d1932016-12-10 01:10:07 -080081# To be removed in favor of OAM
Zsolt Haraszti89a27302016-12-08 16:53:06 -080082class TBJSON(Packet):
83 """ TBJSON 'packet' layer. """
84 name = "TBJSON"
85 fields_desc = [StrField("data", default="")]
86
Nathan Knuth6e57f332016-12-22 15:49:20 -080087bind_layers(Ether, TBJSON, type=0x9001)
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080088
Zsolt Haraszti85f12852016-12-24 08:30:58 -080089
Zsolt Harasztied091602016-12-08 13:36:38 -080090@implementer(IAdapterInterface)
91class TibitOltAdapter(object):
92
93 name = 'tibit_olt'
94
95 supported_device_types = [
96 DeviceType(
97 id='tibit_olt',
98 adapter=name,
99 accepts_bulk_flow_update=True
100 )
101 ]
102
103 def __init__(self, adapter_agent, config):
104 self.adapter_agent = adapter_agent
105 self.config = config
106 self.descriptor = Adapter(
107 id=self.name,
108 vendor='Tibit Communications Inc.',
109 version='0.1',
110 config=AdapterConfig(log_level=LogLevel.INFO)
111 )
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800112 self.interface = registry('main').get_args().interface
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800113 self.io_port = None
Nathan Knuth6e57f332016-12-22 15:49:20 -0800114 self.incoming_queues = {} # OLT mac_address -> DeferredQueue()
115 self.device_ids = {} # OLT mac_address -> device_id
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800116 self.vlan_to_device_ids = {} # c-vid -> (device_id, logical_device_id)
Zsolt Harasztied091602016-12-08 13:36:38 -0800117
118 def start(self):
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800119 log.debug('starting', interface=self.interface)
120 log.info('started', interface=self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800121
122 def stop(self):
123 log.debug('stopping')
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800124 if self.io_port is not None:
125 registry('frameio').del_interface(self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800126 log.info('stopped')
127
128 def adapter_descriptor(self):
129 return self.descriptor
130
131 def device_types(self):
132 return DeviceTypes(items=self.supported_device_types)
133
134 def health(self):
135 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
136
137 def change_master_state(self, master):
138 raise NotImplementedError()
139
140 def adopt_device(self, device):
141 log.info('adopt-device', device=device)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800142 self._activate_io_port()
143 reactor.callLater(0, self._launch_device_activation, device)
Zsolt Harasztied091602016-12-08 13:36:38 -0800144
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800145 def _activate_io_port(self):
146 if self.io_port is None:
147 self.io_port = registry('frameio').add_interface(
148 self.interface, self._rcv_io, is_tibit_frame)
149
150 @inlineCallbacks
151 def _launch_device_activation(self, device):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800152 try:
153 log.debug('launch_dev_activation')
154 # prepare receive queue
155 self.incoming_queues[device.mac_address] = DeferredQueue(size=100)
156
Nathan Knuth6e57f332016-12-22 15:49:20 -0800157 # add mac_address to device_ids table
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800158 olt_mac = device.mac_address
Nathan Knuth6e57f332016-12-22 15:49:20 -0800159 self.device_ids[olt_mac] = device.id
160
161 # send out ping to OLT device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800162 ping_frame = self._make_ping_frame(mac_address=olt_mac)
163 self.io_port.send(ping_frame)
164
165 # wait till we receive a response
Nathan Knuth6e57f332016-12-22 15:49:20 -0800166 ## TODO add timeout mechanism so we can signal if we cannot reach
167 ##device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800168 while True:
169 response = yield self.incoming_queues[olt_mac].get()
170 # verify response and if not the expected response
171 if 1: # TODO check if it is really what we expect, and wait if not
172 break
173
174 except Exception, e:
175 log.exception('launch device failed', e=e)
176
177 # if we got response, we can fill out the device info, mark the device
178 # reachable
Zsolt Haraszti80175202016-12-24 00:17:51 -0800179 # jdev = json.loads(response.data[5:])
180 jdev = json.loads(response.payload.payload.body.load)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800181 device.root = True
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800182 device.vendor = 'Tibit Communications, Inc.'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800183 device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800184 device.hardware_version = jdev['results']['datecode']
185 device.firmware_version = jdev['results']['firmware']
186 device.software_version = jdev['results']['modelversion']
187 device.serial_number = jdev['results']['manufacturer']
Nathan Knuth6e57f332016-12-22 15:49:20 -0800188
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800189 device.connect_status = ConnectStatus.REACHABLE
190 self.adapter_agent.update_device(device)
191
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800192 # then shortly after we create some ports for the device
193 log.info('create-port')
194 nni_port = Port(
195 port_no=2,
196 label='NNI facing Ethernet port',
197 type=Port.ETHERNET_NNI,
198 admin_state=AdminState.ENABLED,
199 oper_status=OperStatus.ACTIVE
200 )
201 self.adapter_agent.add_port(device.id, nni_port)
202 self.adapter_agent.add_port(device.id, Port(
203 port_no=1,
204 label='PON port',
205 type=Port.PON_OLT,
206 admin_state=AdminState.ENABLED,
207 oper_status=OperStatus.ACTIVE
208 ))
209
210 log.info('create-logical-device')
211 # then shortly after we create the logical device with one port
212 # that will correspond to the NNI port
213 logical_device_id = uuid4().hex[:12]
214 ld = LogicalDevice(
215 id=logical_device_id,
216 datapath_id=int('0x' + logical_device_id[:8], 16), # from id
217 desc=ofp_desc(
218 mfr_desc=device.vendor,
219 hw_desc=jdev['results']['device'],
220 sw_desc=jdev['results']['firmware'],
221 serial_num=uuid4().hex,
222 dp_desc='n/a'
223 ),
224 switch_features=ofp_switch_features(
225 n_buffers=256, # TODO fake for now
226 n_tables=2, # TODO ditto
227 capabilities=( # TODO and ditto
228 OFPC_FLOW_STATS
229 | OFPC_TABLE_STATS
230 | OFPC_PORT_STATS
231 | OFPC_GROUP_STATS
232 )
233 ),
234 root_device_id=device.id
235 )
236 self.adapter_agent.create_logical_device(ld)
237 cap = OFPPF_10GB_FD | OFPPF_FIBER
238 self.adapter_agent.add_logical_port(ld.id, LogicalPort(
239 id='nni',
240 ofp_port=ofp_port(
241 port_no=129,
242 hw_addr=mac_str_to_tuple(device.mac_address),
243 name='nni',
244 config=0,
245 state=OFPPS_LIVE,
246 curr=cap,
247 advertised=cap,
248 peer=cap,
249 curr_speed=OFPPF_10GB_FD,
250 max_speed=OFPPF_10GB_FD
251 ),
252 device_id=device.id,
253 device_port_no=nni_port.port_no,
254 root_port=True
255 ))
256
257 # and finally update to active
258 device = self.adapter_agent.get_device(device.id)
259 device.parent_id = ld.id
260 device.oper_status = OperStatus.ACTIVE
261 self.adapter_agent.update_device(device)
262
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800263 # Just transitioned to ACTIVE, wait a tenth of second
264 # before checking for ONUs
265 reactor.callLater(0.1, self._detect_onus, device)
266
267 @inlineCallbacks
268 def _detect_onus(self, device):
269 # send out get 'links' to the OLT device
270 olt_mac = device.mac_address
271 links_frame = self._make_links_frame(mac_address=olt_mac)
272 self.io_port.send(links_frame)
273 while True:
274 response = yield self.incoming_queues[olt_mac].get()
275 # verify response and if not the expected response
276 if 1: # TODO check if it is really what we expect, and wait if not
277 break
278
Zsolt Haraszti80175202016-12-24 00:17:51 -0800279 jdev = json.loads(response.payload.payload.body.load)
Nathan Knuth6e57f332016-12-22 15:49:20 -0800280 tibit_mac = ''
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800281 for macid in jdev['results']:
282 if macid['macid'] is None:
283 log.info('MAC ID is NONE %s' % str(macid['macid']))
284 else:
Nathan Knuth6e57f332016-12-22 15:49:20 -0800285 tibit_mac = '000c' + macid.get('macid', 'e2000000')[4:]
286 log.info('activate-olt-for-onu-%s' % tibit_mac)
287
288 # Convert from string to colon separated form
289 tibit_mac = ':'.join(s.encode('hex') for s in tibit_mac.decode('hex'))
290
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800291 vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800292 self.adapter_agent.child_device_detected(
293 parent_device_id=device.id,
294 parent_port_no=1,
295 child_device_type='tibit_onu',
Nathan Knuth6e57f332016-12-22 15:49:20 -0800296 mac_address = tibit_mac,
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800297 proxy_address=Device.ProxyAddress(
298 device_id=device.id,
299 channel_id=vlan_id
300 ),
301 vlan=vlan_id
302 )
303
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800304 # also record the vlan_id -> (device_id, logical_device_id) for
305 # later use
306 self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id)
307
Nathan Knuth6e57f332016-12-22 15:49:20 -0800308 def _olt_side_onu_activation(self, serial):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800309 """
310 This is where if this was a real OLT, the OLT-side activation for
311 the new ONU should be performed. By the time we return, the OLT shall
312 be able to provide tunneled (proxy) communication to the given ONU,
313 using the returned information.
314 """
Nathan Knuth6e57f332016-12-22 15:49:20 -0800315 vlan_id = serial + 200
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800316 return vlan_id
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800317
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800318 def _rcv_io(self, port, frame):
319
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800320 log.info('frame-received', frame=hexify(frame))
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800321
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800322 # make into frame to extract source mac
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800323 response = Ether(frame)
324
Nathan Knuth6e57f332016-12-22 15:49:20 -0800325 if response.haslayer(Dot1Q):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800326
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800327 # All OAM responses from the OLT should have a TIBIT_MGMT_VLAN.
328 # Responses from the ONUs should have a TIBIT_MGMT_VLAN followed by a ONU CTAG
329 # All packet-in frames will have the TIBIT_PACKET_IN_VLAN.
330 if response.getlayer(Dot1Q).type == 0x8100:
331
332 if response.getlayer(Dot1Q).vlan == TIBIT_PACKET_IN_VLAN:
333
334 inner_tag_and_rest = response.payload.payload
335
336 inner_tag_and_rest.show() # TODO remove this soon
337
338 if isinstance(inner_tag_and_rest, Dot1Q):
339
340 cvid = inner_tag_and_rest.vlan
341
342 frame = Ether(src=response.src,
343 dst=response.dst,
344 type=inner_tag_and_rest.type) /\
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800345 inner_tag_and_rest.payload
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800346
347 _, logical_device_id = self.vlan_to_device_ids.get(cvid)
348 if logical_device_id is None:
349 log.error('invalid-cvid', cvid=cvid)
350 else:
351 self.adapter_agent.send_packet_in(
352 logical_device_id=logical_device_id,
353 logical_port_no=cvid, # C-VID encodes port no
354 packet=str(frame))
355
356 else:
357 log.error('packet-in-single-tagged',
358 frame=hexify(response))
359
360 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800361 ## Mgmt responses received from the ONU
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800362 ## Since the type of the first layer is 0x8100,
363 ## then the frame must have an inner tag layer
364 olt_mac = response.src
365 device_id = self.device_ids[olt_mac]
366 channel_id = response[Dot1Q:2].vlan
367 log.info('received_channel_id', channel_id=channel_id,
368 device_id=device_id)
369
370 proxy_address=Device.ProxyAddress(
371 device_id=device_id,
372 channel_id=channel_id
373 )
374 # pop dot1q header(s)
375 msg = response.payload.payload
376 self.adapter_agent.receive_proxied_message(proxy_address, msg)
377
Nathan Knuth6e57f332016-12-22 15:49:20 -0800378 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800379 ## Mgmt responses received from the OLT
Nathan Knuth6e57f332016-12-22 15:49:20 -0800380 ## enqueue incoming parsed frame to right device
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800381 log.info('received-dot1q-not-8100')
Nathan Knuth6e57f332016-12-22 15:49:20 -0800382 self.incoming_queues[response.src].put(response)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800383
384 def _make_ping_frame(self, mac_address):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800385 # Create a json packet
386 json_operation_str = '{\"operation\":\"version\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800387 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 -0800388 return str(frame)
389
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800390 def _make_links_frame(self, mac_address):
391 # Create a json packet
392 json_operation_str = '{\"operation\":\"links\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800393 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 -0800394 return str(frame)
395
Zsolt Harasztied091602016-12-08 13:36:38 -0800396 def abandon_device(self, device):
397 raise NotImplementedError(0
398 )
399 def deactivate_device(self, device):
400 raise NotImplementedError()
401
402 def update_flows_bulk(self, device, flows, groups):
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800403 log.info('########################################')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800404 log.info('bulk-flow-update', device_id=device.id,
405 flows=flows, groups=groups)
406
407 assert len(groups.items) == 0, "Cannot yet deal with groups"
408
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800409 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
410 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800411
Zsolt Haraszti80175202016-12-24 00:17:51 -0800412 for flow in flows.items:
413 in_port = get_in_port(flow)
414 assert in_port is not None
415
416 precedence = 255 - min(flow.priority / 256, 255)
417
418 if in_port == 2:
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800419 log.info('#### Downstream Rule ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800420 dn_req = PonPortObject()
421 dn_req /= PortIngressRuleHeader(precedence=precedence)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800422
423 for field in get_ofb_fields(flow):
424
425 if field.type == ETH_TYPE:
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800426 _type = field.eth_type
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800427 log.info('#### field.type == ETH_TYPE ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800428 dn_req /= PortIngressRuleClauseMatchLength02(
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800429 fieldcode=Clause['L2 Type/Len'],
430 operator=Operator['=='],
431 match=_type)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800432
Zsolt Haraszti80175202016-12-24 00:17:51 -0800433 elif field.type == IP_PROTO:
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800434 _proto = field.ip_proto
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800435 log.info('#### field.type == IP_PROTO ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800436 pass # construct ip_proto based condition here
437
438 elif field.type == IN_PORT:
439 _port = field.port
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800440 log.info('#### field.type == IN_PORT ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800441 pass # construct in_port based condition here
442
443 elif field.type == VLAN_VID:
444 _vlan_vid = field.vlan_vid
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800445 log.info('#### field.type == VLAN_VID ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800446 pass # construct VLAN ID based filter condition here
447
448 elif field.type == VLAN_PCP:
449 _vlan_pcp = field.vlan_pcp
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800450 log.info('#### field.type == VLAN_PCP ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800451 pass # construct VLAN PCP based filter condition here
452
Zsolt Haraszti3578a1c2017-01-10 15:29:02 -0800453 elif field.type == UDP_SRC:
454 _udp_src = field.udp_src
455 log.info('#### field.type == UDP_SRC ####')
456 pass # construct UDP SRC based filter here
457
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800458 elif field.type == UDP_DST:
459 _udp_dst = field.udp_dst
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800460 log.info('#### field.type == UDP_DST ####')
Zsolt Haraszti3578a1c2017-01-10 15:29:02 -0800461 pass # construct UDP DST based filter here
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800462
Zsolt Haraszti6a5107c2017-01-09 23:42:41 -0800463 elif field.type == METADATA:
464 pass # safe to ignore
465
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800466 else:
467 raise NotImplementedError('field.type={}'.format(
468 field.type))
Zsolt Haraszti80175202016-12-24 00:17:51 -0800469
470 for action in get_actions(flow):
471
472 if action.type == OUTPUT:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800473 dn_req /= PortIngressRuleResultForward()
Zsolt Haraszti80175202016-12-24 00:17:51 -0800474
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800475 elif action.type == POP_VLAN:
476 pass # construct vlan pop command here
477
Zsolt Haraszti80175202016-12-24 00:17:51 -0800478 elif action.type == PUSH_VLAN:
479 if action.push.ethertype != 0x8100:
480 log.error('unhandled-ether-type',
481 ethertype=action.push.ethertype)
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800482 dn_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
Zsolt Haraszti80175202016-12-24 00:17:51 -0800483
484 elif action.type == SET_FIELD:
485 assert (action.set_field.field.oxm_class ==
486 ofp.OFPXMC_OPENFLOW_BASIC)
487 field = action.set_field.field.ofb_field
488 if field.type == VLAN_VID:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800489 dn_req /= PortIngressRuleResultSet(
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800490 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800491 else:
492 log.error('unsupported-action-set-field-type',
493 field_type=field.type)
494 else:
495 log.error('unsupported-action-type',
496 action_type=action.type)
497
498 # dn_req /= PortIngressRuleTerminator()
499 # dn_req /= AddPortIngressRule()
500
501 # msg = (
502 # Ether(dst=device.mac_address) /
503 # Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
504 # EOAMPayload(
505 # body=CablelabsOUI() / DPoEOpcode_SetRequest() / dn_req)
506 # )
507
508 # self.io_port.send(str(msg))
509
510 elif in_port == 1:
511 # Upstream rule
512 log.info('#### Upstream Rule ####')
513 up_req = PonPortObject()
514 up_req /= PortIngressRuleHeader(precedence=precedence)
515
516 for field in get_ofb_fields(flow):
517
518 if field.type == ETH_TYPE:
519 _type = field.eth_type
520 up_req /= PortIngressRuleClauseMatchLength02(
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800521 fieldcode=Clause['L2 Type/Len'],
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800522 operator=1,
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800523 match=_type)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800524
525 elif field.type == IP_PROTO:
526 _proto = field.ip_proto
527 log.info('#### field.type == IP_PROTO ####')
528 pass # construct ip_proto based condition here
529
530 elif field.type == IN_PORT:
531 _port = field.port
532 log.info('#### field.type == IN_PORT ####')
533 pass # construct in_port based condition here
534
535 elif field.type == VLAN_VID:
536 _vlan_vid = field.vlan_vid
537 log.info('#### field.type == VLAN_VID ####')
538 pass # construct VLAN ID based filter condition here
539
540 elif field.type == VLAN_PCP:
541 _vlan_pcp = field.vlan_pcp
542 log.info('#### field.type == VLAN_PCP ####')
543 pass # construct VLAN PCP based filter condition here
544
Zsolt Haraszti3578a1c2017-01-10 15:29:02 -0800545 elif field.type == UDP_SRC:
546 _udp_src = field.udp_src
547 log.info('#### field.type == UDP_SRC ####')
548 pass # construct UDP SRC based filter here
549
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800550 elif field.type == UDP_DST:
551 _udp_dst = field.udp_dst
552 log.info('#### field.type == UDP_DST ####')
Zsolt Haraszti3578a1c2017-01-10 15:29:02 -0800553 pass # construct UDP DST based filter here
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800554
555 else:
556 raise NotImplementedError('field.type={}'.format(
557 field.type))
558
559 for action in get_actions(flow):
560
561 if action.type == OUTPUT:
562 up_req /= PortIngressRuleResultForward()
563
564 elif action.type == POP_VLAN:
565 pass # construct vlan pop command here
566
567 elif action.type == PUSH_VLAN:
568 if action.push.ethertype != 0x8100:
569 log.error('unhandled-ether-type',
570 ethertype=action.push.ethertype)
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800571 up_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800572
573 elif action.type == SET_FIELD:
574 assert (action.set_field.field.oxm_class ==
575 ofp.OFPXMC_OPENFLOW_BASIC)
576 field = action.set_field.field.ofb_field
577 if field.type == VLAN_VID:
578 up_req /= PortIngressRuleResultSet(
Nathan Knuthd390ceb2017-01-07 15:38:58 -0800579 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800580 else:
581 log.error('unsupported-action-set-field-type',
582 field_type=field.type)
583
584 else:
585 log.error('unsupported-action-type',
586 action_type=action.type)
587
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800588 up_req /= PortIngressRuleTerminator()
589 up_req /= AddPortIngressRule()
Zsolt Haraszti80175202016-12-24 00:17:51 -0800590
591 msg = (
592 Ether(dst=device.mac_address) /
593 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
594 EOAMPayload(
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800595 body=CablelabsOUI() / DPoEOpcode_SetRequest() / up_req)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800596 )
597
598 self.io_port.send(str(msg))
599
600 else:
601 raise Exception('Port should be 1 or 2 by our convention')
Zsolt Harasztied091602016-12-08 13:36:38 -0800602
603 def update_flows_incrementally(self, device, flow_changes, group_changes):
604 raise NotImplementedError()
605
606 def send_proxied_message(self, proxy_address, msg):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800607 log.info('send-proxied-message', proxy_address=proxy_address)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800608 device = self.adapter_agent.get_device(proxy_address.device_id)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800609 frame = Ether(dst=device.mac_address) / \
Nathan Knuth6e57f332016-12-22 15:49:20 -0800610 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
611 Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800612 msg
Nathan Knuth6e57f332016-12-22 15:49:20 -0800613
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800614 self.io_port.send(str(frame))
Zsolt Harasztied091602016-12-08 13:36:38 -0800615
616 def receive_proxied_message(self, proxy_address, msg):
617 raise NotImplementedError()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800618
619 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
620 log.info('packet-out', logical_device_id=logical_device_id,
621 egress_port_no=egress_port_no, msg_len=len(msg))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800622
623 dev_id, logical_dev_id = self.vlan_to_device_ids[egress_port_no]
624 if logical_dev_id != logical_device_id:
625 raise Exception('Internal table mismatch')
626
627 tmp = Ether(msg)
628
629 frame = Ether(dst=tmp.dst, src=tmp.src) / \
630 Dot1Q(vlan=TIBIT_PACKET_OUT_VLAN) / \
631 Dot1Q(vlan=egress_port_no) / \
632 tmp.payload
633
634 self.io_port.send(str(frame))