blob: b836e2f96b37ee652e87f5d288a18cb1b56bc7dc [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
39from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum as Clause
Zsolt Haraszti80175202016-12-24 00:17:51 -080040from voltha.core.flow_decomposer import *
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080041from voltha.core.logical_device_agent import mac_str_to_tuple
Zsolt Harasztied091602016-12-08 13:36:38 -080042from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
Zsolt Haraszti80175202016-12-24 00:17:51 -080043from voltha.protos.common_pb2 import LogLevel, ConnectStatus
44from voltha.protos.common_pb2 import OperStatus, AdminState
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080045from voltha.protos.device_pb2 import Device, Port
Zsolt Harasztied091602016-12-08 13:36:38 -080046from voltha.protos.device_pb2 import DeviceType, DeviceTypes
47from voltha.protos.health_pb2 import HealthStatus
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -080048from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
49from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_10GB_FD, \
50 OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
51 OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
Zsolt Haraszti80175202016-12-24 00:17:51 -080052from voltha.registry import registry
Zsolt Haraszti348d1932016-12-10 01:10:07 -080053log = structlog.get_logger()
Zsolt Harasztied091602016-12-08 13:36:38 -080054
Nathan Knuth6e57f332016-12-22 15:49:20 -080055# Match on the MGMT VLAN, Priority 7
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080056TIBIT_MGMT_VLAN = 4090
57TIBIT_MGMT_PRIORITY = 7
58frame_match_case1 = 'ether[14:2] = 0x{:01x}{:03x}'.format(
59 TIBIT_MGMT_PRIORITY << 1, TIBIT_MGMT_VLAN)
60
61TIBIT_PACKET_IN_VLAN = 4000
62frame_match_case2 = '(ether[14:2] & 0xfff) = 0x{:03x}'.format(
63 TIBIT_PACKET_IN_VLAN)
64
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080065TIBIT_PACKET_OUT_VLAN = 4000
66
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080067is_tibit_frame = BpfProgramFilter('{} or {}'.format(
68 frame_match_case1, frame_match_case2))
69
Nathan Knuth6e57f332016-12-22 15:49:20 -080070#is_tibit_frame = lambda x: True
Zsolt Haraszti89a27302016-12-08 16:53:06 -080071
Nathan Knuthfe2b2e02017-01-06 07:29:02 -080072# Extract OLT MAC address: This is a good
73# example of getting the OLT mac address
74
75#for mac, device in self.device_ids.iteritems():
76# if device == dev_id:
77# olt_mac_address = mac
78# log.info('packet-out', olt_mac_address=olt_mac_address)
Zsolt Haraszti85f12852016-12-24 08:30:58 -080079
Zsolt Haraszti348d1932016-12-10 01:10:07 -080080# To be removed in favor of OAM
Zsolt Haraszti89a27302016-12-08 16:53:06 -080081class TBJSON(Packet):
82 """ TBJSON 'packet' layer. """
83 name = "TBJSON"
84 fields_desc = [StrField("data", default="")]
85
Nathan Knuth6e57f332016-12-22 15:49:20 -080086bind_layers(Ether, TBJSON, type=0x9001)
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080087
Zsolt Haraszti85f12852016-12-24 08:30:58 -080088
Zsolt Harasztied091602016-12-08 13:36:38 -080089@implementer(IAdapterInterface)
90class TibitOltAdapter(object):
91
92 name = 'tibit_olt'
93
94 supported_device_types = [
95 DeviceType(
96 id='tibit_olt',
97 adapter=name,
98 accepts_bulk_flow_update=True
99 )
100 ]
101
102 def __init__(self, adapter_agent, config):
103 self.adapter_agent = adapter_agent
104 self.config = config
105 self.descriptor = Adapter(
106 id=self.name,
107 vendor='Tibit Communications Inc.',
108 version='0.1',
109 config=AdapterConfig(log_level=LogLevel.INFO)
110 )
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800111 self.interface = registry('main').get_args().interface
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800112 self.io_port = None
Nathan Knuth6e57f332016-12-22 15:49:20 -0800113 self.incoming_queues = {} # OLT mac_address -> DeferredQueue()
114 self.device_ids = {} # OLT mac_address -> device_id
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800115 self.vlan_to_device_ids = {} # c-vid -> (device_id, logical_device_id)
Zsolt Harasztied091602016-12-08 13:36:38 -0800116
117 def start(self):
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800118 log.debug('starting', interface=self.interface)
119 log.info('started', interface=self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800120
121 def stop(self):
122 log.debug('stopping')
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800123 if self.io_port is not None:
124 registry('frameio').del_interface(self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800125 log.info('stopped')
126
127 def adapter_descriptor(self):
128 return self.descriptor
129
130 def device_types(self):
131 return DeviceTypes(items=self.supported_device_types)
132
133 def health(self):
134 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
135
136 def change_master_state(self, master):
137 raise NotImplementedError()
138
139 def adopt_device(self, device):
140 log.info('adopt-device', device=device)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800141 self._activate_io_port()
142 reactor.callLater(0, self._launch_device_activation, device)
Zsolt Harasztied091602016-12-08 13:36:38 -0800143
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800144 def _activate_io_port(self):
145 if self.io_port is None:
146 self.io_port = registry('frameio').add_interface(
147 self.interface, self._rcv_io, is_tibit_frame)
148
149 @inlineCallbacks
150 def _launch_device_activation(self, device):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800151 try:
152 log.debug('launch_dev_activation')
153 # prepare receive queue
154 self.incoming_queues[device.mac_address] = DeferredQueue(size=100)
155
Nathan Knuth6e57f332016-12-22 15:49:20 -0800156 # add mac_address to device_ids table
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800157 olt_mac = device.mac_address
Nathan Knuth6e57f332016-12-22 15:49:20 -0800158 self.device_ids[olt_mac] = device.id
159
160 # send out ping to OLT device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800161 ping_frame = self._make_ping_frame(mac_address=olt_mac)
162 self.io_port.send(ping_frame)
163
164 # wait till we receive a response
Nathan Knuth6e57f332016-12-22 15:49:20 -0800165 ## TODO add timeout mechanism so we can signal if we cannot reach
166 ##device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800167 while True:
168 response = yield self.incoming_queues[olt_mac].get()
169 # verify response and if not the expected response
170 if 1: # TODO check if it is really what we expect, and wait if not
171 break
172
173 except Exception, e:
174 log.exception('launch device failed', e=e)
175
176 # if we got response, we can fill out the device info, mark the device
177 # reachable
Zsolt Haraszti80175202016-12-24 00:17:51 -0800178 # jdev = json.loads(response.data[5:])
179 jdev = json.loads(response.payload.payload.body.load)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800180 device.root = True
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800181 device.vendor = 'Tibit Communications, Inc.'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800182 device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800183 device.hardware_version = jdev['results']['datecode']
184 device.firmware_version = jdev['results']['firmware']
185 device.software_version = jdev['results']['modelversion']
186 device.serial_number = jdev['results']['manufacturer']
Nathan Knuth6e57f332016-12-22 15:49:20 -0800187
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800188 device.connect_status = ConnectStatus.REACHABLE
189 self.adapter_agent.update_device(device)
190
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800191 # then shortly after we create some ports for the device
192 log.info('create-port')
193 nni_port = Port(
194 port_no=2,
195 label='NNI facing Ethernet port',
196 type=Port.ETHERNET_NNI,
197 admin_state=AdminState.ENABLED,
198 oper_status=OperStatus.ACTIVE
199 )
200 self.adapter_agent.add_port(device.id, nni_port)
201 self.adapter_agent.add_port(device.id, Port(
202 port_no=1,
203 label='PON port',
204 type=Port.PON_OLT,
205 admin_state=AdminState.ENABLED,
206 oper_status=OperStatus.ACTIVE
207 ))
208
209 log.info('create-logical-device')
210 # then shortly after we create the logical device with one port
211 # that will correspond to the NNI port
212 logical_device_id = uuid4().hex[:12]
213 ld = LogicalDevice(
214 id=logical_device_id,
215 datapath_id=int('0x' + logical_device_id[:8], 16), # from id
216 desc=ofp_desc(
217 mfr_desc=device.vendor,
218 hw_desc=jdev['results']['device'],
219 sw_desc=jdev['results']['firmware'],
220 serial_num=uuid4().hex,
221 dp_desc='n/a'
222 ),
223 switch_features=ofp_switch_features(
224 n_buffers=256, # TODO fake for now
225 n_tables=2, # TODO ditto
226 capabilities=( # TODO and ditto
227 OFPC_FLOW_STATS
228 | OFPC_TABLE_STATS
229 | OFPC_PORT_STATS
230 | OFPC_GROUP_STATS
231 )
232 ),
233 root_device_id=device.id
234 )
235 self.adapter_agent.create_logical_device(ld)
236 cap = OFPPF_10GB_FD | OFPPF_FIBER
237 self.adapter_agent.add_logical_port(ld.id, LogicalPort(
238 id='nni',
239 ofp_port=ofp_port(
240 port_no=129,
241 hw_addr=mac_str_to_tuple(device.mac_address),
242 name='nni',
243 config=0,
244 state=OFPPS_LIVE,
245 curr=cap,
246 advertised=cap,
247 peer=cap,
248 curr_speed=OFPPF_10GB_FD,
249 max_speed=OFPPF_10GB_FD
250 ),
251 device_id=device.id,
252 device_port_no=nni_port.port_no,
253 root_port=True
254 ))
255
256 # and finally update to active
257 device = self.adapter_agent.get_device(device.id)
258 device.parent_id = ld.id
259 device.oper_status = OperStatus.ACTIVE
260 self.adapter_agent.update_device(device)
261
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800262 # Just transitioned to ACTIVE, wait a tenth of second
263 # before checking for ONUs
264 reactor.callLater(0.1, self._detect_onus, device)
265
266 @inlineCallbacks
267 def _detect_onus(self, device):
268 # send out get 'links' to the OLT device
269 olt_mac = device.mac_address
270 links_frame = self._make_links_frame(mac_address=olt_mac)
271 self.io_port.send(links_frame)
272 while True:
273 response = yield self.incoming_queues[olt_mac].get()
274 # verify response and if not the expected response
275 if 1: # TODO check if it is really what we expect, and wait if not
276 break
277
Zsolt Haraszti80175202016-12-24 00:17:51 -0800278 jdev = json.loads(response.payload.payload.body.load)
Nathan Knuth6e57f332016-12-22 15:49:20 -0800279 tibit_mac = ''
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800280 for macid in jdev['results']:
281 if macid['macid'] is None:
282 log.info('MAC ID is NONE %s' % str(macid['macid']))
283 else:
Nathan Knuth6e57f332016-12-22 15:49:20 -0800284 tibit_mac = '000c' + macid.get('macid', 'e2000000')[4:]
285 log.info('activate-olt-for-onu-%s' % tibit_mac)
286
287 # Convert from string to colon separated form
288 tibit_mac = ':'.join(s.encode('hex') for s in tibit_mac.decode('hex'))
289
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800290 vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800291 self.adapter_agent.child_device_detected(
292 parent_device_id=device.id,
293 parent_port_no=1,
294 child_device_type='tibit_onu',
Nathan Knuth6e57f332016-12-22 15:49:20 -0800295 mac_address = tibit_mac,
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800296 proxy_address=Device.ProxyAddress(
297 device_id=device.id,
298 channel_id=vlan_id
299 ),
300 vlan=vlan_id
301 )
302
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800303 # also record the vlan_id -> (device_id, logical_device_id) for
304 # later use
305 self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id)
306
Nathan Knuth6e57f332016-12-22 15:49:20 -0800307 def _olt_side_onu_activation(self, serial):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800308 """
309 This is where if this was a real OLT, the OLT-side activation for
310 the new ONU should be performed. By the time we return, the OLT shall
311 be able to provide tunneled (proxy) communication to the given ONU,
312 using the returned information.
313 """
Nathan Knuth6e57f332016-12-22 15:49:20 -0800314 vlan_id = serial + 200
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800315 return vlan_id
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800316
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800317 def _rcv_io(self, port, frame):
318
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800319 log.info('frame-received', frame=hexify(frame))
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800320
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800321 # make into frame to extract source mac
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800322 response = Ether(frame)
323
Nathan Knuth6e57f332016-12-22 15:49:20 -0800324 if response.haslayer(Dot1Q):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800325
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800326 # All OAM responses from the OLT should have a TIBIT_MGMT_VLAN.
327 # Responses from the ONUs should have a TIBIT_MGMT_VLAN followed by a ONU CTAG
328 # All packet-in frames will have the TIBIT_PACKET_IN_VLAN.
329 if response.getlayer(Dot1Q).type == 0x8100:
330
331 if response.getlayer(Dot1Q).vlan == TIBIT_PACKET_IN_VLAN:
332
333 inner_tag_and_rest = response.payload.payload
334
335 inner_tag_and_rest.show() # TODO remove this soon
336
337 if isinstance(inner_tag_and_rest, Dot1Q):
338
339 cvid = inner_tag_and_rest.vlan
340
341 frame = Ether(src=response.src,
342 dst=response.dst,
343 type=inner_tag_and_rest.type) /\
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800344 inner_tag_and_rest.payload
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800345
346 _, logical_device_id = self.vlan_to_device_ids.get(cvid)
347 if logical_device_id is None:
348 log.error('invalid-cvid', cvid=cvid)
349 else:
350 self.adapter_agent.send_packet_in(
351 logical_device_id=logical_device_id,
352 logical_port_no=cvid, # C-VID encodes port no
353 packet=str(frame))
354
355 else:
356 log.error('packet-in-single-tagged',
357 frame=hexify(response))
358
359 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800360 ## Mgmt responses received from the ONU
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800361 ## Since the type of the first layer is 0x8100,
362 ## then the frame must have an inner tag layer
363 olt_mac = response.src
364 device_id = self.device_ids[olt_mac]
365 channel_id = response[Dot1Q:2].vlan
366 log.info('received_channel_id', channel_id=channel_id,
367 device_id=device_id)
368
369 proxy_address=Device.ProxyAddress(
370 device_id=device_id,
371 channel_id=channel_id
372 )
373 # pop dot1q header(s)
374 msg = response.payload.payload
375 self.adapter_agent.receive_proxied_message(proxy_address, msg)
376
Nathan Knuth6e57f332016-12-22 15:49:20 -0800377 else:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800378 ## Mgmt responses received from the OLT
Nathan Knuth6e57f332016-12-22 15:49:20 -0800379 ## enqueue incoming parsed frame to right device
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800380 log.info('received-dot1q-not-8100')
Nathan Knuth6e57f332016-12-22 15:49:20 -0800381 self.incoming_queues[response.src].put(response)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800382
383 def _make_ping_frame(self, mac_address):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800384 # Create a json packet
385 json_operation_str = '{\"operation\":\"version\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800386 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 -0800387 return str(frame)
388
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800389 def _make_links_frame(self, mac_address):
390 # Create a json packet
391 json_operation_str = '{\"operation\":\"links\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800392 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 -0800393 return str(frame)
394
Zsolt Harasztied091602016-12-08 13:36:38 -0800395 def abandon_device(self, device):
396 raise NotImplementedError(0
397 )
398 def deactivate_device(self, device):
399 raise NotImplementedError()
400
401 def update_flows_bulk(self, device, flows, groups):
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800402 log.info('########################################')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800403 log.info('bulk-flow-update', device_id=device.id,
404 flows=flows, groups=groups)
405
406 assert len(groups.items) == 0, "Cannot yet deal with groups"
407
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800408 ClauseFields = {v: k for k, v in Clause.iteritems()}
409
Zsolt Haraszti80175202016-12-24 00:17:51 -0800410 for flow in flows.items:
411 in_port = get_in_port(flow)
412 assert in_port is not None
413
414 precedence = 255 - min(flow.priority / 256, 255)
415
416 if in_port == 2:
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800417 log.info('#### Downstream Rule ####')
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800418 dn_req = PonPortObject()
419 dn_req /= PortIngressRuleHeader(precedence=precedence)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800420
421 for field in get_ofb_fields(flow):
422
423 if field.type == ETH_TYPE:
424 log.info('#### field.type == ETH_TYPE ####')
425 _type = field.eth_type
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800426 dn_req /= PortIngressRuleClauseMatchLength02(
Zsolt Haraszti80175202016-12-24 00:17:51 -0800427 fieldcode=3,
428 operator=1,
429 match0=(_type >> 8) & 0xff,
430 match1=_type & 0xff)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800431
Zsolt Haraszti80175202016-12-24 00:17:51 -0800432 elif field.type == IP_PROTO:
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800433 _proto = field.ip_proto
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800434 log.info('#### field.type == IP_PROTO ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800435 pass # construct ip_proto based condition here
436
437 elif field.type == IN_PORT:
438 _port = field.port
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800439 log.info('#### field.type == IN_PORT ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800440 pass # construct in_port based condition here
441
442 elif field.type == VLAN_VID:
443 _vlan_vid = field.vlan_vid
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800444 log.info('#### field.type == VLAN_VID ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800445 pass # construct VLAN ID based filter condition here
446
447 elif field.type == VLAN_PCP:
448 _vlan_pcp = field.vlan_pcp
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800449 log.info('#### field.type == VLAN_PCP ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800450 pass # construct VLAN PCP based filter condition here
451
452 elif field.type == UDP_DST:
453 _udp_dst = field.udp_dst
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800454 log.info('#### field.type == UDP_DST ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800455 pass # construct UDP SDT based filter here
456
457 else:
458 raise NotImplementedError('field.type={}'.format(
459 field.type))
Zsolt Haraszti80175202016-12-24 00:17:51 -0800460
461 for action in get_actions(flow):
462
463 if action.type == OUTPUT:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800464 dn_req /= PortIngressRuleResultForward()
Zsolt Haraszti80175202016-12-24 00:17:51 -0800465
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800466 elif action.type == POP_VLAN:
467 pass # construct vlan pop command here
468
Zsolt Haraszti80175202016-12-24 00:17:51 -0800469 elif action.type == PUSH_VLAN:
470 if action.push.ethertype != 0x8100:
471 log.error('unhandled-ether-type',
472 ethertype=action.push.ethertype)
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800473 dn_req /= PortIngressRuleResultInsert(fieldcode=ClauseFields['C-VLAN Tag'])
Zsolt Haraszti80175202016-12-24 00:17:51 -0800474
475 elif action.type == SET_FIELD:
476 assert (action.set_field.field.oxm_class ==
477 ofp.OFPXMC_OPENFLOW_BASIC)
478 field = action.set_field.field.ofb_field
479 if field.type == VLAN_VID:
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800480 dn_req /= PortIngressRuleResultSet(
481 fieldcode=ClauseFields['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
482 else:
483 log.error('unsupported-action-set-field-type',
484 field_type=field.type)
485 else:
486 log.error('unsupported-action-type',
487 action_type=action.type)
488
489 # dn_req /= PortIngressRuleTerminator()
490 # dn_req /= AddPortIngressRule()
491
492 # msg = (
493 # Ether(dst=device.mac_address) /
494 # Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
495 # EOAMPayload(
496 # body=CablelabsOUI() / DPoEOpcode_SetRequest() / dn_req)
497 # )
498
499 # self.io_port.send(str(msg))
500
501 elif in_port == 1:
502 # Upstream rule
503 log.info('#### Upstream Rule ####')
504 up_req = PonPortObject()
505 up_req /= PortIngressRuleHeader(precedence=precedence)
506
507 for field in get_ofb_fields(flow):
508
509 if field.type == ETH_TYPE:
510 _type = field.eth_type
511 up_req /= PortIngressRuleClauseMatchLength02(
512 fieldcode=3,
513 operator=1,
514 match0=(_type >> 8) & 0xff,
515 match1=_type & 0xff)
516
517 elif field.type == IP_PROTO:
518 _proto = field.ip_proto
519 log.info('#### field.type == IP_PROTO ####')
520 pass # construct ip_proto based condition here
521
522 elif field.type == IN_PORT:
523 _port = field.port
524 log.info('#### field.type == IN_PORT ####')
525 pass # construct in_port based condition here
526
527 elif field.type == VLAN_VID:
528 _vlan_vid = field.vlan_vid
529 log.info('#### field.type == VLAN_VID ####')
530 pass # construct VLAN ID based filter condition here
531
532 elif field.type == VLAN_PCP:
533 _vlan_pcp = field.vlan_pcp
534 log.info('#### field.type == VLAN_PCP ####')
535 pass # construct VLAN PCP based filter condition here
536
537 elif field.type == UDP_DST:
538 _udp_dst = field.udp_dst
539 log.info('#### field.type == UDP_DST ####')
540 pass # construct UDP SDT based filter here
541
542 else:
543 raise NotImplementedError('field.type={}'.format(
544 field.type))
545
546 for action in get_actions(flow):
547
548 if action.type == OUTPUT:
549 up_req /= PortIngressRuleResultForward()
550
551 elif action.type == POP_VLAN:
552 pass # construct vlan pop command here
553
554 elif action.type == PUSH_VLAN:
555 if action.push.ethertype != 0x8100:
556 log.error('unhandled-ether-type',
557 ethertype=action.push.ethertype)
558 up_req /= PortIngressRuleResultInsert(fieldcode=ClauseFields['C-VLAN Tag'])
559
560 elif action.type == SET_FIELD:
561 assert (action.set_field.field.oxm_class ==
562 ofp.OFPXMC_OPENFLOW_BASIC)
563 field = action.set_field.field.ofb_field
564 if field.type == VLAN_VID:
565 up_req /= PortIngressRuleResultSet(
566 fieldcode=ClauseFields['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800567 else:
568 log.error('unsupported-action-set-field-type',
569 field_type=field.type)
570
571 else:
572 log.error('unsupported-action-type',
573 action_type=action.type)
574
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800575 up_req /= PortIngressRuleTerminator()
576 up_req /= AddPortIngressRule()
Zsolt Haraszti80175202016-12-24 00:17:51 -0800577
578 msg = (
579 Ether(dst=device.mac_address) /
580 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
581 EOAMPayload(
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800582 body=CablelabsOUI() / DPoEOpcode_SetRequest() / up_req)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800583 )
584
585 self.io_port.send(str(msg))
586
587 else:
588 raise Exception('Port should be 1 or 2 by our convention')
Zsolt Harasztied091602016-12-08 13:36:38 -0800589
590 def update_flows_incrementally(self, device, flow_changes, group_changes):
591 raise NotImplementedError()
592
593 def send_proxied_message(self, proxy_address, msg):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800594 log.info('send-proxied-message', proxy_address=proxy_address)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800595 device = self.adapter_agent.get_device(proxy_address.device_id)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800596 frame = Ether(dst=device.mac_address) / \
Nathan Knuth6e57f332016-12-22 15:49:20 -0800597 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
598 Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800599 msg
Nathan Knuth6e57f332016-12-22 15:49:20 -0800600
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800601 self.io_port.send(str(frame))
Zsolt Harasztied091602016-12-08 13:36:38 -0800602
603 def receive_proxied_message(self, proxy_address, msg):
604 raise NotImplementedError()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800605
606 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
607 log.info('packet-out', logical_device_id=logical_device_id,
608 egress_port_no=egress_port_no, msg_len=len(msg))
Nathan Knuthfe2b2e02017-01-06 07:29:02 -0800609
610 dev_id, logical_dev_id = self.vlan_to_device_ids[egress_port_no]
611 if logical_dev_id != logical_device_id:
612 raise Exception('Internal table mismatch')
613
614 tmp = Ether(msg)
615
616 frame = Ether(dst=tmp.dst, src=tmp.src) / \
617 Dot1Q(vlan=TIBIT_PACKET_OUT_VLAN) / \
618 Dot1Q(vlan=egress_port_no) / \
619 tmp.payload
620
621 self.io_port.send(str(frame))