blob: 96cd35305377f2d572ef7eebf3c8e1751399bc51 [file] [log] [blame]
Chip Boling8e042f62019-02-12 16:14:34 -06001# Copyright 2017-present Adtran, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import structlog
16from pyvoltha.protos.common_pb2 import OperStatus, AdminState
17from pyvoltha.protos.device_pb2 import Port
18from pyvoltha.protos.openflow_13_pb2 import OFPPF_10GB_FD
19from pyvoltha.protos.logical_device_pb2 import LogicalPort
20from pyvoltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER
21from pyvoltha.protos.openflow_13_pb2 import ofp_port
22import adtran_olt.resources.adtranolt_platform as platform
23
24
25class UniPort(object):
26 """Wraps southbound-port(s) support for ONU"""
27 def __init__(self, handler, name, port_no, ofp_port_no):
28 self.log = structlog.get_logger(device_id=handler.device_id, port_no=port_no)
29 self._enabled = False
30 self._handler = handler
31 self._name = name
32 self.uni_id = platform.uni_id_from_uni_port(port_no)
33 self._port = None
34 self._port_number = port_no
35 self._ofp_port_no = ofp_port_no # Set at by creator (vENET create)
36 self._logical_port_number = None # Set at time of logical port creation
37 self._entity_id = None # TODO: Use port number from UNI-G entity ID
38 self._mac_bridge_port_num = 0
39
40 self._admin_state = AdminState.ENABLED
41 self._oper_status = OperStatus.ACTIVE
42 # TODO Add state, stats, alarm reference, ...
43 pass
44
45 def __str__(self):
46 return "UniPort: {}:{}".format(self.name, self.port_number)
47
48 @staticmethod
49 def create(handler, name, port_no, ofp_port_no):
50 port = UniPort(handler, name, port_no, ofp_port_no)
51 return port
52
53 def _start(self):
54 self._cancel_deferred()
55
56 self._admin_state = AdminState.ENABLED
57 self._oper_status = OperStatus.ACTIVE
58 self._update_adapter_agent()
59 # TODO: start h/w sync
60 # TODO: Enable the actual physical port?
61 pass
62
63 def _stop(self):
64 self._cancel_deferred()
65
66 self._admin_state = AdminState.DISABLED
67 self._oper_status = OperStatus.UNKNOWN
68 self._update_adapter_agent()
69 # TODO: Disable/power-down the actual physical port?
70 pass
71
72 def delete(self):
73 self.enabled = False
74 self._handler = None
75
76 def _cancel_deferred(self):
77 pass
78
79 @property
80 def name(self):
81 return self._name
82
83 @property
84 def enabled(self):
85 return self._enabled
86
87 @enabled.setter
88 def enabled(self, value):
89 if self._enabled != value:
90 self._enabled = value
91
92 if value:
93 self._start()
94 else:
95 self._stop()
96
97 @property
98 def port_number(self):
99 """
100 Physical device port number
101 :return: (int) port number
102 """
103 return self._port_number
104
105 @property
106 def mac_bridge_port_num(self):
107 """
108 Port number used when creating MacBridgePortConfigurationDataFrame port number
109 :return: (int) port number
110 """
111 self.log.debug('function-entry')
112 return self._mac_bridge_port_num
113
114 @mac_bridge_port_num.setter
115 def mac_bridge_port_num(self, value):
116 self.log.debug('function-entry')
117 self._mac_bridge_port_num = value
118
119 @property
120 def entity_id(self):
121 """
122 OMCI UNI_G entity ID for port
123 """
124 return self._entity_id
125
126 @entity_id.setter
127 def entity_id(self, value):
128 assert self._entity_id is None, 'Cannot reset the Entity ID'
129 self._entity_id = value
130
131 @property
132 def logical_port_number(self):
133 """
134 Logical device port number (used as OpenFlow port for UNI)
135 :return: (int) port number
136 """
137 return self._logical_port_number
138
139 def _update_adapter_agent(self):
140 """
141 Update the port status and state in the core
142 """
143 self.log.debug('update-adapter-agent', admin_state=self._admin_state,
144 oper_status=self._oper_status)
145
146 if self._port is not None:
147 self._port.admin_state = self._admin_state
148 self._port.oper_status = self._oper_status
149
150 try:
151 # adapter_agent add_port also does an update of existing port
152 self._handler.adapter_agent.add_port(self._handler.device_id,
153 self.get_port())
154 except KeyError: # Expected exception during ONU disabling
155 pass
156 except Exception as e: # Expected exception during ONU disabling
157 self.log.exception('update-port', e=e)
158
159 def get_port(self):
160 """
161 Get the VOLTHA PORT object for this port
162 :return: VOLTHA Port object
163 """
164 if self._port is None:
165 self._port = Port(port_no=self.port_number,
166 label=self.port_id_name(),
167 type=Port.ETHERNET_UNI,
168 admin_state=self._admin_state,
169 oper_status=self._oper_status)
170 return self._port
171
172 def port_id_name(self):
173 return 'uni-{}'.format(self._port_number)
174
175 def add_logical_port(self, openflow_port_no, multi_uni_naming,
176 capabilities=OFPPF_10GB_FD | OFPPF_FIBER,
177 speed=OFPPF_10GB_FD):
178
179 if self._logical_port_number is not None:
180 # delete old logical port if it exists
181 try:
182 port = self._handler.adapter_agent.get_logical_port(self._handler.logical_device_id,
183 self.port_id_name())
184 self._handler.adapter_agent.delete_logical_port(self._handler.logical_device_id, port)
185
186 except Exception as e:
187 # assume this exception was because logical port does not already exist
188 pass
189
190 self._logical_port_number = None
191
192 # Use vENET provisioned values if none supplied
193 port_no = openflow_port_no or self._ofp_port_no
194
195 if self._logical_port_number is None and port_no is not None:
196 self._logical_port_number = port_no
197 device = self._handler.adapter_agent.get_device(self._handler.device_id)
198
199 def mac_str_to_tuple(mac):
200 """
201 Convert 'xx:xx:xx:xx:xx:xx' MAC address string to a tuple of integers.
202 Example: mac_str_to_tuple('00:01:02:03:04:05') == (0, 1, 2, 3, 4, 5)
203 """
204 return tuple(int(d, 16) for d in mac.split(':'))
205
206 openflow_port = ofp_port(
207 port_no=port_no,
208 hw_addr=mac_str_to_tuple('08:00:%02x:%02x:%02x:%02x' %
209 ((device.parent_port_no >> 8 & 0xff),
210 device.parent_port_no & 0xff,
211 (port_no >> 8) & 0xff,
212 port_no & 0xff)),
213 name=device.serial_number + ['', '-' + str(self._mac_bridge_port_num)][multi_uni_naming],
214 config=0,
215 state=OFPPS_LIVE,
216 curr=capabilities,
217 advertised=capabilities,
218 peer=capabilities,
219 curr_speed=speed,
220 max_speed=speed
221 )
222 self._handler.adapter_agent.add_logical_port(self._handler.logical_device_id,
223 LogicalPort(
224 id=self.port_id_name(),
225 ofp_port=openflow_port,
226 device_id=device.id,
227 device_port_no=self._port_number))