blob: 2b445475115423d5dc5ea89424d0bb4295577cd4 [file] [log] [blame]
Shad Ansari2825d012018-02-22 23:57:46 +00001#
2# Copyright 2018 the original author or authors.
3#
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
17import structlog
18import threading
19import grpc
20import collections
Shad Ansari2825d012018-02-22 23:57:46 +000021
Shad Ansari15928d12018-04-17 02:42:13 +000022from twisted.internet import reactor
Shad Ansari0346f0d2018-04-26 06:54:09 +000023from scapy.layers.l2 import Ether, Dot1Q
24import binascii
Shad Ansari22efe832018-05-19 05:37:03 +000025from transitions import Machine
Shad Ansari15928d12018-04-17 02:42:13 +000026
Shad Ansari2825d012018-02-22 23:57:46 +000027from voltha.protos.device_pb2 import Port, Device
28from voltha.protos.common_pb2 import OperStatus, AdminState, ConnectStatus
29from voltha.protos.logical_device_pb2 import LogicalDevice
Shad Ansari2dda4f32018-05-17 07:16:07 +000030from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
Shad Ansari2825d012018-02-22 23:57:46 +000031 OFPPF_1GB_FD, OFPC_GROUP_STATS, OFPC_PORT_STATS, OFPC_TABLE_STATS, \
Shad Ansari2dda4f32018-05-17 07:16:07 +000032 OFPC_FLOW_STATS, ofp_switch_features, ofp_port
Shad Ansari2825d012018-02-22 23:57:46 +000033from voltha.protos.logical_device_pb2 import LogicalPort, LogicalDevice
34from voltha.core.logical_device_agent import mac_str_to_tuple
35from voltha.registry import registry
36from voltha.adapters.openolt.protos import openolt_pb2_grpc, openolt_pb2
Shad Ansari2825d012018-02-22 23:57:46 +000037import voltha.core.flow_decomposer as fd
38
Shad Ansari22920932018-05-17 00:33:34 +000039import openolt_platform as platform
Shad Ansari2dda4f32018-05-17 07:16:07 +000040from openolt_flow_mgr import OpenOltFlowMgr
Shad Ansari801f7372018-04-27 02:15:41 +000041
Shad Ansari803900a2018-05-02 06:26:00 +000042OnuKey = collections.namedtuple('OnuKey', ['intf_id', 'onu_id'])
43OnuRec = collections.namedtuple('OnuRec', ['serial_number', 'state'])
Shad Ansari2825d012018-02-22 23:57:46 +000044
45"""
46OpenoltDevice represents an OLT.
47"""
48class OpenoltDevice(object):
49
Shad Ansari22efe832018-05-19 05:37:03 +000050 states = ['up', 'down']
51 transitions = [
52 { 'trigger': 'olt_up', 'source': 'down', 'dest': 'up', 'before': 'olt_indication_up' },
53 { 'trigger': 'olt_down', 'source': 'up', 'dest': 'down', 'before': 'olt_indication_down' }
54 ]
55
Shad Ansari2825d012018-02-22 23:57:46 +000056 def __init__(self, **kwargs):
57 super(OpenoltDevice, self).__init__()
58
59 self.adapter_agent = kwargs['adapter_agent']
Shad Ansari5dbc9c82018-05-10 03:29:31 +000060 self.device_num = kwargs['device_num']
Shad Ansari2825d012018-02-22 23:57:46 +000061 device = kwargs['device']
62 self.device_id = device.id
63 self.host_and_port = device.host_and_port
64 self.log = structlog.get_logger(id=self.device_id, ip=self.host_and_port)
Shad Ansari2825d012018-02-22 23:57:46 +000065 self.nni_oper_state = dict() #intf_id -> oper_state
Shad Ansari803900a2018-05-02 06:26:00 +000066 self.onus = {} # OnuKey -> OnuRec
Shad Ansari2825d012018-02-22 23:57:46 +000067
Shad Ansari2825d012018-02-22 23:57:46 +000068 # Update device
69 device.root = True
Shad Ansari2825d012018-02-22 23:57:46 +000070 device.serial_number = self.host_and_port # FIXME
Shad Ansari2825d012018-02-22 23:57:46 +000071 device.connect_status = ConnectStatus.REACHABLE
72 device.oper_status = OperStatus.ACTIVATING
73 self.adapter_agent.update_device(device)
74
Shad Ansari22efe832018-05-19 05:37:03 +000075 # Initialize the OLT state machine
76 self.machine = Machine(model=self, states=OpenoltDevice.states,
77 transitions=OpenoltDevice.transitions,
78 send_event=True, initial='down', ignore_invalid_triggers=True)
79 self.machine.add_transition(trigger='olt_ind_up', source='down', dest='up')
80 self.machine.add_transition(trigger='olt_ind_loss', source='up', dest='down')
81
Shad Ansari2825d012018-02-22 23:57:46 +000082 # Initialize gRPC
83 self.channel = grpc.insecure_channel(self.host_and_port)
Shad Ansari8f1b2532018-04-21 07:51:39 +000084 self.channel_ready_future = grpc.channel_ready_future(self.channel)
Shad Ansari2825d012018-02-22 23:57:46 +000085
86 # Start indications thread
Shad Ansari8f1b2532018-04-21 07:51:39 +000087 self.indications_thread = threading.Thread(target=self.process_indications)
Shad Ansari2825d012018-02-22 23:57:46 +000088 self.indications_thread.daemon = True
89 self.indications_thread.start()
90
Shad Ansari8f1b2532018-04-21 07:51:39 +000091 def process_indications(self):
Shad Ansari2dda4f32018-05-17 07:16:07 +000092
Shad Ansari8f1b2532018-04-21 07:51:39 +000093 self.channel_ready_future.result() # blocks till gRPC connection is complete
Shad Ansari2dda4f32018-05-17 07:16:07 +000094
Shad Ansari8f1b2532018-04-21 07:51:39 +000095 self.stub = openolt_pb2_grpc.OpenoltStub(self.channel)
Shad Ansari2dda4f32018-05-17 07:16:07 +000096 self.flow_mgr = OpenOltFlowMgr(self.log, self.stub)
Shad Ansari15928d12018-04-17 02:42:13 +000097 self.indications = self.stub.EnableIndication(openolt_pb2.Empty())
Shad Ansari2dda4f32018-05-17 07:16:07 +000098
Shad Ansari8f1b2532018-04-21 07:51:39 +000099 while True:
Shad Ansari15928d12018-04-17 02:42:13 +0000100 # get the next indication from olt
Shad Ansari2825d012018-02-22 23:57:46 +0000101 ind = next(self.indications)
102 self.log.debug("rx indication", indication=ind)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000103
104 # indication handlers run in the main event loop
Shad Ansari2825d012018-02-22 23:57:46 +0000105 if ind.HasField('olt_ind'):
Shad Ansari15928d12018-04-17 02:42:13 +0000106 reactor.callFromThread(self.olt_indication, ind.olt_ind)
Shad Ansari2825d012018-02-22 23:57:46 +0000107 elif ind.HasField('intf_ind'):
Shad Ansari15928d12018-04-17 02:42:13 +0000108 reactor.callFromThread(self.intf_indication, ind.intf_ind)
Shad Ansari2825d012018-02-22 23:57:46 +0000109 elif ind.HasField('intf_oper_ind'):
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000110 reactor.callFromThread(self.intf_oper_indication,
111 ind.intf_oper_ind)
Shad Ansari2825d012018-02-22 23:57:46 +0000112 elif ind.HasField('onu_disc_ind'):
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000113 reactor.callFromThread(self.onu_discovery_indication,
114 ind.onu_disc_ind)
Shad Ansari2825d012018-02-22 23:57:46 +0000115 elif ind.HasField('onu_ind'):
Shad Ansari15928d12018-04-17 02:42:13 +0000116 reactor.callFromThread(self.onu_indication, ind.onu_ind)
Shad Ansari2825d012018-02-22 23:57:46 +0000117 elif ind.HasField('omci_ind'):
Shad Ansari15928d12018-04-17 02:42:13 +0000118 reactor.callFromThread(self.omci_indication, ind.omci_ind)
Shad Ansari42db7342018-04-25 21:39:46 +0000119 elif ind.HasField('pkt_ind'):
120 reactor.callFromThread(self.packet_indication, ind.pkt_ind)
Shad Ansari2825d012018-02-22 23:57:46 +0000121
122 def olt_indication(self, olt_indication):
Shad Ansari22efe832018-05-19 05:37:03 +0000123 if olt_indication.oper_state == "up":
124 self.olt_up(ind=olt_indication)
125 elif olt_indication.oper_state == "down":
126 self.olt_down(ind=olt_indication)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000127
Shad Ansari22efe832018-05-19 05:37:03 +0000128 def olt_indication_up(self, event):
129 olt_indication = event.kwargs.get('ind', None)
130 self.log.debug("olt indication", olt_ind=olt_indication)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000131
Shad Ansari89b09d52018-05-21 07:28:14 +0000132 dpid = '00:00:' + self.ip_hex(self.host_and_port.split(":")[0])
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000133
134 # Create logical OF device
Jonathan Hart7687e0a2018-05-16 10:54:47 -0700135 ld = LogicalDevice(
136 root_device_id=self.device_id,
137 switch_features=ofp_switch_features(
138 n_buffers=256, # TODO fake for now
139 n_tables=2, # TODO ditto
140 capabilities=( # TODO and ditto
141 OFPC_FLOW_STATS
142 | OFPC_TABLE_STATS
143 | OFPC_PORT_STATS
144 | OFPC_GROUP_STATS
145 )
146 )
147 )
Shad Ansari89b09d52018-05-21 07:28:14 +0000148 ld_initialized = self.adapter_agent.create_logical_device(ld, dpid=dpid)
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000149 self.logical_device_id = ld_initialized.id
150
151 # Update phys OF device
152 device = self.adapter_agent.get_device(self.device_id)
153 device.parent_id = self.logical_device_id
154 device.oper_status = OperStatus.ACTIVE
155 self.adapter_agent.update_device(device)
156
Shad Ansari22efe832018-05-19 05:37:03 +0000157 def olt_indication_down(self, event):
158 olt_indication = event.kwargs.get('ind', None)
159 self.log.debug("olt indication", olt_ind=olt_indication)
Shad Ansari2825d012018-02-22 23:57:46 +0000160
161 def intf_indication(self, intf_indication):
162 self.log.debug("intf indication", intf_id=intf_indication.intf_id,
163 oper_state=intf_indication.oper_state)
164
165 if intf_indication.oper_state == "up":
166 oper_status = OperStatus.ACTIVE
167 else:
168 oper_status = OperStatus.DISCOVERED
169
170 # FIXME - If port exists, update oper state
171 self.add_port(intf_indication.intf_id, Port.PON_OLT, oper_status)
172
173 def intf_oper_indication(self, intf_oper_indication):
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000174 self.log.debug("Received interface oper state change indication",
175 intf_id=intf_oper_indication.intf_id,
176 type=intf_oper_indication.type,
177 oper_state=intf_oper_indication.oper_state)
Shad Ansari2825d012018-02-22 23:57:46 +0000178
179 if intf_oper_indication.oper_state == "up":
180 oper_state = OperStatus.ACTIVE
181 else:
182 oper_state = OperStatus.DISCOVERED
183
184 if intf_oper_indication.type == "nni":
185
Shad Ansari0346f0d2018-04-26 06:54:09 +0000186 # FIXME - creating logical port for 2nd interface throws exception!
Shad Ansari2825d012018-02-22 23:57:46 +0000187 if intf_oper_indication.intf_id != 0:
188 return
189
190 if intf_oper_indication.intf_id not in self.nni_oper_state:
191 self.nni_oper_state[intf_oper_indication.intf_id] = oper_state
192 port_no, label = self.add_port(intf_oper_indication.intf_id, Port.ETHERNET_NNI, oper_state)
193 self.log.debug("int_oper_indication", port_no=port_no, label=label)
Shad Ansari4a232ca2018-05-05 05:24:17 +0000194 self.add_logical_port(port_no, intf_oper_indication.intf_id) # FIXME - add oper_state
Shad Ansari2825d012018-02-22 23:57:46 +0000195 elif intf_oper_indication.intf_id != self.nni_oper_state:
196 # FIXME - handle subsequent NNI oper state change
197 pass
198
199 elif intf_oper_indication.type == "pon":
200 # FIXME - handle PON oper state change
201 pass
202
203 def onu_discovery_indication(self, onu_disc_indication):
Shad Ansari803900a2018-05-02 06:26:00 +0000204 intf_id = onu_disc_indication.intf_id
205 serial_number=onu_disc_indication.serial_number
Shad Ansari2825d012018-02-22 23:57:46 +0000206
Shad Ansari803900a2018-05-02 06:26:00 +0000207 self.log.debug("onu discovery indication", intf_id=intf_id,
208 serial_number=serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000209
Shad Ansari803900a2018-05-02 06:26:00 +0000210 key = self.lookup_key(serial_number=serial_number)
211
212 if key is None:
213 onu_id = self.new_onu_id(intf_id)
Shad Ansari15928d12018-04-17 02:42:13 +0000214 try:
Shad Ansari803900a2018-05-02 06:26:00 +0000215 self.add_onu_device(intf_id,
Shad Ansari22920932018-05-17 00:33:34 +0000216 platform.intf_id_to_port_no(intf_id, Port.PON_OLT),
Shad Ansari803900a2018-05-02 06:26:00 +0000217 onu_id, serial_number)
Shad Ansari15928d12018-04-17 02:42:13 +0000218 except Exception as e:
219 self.log.exception('onu activation failed', e=e)
220 else:
Shad Ansari803900a2018-05-02 06:26:00 +0000221 self.log.info("activate onu", intf_id=intf_id, onu_id=onu_id,
222 serial_number=serial_number)
223 self.onus[OnuKey(intf_id=intf_id, onu_id=onu_id)] \
224 = OnuRec(serial_number=serial_number, state='discovered')
225 onu = openolt_pb2.Onu(intf_id=intf_id, onu_id=onu_id,
226 serial_number=serial_number)
227 self.stub.ActivateOnu(onu)
Shad Ansari2825d012018-02-22 23:57:46 +0000228 else:
Shad Ansari803900a2018-05-02 06:26:00 +0000229 # FIXME - handle onu discover indication for a discovered/activated onu
230 onu_id = key.onu_id
231 intf_id = key.intf_id
232 if self.onus[key].state == 'discovered' or \
233 self.onus[key].state == 'active':
234 self.log.info("ignore onu discovery indication", intf_id=intf_id,
235 onu_id=onu_id, state=self.onus[key].state)
Shad Ansari2825d012018-02-22 23:57:46 +0000236
Shad Ansari2825d012018-02-22 23:57:46 +0000237 def onu_indication(self, onu_indication):
Shad Ansari2825d012018-02-22 23:57:46 +0000238 self.log.debug("onu indication", intf_id=onu_indication.intf_id,
239 onu_id=onu_indication.onu_id)
240
Shad Ansari803900a2018-05-02 06:26:00 +0000241 key = self.lookup_key(serial_number=onu_indication.serial_number)
242
243 # FIXME - handle serial_number mismatch
244 assert key is not None
245
246 # FIXME - handle intf_id mismatch (ONU move?)
247 assert onu_indication.intf_id == key.intf_id
248
249 # FIXME - handle onu id mismatch
250 assert onu_indication.onu_id == key.onu_id
251
252 if self.onus[key].state is not 'discovered':
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000253 self.log.debug("ignore onu indication",
254 intf_id=onu_indication.intf_id,
255 onu_id=onu_indication.onu_id,
256 state=self.onus[key].state)
Shad Ansari803900a2018-05-02 06:26:00 +0000257 return
258
259 self.onus[key] = self.onus[key]._replace(state='active')
Shad Ansari2825d012018-02-22 23:57:46 +0000260
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000261 onu_device = self.adapter_agent.get_child_device(self.device_id,
262 onu_id=onu_indication.onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000263 assert onu_device is not None
264
265 msg = {'proxy_address':onu_device.proxy_address,
266 'event':'activation-completed',
267 'event_data':{'activation_successful':True}}
268 self.adapter_agent.publish_inter_adapter_message(onu_device.id, msg)
269
270 #
271 # tcont create (onu)
272 #
Shad Ansari22920932018-05-17 00:33:34 +0000273 alloc_id = platform.mk_alloc_id(onu_indication.onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000274 msg = {'proxy_address':onu_device.proxy_address,
275 'event':'create-tcont',
276 'event_data':{'alloc_id':alloc_id}}
277 self.adapter_agent.publish_inter_adapter_message(onu_device.id, msg)
278
279 #
280 # v_enet create (olt)
281 #
Shad Ansari22920932018-05-17 00:33:34 +0000282 uni_no = platform.mk_uni_port_num(onu_indication.intf_id, onu_indication.onu_id)
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000283 uni_name = self.port_name(uni_no, Port.ETHERNET_UNI,
284 serial_number=onu_indication.serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000285 self.adapter_agent.add_port(
286 self.device_id,
287 Port(
288 port_no=uni_no,
289 label=uni_name,
290 type=Port.ETHERNET_UNI,
291 admin_state=AdminState.ENABLED,
292 oper_status=OperStatus.ACTIVE))
293
294 #
295 # v_enet create (onu)
296 #
Shad Ansari2825d012018-02-22 23:57:46 +0000297 msg = {'proxy_address':onu_device.proxy_address,
298 'event':'create-venet',
299 'event_data':{'uni_name':uni_name, 'interface_name':uni_name}}
300 self.adapter_agent.publish_inter_adapter_message(onu_device.id, msg)
301
302 #
303 # gem port create
304 #
Shad Ansari22920932018-05-17 00:33:34 +0000305 gemport_id = platform.mk_gemport_id(onu_indication.onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000306 msg = {'proxy_address':onu_device.proxy_address,
307 'event':'create-gemport',
308 'event_data':{'gemport_id':gemport_id}}
309 self.adapter_agent.publish_inter_adapter_message(onu_device.id, msg)
310
Shad Ansari2825d012018-02-22 23:57:46 +0000311 def omci_indication(self, omci_indication):
312
313 self.log.debug("omci indication", intf_id=omci_indication.intf_id,
314 onu_id=omci_indication.onu_id)
315
Shad Ansari0efa6512018-04-28 06:42:54 +0000316 onu_device = self.adapter_agent.get_child_device(self.device_id,
317 onu_id=omci_indication.onu_id)
318
319 self.adapter_agent.receive_proxied_message(onu_device.proxy_address,
320 omci_indication.pkt)
Shad Ansari2825d012018-02-22 23:57:46 +0000321
Shad Ansari42db7342018-04-25 21:39:46 +0000322 def packet_indication(self, pkt_indication):
323
324 self.log.debug("packet indication", intf_id=pkt_indication.intf_id,
325 gemport_id=pkt_indication.gemport_id,
326 flow_id=pkt_indication.flow_id)
327
Shad Ansari22920932018-05-17 00:33:34 +0000328 onu_id = platform.onu_id_from_gemport_id(pkt_indication.gemport_id)
329 logical_port_num = platform.mk_uni_port_num(pkt_indication.intf_id, onu_id)
Shad Ansari42db7342018-04-25 21:39:46 +0000330
331 pkt = Ether(pkt_indication.pkt)
Shad Ansari0efa6512018-04-28 06:42:54 +0000332 kw = dict(logical_device_id=self.logical_device_id,
333 logical_port_no=logical_port_num)
Shad Ansari42db7342018-04-25 21:39:46 +0000334 self.adapter_agent.send_packet_in(packet=str(pkt), **kw)
335
336 def packet_out(self, egress_port, msg):
Shad Ansari0346f0d2018-04-26 06:54:09 +0000337 pkt = Ether(msg)
338 self.log.info('packet out', egress_port=egress_port,
339 packet=str(pkt).encode("HEX"))
340
341 if pkt.haslayer(Dot1Q):
342 outer_shim = pkt.getlayer(Dot1Q)
343 if isinstance(outer_shim.payload, Dot1Q):
344 payload = (
345 Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
346 outer_shim.payload
347 )
348 else:
349 payload = pkt
350 else:
351 payload = pkt
352
353 self.log.info('sending-packet-to-device', egress_port=egress_port,
354 packet=str(payload).encode("HEX"))
355
356 send_pkt = binascii.unhexlify(str(payload).encode("HEX"))
357
Shad Ansari22920932018-05-17 00:33:34 +0000358 onu_pkt = openolt_pb2.OnuPacket(intf_id=platform.intf_id_from_port_num(egress_port),
359 onu_id=platform.onu_id_from_port_num(egress_port), pkt=send_pkt)
Shad Ansari0346f0d2018-04-26 06:54:09 +0000360
Jonathan Harta58dc382018-05-14 16:29:19 -0700361 self.stub.OnuPacketOut(onu_pkt)
Shad Ansari42db7342018-04-25 21:39:46 +0000362
Shad Ansari2825d012018-02-22 23:57:46 +0000363 def send_proxied_message(self, proxy_address, msg):
Shad Ansari0efa6512018-04-28 06:42:54 +0000364 omci = openolt_pb2.OmciMsg(intf_id=proxy_address.channel_id, # intf_id
365 onu_id=proxy_address.onu_id, pkt=str(msg))
Shad Ansari2825d012018-02-22 23:57:46 +0000366 self.stub.OmciMsgOut(omci)
367
368 def add_onu_device(self, intf_id, port_no, onu_id, serial_number):
Shad Ansari2825d012018-02-22 23:57:46 +0000369 self.log.info("Adding ONU", port_no=port_no, onu_id=onu_id,
Shad Ansari0efa6512018-04-28 06:42:54 +0000370 serial_number=serial_number)
Shad Ansari2825d012018-02-22 23:57:46 +0000371
372 # NOTE - channel_id of onu is set to intf_id
Shad Ansari0efa6512018-04-28 06:42:54 +0000373 proxy_address = Device.ProxyAddress(device_id=self.device_id,
374 channel_id=intf_id, onu_id=onu_id, onu_session_id=onu_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000375
376 self.log.info("Adding ONU", proxy_address=proxy_address)
377
Shad Ansari0efa6512018-04-28 06:42:54 +0000378 serial_number_str = ''.join([serial_number.vendor_id,
379 self.stringify_vendor_specific(serial_number.vendor_specific)])
Shad Ansari2825d012018-02-22 23:57:46 +0000380
Shad Ansari0efa6512018-04-28 06:42:54 +0000381 self.adapter_agent.add_onu_device(parent_device_id=self.device_id,
382 parent_port_no=port_no, vendor_id=serial_number.vendor_id,
383 proxy_address=proxy_address, root=True,
384 serial_number=serial_number_str, admin_state=AdminState.ENABLED)
Shad Ansari2825d012018-02-22 23:57:46 +0000385
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000386 def port_name(self, port_no, port_type, intf_id=None, serial_number=None):
Shad Ansari2825d012018-02-22 23:57:46 +0000387 if port_type is Port.ETHERNET_NNI:
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000388 return "nni" "-" + str(port_no)
Shad Ansari2825d012018-02-22 23:57:46 +0000389 elif port_type is Port.PON_OLT:
Shad Ansari4a232ca2018-05-05 05:24:17 +0000390 return "pon" + str(intf_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000391 elif port_type is Port.ETHERNET_UNI:
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000392 return ''.join([serial_number.vendor_id,
393 self.stringify_vendor_specific(serial_number.vendor_specific)])
Shad Ansari2825d012018-02-22 23:57:46 +0000394
Shad Ansari4a232ca2018-05-05 05:24:17 +0000395 def add_logical_port(self, port_no, intf_id):
Shad Ansari2825d012018-02-22 23:57:46 +0000396 self.log.info('adding-logical-port', port_no=port_no)
397
398 label = self.port_name(port_no, Port.ETHERNET_NNI)
399
400 cap = OFPPF_1GB_FD | OFPPF_FIBER
401 curr_speed = OFPPF_1GB_FD
402 max_speed = OFPPF_1GB_FD
403
Shad Ansari0efa6512018-04-28 06:42:54 +0000404 ofp = ofp_port(port_no=port_no,
405 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
406 name=label, config=0, state=OFPPS_LIVE, curr=cap,
407 advertised=cap, peer=cap, curr_speed=curr_speed,
408 max_speed=max_speed)
Shad Ansari2825d012018-02-22 23:57:46 +0000409
Shad Ansari0efa6512018-04-28 06:42:54 +0000410 logical_port = LogicalPort(id=label, ofp_port=ofp,
411 device_id=self.device_id, device_port_no=port_no,
412 root_port=True)
Shad Ansari2825d012018-02-22 23:57:46 +0000413
414 self.adapter_agent.add_logical_port(self.logical_device_id, logical_port)
415
416 def add_port(self, intf_id, port_type, oper_status):
Shad Ansari22920932018-05-17 00:33:34 +0000417 port_no = platform.intf_id_to_port_no(intf_id, port_type)
Shad Ansari2825d012018-02-22 23:57:46 +0000418
Shad Ansari4a232ca2018-05-05 05:24:17 +0000419 label = self.port_name(port_no, port_type, intf_id)
Shad Ansari2825d012018-02-22 23:57:46 +0000420
Shad Ansari0efa6512018-04-28 06:42:54 +0000421 self.log.info('adding-port', port_no=port_no, label=label,
422 port_type=port_type)
423
424 port = Port(port_no=port_no, label=label, type=port_type,
425 admin_state=AdminState.ENABLED, oper_status=oper_status)
426
Shad Ansari2825d012018-02-22 23:57:46 +0000427 self.adapter_agent.add_port(self.device_id, port)
Shad Ansari0efa6512018-04-28 06:42:54 +0000428
Shad Ansari2825d012018-02-22 23:57:46 +0000429 return port_no, label
430
Shad Ansari2825d012018-02-22 23:57:46 +0000431 def new_onu_id(self, intf_id):
432 onu_id = None
Shad Ansari5dbc9c82018-05-10 03:29:31 +0000433 for i in range(1, 512):
Shad Ansari803900a2018-05-02 06:26:00 +0000434 key = OnuKey(intf_id=intf_id, onu_id=i)
435 if key not in self.onus:
Shad Ansari2825d012018-02-22 23:57:46 +0000436 onu_id = i
437 break
438 return onu_id
439
440 def stringify_vendor_specific(self, vendor_specific):
441 return ''.join(str(i) for i in [
Shad Ansari1fd9eb22018-05-15 05:13:49 +0000442 hex(ord(vendor_specific[0])>>4 & 0x0f)[2:],
443 hex(ord(vendor_specific[0]) & 0x0f)[2:],
444 hex(ord(vendor_specific[1])>>4 & 0x0f)[2:],
445 hex(ord(vendor_specific[1]) & 0x0f)[2:],
446 hex(ord(vendor_specific[2])>>4 & 0x0f)[2:],
447 hex(ord(vendor_specific[2]) & 0x0f)[2:],
448 hex(ord(vendor_specific[3])>>4 & 0x0f)[2:],
449 hex(ord(vendor_specific[3]) & 0x0f)[2:]])
Shad Ansari2825d012018-02-22 23:57:46 +0000450
Shad Ansari803900a2018-05-02 06:26:00 +0000451 def lookup_key(self, serial_number):
452 key = None
453 for k, r in self.onus.iteritems():
454 if r.serial_number.vendor_id == serial_number.vendor_id:
455 str1 = self.stringify_vendor_specific(r.serial_number.vendor_specific)
Shad Ansari2825d012018-02-22 23:57:46 +0000456 str2 = self.stringify_vendor_specific(serial_number.vendor_specific)
457 if str1 == str2:
Shad Ansari803900a2018-05-02 06:26:00 +0000458 key = k
Shad Ansari2825d012018-02-22 23:57:46 +0000459 break
Shad Ansari803900a2018-05-02 06:26:00 +0000460 return key
Shad Ansari2825d012018-02-22 23:57:46 +0000461
462 def update_flow_table(self, flows):
463 device = self.adapter_agent.get_device(self.device_id)
Shad Ansaricd2e8ff2018-05-11 20:26:22 +0000464 self.log.debug('update flow table')
Shad Ansari2dda4f32018-05-17 07:16:07 +0000465 in_port = None
Shad Ansari2825d012018-02-22 23:57:46 +0000466
467 for flow in flows:
Shad Ansari2825d012018-02-22 23:57:46 +0000468 is_down_stream = None
Shad Ansari2dda4f32018-05-17 07:16:07 +0000469 in_port = fd.get_in_port(flow)
470 assert in_port is not None
471 # Right now there is only one NNI port. Get the NNI PORT and compare
472 # with IN_PUT port number. Need to find better way.
473 ports = self.adapter_agent.get_ports(device.id, Port.ETHERNET_NNI)
Shad Ansari2825d012018-02-22 23:57:46 +0000474
Shad Ansari2dda4f32018-05-17 07:16:07 +0000475 for port in ports:
476 if (port.port_no == in_port):
477 self.log.info('downstream-flow')
478 is_down_stream = True
479 break
480 if is_down_stream is None:
481 is_down_stream = False
482 self.log.info('upstream-flow')
Shad Ansari2825d012018-02-22 23:57:46 +0000483
Shad Ansari2dda4f32018-05-17 07:16:07 +0000484 for flow in flows:
485 try:
486 self.flow_mgr.add_flow(flow, is_down_stream)
487 except Exception as e:
488 self.log.exception('failed-to-install-flow', e=e, flow=flow)
Shad Ansari89b09d52018-05-21 07:28:14 +0000489
490 # There has to be a better way to do this
491 def ip_hex(self, ip):
492 octets = ip.split(".")
493 hex_ip = []
494 for octet in octets:
495 octet_hex = hex(int(octet))
496 octet_hex = octet_hex.split('0x')[1]
497 octet_hex = octet_hex.rjust(2, '0')
498 hex_ip.append(octet_hex)
499 return ":".join(hex_ip)