blob: 19775cb3787fce314579d327c675c736584c3ffb [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001#
2# Copyright 2017 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
17"""
18Fully simulated OLT/ONU adapter.
19"""
20
21import sys
22import structlog
khenaidoo92e62c52018-10-03 14:02:54 -040023from twisted.internet.defer import DeferredQueue, inlineCallbacks, returnValue
khenaidoob9203542018-09-17 22:56:37 -040024from adapters.common.utils.asleep import asleep
25
26from adapters.iadapter import OnuAdapter
27from adapters.protos import third_party
28from adapters.protos.common_pb2 import OperStatus, ConnectStatus, AdminState
29from adapters.protos.device_pb2 import Port
30from adapters.protos.logical_device_pb2 import LogicalPort
31from adapters.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
32 OFPPF_1GB_FD
33from adapters.protos.openflow_13_pb2 import ofp_port
34from adapters.protos.ponsim_pb2 import FlowTable
35from adapters.protos.core_adapter_pb2 import PortCapability
36
37_ = third_party
38log = structlog.get_logger()
39
40
41def mac_str_to_tuple(mac):
42 return tuple(int(d, 16) for d in mac.split(':'))
43
44class PonSimOnuAdapter(OnuAdapter):
45 def __init__(self, adapter_agent, config):
46 # DeviceType of ONU should be same as VENDOR ID of ONU Serial Number as specified by standard
47 # requires for identifying correct adapter or ranged ONU
48 super(PonSimOnuAdapter, self).__init__(adapter_agent=adapter_agent,
49 config=config,
50 device_handler_class=PonSimOnuHandler,
51 name='ponsim_onu',
52 vendor='Voltha project',
53 version='0.4',
54 device_type='ponsim_onu',
55 vendor_id='PSMO',
56 accepts_bulk_flow_update=True,
57 accepts_add_remove_flow_updates=False)
58
59
60class PonSimOnuHandler(object):
61 def __init__(self, adapter, device_id):
62 self.adapter = adapter
63 self.adapter_agent = adapter.adapter_agent
64 self.device_id = device_id
65 self.log = structlog.get_logger(device_id=device_id)
66 self.incoming_messages = DeferredQueue()
67 self.proxy_address = None
68 # reference of uni_port is required when re-enabling the device if
69 # it was disabled previously
70 self.uni_port = None
71 self.pon_port = None
72
73 def receive_message(self, msg):
74 self.incoming_messages.put(msg)
75
76
77 @inlineCallbacks
78 def activate(self, device):
79 self.log.info('activating')
80
81 # TODO: Register for proxy address
khenaidoob9203542018-09-17 22:56:37 -040082
83 # populate device info
84 device.root = False
85 device.vendor = 'ponsim'
86 device.model = 'n/a'
khenaidoo92e62c52018-10-03 14:02:54 -040087 # device.connect_status = ConnectStatus.REACHABLE
khenaidoob9203542018-09-17 22:56:37 -040088 yield self.adapter_agent.device_update(device)
89
khenaidoo4d4802d2018-10-04 21:59:49 -040090 # register physical ports
khenaidoob9203542018-09-17 22:56:37 -040091 self.uni_port = Port(
92 port_no=2,
93 label='UNI facing Ethernet port',
94 type=Port.ETHERNET_UNI,
95 admin_state=AdminState.ENABLED,
96 oper_status=OperStatus.ACTIVE
97 )
98 self.pon_port = Port(
99 port_no=1,
100 label='PON port',
101 type=Port.PON_ONU,
102 admin_state=AdminState.ENABLED,
103 oper_status=OperStatus.ACTIVE,
104 peers=[
105 Port.PeerPort(
106 device_id=device.parent_id,
107 port_no=device.parent_port_no
108 )
109 ]
110 )
111 self.adapter_agent.port_created(device.id, self.uni_port)
112 self.adapter_agent.port_created(device.id, self.pon_port)
113
khenaidoo92e62c52018-10-03 14:02:54 -0400114 yield self.adapter_agent.device_state_update(device.id, connect_status=ConnectStatus.REACHABLE, oper_status=OperStatus.ACTIVE)
khenaidoob9203542018-09-17 22:56:37 -0400115
116
khenaidoo19d7b632018-10-30 10:49:50 -0400117 # TODO: Return only port specific info
khenaidoob9203542018-09-17 22:56:37 -0400118 def get_ofp_port_info(self, device, port_no):
119 # Since the adapter created the device port then it has the reference of the port to
khenaidoo19d7b632018-10-30 10:49:50 -0400120 # return the capability. TODO: Do a lookup on the UNI port number and return the
khenaidoob9203542018-09-17 22:56:37 -0400121 # appropriate attributes
122 self.log.info('get_ofp_port_info', port_no=port_no, device_id=device.id)
123 # port_no = device.proxy_address.channel_id
124 cap = OFPPF_1GB_FD | OFPPF_FIBER
125 return PortCapability(
126 port = LogicalPort (
khenaidoo19d7b632018-10-30 10:49:50 -0400127 # id='uni-{}'.format(port_no),
khenaidoob9203542018-09-17 22:56:37 -0400128 ofp_port=ofp_port(
khenaidoo19d7b632018-10-30 10:49:50 -0400129 # port_no=port_no,
khenaidoob9203542018-09-17 22:56:37 -0400130 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
khenaidoo19d7b632018-10-30 10:49:50 -0400131 # name='uni-{}'.format(port_no),
khenaidoob9203542018-09-17 22:56:37 -0400132 config=0,
133 state=OFPPS_LIVE,
134 curr=cap,
135 advertised=cap,
136 peer=cap,
137 curr_speed=OFPPF_1GB_FD,
138 max_speed=OFPPF_1GB_FD
khenaidoo19d7b632018-10-30 10:49:50 -0400139 ),
140 device_id=device.id,
141 device_port_no=port_no
khenaidoob9203542018-09-17 22:56:37 -0400142 )
143 )
144
khenaidoo92e62c52018-10-03 14:02:54 -0400145 @inlineCallbacks
146 def _get_uni_port(self):
147 ports = yield self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_UNI)
148 returnValue(ports)
149
150 @inlineCallbacks
khenaidoob9203542018-09-17 22:56:37 -0400151 def _get_pon_port(self):
khenaidoo92e62c52018-10-03 14:02:54 -0400152 ports = yield self.adapter_agent.get_ports(self.device_id, Port.PON_ONU)
153 returnValue(ports)
154
khenaidoob9203542018-09-17 22:56:37 -0400155 def reconcile(self, device):
156 self.log.info('reconciling-ONU-device-starts')
157
158 # first we verify that we got parent reference and proxy info
159 assert device.parent_id
160 assert device.proxy_address.device_id
161 assert device.proxy_address.channel_id
162
163 # register for proxied messages right away
164 self.proxy_address = device.proxy_address
165 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
166
167 # Set the connection status to REACHABLE
168 device.connect_status = ConnectStatus.REACHABLE
169 self.adapter_agent.update_device(device)
170
171 # TODO: Verify that the uni, pon and logical ports exists
172
173 # Mark the device as REACHABLE and ACTIVE
174 device = self.adapter_agent.get_device(device.id)
175 device.connect_status = ConnectStatus.REACHABLE
176 device.oper_status = OperStatus.ACTIVE
177 self.adapter_agent.update_device(device)
178
179 self.log.info('reconciling-ONU-device-ends')
180
181 @inlineCallbacks
182 def update_flow_table(self, flows):
183
184 # we need to proxy through the OLT to get to the ONU
185
186 # reset response queue
187 while self.incoming_messages.pending:
188 yield self.incoming_messages.get()
189
190 msg = FlowTable(
191 port=self.proxy_address.channel_id,
192 flows=flows
193 )
194 self.adapter_agent.send_proxied_message(self.proxy_address, msg)
195
196 yield self.incoming_messages.get()
197
198 def remove_from_flow_table(self, flows):
199 self.log.debug('remove-from-flow-table', flows=flows)
200 # TODO: Update PONSIM code to accept incremental flow changes.
201 # Once completed, the accepts_add_remove_flow_updates for this
202 # device type can be set to True
203
204 def add_to_flow_table(self, flows):
205 self.log.debug('add-to-flow-table', flows=flows)
206 # TODO: Update PONSIM code to accept incremental flow changes
207 # Once completed, the accepts_add_remove_flow_updates for this
208 # device type can be set to True
209
210 @inlineCallbacks
211 def reboot(self):
212 self.log.info('rebooting', device_id=self.device_id)
213
khenaidoo4d4802d2018-10-04 21:59:49 -0400214 # Update the connect status to UNREACHABLE
215 yield self.adapter_agent.device_state_update(self.device_id, connect_status=ConnectStatus.UNREACHABLE)
khenaidoob9203542018-09-17 22:56:37 -0400216
217 # Sleep 10 secs, simulating a reboot
218 # TODO: send alert and clear alert after the reboot
219 yield asleep(10)
220
khenaidoo4d4802d2018-10-04 21:59:49 -0400221 # Change the connection status back to REACHABLE. With a
222 # real ONU the connection state must be the actual state
223 yield self.adapter_agent.device_state_update(self.device_id, connect_status=ConnectStatus.REACHABLE)
224
khenaidoob9203542018-09-17 22:56:37 -0400225 self.log.info('rebooted', device_id=self.device_id)
226
227 def self_test_device(self, device):
228 """
229 This is called to Self a device based on a NBI call.
230 :param device: A Voltha.Device object.
231 :return: Will return result of self test
232 """
233 log.info('self-test-device', device=device.id)
234 raise NotImplementedError()
235
khenaidoo92e62c52018-10-03 14:02:54 -0400236
237 @inlineCallbacks
khenaidoob9203542018-09-17 22:56:37 -0400238 def disable(self):
239 self.log.info('disabling', device_id=self.device_id)
240
khenaidoob9203542018-09-17 22:56:37 -0400241 # Update the device operational status to UNKNOWN
khenaidoo92e62c52018-10-03 14:02:54 -0400242 yield self.adapter_agent.device_state_update(self.device_id, oper_status=OperStatus.UNKNOWN, connect_status=ConnectStatus.UNREACHABLE)
khenaidoob9203542018-09-17 22:56:37 -0400243
244 # TODO:
245 # 1) Remove all flows from the device
246 # 2) Remove the device from ponsim
247
khenaidoo92e62c52018-10-03 14:02:54 -0400248 self.log.info('disabled', device_id=self.device_id)
khenaidoob9203542018-09-17 22:56:37 -0400249
khenaidoo92e62c52018-10-03 14:02:54 -0400250 @inlineCallbacks
khenaidoob9203542018-09-17 22:56:37 -0400251 def reenable(self):
252 self.log.info('re-enabling', device_id=self.device_id)
253 try:
khenaidoob9203542018-09-17 22:56:37 -0400254
khenaidoo92e62c52018-10-03 14:02:54 -0400255 # Refresh the port reference - we only use one port for now
256 ports = yield self._get_uni_port()
257 self.log.info('re-enabling-uni-ports', ports=ports)
258 if ports.items:
259 self.uni_port = ports.items[0]
khenaidoob9203542018-09-17 22:56:37 -0400260
khenaidoo92e62c52018-10-03 14:02:54 -0400261 ports = yield self._get_pon_port()
262 self.log.info('re-enabling-pon-ports', ports=ports)
263 if ports.items:
264 self.pon_port = ports.items[0]
265
266 # Update the state of the UNI port
267 yield self.adapter_agent.port_state_update(self.device_id,
268 port_type=Port.ETHERNET_UNI,
269 port_no=self.uni_port.port_no,
270 oper_status=OperStatus.ACTIVE)
271
272 # Update the state of the PON port
273 yield self.adapter_agent.port_state_update(self.device_id,
274 port_type=Port.PON_ONU,
275 port_no=self.pon_port.port_no,
276 oper_status=OperStatus.ACTIVE)
277
khenaidoo92e62c52018-10-03 14:02:54 -0400278 yield self.adapter_agent.device_state_update(self.device_id, oper_status=OperStatus.ACTIVE, connect_status=ConnectStatus.REACHABLE)
279
280 self.log.info('re-enabled', device_id=self.device_id)
khenaidoob9203542018-09-17 22:56:37 -0400281 except Exception, e:
282 self.log.exception('error-reenabling', e=e)
283
284 def delete(self):
285 self.log.info('deleting', device_id=self.device_id)
286
khenaidoob9203542018-09-17 22:56:37 -0400287 # TODO:
288 # 1) Remove all flows from the device
289 # 2) Remove the device from ponsim
290
291 self.log.info('deleted', device_id=self.device_id)