VOL-791: Support for OLT disable/enable on ASFvOLT16
Change-Id: I2d5c12a8da0ef28eb53f918a5724596618446dcc
diff --git a/cli/main.py b/cli/main.py
index 6060435..a1c7226 100755
--- a/cli/main.py
+++ b/cli/main.py
@@ -334,7 +334,7 @@
break
self.poutput('waiting for device to be enabled...')
sleep(.5)
- except Exception, e:
+ except Exception as e:
self.poutput('Error enabling {}. Error:{}'.format(device_id, e))
complete_activate_olt = complete_device
@@ -349,7 +349,7 @@
stub = self.get_stub()
stub.RebootDevice(voltha_pb2.ID(id=device_id))
self.poutput('rebooted {}'.format(device_id))
- except Exception, e:
+ except Exception as e:
self.poutput('Error rebooting {}. Error:{}'.format(device_id, e))
def do_self_test(self, line):
@@ -363,7 +363,7 @@
res = stub.SelfTest(voltha_pb2.ID(id=device_id))
self.poutput('Self Tested {}'.format(device_id))
self.poutput(dumps(pb2dict(res), indent=4))
- except Exception, e:
+ except Exception as e:
self.poutput('Error in self test {}. Error:{}'.format(device_id, e))
def do_delete(self, line):
@@ -376,7 +376,7 @@
stub = self.get_stub()
stub.DeleteDevice(voltha_pb2.ID(id=device_id))
self.poutput('deleted {}'.format(device_id))
- except Exception, e:
+ except Exception as e:
self.poutput('Error deleting {}. Error:{}'.format(device_id, e))
def do_disable(self, line):
@@ -392,15 +392,14 @@
# Do device query and verify that the device admin status is
# DISABLED and Operational Status is unknown
device = stub.GetDevice(voltha_pb2.ID(id=device_id))
- if device.oper_status == voltha_pb2.OperStatus.UNKNOWN and \
- device.admin_state == voltha_pb2.AdminState.DISABLED:
+ if device.admin_state == voltha_pb2.AdminState.DISABLED:
self.poutput('disabled successfully {}'.format(device_id))
else:
self.poutput('disabling failed {}. Admin State:{} '
'Operation State: {}'.format(device_id,
device.admin_state,
device.oper_status))
- except Exception, e:
+ except Exception as e:
self.poutput('Error disabling {}. Error:{}'.format(device_id, e))
def do_test(self, line):
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_device_handler.py b/voltha/adapters/asfvolt16_olt/asfvolt16_device_handler.py
index ee1a45f..4075899 100644
--- a/voltha/adapters/asfvolt16_olt/asfvolt16_device_handler.py
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_device_handler.py
@@ -19,7 +19,7 @@
"""
import arrow
-from twisted.internet.defer import inlineCallbacks
+from twisted.internet.defer import inlineCallbacks, DeferredQueue, QueueOverflow, QueueUnderflow
from itertools import count, ifilterfalse
from voltha.protos.events_pb2 import KpiEvent, MetricValuePairs
from voltha.protos.events_pb2 import KpiEventType
@@ -219,6 +219,7 @@
self.transceiver_type = bal_model_types_pb2.BAL_TRX_TYPE_XGPON_LTH_7226_PC
self.asfvolt_device_info = Asfvolt16DeviceInfo(self.bal,
self.log, self.device_id)
+ self.pon_port_config_resp = DeferredQueue(size=1)
def __del__(self):
super(Asfvolt16Handler, self).__del__()
@@ -259,10 +260,17 @@
return v_enet
return None
- def get_v_ont_ani(self, name):
- for key, v_ont_ani in self.v_ont_anis.items():
- if key == name:
- return v_ont_ani
+ def get_v_ont_ani(self, **kwargs):
+ name = kwargs.pop('name', None)
+ onu_id = kwargs.pop('onu_id', None)
+ if name is not None:
+ for key, v_ont_ani in self.v_ont_anis.items():
+ if key == name:
+ return v_ont_ani
+ if onu_id is not None:
+ for key, v_ont_ani in self.v_ont_anis.items():
+ if onu_id == v_ont_ani.v_ont_ani.data.onu_id:
+ return v_ont_ani
return None
def get_gem_port_info(self, v_enet, **kwargs):
@@ -375,7 +383,7 @@
self.log.error('Failed-to-get-v-enet', gem_port_id=gem_port_id)
return
- v_ont_ani = self.get_v_ont_ani(v_enet.v_enet.data.v_ontani_ref)
+ v_ont_ani = self.get_v_ont_ani(name=v_enet.v_enet.data.v_ontani_ref)
if v_ont_ani is None:
self.log.info('Failed-to-get-v_ont_ani',
v_ont_ani=v_enet.v_enet.data.v_ontani_ref)
@@ -596,6 +604,14 @@
self.adapter_agent.update_device(device)
heartbeat_alarm(device, 1, self.heartbeat_miss)
+ child_devices = self.adapter_agent.get_child_devices(self.device_id)
+ for child in child_devices:
+ msg = {'proxy_address': child.proxy_address,
+ 'event': 'olt-reboot'}
+ # Send the event message to the ONU adapter
+ self.adapter_agent.publish_inter_adapter_message(child.id,
+ msg)
+
self.heartbeat_count += 1
reactor.callLater(self.heartbeat_interval, self.heartbeat)
@@ -757,6 +773,12 @@
def BalIfaceIndication(self, device_id, Iface_ID):
self.log.info('Interface-Indication')
+
+ try:
+ self.pon_port_config_resp.get()
+ except QueueUnderflow:
+ self.log.error("no-data-in-queue")
+
device = self.adapter_agent.get_device(self.device_id)
self._handle_pon_pm_counter_req_towards_device(device,Iface_ID)
@@ -995,10 +1017,13 @@
device.reason = 'OLT activated successfully'
self.adapter_agent.update_device(device)
- else:
+ elif ind_info['deactivation_successful'] is True:
device.oper_status = OperStatus.FAILED
- device.reason = 'Failed to Intialize OLT'
+ device.reason = 'device deactivated successfully'
self.adapter_agent.update_device(device)
+ else:
+ device.oper_status = OperStatus.UNKNOWN
+ device.reason = 'operation status unknown'
reactor.callLater(15, self.activate, device)
return
@@ -1217,6 +1242,7 @@
onu_id=child_device.proxy_address.onu_id,
serial_number=serial_number)
+ @inlineCallbacks
def create_interface(self, data):
try:
if isinstance(data, ChannelgroupConfig):
@@ -1254,6 +1280,18 @@
self.log.info('Activating-PON-port-at-OLT',
pon_id=data.data.xgs_ponid)
+
+ # We put the transaction in a deferredQueue
+ # Only one transaction can exist in the queue at a given time.
+ # We do this we enable the pon ports sequentially.
+ while True:
+ try:
+ self.pon_port_config_resp.put(data)
+ break
+ except QueueOverflow:
+ self.log.info('another-pon-port-enable-pending')
+ yield asleep(0.3)
+
self.add_port(port_no=data.data.xgs_ponid,
port_type=Port.PON_OLT,
label=data.name)
@@ -1451,8 +1489,111 @@
self.log.info('VEnet-is-not-configured-yet.',
gem_port_info=data)
+ @inlineCallbacks
def disable(self):
- super(Asfvolt16Handler, self).disable()
+ self.log.info("disable")
+ device = self.adapter_agent.get_device(self.device_id)
+ for channel_termination in self.channel_terminations.itervalues():
+ pon_port = channel_termination.data.xgs_ponid
+
+ while True:
+ try:
+ self.pon_port_config_resp.put(channel_termination)
+ break
+ except QueueOverflow:
+ self.log.info('another-pon-port-disable-pending')
+ yield asleep(0.3)
+
+ yield self.bal.deactivate_pon_port(olt_no=self.olt_id,
+ pon_port=pon_port,
+ transceiver_type=
+ self.transceiver_type)
+
+ # deactivate olt
+ yield self.bal.deactivate_olt()
+ device.admin_state = AdminState.DISABLED
+ device.oper_status = OperStatus.FAILED
+ device.connect_status = ConnectStatus.UNREACHABLE
+ self.adapter_agent.update_device(device)
+ # deactivate nni port
+ for port in self.asfvolt_device_info.sfp_device_presence_map.iterkeys():
+ # ignore any sfp other than the NNI.
+ if not self._valid_nni_port(port):
+ continue
+
+ # Since OLT is reachable after reboot, OLT should configurable with
+ # all the old existing flows. NNI ports should be mark it as down for
+ # ONOS to push the old flows
+ nni_intf_id = (port -
+ self.asfvolt_device_info.
+ asfvolt16_device_topology.num_of_pon_ports)
+ self.update_logical_port(nni_intf_id + MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM,
+ Port.ETHERNET_NNI,
+ OFPPS_LINK_DOWN)
+
+ # send event to child devices(onus)
+ for child_device in self.adapter_agent.\
+ get_child_devices(self.device_id):
+ msg = {'proxy_address': child_device.proxy_address,
+ 'event': 'olt-disabled'}
+ # Send evnt to such child devices which were REACHABLE,
+ # so that those devices can be marked UNREACHABLE
+ if child_device.connect_status == ConnectStatus.REACHABLE:
+ self.adapter_agent.publish_inter_adapter_message(child_device.id,
+ msg)
+
+ @inlineCallbacks
+ def reenable(self):
+ self.log.info("enable")
+ device = self.adapter_agent.get_device(self.device_id)
+ yield self.bal.activate_olt()
+ # activate pon ports
+ for channel_termination in self.channel_terminations.itervalues():
+ pon_port = channel_termination.data.xgs_ponid
+
+ while True:
+ try:
+ self.pon_port_config_resp.put(channel_termination)
+ break
+ except QueueOverflow:
+ self.log.info('another-pon-port-enable-pending')
+ yield asleep(0.3)
+
+ yield self.bal.activate_pon_port(olt_no=self.olt_id,
+ pon_port=pon_port,
+ transceiver_type=
+ self.transceiver_type)
+
+ device.oper_status = OperStatus.ACTIVE
+ device.connect_status = ConnectStatus.REACHABLE
+ self.adapter_agent.update_device(device)
+
+ # activate nni port
+ for port in self.asfvolt_device_info.sfp_device_presence_map.iterkeys():
+ # ignore any sfp other than the NNI.
+ if not self._valid_nni_port(port):
+ continue
+
+ # Since OLT is reachable after reboot, OLT should configurable with
+ # all the old existing flows. NNI ports should be mark it as down for
+ # ONOS to push the old flows
+ nni_intf_id = (port -
+ self.asfvolt_device_info.
+ asfvolt16_device_topology.num_of_pon_ports)
+ self.update_logical_port(nni_intf_id + MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM,
+ Port.ETHERNET_NNI,
+ OFPPS_LIVE)
+
+ # send event to child devices(onus)
+ for child_device in self.adapter_agent.\
+ get_child_devices(self.device_id):
+ msg = {'proxy_address': child_device.proxy_address,
+ 'event': 'olt-enabled'}
+ # Send evnt to such child devices which were UNREACHABLE,
+ # so that those devices can be marked REACHABLE
+ if child_device.connect_status == ConnectStatus.UNREACHABLE:
+ self.adapter_agent.publish_inter_adapter_message(child_device.id,
+ msg)
def delete(self):
super(Asfvolt16Handler, self).delete()
@@ -1743,7 +1884,7 @@
self.store_flows(uplink_classifier, uplink_action,
v_enet, traffic_class=2)
return
- v_ont_ani = self.get_v_ont_ani(v_enet.v_enet.data.v_ontani_ref)
+ v_ont_ani = self.get_v_ont_ani(name=v_enet.v_enet.data.v_ontani_ref)
if v_ont_ani is None:
self.log.info('Failed-to-get-v_ont_ani',
v_ont_ani=v_enet.v_enet.data.v_ontani_ref)
@@ -1849,7 +1990,7 @@
self.store_flows(uplink_classifier, uplink_action,
v_enet, traffic_class=2)
return
- v_ont_ani = self.get_v_ont_ani(v_enet.v_enet.data.v_ontani_ref)
+ v_ont_ani = self.get_v_ont_ani(name=v_enet.v_enet.data.v_ontani_ref)
if v_ont_ani is None:
self.log.error('Failed-to-get-v_ont_ani',
v_ont_ani=v_enet.v_enet.data.v_ontani_ref)
@@ -1988,7 +2129,7 @@
self.store_flows(uplink_classifier, uplink_action,
v_enet, traffic_class=2)
return
- v_ont_ani = self.get_v_ont_ani(v_enet.v_enet.data.v_ontani_ref)
+ v_ont_ani = self.get_v_ont_ani(name=v_enet.v_enet.data.v_ontani_ref)
if v_ont_ani is None:
self.log.info('Failed-to-get-v_ont_ani',
v_ont_ani=v_enet.v_enet.data.v_ontani_ref)
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_ind_handler.py b/voltha/adapters/asfvolt16_olt/asfvolt16_ind_handler.py
index 0ba2a21..0369528 100644
--- a/voltha/adapters/asfvolt16_olt/asfvolt16_ind_handler.py
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_ind_handler.py
@@ -39,16 +39,22 @@
def bal_acc_term_ind(self, indication, device_handler):
# ind_info: {'_object_type': <str>
# 'actv_status': <str>}
+ self.log.info("access-term-ind",indication=indication)
ind_info = dict()
ind_info['_object_type'] = 'access_terminal_indication'
ind_info['_sub_group_type'] = 'access_terminal_indication'
- if ((indication.access_term_ind.data.admin_state == \
- bal_model_types_pb2.BAL_STATE_UP) and \
- (indication.access_term_ind.data.oper_status == \
- bal_model_types_pb2.BAL_STATUS_UP)):
- ind_info['activation_successful'] = True
- else:
- ind_info['activation_successful'] = False
+ ind_info['activation_successful'] = False
+ ind_info['deactivation_successful'] = False
+ if indication.access_term_ind.data.admin_state == \
+ bal_model_types_pb2.BAL_STATE_UP:
+ if indication.access_term_ind.data.oper_status == \
+ bal_model_types_pb2.BAL_STATUS_UP:
+ ind_info['activation_successful'] = True
+ elif indication.access_term_ind.data.admin_state == \
+ bal_model_types_pb2.BAL_STATE_DOWN:
+ if indication.access_term_ind.data.oper_status == \
+ bal_model_types_pb2.BAL_STATUS_DOWN:
+ ind_info['deactivation_successful'] = True
reactor.callLater(0,
device_handler.handle_access_term_ind,
diff --git a/voltha/adapters/asfvolt16_olt/bal.py b/voltha/adapters/asfvolt16_olt/bal.py
index 7d93b66..409c223 100644
--- a/voltha/adapters/asfvolt16_olt/bal.py
+++ b/voltha/adapters/asfvolt16_olt/bal.py
@@ -79,6 +79,10 @@
self.log.info('activating-olt')
self.set_access_terminal_admin_state(bal_model_types_pb2.BAL_STATE_UP)
+ def deactivate_olt(self):
+ self.log.info('deactivating-olt')
+ self.set_access_terminal_admin_state(bal_model_types_pb2.BAL_STATE_DOWN)
+
@inlineCallbacks
def set_access_terminal_admin_state(self, admin_state):
obj = bal_pb2.BalCfg()
@@ -86,7 +90,7 @@
obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_ACCESS_TERMINAL
obj.cfg.key.access_term_id = 0
obj.cfg.data.admin_state = admin_state
- self.log.info('Activating-Access-Terminal-Device',
+ self.log.info('Admin-stage-change-Access-Terminal-Device',
admin_state=admin_state, device_id=self.device_id,
access_terminal_details=obj)
yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
@@ -128,6 +132,7 @@
olt=olt_no, pon_port=pon_port,
pon_port_details=obj,
transceiver_type=transceiver_type)
+ yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
except Exception as e:
self.log.info('deactivating-pon-port in olt-exception', exc=str(e))
return
diff --git a/voltha/adapters/broadcom_onu/broadcom_onu.py b/voltha/adapters/broadcom_onu/broadcom_onu.py
index d5c966f..2811eb6 100644
--- a/voltha/adapters/broadcom_onu/broadcom_onu.py
+++ b/voltha/adapters/broadcom_onu/broadcom_onu.py
@@ -356,10 +356,15 @@
elif event_msg['event'] == 'deactivate-onu':
device = self.adapter_agent.get_device(self.device_id)
+ self.disable_ports(device)
device.connect_status = ConnectStatus.UNREACHABLE
device.oper_status = OperStatus.DISCOVERED
self.adapter_agent.update_device(device)
- self.disable_ports(device)
+
+ elif (event_msg['event'] == 'olt-reboot'):
+ device = self.adapter_agent.get_device(self.device_id)
+ device.connect_status = ConnectStatus.UNREACHABLE
+ self.adapter_agent.update_device(device)
elif event_msg['event'] == 'ranging-completed':
@@ -387,6 +392,15 @@
gem_port = GemportsConfigData()
gem_port.gemport_id = event_msg['event_data']['gemport_id']
self.create_gemport(gem_port)
+ elif event_msg['event'] == 'olt-disabled':
+ device = self.adapter_agent.get_device(self.device_id)
+ device.connect_status = ConnectStatus.UNREACHABLE
+ self.adapter_agent.update_device(device)
+
+ elif event_msg['event'] == 'olt-enabled':
+ device = self.adapter_agent.get_device(self.device_id)
+ device.connect_status = ConnectStatus.REACHABLE
+ self.adapter_agent.update_device(device)
# Handle next event
reactor.callLater(0, self.handle_onu_events)
@@ -1770,3 +1784,18 @@
for port in ports:
port_id = 'uni-{}'.format(port.port_no)
self.update_logical_port(logical_device_id, port_id, OFPPS_LINK_DOWN)
+
+ def enable_ports(self, onu_device):
+ self.log.info('enable-ports', device_id=self.device_id)
+
+ # Disable all ports on that device
+ self.adapter_agent.enable_all_ports(self.device_id)
+
+ parent_device = self.adapter_agent.get_device(onu_device.parent_id)
+ assert parent_device
+ logical_device_id = parent_device.parent_id
+ assert logical_device_id
+ ports = self.adapter_agent.get_ports(onu_device.id, Port.ETHERNET_UNI)
+ for port in ports:
+ port_id = 'uni-{}'.format(port.port_no)
+ self.update_logical_port(logical_device_id, port_id, OFPPS_LIVE)
diff --git a/voltha/core/core.py b/voltha/core/core.py
index 47cb4d1..c7dccea 100644
--- a/voltha/core/core.py
+++ b/voltha/core/core.py
@@ -213,6 +213,8 @@
self.device_agents[device.id] = \
yield DeviceAgent(self, device).start(device=device,
reconcile=reconcile)
+ path = '/devices/{}'.format(device.id)
+ self.xpon_agent.register_interface(device.id, path, update=False)
@inlineCallbacks
def _handle_remove_device(self, device):
diff --git a/voltha/core/device_agent.py b/voltha/core/device_agent.py
index 129390b..ba27c1a 100644
--- a/voltha/core/device_agent.py
+++ b/voltha/core/device_agent.py
@@ -307,7 +307,9 @@
def update_device(self, device):
self.last_data = device # so that we don't propagate back
self.proxy.update('/', device)
- if device.oper_status == OperStatus.ACTIVE and device.connect_status == ConnectStatus.REACHABLE:
+ if device.admin_state == AdminState.ENABLED and \
+ device.oper_status == OperStatus.ACTIVE and \
+ device.connect_status == ConnectStatus.REACHABLE:
self.log.info('replay-create-interfaces ', device=device.id)
self.core.xpon_agent.replay_interface(device.id)
# if device accepts bulk flow update, lets just call that
@@ -320,7 +322,6 @@
flows=flows,
groups=groups)
-
def update_device_pm_config(self, device_pm_config, init=False):
self.callback_data = init# so that we don't push init data
self.pm_config_proxy.update('/', device_pm_config)