blob: 564674d09e0408d8e96e33fb8f84ea88accd51b9 [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
65is_tibit_frame = BpfProgramFilter('{} or {}'.format(
66 frame_match_case1, frame_match_case2))
67
Nathan Knuth6e57f332016-12-22 15:49:20 -080068#is_tibit_frame = lambda x: True
Zsolt Haraszti89a27302016-12-08 16:53:06 -080069
Zsolt Haraszti85f12852016-12-24 08:30:58 -080070
Zsolt Haraszti348d1932016-12-10 01:10:07 -080071# To be removed in favor of OAM
Zsolt Haraszti89a27302016-12-08 16:53:06 -080072class TBJSON(Packet):
73 """ TBJSON 'packet' layer. """
74 name = "TBJSON"
75 fields_desc = [StrField("data", default="")]
76
Nathan Knuth6e57f332016-12-22 15:49:20 -080077bind_layers(Ether, TBJSON, type=0x9001)
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -080078
Zsolt Haraszti85f12852016-12-24 08:30:58 -080079
Zsolt Harasztied091602016-12-08 13:36:38 -080080@implementer(IAdapterInterface)
81class TibitOltAdapter(object):
82
83 name = 'tibit_olt'
84
85 supported_device_types = [
86 DeviceType(
87 id='tibit_olt',
88 adapter=name,
89 accepts_bulk_flow_update=True
90 )
91 ]
92
93 def __init__(self, adapter_agent, config):
94 self.adapter_agent = adapter_agent
95 self.config = config
96 self.descriptor = Adapter(
97 id=self.name,
98 vendor='Tibit Communications Inc.',
99 version='0.1',
100 config=AdapterConfig(log_level=LogLevel.INFO)
101 )
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800102 self.interface = registry('main').get_args().interface
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800103 self.io_port = None
Nathan Knuth6e57f332016-12-22 15:49:20 -0800104 self.incoming_queues = {} # OLT mac_address -> DeferredQueue()
105 self.device_ids = {} # OLT mac_address -> device_id
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800106 self.vlan_to_device_ids = {} # c-vid -> (device_id, logical_device_id)
Zsolt Harasztied091602016-12-08 13:36:38 -0800107
108 def start(self):
Zsolt Harasztia17f3ec2016-12-08 14:55:49 -0800109 log.debug('starting', interface=self.interface)
110 log.info('started', interface=self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800111
112 def stop(self):
113 log.debug('stopping')
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800114 if self.io_port is not None:
115 registry('frameio').del_interface(self.interface)
Zsolt Harasztied091602016-12-08 13:36:38 -0800116 log.info('stopped')
117
118 def adapter_descriptor(self):
119 return self.descriptor
120
121 def device_types(self):
122 return DeviceTypes(items=self.supported_device_types)
123
124 def health(self):
125 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
126
127 def change_master_state(self, master):
128 raise NotImplementedError()
129
130 def adopt_device(self, device):
131 log.info('adopt-device', device=device)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800132 self._activate_io_port()
133 reactor.callLater(0, self._launch_device_activation, device)
Zsolt Harasztied091602016-12-08 13:36:38 -0800134
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800135 def _activate_io_port(self):
136 if self.io_port is None:
137 self.io_port = registry('frameio').add_interface(
138 self.interface, self._rcv_io, is_tibit_frame)
139
140 @inlineCallbacks
141 def _launch_device_activation(self, device):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800142 try:
143 log.debug('launch_dev_activation')
144 # prepare receive queue
145 self.incoming_queues[device.mac_address] = DeferredQueue(size=100)
146
Nathan Knuth6e57f332016-12-22 15:49:20 -0800147 # add mac_address to device_ids table
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800148 olt_mac = device.mac_address
Nathan Knuth6e57f332016-12-22 15:49:20 -0800149 self.device_ids[olt_mac] = device.id
150
151 # send out ping to OLT device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800152 ping_frame = self._make_ping_frame(mac_address=olt_mac)
153 self.io_port.send(ping_frame)
154
155 # wait till we receive a response
Nathan Knuth6e57f332016-12-22 15:49:20 -0800156 ## TODO add timeout mechanism so we can signal if we cannot reach
157 ##device
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800158 while True:
159 response = yield self.incoming_queues[olt_mac].get()
160 # verify response and if not the expected response
161 if 1: # TODO check if it is really what we expect, and wait if not
162 break
163
164 except Exception, e:
165 log.exception('launch device failed', e=e)
166
167 # if we got response, we can fill out the device info, mark the device
168 # reachable
Zsolt Haraszti80175202016-12-24 00:17:51 -0800169 # jdev = json.loads(response.data[5:])
170 jdev = json.loads(response.payload.payload.body.load)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800171 device.root = True
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800172 device.vendor = 'Tibit Communications, Inc.'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800173 device.model = jdev.get('results', {}).get('device', 'DEVICE_UNKNOWN')
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800174 device.hardware_version = jdev['results']['datecode']
175 device.firmware_version = jdev['results']['firmware']
176 device.software_version = jdev['results']['modelversion']
177 device.serial_number = jdev['results']['manufacturer']
Nathan Knuth6e57f332016-12-22 15:49:20 -0800178
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800179 device.connect_status = ConnectStatus.REACHABLE
180 self.adapter_agent.update_device(device)
181
Zsolt Harasztiaa4626e2016-12-08 16:53:06 -0800182 # then shortly after we create some ports for the device
183 log.info('create-port')
184 nni_port = Port(
185 port_no=2,
186 label='NNI facing Ethernet port',
187 type=Port.ETHERNET_NNI,
188 admin_state=AdminState.ENABLED,
189 oper_status=OperStatus.ACTIVE
190 )
191 self.adapter_agent.add_port(device.id, nni_port)
192 self.adapter_agent.add_port(device.id, Port(
193 port_no=1,
194 label='PON port',
195 type=Port.PON_OLT,
196 admin_state=AdminState.ENABLED,
197 oper_status=OperStatus.ACTIVE
198 ))
199
200 log.info('create-logical-device')
201 # then shortly after we create the logical device with one port
202 # that will correspond to the NNI port
203 logical_device_id = uuid4().hex[:12]
204 ld = LogicalDevice(
205 id=logical_device_id,
206 datapath_id=int('0x' + logical_device_id[:8], 16), # from id
207 desc=ofp_desc(
208 mfr_desc=device.vendor,
209 hw_desc=jdev['results']['device'],
210 sw_desc=jdev['results']['firmware'],
211 serial_num=uuid4().hex,
212 dp_desc='n/a'
213 ),
214 switch_features=ofp_switch_features(
215 n_buffers=256, # TODO fake for now
216 n_tables=2, # TODO ditto
217 capabilities=( # TODO and ditto
218 OFPC_FLOW_STATS
219 | OFPC_TABLE_STATS
220 | OFPC_PORT_STATS
221 | OFPC_GROUP_STATS
222 )
223 ),
224 root_device_id=device.id
225 )
226 self.adapter_agent.create_logical_device(ld)
227 cap = OFPPF_10GB_FD | OFPPF_FIBER
228 self.adapter_agent.add_logical_port(ld.id, LogicalPort(
229 id='nni',
230 ofp_port=ofp_port(
231 port_no=129,
232 hw_addr=mac_str_to_tuple(device.mac_address),
233 name='nni',
234 config=0,
235 state=OFPPS_LIVE,
236 curr=cap,
237 advertised=cap,
238 peer=cap,
239 curr_speed=OFPPF_10GB_FD,
240 max_speed=OFPPF_10GB_FD
241 ),
242 device_id=device.id,
243 device_port_no=nni_port.port_no,
244 root_port=True
245 ))
246
247 # and finally update to active
248 device = self.adapter_agent.get_device(device.id)
249 device.parent_id = ld.id
250 device.oper_status = OperStatus.ACTIVE
251 self.adapter_agent.update_device(device)
252
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800253 # Just transitioned to ACTIVE, wait a tenth of second
254 # before checking for ONUs
255 reactor.callLater(0.1, self._detect_onus, device)
256
257 @inlineCallbacks
258 def _detect_onus(self, device):
259 # send out get 'links' to the OLT device
260 olt_mac = device.mac_address
261 links_frame = self._make_links_frame(mac_address=olt_mac)
262 self.io_port.send(links_frame)
263 while True:
264 response = yield self.incoming_queues[olt_mac].get()
265 # verify response and if not the expected response
266 if 1: # TODO check if it is really what we expect, and wait if not
267 break
268
Zsolt Haraszti80175202016-12-24 00:17:51 -0800269 jdev = json.loads(response.payload.payload.body.load)
Nathan Knuth6e57f332016-12-22 15:49:20 -0800270 tibit_mac = ''
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800271 for macid in jdev['results']:
272 if macid['macid'] is None:
273 log.info('MAC ID is NONE %s' % str(macid['macid']))
274 else:
Nathan Knuth6e57f332016-12-22 15:49:20 -0800275 tibit_mac = '000c' + macid.get('macid', 'e2000000')[4:]
276 log.info('activate-olt-for-onu-%s' % tibit_mac)
277
278 # Convert from string to colon separated form
279 tibit_mac = ':'.join(s.encode('hex') for s in tibit_mac.decode('hex'))
280
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800281 vlan_id = self._olt_side_onu_activation(int(macid['macid'][-4:-2], 16))
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800282 self.adapter_agent.child_device_detected(
283 parent_device_id=device.id,
284 parent_port_no=1,
285 child_device_type='tibit_onu',
Nathan Knuth6e57f332016-12-22 15:49:20 -0800286 mac_address = tibit_mac,
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800287 proxy_address=Device.ProxyAddress(
288 device_id=device.id,
289 channel_id=vlan_id
290 ),
291 vlan=vlan_id
292 )
293
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800294 # also record the vlan_id -> (device_id, logical_device_id) for
295 # later use
296 self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id)
297
Nathan Knuth6e57f332016-12-22 15:49:20 -0800298 def _olt_side_onu_activation(self, serial):
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800299 """
300 This is where if this was a real OLT, the OLT-side activation for
301 the new ONU should be performed. By the time we return, the OLT shall
302 be able to provide tunneled (proxy) communication to the given ONU,
303 using the returned information.
304 """
Nathan Knuth6e57f332016-12-22 15:49:20 -0800305 vlan_id = serial + 200
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800306 return vlan_id
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800307
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800308 def _rcv_io(self, port, frame):
309
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800310 log.info('frame-received', frame=hexify(frame))
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800311
Zsolt Haraszti4ef0a9a2016-12-20 01:35:48 -0800312 # make into frame to extract source mac
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800313 response = Ether(frame)
314
Nathan Knuth6e57f332016-12-22 15:49:20 -0800315 if response.haslayer(Dot1Q):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800316
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800317 # All OAM responses from the OLT should have a TIBIT_MGMT_VLAN.
318 # Responses from the ONUs should have a TIBIT_MGMT_VLAN followed by a ONU CTAG
319 # All packet-in frames will have the TIBIT_PACKET_IN_VLAN.
320 if response.getlayer(Dot1Q).type == 0x8100:
321
322 if response.getlayer(Dot1Q).vlan == TIBIT_PACKET_IN_VLAN:
323
324 inner_tag_and_rest = response.payload.payload
325
326 inner_tag_and_rest.show() # TODO remove this soon
327
328 if isinstance(inner_tag_and_rest, Dot1Q):
329
330 cvid = inner_tag_and_rest.vlan
331
332 frame = Ether(src=response.src,
333 dst=response.dst,
334 type=inner_tag_and_rest.type) /\
335 inner_tag_and_rest.payload
336
337 _, logical_device_id = self.vlan_to_device_ids.get(cvid)
338 if logical_device_id is None:
339 log.error('invalid-cvid', cvid=cvid)
340 else:
341 self.adapter_agent.send_packet_in(
342 logical_device_id=logical_device_id,
343 logical_port_no=cvid, # C-VID encodes port no
344 packet=str(frame))
345
346 else:
347 log.error('packet-in-single-tagged',
348 frame=hexify(response))
349
350 else:
351 ## Responses from the ONU
352 ## Since the type of the first layer is 0x8100,
353 ## then the frame must have an inner tag layer
354 olt_mac = response.src
355 device_id = self.device_ids[olt_mac]
356 channel_id = response[Dot1Q:2].vlan
357 log.info('received_channel_id', channel_id=channel_id,
358 device_id=device_id)
359
360 proxy_address=Device.ProxyAddress(
361 device_id=device_id,
362 channel_id=channel_id
363 )
364 # pop dot1q header(s)
365 msg = response.payload.payload
366 self.adapter_agent.receive_proxied_message(proxy_address, msg)
367
Nathan Knuth6e57f332016-12-22 15:49:20 -0800368 else:
369 ## Respones from the OLT
370 ## enqueue incoming parsed frame to right device
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800371 log.info('received-dot1q-not-8100')
Nathan Knuth6e57f332016-12-22 15:49:20 -0800372 self.incoming_queues[response.src].put(response)
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800373
374 def _make_ping_frame(self, mac_address):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800375 # Create a json packet
376 json_operation_str = '{\"operation\":\"version\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800377 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 -0800378 return str(frame)
379
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800380 def _make_links_frame(self, mac_address):
381 # Create a json packet
382 json_operation_str = '{\"operation\":\"links\"}'
Nathan Knuth6e57f332016-12-22 15:49:20 -0800383 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 -0800384 return str(frame)
385
Zsolt Harasztied091602016-12-08 13:36:38 -0800386 def abandon_device(self, device):
387 raise NotImplementedError(0
388 )
389 def deactivate_device(self, device):
390 raise NotImplementedError()
391
392 def update_flows_bulk(self, device, flows, groups):
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800393 log.info('########################################')
Zsolt Haraszti80175202016-12-24 00:17:51 -0800394 log.info('bulk-flow-update', device_id=device.id,
395 flows=flows, groups=groups)
396
397 assert len(groups.items) == 0, "Cannot yet deal with groups"
398
399 for flow in flows.items:
400 in_port = get_in_port(flow)
401 assert in_port is not None
402
403 precedence = 255 - min(flow.priority / 256, 255)
404
405 if in_port == 2:
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800406 log.info('#### Downstream Rule ####')
407
408 for field in get_ofb_fields(flow):
409
410 if field.type == ETH_TYPE:
411 log.info('#### field.type == ETH_TYPE ####')
412 _type = field.eth_type
413 req /= PortIngressRuleClauseMatchLength02(
414 fieldcode=3,
415 operator=1,
416 match0=(_type >> 8) & 0xff,
417 match1=_type & 0xff)
418
419 elif field.type == IP_PROTO:
420 _proto = field.ip_proto
421 log.info('#### field.type == IP_PROTO ####')
422 pass # construct ip_proto based condition here
423
424 elif field.type == IN_PORT:
425 _port = field.port
426 log.info('#### field.type == IN_PORT ####')
427 pass # construct in_port based condition here
428
429 elif field.type == VLAN_VID:
430 _vlan_vid = field.vlan_vid
431 log.info('#### field.type == VLAN_VID ####')
432 pass # construct VLAN ID based filter condition here
433
434 elif field.type == VLAN_PCP:
435 _vlan_pcp = field.vlan_pcp
436 log.info('#### field.type == VLAN_PCP ####')
437 pass # construct VLAN PCP based filter condition here
438
439 elif field.type == UDP_DST:
440 _udp_dst = field.udp_dst
441 log.info('#### field.type == UDP_DST ####')
442 pass # construct UDP SDT based filter here
443
444 else:
445 raise NotImplementedError('field.type={}'.format(
446 field.type))
447
448 for action in get_actions(flow):
449
450 if action.type == OUTPUT:
451 req /= PortIngressRuleResultForward()
452
453 elif action.type == POP_VLAN:
454 pass # construct vlan pop command here
455
456 elif action.type == PUSH_VLAN:
457 if action.push.ethertype != 0x8100:
458 log.error('unhandled-ether-type',
459 ethertype=action.push.ethertype)
460 req /= PortIngressRuleResultInsert(fieldcode=7)
461
462 elif action.type == SET_FIELD:
463 assert (action.set_field.field.oxm_class ==
464 ofp.OFPXMC_OPENFLOW_BASIC)
465 field = action.set_field.field.ofb_field
466 if field.type == VLAN_VID:
467 req /= PortIngressRuleResultSet(
468 fieldcode=7, value=field.vlan_vid & 0xfff)
469 else:
470 log.error('unsupported-action-set-field-type',
471 field_type=field.type)
472 else:
473 log.error('unsupported-action-type',
474 action_type=action.type)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800475
476 elif in_port == 1:
477 # Upstream rule
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800478 log.info('#### Upstream Rule ####')
Zsolt Haraszti313c4be2016-12-27 11:06:53 -0800479 req = PonPortObject()
Zsolt Haraszti80175202016-12-24 00:17:51 -0800480 req /= PortIngressRuleHeader(precedence=precedence)
481
482 for field in get_ofb_fields(flow):
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800483
Zsolt Haraszti80175202016-12-24 00:17:51 -0800484 if field.type == ETH_TYPE:
485 _type = field.eth_type
486 req /= PortIngressRuleClauseMatchLength02(
487 fieldcode=3,
488 operator=1,
489 match0=(_type >> 8) & 0xff,
490 match1=_type & 0xff)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800491
Zsolt Haraszti80175202016-12-24 00:17:51 -0800492 elif field.type == IP_PROTO:
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800493 _proto = field.ip_proto
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800494 log.info('#### field.type == IP_PROTO ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800495 pass # construct ip_proto based condition here
496
497 elif field.type == IN_PORT:
498 _port = field.port
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800499 log.info('#### field.type == IN_PORT ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800500 pass # construct in_port based condition here
501
502 elif field.type == VLAN_VID:
503 _vlan_vid = field.vlan_vid
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800504 log.info('#### field.type == VLAN_VID ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800505 pass # construct VLAN ID based filter condition here
506
507 elif field.type == VLAN_PCP:
508 _vlan_pcp = field.vlan_pcp
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800509 log.info('#### field.type == VLAN_PCP ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800510 pass # construct VLAN PCP based filter condition here
511
512 elif field.type == UDP_DST:
513 _udp_dst = field.udp_dst
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800514 log.info('#### field.type == UDP_DST ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800515 pass # construct UDP SDT based filter here
516
517 else:
518 raise NotImplementedError('field.type={}'.format(
519 field.type))
Zsolt Haraszti80175202016-12-24 00:17:51 -0800520
521 for action in get_actions(flow):
522
523 if action.type == OUTPUT:
524 req /= PortIngressRuleResultForward()
525
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800526 elif action.type == POP_VLAN:
527 pass # construct vlan pop command here
528
Zsolt Haraszti80175202016-12-24 00:17:51 -0800529 elif action.type == PUSH_VLAN:
530 if action.push.ethertype != 0x8100:
531 log.error('unhandled-ether-type',
532 ethertype=action.push.ethertype)
533 req /= PortIngressRuleResultInsert(fieldcode=7)
534
535 elif action.type == SET_FIELD:
536 assert (action.set_field.field.oxm_class ==
537 ofp.OFPXMC_OPENFLOW_BASIC)
538 field = action.set_field.field.ofb_field
539 if field.type == VLAN_VID:
540 req /= PortIngressRuleResultSet(
541 fieldcode=7, value=field.vlan_vid & 0xfff)
542 else:
543 log.error('unsupported-action-set-field-type',
544 field_type=field.type)
545
546 else:
547 log.error('unsupported-action-type',
548 action_type=action.type)
549
550 req /= PortIngressRuleTerminator()
551 req /= AddPortIngressRule()
552
553 msg = (
554 Ether(dst=device.mac_address) /
555 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) /
556 EOAMPayload(
557 body=CablelabsOUI() / DPoEOpcode_SetRequest() / req)
558 )
559
560 self.io_port.send(str(msg))
561
562 else:
563 raise Exception('Port should be 1 or 2 by our convention')
Zsolt Harasztied091602016-12-08 13:36:38 -0800564
565 def update_flows_incrementally(self, device, flow_changes, group_changes):
566 raise NotImplementedError()
567
568 def send_proxied_message(self, proxy_address, msg):
Nathan Knuth6e57f332016-12-22 15:49:20 -0800569 log.info('send-proxied-message', proxy_address=proxy_address)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800570 device = self.adapter_agent.get_device(proxy_address.device_id)
Nathan Knuthe69ceb12017-01-04 21:13:39 -0800571 frame = Ether(dst=device.mac_address) / \
Nathan Knuth6e57f332016-12-22 15:49:20 -0800572 Dot1Q(vlan=TIBIT_MGMT_VLAN, prio=TIBIT_MGMT_PRIORITY) / \
573 Dot1Q(vlan=proxy_address.channel_id, prio=TIBIT_MGMT_PRIORITY) / \
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800574 msg
Nathan Knuth6e57f332016-12-22 15:49:20 -0800575
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800576 self.io_port.send(str(frame))
Zsolt Harasztied091602016-12-08 13:36:38 -0800577
578 def receive_proxied_message(self, proxy_address, msg):
579 raise NotImplementedError()
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800580
581 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
582 log.info('packet-out', logical_device_id=logical_device_id,
583 egress_port_no=egress_port_no, msg_len=len(msg))