blob: a9d37105fa0d9e2205bf3dae715f17287d7374d1 [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
117 def get_ofp_port_info(self, device, port_no):
118 # Since the adapter created the device port then it has the reference of the port to
119 # return the capability. TODO: Do a lookup on the NNI port number and return the
120 # appropriate attributes
121 self.log.info('get_ofp_port_info', port_no=port_no, device_id=device.id)
122 # port_no = device.proxy_address.channel_id
123 cap = OFPPF_1GB_FD | OFPPF_FIBER
124 return PortCapability(
125 port = LogicalPort (
126 id='uni-{}'.format(port_no),
127 ofp_port=ofp_port(
128 port_no=port_no,
129 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
130 name='uni-{}'.format(port_no),
131 config=0,
132 state=OFPPS_LIVE,
133 curr=cap,
134 advertised=cap,
135 peer=cap,
136 curr_speed=OFPPF_1GB_FD,
137 max_speed=OFPPF_1GB_FD
138 )
139 )
140 )
141
khenaidoo92e62c52018-10-03 14:02:54 -0400142 @inlineCallbacks
143 def _get_uni_port(self):
144 ports = yield self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_UNI)
145 returnValue(ports)
146
147 @inlineCallbacks
khenaidoob9203542018-09-17 22:56:37 -0400148 def _get_pon_port(self):
khenaidoo92e62c52018-10-03 14:02:54 -0400149 ports = yield self.adapter_agent.get_ports(self.device_id, Port.PON_ONU)
150 returnValue(ports)
151
khenaidoob9203542018-09-17 22:56:37 -0400152 def reconcile(self, device):
153 self.log.info('reconciling-ONU-device-starts')
154
155 # first we verify that we got parent reference and proxy info
156 assert device.parent_id
157 assert device.proxy_address.device_id
158 assert device.proxy_address.channel_id
159
160 # register for proxied messages right away
161 self.proxy_address = device.proxy_address
162 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
163
164 # Set the connection status to REACHABLE
165 device.connect_status = ConnectStatus.REACHABLE
166 self.adapter_agent.update_device(device)
167
168 # TODO: Verify that the uni, pon and logical ports exists
169
170 # Mark the device as REACHABLE and ACTIVE
171 device = self.adapter_agent.get_device(device.id)
172 device.connect_status = ConnectStatus.REACHABLE
173 device.oper_status = OperStatus.ACTIVE
174 self.adapter_agent.update_device(device)
175
176 self.log.info('reconciling-ONU-device-ends')
177
178 @inlineCallbacks
179 def update_flow_table(self, flows):
180
181 # we need to proxy through the OLT to get to the ONU
182
183 # reset response queue
184 while self.incoming_messages.pending:
185 yield self.incoming_messages.get()
186
187 msg = FlowTable(
188 port=self.proxy_address.channel_id,
189 flows=flows
190 )
191 self.adapter_agent.send_proxied_message(self.proxy_address, msg)
192
193 yield self.incoming_messages.get()
194
195 def remove_from_flow_table(self, flows):
196 self.log.debug('remove-from-flow-table', flows=flows)
197 # TODO: Update PONSIM code to accept incremental flow changes.
198 # Once completed, the accepts_add_remove_flow_updates for this
199 # device type can be set to True
200
201 def add_to_flow_table(self, flows):
202 self.log.debug('add-to-flow-table', flows=flows)
203 # TODO: Update PONSIM code to accept incremental flow changes
204 # Once completed, the accepts_add_remove_flow_updates for this
205 # device type can be set to True
206
207 @inlineCallbacks
208 def reboot(self):
209 self.log.info('rebooting', device_id=self.device_id)
210
khenaidoo4d4802d2018-10-04 21:59:49 -0400211 # Update the connect status to UNREACHABLE
212 yield self.adapter_agent.device_state_update(self.device_id, connect_status=ConnectStatus.UNREACHABLE)
khenaidoob9203542018-09-17 22:56:37 -0400213
214 # Sleep 10 secs, simulating a reboot
215 # TODO: send alert and clear alert after the reboot
216 yield asleep(10)
217
khenaidoo4d4802d2018-10-04 21:59:49 -0400218 # Change the connection status back to REACHABLE. With a
219 # real ONU the connection state must be the actual state
220 yield self.adapter_agent.device_state_update(self.device_id, connect_status=ConnectStatus.REACHABLE)
221
khenaidoob9203542018-09-17 22:56:37 -0400222 self.log.info('rebooted', device_id=self.device_id)
223
224 def self_test_device(self, device):
225 """
226 This is called to Self a device based on a NBI call.
227 :param device: A Voltha.Device object.
228 :return: Will return result of self test
229 """
230 log.info('self-test-device', device=device.id)
231 raise NotImplementedError()
232
khenaidoo92e62c52018-10-03 14:02:54 -0400233
234 @inlineCallbacks
khenaidoob9203542018-09-17 22:56:37 -0400235 def disable(self):
236 self.log.info('disabling', device_id=self.device_id)
237
khenaidoob9203542018-09-17 22:56:37 -0400238 # Update the device operational status to UNKNOWN
khenaidoo92e62c52018-10-03 14:02:54 -0400239 yield self.adapter_agent.device_state_update(self.device_id, oper_status=OperStatus.UNKNOWN, connect_status=ConnectStatus.UNREACHABLE)
khenaidoob9203542018-09-17 22:56:37 -0400240
241 # TODO:
242 # 1) Remove all flows from the device
243 # 2) Remove the device from ponsim
244
khenaidoo92e62c52018-10-03 14:02:54 -0400245 self.log.info('disabled', device_id=self.device_id)
khenaidoob9203542018-09-17 22:56:37 -0400246
khenaidoo92e62c52018-10-03 14:02:54 -0400247 @inlineCallbacks
khenaidoob9203542018-09-17 22:56:37 -0400248 def reenable(self):
249 self.log.info('re-enabling', device_id=self.device_id)
250 try:
khenaidoob9203542018-09-17 22:56:37 -0400251
khenaidoo92e62c52018-10-03 14:02:54 -0400252 # Refresh the port reference - we only use one port for now
253 ports = yield self._get_uni_port()
254 self.log.info('re-enabling-uni-ports', ports=ports)
255 if ports.items:
256 self.uni_port = ports.items[0]
khenaidoob9203542018-09-17 22:56:37 -0400257
khenaidoo92e62c52018-10-03 14:02:54 -0400258 ports = yield self._get_pon_port()
259 self.log.info('re-enabling-pon-ports', ports=ports)
260 if ports.items:
261 self.pon_port = ports.items[0]
262
263 # Update the state of the UNI port
264 yield self.adapter_agent.port_state_update(self.device_id,
265 port_type=Port.ETHERNET_UNI,
266 port_no=self.uni_port.port_no,
267 oper_status=OperStatus.ACTIVE)
268
269 # Update the state of the PON port
270 yield self.adapter_agent.port_state_update(self.device_id,
271 port_type=Port.PON_ONU,
272 port_no=self.pon_port.port_no,
273 oper_status=OperStatus.ACTIVE)
274
khenaidoo92e62c52018-10-03 14:02:54 -0400275 yield self.adapter_agent.device_state_update(self.device_id, oper_status=OperStatus.ACTIVE, connect_status=ConnectStatus.REACHABLE)
276
277 self.log.info('re-enabled', device_id=self.device_id)
khenaidoob9203542018-09-17 22:56:37 -0400278 except Exception, e:
279 self.log.exception('error-reenabling', e=e)
280
281 def delete(self):
282 self.log.info('deleting', device_id=self.device_id)
283
khenaidoob9203542018-09-17 22:56:37 -0400284 # TODO:
285 # 1) Remove all flows from the device
286 # 2) Remove the device from ponsim
287
288 self.log.info('deleted', device_id=self.device_id)