VOL-1236: TDP update for the subscribers is to be addressed as part of this JIRA. The BAL interface is also upgraded to 2.6 version

Change-Id: I2d7cf4eac056549764796643c38adf3f28e42e4a
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_device_handler.py b/voltha/adapters/asfvolt16_olt/asfvolt16_device_handler.py
index 043ce4c..1ebae7d 100644
--- a/voltha/adapters/asfvolt16_olt/asfvolt16_device_handler.py
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_device_handler.py
@@ -19,11 +19,12 @@
 """
 
 import arrow
-from twisted.internet.defer import inlineCallbacks, DeferredQueue, QueueOverflow, QueueUnderflow
+from Queue import Queue, Full, Empty
+from twisted.internet.defer import inlineCallbacks
 from itertools import count, ifilterfalse
 from voltha.protos.events_pb2 import KpiEvent, MetricValuePairs
 from voltha.protos.events_pb2 import KpiEventType
-from voltha.protos.device_pb2 import PmConfigs, PmConfig,PmGroupConfig
+from voltha.protos.device_pb2 import PmConfigs, PmConfig, PmGroupConfig
 from voltha.adapters.asfvolt16_olt.protos import bal_errno_pb2, bal_pb2, bal_model_types_pb2
 from voltha.protos.events_pb2 import AlarmEvent, AlarmEventType, \
     AlarmEventSeverity, AlarmEventState, AlarmEventCategory
@@ -37,6 +38,7 @@
 from voltha.protos.device_pb2 import Port
 from voltha.protos.common_pb2 import AdminState
 from voltha.protos.logical_device_pb2 import LogicalPort, LogicalDevice
+from voltha.protos import openflow_13_pb2 as ofp
 from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, OFPPS_LINK_DOWN, \
     OFPPF_1GB_FD, OFPC_GROUP_STATS, OFPC_PORT_STATS, OFPC_TABLE_STATS, \
     OFPC_FLOW_STATS, ofp_switch_features, ofp_desc, ofp_port, \
@@ -52,6 +54,8 @@
     TrafficDescriptorProfileData
 from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
 from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
+from voltha.adapters.asfvolt16_olt.asfvolt16_kv_store import Asfvolt16KvStore
+from voltha.registry import registry
 import binascii
 from argparse import ArgumentParser, ArgumentError
 import shlex
@@ -96,11 +100,27 @@
 
 RESERVED_VLAN_ID = 4095
 
+ASFVOLT16_NUM_PON_PORTS = 16
+
+ASFVOLT16_PON_PORT_SCHEDULER_ID_START = 16384
+ASFVOLT16_NNI_PORT_SCHEDULER_ID_START = 18432
+
+ASFVOLT16_MAX_BURST_BYTES_AT_PBR = 10000
+
+ASFVOLT16_DEFAULT_QUEUE_ID_START = 0
+ASFVOLT16_DEFAULT_QUEUE_ID_END = 3
+
+# This flow id shouldn't collide with flow_id assigned by
+# get_flow_id api. It doesn't collide currently.
+ASFVOLT16_LLDP_DL_FLOW_ID = 16368
+
 # get_flow_id api uses 7 bit of the ONU id and hence
 # limits the max ONUs per pon port to 128. This should
 # be sufficient for most practical uses cases
-MAX_ONU_ID_PER_PON_PORT = 127
+MAX_ONU_ID_PER_PON_PORT = 128
 
+# traffic class specifier
+TRAFFIC_CLASS_2 = 2
 
 class FlowInfo(object):
 
@@ -134,27 +154,27 @@
 
     def __init__(self,device, log):
         self.pm_names = {
-             "rx_bytes", "rx_packets", "rx_ucast_packets", "rx_mcast_packets",
-             "rx_bcast_packets", "rx_error_packets", "rx_unknown_protos",
-             "tx_bytes", "tx_packets", "tx_ucast_packets", "tx_mcast_packets",
-             "tx_bcast_packets", "tx_error_packets", "rx_crc_errors", "bip_errors"
+            "rx_bytes", "rx_packets", "rx_ucast_packets", "rx_mcast_packets",
+            "rx_bcast_packets", "rx_error_packets", "rx_unknown_protos",
+            "tx_bytes", "tx_packets", "tx_ucast_packets", "tx_mcast_packets",
+            "tx_bcast_packets", "tx_error_packets", "rx_crc_errors", "bip_errors"
         }
         self.device = device
         self.log = log
         self.id = device.id
         # To collect pm metrices for each 'pm_default_freq/10' secs
-        self.pm_default_freq = 20
+        self.pm_default_freq = 50
         self.pon_metrics = dict()
         self.nni_metrics = dict()
         for m in self.pm_names:
             self.pon_metrics[m] = \
-                    self.Metrics(config = PmConfig(name=m,
-                                                   type=PmConfig.COUNTER,
-                                                   enabled=True), value = 0)
+                self.Metrics(config=PmConfig(name=m,
+                                             type=PmConfig.COUNTER,
+                                             enabled=True), value=0)
             self.nni_metrics[m] = \
-                    self.Metrics(config = PmConfig(name=m,
-                                                   type=PmConfig.COUNTER,
-                                                   enabled=True), value = 0)
+                self.Metrics(config=PmConfig(name=m,
+                                             type=PmConfig.COUNTER,
+                                             enabled=True), value=0)
 
     def update(self, device, pm_config):
         if self.pm_default_freq != pm_config.default_freq:
@@ -171,8 +191,8 @@
         pm_config = PmConfigs(
             id=self.id,
             default_freq=self.pm_default_freq,
-            grouped = False,
-            freq_override = False)
+            grouped=False,
+            freq_override=False)
         return pm_config
 
 
@@ -185,6 +205,10 @@
 
 class Asfvolt16Handler(OltDeviceHandler):
 
+    ONU_ID_BITS = 6
+    PON_INTF_BITS = 4
+    FLOW_ID_BITS = 4
+
     def __init__(self, adapter, device_id):
         super(Asfvolt16Handler, self).__init__(adapter, device_id)
         self.filter = is_inband_frame
@@ -212,10 +236,26 @@
         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.is_device_reachable = False
+
         # We allow only one pon port enabling at a time.
-        self.pon_port_config_resp = DeferredQueue(size=1)
+        self.pon_port_config_resp = Queue(maxsize=1)
+        self.args = registry('main').get_args()
+
+        # to be derived from args
+        host, port = '127.0.0.1', 8500
+        if self.args.backend == 'etcd':
+            host, port = self.args.etcd.split(':', 1)
+        elif self.args.backend == 'consul':
+            host, port = self.args.consul.split(':', 1)
+        else:
+            self.log.exception('invalid-backend')
+
+        self.kv_store = Asfvolt16KvStore(self.args.backend, host, int(port))
+        self.flow_mapping_list = list()
+        self.flow_config_in_progress = False
         self.reconcile_in_progress = False
-        # defaults to first NNI port. Overriden after reading from the device
+        # defaults to first NNI ports. Overriden after reading from the device 
         self.nni_intf_id = 0
 
     def __del__(self):
@@ -311,12 +351,13 @@
     def get_flow_id(self, onu_id, intf_id, id):
         # BAL accepts flow_id till 16384 (14 bits).
         # ++++++++++++++++++++++++++++++++++++++++++++++
-        # + 7 bits onu_id | 4 bits intf_id | 3 bits id +
+        # + 6 bits onu_id | 4 bits intf_id | 4 bits id +
         # ++++++++++++++++++++++++++++++++++++++++++++++
-        # Note: Theoritical limit of onu_id is 255, but
-        # practically we have upto 64 or 128 ONUs per pon port.
-        # Hence limiting onu_id to 7 bits
-        return ((onu_id << 7) | (intf_id << 3) | (id))
+        # Note: Theoretical limit of onu_id is 255, but
+        # practically we have upto 32 or 64 or 128 ONUs per pon port.
+        # For now limiting the ONU Id to 6 bits (or 32 ONUs)
+        return (onu_id << (self.FLOW_ID_BITS + self.PON_INTF_BITS)
+                | (intf_id << self.FLOW_ID_BITS) | id)
 
     def get_uni_port(self, device_id):
         ports = self.adapter_agent.get_ports(device_id, Port.ETHERNET_UNI)
@@ -325,6 +366,36 @@
             return ports[0]
         return None
 
+    @staticmethod
+    def get_sched_id(direction, port_id):
+        if direction == 'downstream':
+            return ASFVOLT16_PON_PORT_SCHEDULER_ID_START + port_id
+        else:
+            return ASFVOLT16_NNI_PORT_SCHEDULER_ID_START + port_id
+
+    @staticmethod
+    def get_queue_id(onu_id):
+        '''
+        To-Do:Need to use a better approach to derive queue id in case of
+               onu's connected on multiple pon ports
+        '''
+        return ASFVOLT16_DEFAULT_QUEUE_ID_END + onu_id
+
+    def _get_pon_port_from_pref_chanpair_ref(self, chanpair_ref):
+        pon_id = -1
+        # return the pon port corresponding to the channel_termination
+        # whose chanpair_ref mathes the passed channelpair_ref
+        for channel_termination in self.channel_terminations.itervalues():
+            if channel_termination.data.channelpair_ref == chanpair_ref:
+                self.log.debug("channel-termination-entry-found",
+                               pon_id=channel_termination.data.xgs_ponid,
+                               chanpair_ref=chanpair_ref)
+                return channel_termination.data.xgs_ponid
+
+        if pon_id < 0:
+            raise Exception("pon-id-not-found-for-chanpair-ref {}".
+                            format(chanpair_ref))
+
     def create_pon_id_and_gem_port_to_uni_port_map(self,
                                                    gem_port, v_enet
                                                    ):
@@ -336,11 +407,11 @@
         # xgs_ponid from this channel_termination.
         for channel_termination in self.channel_terminations.itervalues():
             if v_ont_ani.v_ont_ani.data.preferred_chanpair == \
-                   channel_termination.data.channelpair_ref:
+                    channel_termination.data.channelpair_ref:
                 pon_id = channel_termination.data.xgs_ponid
                 self.pon_id_gem_port_to_v_enet_name[(pon_id, gem_port)] = v_enet_name
                 self.log.debug("entry-created", pon_id=pon_id,
-                                gem_port=gem_port, v_enet_name=v_enet_name)
+                               gem_port=gem_port, v_enet_name=v_enet_name)
                 break
         if pon_id < 0:
             raise Exception("pon-id-gem-port-to-uni-port-map-creation-failed")
@@ -356,11 +427,11 @@
         # xgs_ponid from this channel_termination.
         for channel_termination in self.channel_terminations.itervalues():
             if v_ont_ani.v_ont_ani.data.preferred_chanpair == \
-                   channel_termination.data.channelpair_ref:
+                    channel_termination.data.channelpair_ref:
                 pon_id = channel_termination.data.xgs_ponid
                 del self.pon_id_gem_port_to_v_enet_name[(pon_id, gem_port)]
                 self.log.debug("entry-deleted", pon_id=pon_id,
-                                gem_port=gem_port, v_enet_name=v_enet_name)
+                               gem_port=gem_port, v_enet_name=v_enet_name)
                 break
         if pon_id < 0:
             raise Exception("pon-id-gem-port-to-uni-port-map-deletion-failed")
@@ -379,7 +450,8 @@
             if flow.traffic_class == traffic_class:
                 self.divide_and_add_flow(v_enet,
                                          flow.classifier,
-                                         flow.action)
+                                         flow.action,
+                                         flow.priority)
                 v_enet.pending_flows.remove(flow)
         return
 
@@ -396,8 +468,8 @@
                           v_ont_ani=v_enet.v_enet.data.v_ontani_ref)
             return
 
-        pon_port = self._get_pon_port_from_pref_chanpair_ref(\
-                        v_ont_ani.v_ont_ani.data.preferred_chanpair)
+        pon_port = self._get_pon_port_from_pref_chanpair_ref(
+            v_ont_ani.v_ont_ani.data.preferred_chanpair)
         onu_device = self.adapter_agent.get_child_device(
             self.device_id, onu_id=v_ont_ani.v_ont_ani.data.onu_id,
             parent_port_no=pon_port)
@@ -408,7 +480,7 @@
 
         uni = self.get_uni_port(onu_device.id)
         if uni is not None:
-           logical_port = uni.port_no
+            logical_port = uni.port_no
         return logical_port
 
     def get_logical_port_from_pon_id_and_gem_port(self, pon_id, gem_port):
@@ -420,8 +492,10 @@
                     return port.port_no
         return None
 
+    @inlineCallbacks
     def activate(self, device):
         self.log.info('activating-asfvolt16-olt', device=device)
+        asfvolt_system_info = None
 
         if not device.host_and_port:
             device.oper_status = OperStatus.FAILED
@@ -440,19 +514,41 @@
                 self.adapter_agent.update_device(device)
                 return
 
-        self.bal.connect_olt(device.host_and_port, self.device_id)
+        # Start the gRPC client and establish connection to gRPC server
+        # on the OLT
+        yield self.bal.connect_olt(device.host_and_port, self.device_id)
 
         if self.logical_device_id is None:
+            # This code snippet gets executed only once in the lifecycle of the
+            # OLT device, i.e., the first time when the device is created and
+            # enabled.
 
-            self.host_and_port = device.host_and_port
+            reactor.callInThread(self.bal.get_indication_info, self.device_id)
+
+            try:
+                # Query the ASFvOLT16 device information (serial_num,
+                # mac_address etc.)
+                asfvolt_system_info = \
+                    yield self.bal.get_asfvolt_system_info(self.device_id)
+            except Exception as e:
+                # asfvolt_system_info defaults to None in this case
+                self.log.error("error-retrieving-device-info", e=e)
+
+            self.add_logical_device(device.id, asfvolt_system_info)
+
+            # Update the device parameters that don't change for the device.
             device.root = True
             device.vendor = 'Edgecore'
             device.model = 'ASFvOLT16'
-            device.serial_number = device.host_and_port
+            # If ASFvOLT16 system information is available, retrieve
+            # the serial_num, else it defaults to host_and_port
+            if asfvolt_system_info:
+                device.serial_number = asfvolt_system_info.serial_num
+            else:
+                device.serial_number = device.host_and_port
             self.adapter_agent.update_device(device)
-            self.add_logical_device(device_id=device.id)
-            reactor.callInThread(self.bal.get_indication_info, self.device_id)
 
+        # Activate the OLT
         self.bal.activate_olt()
 
         device.parent_id = self.logical_device_id
@@ -461,7 +557,7 @@
         self.adapter_agent.update_device(device)
 
     def reconcile(self, device):
-        self.log.info('reconciling-asfvolt16-starts',device=device)
+        self.log.info('reconciling-asfvolt16-starts', device=device)
         self.reconcile_in_progress = True
 
         if not device.host_and_port:
@@ -473,8 +569,12 @@
         try:
             # Establishing connection towards OLT
             self.host_and_port = device.host_and_port
-            self.bal.connect_olt(device.host_and_port, self.device_id, is_init=False)
+            yield self.bal.connect_olt(device.host_and_port, self.device_id, is_init=False)
             reactor.callInThread(self.bal.get_indication_info, self.device_id)
+            # Update the NNI Interface Id as part of reconcile
+            self._retrieve_access_term_config()
+            self._update_nni_port()
+
         except Exception as e:
             self.log.exception('device-unreachable', error=e)
             device.connect_status = ConnectStatus.UNREACHABLE
@@ -487,16 +587,17 @@
             self.start_heartbeat()
 
             # Now set the initial PM configuration for this device
-            self.pm_metrics=Asfvolt16OltPmMetrics(device, self.log)
+            self.pm_metrics = Asfvolt16OltPmMetrics(device, self.log)
             pm_config = self.pm_metrics.make_proto()
             self.log.info("initial-pm-config", pm_config=pm_config)
-            self.adapter_agent.update_device_pm_config(pm_config,init=True)
+            self.adapter_agent.update_device_pm_config(pm_config, init=True)
 
             # Apply the PM configuration
             self.update_pm_config(device, pm_config)
 
+            self.is_device_reachable = True
             # Request PM counters from OLT device.
-            self._handle_pm_counter_req_towards_device(device)
+            reactor.callInThread(self._handle_pm_counter_req_towards_device)
 
         # Set the logical device id
         device = self.adapter_agent.get_device(device.id)
@@ -516,10 +617,21 @@
         self.adapter_agent.update_device(device)
 
         self.reconcile_in_progress = False
-        self.log.info('reconciling-asfvolt16-device-ends',device=device)
+        self.log.info('reconciling-asfvolt16-device-ends', device=device)
+
+    def get_datapath_id(self):
+        datapath_hex_id = None
+        try:
+            logical_device = self.adapter_agent.get_logical_device(
+                self.logical_device_id)
+            datapath_hex_id = format(logical_device.datapath_id, '016x')
+            self.log.info('datapath_hex_id', datapath_hex_id=datapath_hex_id)
+        except Exception as e:
+            self.log.exception("datapathid error:", e=e)
+        return datapath_hex_id
 
     @inlineCallbacks
-    def heartbeat(self, state = 'run'):
+    def heartbeat(self, state='run'):
         device = self.adapter_agent.get_device(self.device_id)
 
         # Commenting this unnecessary debug. Debug prints only in case of
@@ -534,7 +646,7 @@
             try:
                 ts = arrow.utcnow().timestamp
 
-                alarm_data = {'heartbeats_missed':str(heartbeat_misses)}
+                alarm_data = {'heartbeats_missed': str(heartbeat_misses)}
 
                 alarm_event = self.adapter_agent.create_alarm(
                     id='voltha.{}.{}.olt'.format(self.adapter.name, device),
@@ -543,12 +655,12 @@
                     category=AlarmEventCategory.OLT,
                     severity=AlarmEventSeverity.CRITICAL,
                     state=AlarmEventState.RAISED if status else
-                        AlarmEventState.CLEARED,
+                    AlarmEventState.CLEARED,
                     description='OLT Alarm - Connection to OLT - {}'.format('Lost'
-                                                                    if status
-                                                                    else 'Regained'),
+                                                                            if status
+                                                                            else 'Regained'),
                     context=alarm_data,
-                    raised_ts = ts)
+                    raised_ts=ts)
 
                 self.adapter_agent.submit_alarm(device, alarm_event)
                 self.log.debug('olt-heartbeat alarm sent')
@@ -558,13 +670,13 @@
 
         try:
             d = yield self.bal.get_bal_heartbeat(self.device_id.__str__())
-        except Exception as e:
+        except Exception:
             d = None
 
-        if d == None:
+        if d is None:
             # something is not right - OLT is not Reachable
             self.heartbeat_miss += 1
-            self.log.info('olt-heartbeat-miss',d=d,
+            self.log.info('olt-heartbeat-miss', d=d,
                           count=self.heartbeat_count, miss=self.heartbeat_miss)
         else:
             if self.heartbeat_miss > 0:
@@ -578,38 +690,49 @@
 
                     for key, v_ont_ani in self.v_ont_anis.items():
 
-                        pon_port = self._get_pon_port_from_pref_chanpair_ref(\
-                                      v_ont_ani.v_ont_ani.data.preferred_chanpair)
+                        pon_port = self._get_pon_port_from_pref_chanpair_ref(
+                            v_ont_ani.v_ont_ani.data.preferred_chanpair)
                         child_device = self.adapter_agent.get_child_device(
-                           self.device_id, onu_id=v_ont_ani.v_ont_ani.data.onu_id,
-                           parent_port_no=pon_port)
+                            self.device_id, onu_id=v_ont_ani.v_ont_ani.data.onu_id,
+                            parent_port_no=pon_port)
+                        self.log.info("before-sending-inter-adapter-message", child_device=child_device)
                         if child_device:
                             msg = {'proxy_address': child_device.proxy_address,
                                    'event': 'deactivate-onu', 'event_data': "olt-reboot"}
                             # Send the event message to the ONU adapter
                             self.adapter_agent.publish_inter_adapter_message(child_device.id,
                                                                              msg)
-                    #Activate Device
+                    # Activate Device
                     self.activate(device)
                 else:
                     device.connect_status = ConnectStatus.REACHABLE
                     device.oper_status = OperStatus.ACTIVE
                     device.reason = ''
                     self.adapter_agent.update_device(device)
+                    self.is_device_reachable = True
                     # Update the device control block with the latest update
                     self.log.debug("all-fine-no-heartbeat-miss", device=device)
                 self.log.info('clearing-heartbeat-alarm')
                 heartbeat_alarm(device, 0)
 
         if (self.heartbeat_miss >= self.heartbeat_failed_limit) and \
-           (device.connect_status == ConnectStatus.REACHABLE):
+                (device.connect_status == ConnectStatus.REACHABLE):
             self.log.info('olt-heartbeat-failed', count=self.heartbeat_miss)
             device.connect_status = ConnectStatus.UNREACHABLE
             device.oper_status = OperStatus.FAILED
             device.reason = 'Lost connectivity to OLT'
+
             self.adapter_agent.update_device(device)
             heartbeat_alarm(device, 1, self.heartbeat_miss)
 
+            # Clear all the flow stored in the consul (if there were any)
+            # This way all the flows are replayed again
+            self.log.debug('clear-kv-store-flows')
+            self.kv_store.clear_kv_store(self.device_id)
+
+            # Clear pon port config response queue
+            self._remove_port_config_from_queue()
+
             child_devices = self.adapter_agent.get_child_devices(self.device_id)
             for child in child_devices:
                 msg = {'proxy_address': child.proxy_address,
@@ -623,34 +746,40 @@
 
     @inlineCallbacks
     def reboot(self):
-        err_status  = yield self.bal.set_bal_reboot(self.device_id.__str__())
-        self.log.info('Reboot-Status', err_status = err_status)
-
-    def _handle_pm_counter_req_towards_device(self, device):
-        self._handle_nni_pm_counter_req_towards_device(device, self.nni_intf_id)
-        for value in self.channel_terminations.itervalues():
-            self._handle_pon_pm_counter_req_towards_device(device,
-                                                           value.data.xgs_ponid)
-        reactor.callLater(self.pm_metrics.pm_default_freq / 10,
-                          self._handle_pm_counter_req_towards_device,
-                          device)
+        err_status = yield self.bal.set_bal_reboot(self.device_id.__str__())
+        self.log.info('Reboot-Status', err_status=err_status)
 
     @inlineCallbacks
-    def _handle_nni_pm_counter_req_towards_device(self, device, intf_id):
+    def _handle_pm_counter_req_towards_device(self):
+        while True:
+            if self.is_device_reachable is True:
+                yield self._handle_nni_pm_counter_req_towards_device(self.nni_intf_id)
+                for value in self.channel_terminations.itervalues():
+                    yield self._handle_pon_pm_counter_req_towards_device(value.data.xgs_ponid)
+
+            yield asleep(self.pm_metrics.pm_default_freq / 10)
+
+    @inlineCallbacks
+    def _handle_nni_pm_counter_req_towards_device(self, intf_id):
         interface_type = bal_model_types_pb2.BAL_INTF_TYPE_NNI
-        yield self._req_pm_counter_from_device(device, interface_type, intf_id)
+        yield self._req_pm_counter_from_device(interface_type, intf_id)
 
     @inlineCallbacks
-    def _handle_pon_pm_counter_req_towards_device(self, device, intf_id):
+    def _handle_pon_pm_counter_req_towards_device(self, intf_id):
         interface_type = bal_model_types_pb2.BAL_INTF_TYPE_PON
-        yield self._req_pm_counter_from_device(device, interface_type, intf_id)
+        yield self._req_pm_counter_from_device(interface_type, intf_id)
 
     @inlineCallbacks
-    def _req_pm_counter_from_device(self, device, interface_type, intf_id):
+    def _req_pm_counter_from_device(self, interface_type, intf_id):
         # NNI port is hardcoded to 0
         kpi_status = -1
+        stats_info = None
+
+        # Get the device status before querying stats
+        device = self.adapter_agent.get_device(self.device_id)
         if device.connect_status == ConnectStatus.UNREACHABLE:
-           self.log.info('Device-is-not-Reachable')
+            self.log.info('Device-is-not-Reachable')
+            self.is_device_reachable = False
         else:
             try:
                 stats_info = yield self.bal.get_bal_interface_stats(intf_id, interface_type)
@@ -661,37 +790,68 @@
             except Exception as e:
                 kpi_status = -1
 
-        if kpi_status == 0 and stats_info != None:
-            pm_data = {}
+        if kpi_status == 0 and stats_info is not None:
+            pm_data = dict()
             pm_data["rx_bytes"] = stats_info.data.rx_bytes
             pm_data["rx_packets"] = stats_info.data.rx_packets
+            pm_data["rx_data_bytes"] = stats_info.data.rx_data_bytes
             pm_data["rx_ucast_packets"] = stats_info.data.rx_ucast_packets
             pm_data["rx_mcast_packets"] = stats_info.data.rx_mcast_packets
             pm_data["rx_bcast_packets"] = stats_info.data.rx_bcast_packets
+            pm_data["rx_64_packets"] = stats_info.data.rx_64_packets
+            pm_data["rx_65_127_packets"] = stats_info.data.rx_65_127_packets
+            pm_data["rx_128_255_packets"] = stats_info.data.rx_128_255_packets
+            pm_data["rx_256_511_packets"] = stats_info.data.rx_256_511_packets
+            pm_data["rx_512_1023_packets"] = stats_info.data.rx_512_1023_packets
+            pm_data["rx_1024_1518_packets"] = stats_info.data.rx_1024_1518_packets
+            pm_data["rx_1519_2047_packets"] = stats_info.data.rx_1519_2047_packets
+            pm_data["rx_2048_4095_packets"] = stats_info.data.rx_2048_4095_packets
+            pm_data["rx_4096_9216_packets"] = stats_info.data.rx_4096_9216_packets
+            pm_data["rx_9217_16383_packets"] = stats_info.data.rx_9217_16383_packets
             pm_data["rx_error_packets"] = stats_info.data.rx_error_packets
             pm_data["rx_unknown_protos"] = stats_info.data.rx_unknown_protos
+            pm_data["rx_crc_errors"] = stats_info.data.rx_crc_errors
+            pm_data["bip_errors"] = stats_info.data.bip_errors
+            pm_data["rx_mpcp"] = stats_info.data.rx_mpcp
+            pm_data["rx_report"] = stats_info.data.rx_report
+            pm_data["rx_oam_bytes"] = stats_info.data.rx_oam_bytes
+            pm_data["rx_oam_packets"] = stats_info.data.rx_oam_packets
             pm_data["tx_bytes"] = stats_info.data.tx_bytes
             pm_data["tx_packets"] = stats_info.data.tx_packets
+            pm_data["tx_data_bytes"] = stats_info.data.tx_data_bytes
             pm_data["tx_ucast_packets"] = stats_info.data.tx_ucast_packets
             pm_data["tx_mcast_packets"] = stats_info.data.tx_mcast_packets
             pm_data["tx_bcast_packets"] = stats_info.data.tx_bcast_packets
+            pm_data["tx_64_packets"] = stats_info.data.tx_64_packets
+            pm_data["tx_65_127_packets"] = stats_info.data.tx_65_127_packets
+            pm_data["tx_128_255_packets"] = stats_info.data.tx_128_255_packets
+            pm_data["tx_256_511_packets"] = stats_info.data.tx_256_511_packets
+            pm_data["tx_512_1023_packets"] = stats_info.data.tx_512_1023_packets
+            pm_data["tx_1024_1518_packets"] = stats_info.data.tx_1024_1518_packets
+            pm_data["tx_1519_2047_packets"] = stats_info.data.tx_1519_2047_packets
+            pm_data["tx_2048_4095_packets"] = stats_info.data.tx_2048_4095_packets
+            pm_data["tx_4096_9216_packets"] = stats_info.data.tx_4096_9216_packets
+            pm_data["tx_9217_16383_packets"] = stats_info.data.tx_9217_16383_packets
             pm_data["tx_error_packets"] = stats_info.data.tx_error_packets
-            pm_data["rx_crc_errors"] = stats_info.data.rx_crc_errors
-            pm_data["bip_errors"] = stats_info.data.bip_errors
+            pm_data["tx_mpcp"] = stats_info.data.tx_mpcp
+            pm_data["tx_gate"] = stats_info.data.tx_gate
+            pm_data["tx_oam_bytes"] = stats_info.data.tx_oam_bytes
+            pm_data["tx_oam_packets"] = stats_info.data.tx_oam_packets
 
             # Commenting this unnecessary debug log. The statistics information
             # is also available from kafka_proxy.send_message debug log.
             # self.log.debug('KPI stats', pm_data=pm_data)
             name = 'asfvolt16_olt'
             prefix = 'voltha.{}.{}'.format(name, self.device_id)
+            prefixes = None
             ts = arrow.utcnow().timestamp
             if stats_info.key.intf_type == bal_model_types_pb2.BAL_INTF_TYPE_NNI:
                 prefixes = {
-                    prefix + '.nni': MetricValuePairs(metrics=pm_data)
+                    prefix + '.nni' + str(intf_id): MetricValuePairs(metrics=pm_data)
                 }
             elif stats_info.key.intf_type == bal_model_types_pb2.BAL_INTF_TYPE_PON:
                 prefixes = {
-                    prefix + '.pon': MetricValuePairs(metrics=pm_data)
+                    prefix + '.pon' + str(intf_id): MetricValuePairs(metrics=pm_data)
                 }
 
             kpi_event = KpiEvent(
@@ -701,6 +861,7 @@
             self.adapter_agent.submit_kpis(kpi_event)
         else:
             self.log.info('Lost-Connectivity-to-OLT')
+            self.is_device_reachable = False
 
     def update_pm_config(self, device, pm_config):
         self.log.info("update-pm-config", device=device, pm_config=pm_config)
@@ -710,18 +871,27 @@
                       status, priority,
                       alarm_data=None):
         self.log.info('received-alarm-msg',
-                 object=_object,
-                 key=key,
-                 alarm=alarm,
-                 status=status,
-                 priority=priority,
-                 alarm_data=alarm_data)
+                      object=_object,
+                      key=key,
+                      alarm=alarm,
+                      status=status,
+                      priority=priority,
+                      alarm_data=alarm_data)
 
+        device = self.adapter_agent.get_device(_device_id)
+        if self.logical_device_id:
+            logical_device = self.adapter_agent.get_logical_device(
+                self.logical_device_id)
+            alarm_data['olt_serial_number'] = logical_device.desc.serial_num
+        else:
+            alarm_data['olt_serial_number'] = device.serial_number
+
+        alarm_data['host'] = (device.host_and_port.split(':')[0]).__str__()
         id = 'voltha.{}.{}.{}'.format(self.adapter.name,
-                                     _device_id, _object)
+                                      _device_id, _object)
         description = '{} Alarm - {} - {}'.format(_object.upper(),
-                                      alarm.upper(),
-                                      'Raised' if status else 'Cleared')
+                                                  alarm.upper(),
+                                                  'Raised' if status else 'Cleared')
 
         if priority == 'low':
             severity = AlarmEventSeverity.MINOR
@@ -734,12 +904,22 @@
 
         try:
             ts = arrow.utcnow().timestamp
+            if _object == "nni":
+                category = AlarmEventCategory.NNI
+            elif _object == "pon":
+                category = AlarmEventCategory.PON
+            elif _object == "onu":
+                category = AlarmEventCategory.ONT
+            else:
+                self.log.error("invalid-alarm-object",object=_object)
+                return
+
 
             alarm_event = self.adapter_agent.create_alarm(
                 id=id,
                 resource_id=str(key),
                 type=AlarmEventType.EQUIPMENT,
-                category=AlarmEventCategory.PON,
+                category=category,
                 severity=severity,
                 state=AlarmEventState.RAISED if status else AlarmEventState.CLEARED,
                 description=description,
@@ -763,82 +943,97 @@
             # status: <False|True>
             pass
 
-    def BalIfaceLosAlarm(self, device_id, Iface_ID,\
+    def BalIfaceLosAlarm(self, device_id, indication,
                          los_status, IfaceLos_data):
         self.log.info('Interface-Loss-Of-Signal-Alarm')
-        self.handle_alarms(device_id,"pon_ni",\
-                           Iface_ID,\
-                           "loss_of_signal",los_status,"high",\
+        iface_id = indication.interface_los.key.intf_id
+        if indication.interface_los.key.intf_type == 0:
+            intf_type = "nni"
+        elif indication.interface_los.key.intf_type == 1:
+            intf_type = "pon"
+        else:
+            self.log.error("invalid-intf-type",
+                           intf_type=indication.interface_los.key.intf_type)
+            return
+        self.handle_alarms(device_id, intf_type,
+                           iface_id,
+                           "loss_of_signal", los_status, "high",
                            IfaceLos_data)
 
-    def BalIfaceIndication(self, device_id, Iface_ID):
+    def BalIfaceOperStatusChange(self, iface_id, ind_info):
         self.log.info('Interface-Indication')
+        self._remove_port_config_from_queue()
 
-        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)
-
-    def BalSubsTermDgiAlarm(self, device_id, intf_id,\
-                            onu_id, dgi_status, balSubTermDgi_data,\
+    def BalSubsTermDgiAlarm(self, device_id, intf_id,
+                            onu_id, dgi_status, balSubTermDgi_data,
                             ind_info):
         self.log.info('Subscriber-terminal-dying-gasp')
 
-        self.handle_alarms(device_id,"onu",\
-                           intf_id,\
-                           "dgi_indication",dgi_status,"medium",\
+        v_ont_ani = self.get_v_ont_ani(onu_id=onu_id, pon_port=intf_id)
+        if v_ont_ani is None:
+            self.log.info('Failed-to-get-v_ont_ani info',
+                          onu_id=onu_id)
+            return
+        balSubTermDgi_data['registration_id'] = \
+            v_ont_ani.v_ont_ani.data.expected_registration_id
+        balSubTermDgi_data['serial_number'] = \
+            v_ont_ani.v_ont_ani.data.expected_serial_number
+        balSubTermDgi_data['onu_id'] = onu_id.__str__()
+
+        self.handle_alarms(device_id, "onu",
+                           intf_id,
+                           "dgi_indication", dgi_status, "medium",
                            balSubTermDgi_data)
         if dgi_status == 1:
+            pon_port = self._get_pon_port_from_pref_chanpair_ref(
+                v_ont_ani.v_ont_ani.data.preferred_chanpair)
             child_device = self.adapter_agent.get_child_device(
-                           device_id, onu_id=onu_id,
-                           parent_port_no=intf_id)
+                device_id, onu_id=onu_id,
+                parent_port_no=pon_port)
             if child_device is None:
-               self.log.info('Onu-is-not-configured', onu_id=onu_id)
-               return
+                self.log.info('Onu-is-not-configured', onu_id=onu_id)
+                return
             msg = {'proxy_address': child_device.proxy_address,
                    'event': 'deactivate-onu', 'event_data': ind_info}
 
             # Send the event message to the ONU adapter
             self.adapter_agent.publish_inter_adapter_message(child_device.id,
-                                                                 msg)
+                                                             msg)
 
     def BalSubsTermLosAlarm(self, device_id, Iface_ID,
-                         los_status, SubTermAlarm_Data):
+                            los_status, SubTermAlarm_Data):
         self.log.info('ONU-Alarms-for-Subscriber-Terminal-LOS')
-        self.handle_alarms(device_id,"onu",\
-                           Iface_ID,\
-                           "ONU : Loss Of Signal",\
-                           los_status, "medium",\
+        self.handle_alarms(device_id, "onu",
+                           Iface_ID,
+                           "ONU : Loss Of Signal",
+                           los_status, "medium",
                            SubTermAlarm_Data)
 
     def BalSubsTermLobAlarm(self, device_id, Iface_ID,
-                         lob_status, SubTermAlarm_Data):
+                            lob_status, SubTermAlarm_Data):
         self.log.info('ONU-Alarms-for-Subscriber-Terminal-LOB')
-        self.handle_alarms(device_id,"onu",\
-                           Iface_ID,\
-                           "ONU : Loss Of Burst",\
-                           lob_status, "medium",\
+        self.handle_alarms(device_id, "onu",
+                           Iface_ID,
+                           "ONU : Loss Of Burst",
+                           lob_status, "medium",
                            SubTermAlarm_Data)
 
     def BalSubsTermLopcMissAlarm(self, device_id, Iface_ID,
-                         lopc_miss_status, SubTermAlarm_Data):
+                                 lopc_miss_status, SubTermAlarm_Data):
         self.log.info('ONU-Alarms-for-Subscriber-Terminal-LOPC-Miss')
-        self.handle_alarms(device_id,"onu",\
-                           Iface_ID,\
-                           "ONU : Loss Of PLOAM miss channel",\
-                           lopc_miss_status, "medium",\
+        self.handle_alarms(device_id, "onu",
+                           Iface_ID,
+                           "ONU : Loss Of PLOAM miss channel",
+                           lopc_miss_status, "medium",
                            SubTermAlarm_Data)
 
     def BalSubsTermLopcMicErrorAlarm(self, device_id, Iface_ID,
-                         lopc_mic_error_status, SubTermAlarm_Data):
+                                     lopc_mic_error_status, SubTermAlarm_Data):
         self.log.info('ONU-Alarms-for-Subscriber-Terminal-LOPC-Mic-Error')
-        self.handle_alarms(device_id,"onu",\
-                           Iface_ID,\
-                           "ONU : Loss Of PLOAM MIC Error",\
-                           lopc_mic_error_status, "medium",\
+        self.handle_alarms(device_id, "onu",
+                           Iface_ID,
+                           "ONU : Loss Of PLOAM MIC Error",
+                           lopc_mic_error_status, "medium",
                            SubTermAlarm_Data)
 
     def add_port(self, port_no, port_type, label):
@@ -866,36 +1061,33 @@
         self.log.info('deleting-port', port_no=port_no,
                       port_type=port_type, label=label)
         ports = self.adapter_agent.get_ports(self.device_id, port_type)
+        port = None
         for port in ports:
             if port.label == label:
                 break
-        self.adapter_agent.delete_port(self.device_id, port)
+        if port is not None:
+            self.adapter_agent.delete_port(self.device_id, port)
 
-    @inlineCallbacks
-    def add_logical_device(self, device_id):
+    def add_logical_device(self, device_id, asfvolt_system_info=None):
         self.log.info('adding-logical-device', device_id=device_id)
         # Initialze default values for dpid and serial_num
         dpid = None
         serial_num = self.host_and_port
 
-        try:
-            asfvolt_system_info = \
-                yield self.bal.get_asfvolt_system_info(device_id)
-            if asfvolt_system_info is not None:
-                if asfvolt_system_info.mac_address is not None:
-                    dpid = asfvolt_system_info.mac_address
-                if asfvolt_system_info.serial_num is not None:
-                    serial_num = asfvolt_system_info.serial_num
-        except Exception as e:
-            self.log.error('using-default-values', exc=str(e))
+        if asfvolt_system_info is not None:
+            dpid = asfvolt_system_info.mac_address
+            serial_num = asfvolt_system_info.serial_num
+        else:
+            self.log.info('using-default-values')
 
         ld = LogicalDevice(
             # not setting id and datapth_id will let the adapter
             # agent pick id
             desc=ofp_desc(
-                hw_desc='n/a',
-                sw_desc='logical device for Edgecore ASFvOLT16 OLT',
-                #serial_num=uuid4().hex,
+                mfr_desc='PMC GPON Networks',
+                hw_desc='PAS5211 v2',
+                sw_desc='vOLT version 1.5.3.9',
+                # serial_num=uuid4().hex,
                 serial_num=serial_num,
                 dp_desc='n/a'
             ),
@@ -903,10 +1095,10 @@
                 n_buffers=256,  # TODO fake for now
                 n_tables=2,  # TODO ditto
                 capabilities=(  # TODO and ditto
-                    OFPC_FLOW_STATS |
-                    OFPC_TABLE_STATS |
-                    OFPC_PORT_STATS |
-                    OFPC_GROUP_STATS
+                        OFPC_FLOW_STATS |
+                        OFPC_TABLE_STATS |
+                        OFPC_PORT_STATS |
+                        OFPC_GROUP_STATS
                 )
             ),
             root_device_id=device_id
@@ -959,66 +1151,54 @@
         else:
             self.log.error('invalid-port-type', port_type=port_type)
             return
-        logical_port = self.adapter_agent.get_logical_port(self.logical_device_id,
-                                                           label)
-        logical_port.ofp_port.state = state
-        self.adapter_agent.update_logical_port(self.logical_device_id,
-                                               logical_port)
+        try:
+            logical_port = self.adapter_agent.get_logical_port(
+                                    self.logical_device_id, label)
+            logical_port.ofp_port.state = state
+            self.adapter_agent.update_logical_port(self.logical_device_id,
+                                                   logical_port)
+        except KeyError as err:
+            self.log.error("no-logical-port-exist", err=err)
+            return
 
-    def handle_access_term_ind(self, ind_info, access_term_ind):
+    @inlineCallbacks
+    def handle_access_term_oper_status_change(self, ind_info):
         device = self.adapter_agent.get_device(self.device_id)
         if ind_info['activation_successful'] is True:
-            self.log.info('successful-access-terminal-Indication',
+            self.log.info('admin-oper-status-up',
                           olt_id=self.olt_id)
 
-            self.asfvolt_device_info.update_device_topology(access_term_ind)
-            self.asfvolt_device_info.update_device_software_info(access_term_ind)
-            self.asfvolt_device_info.read_and_build_device_sfp_presence_map()
-
-            # For all the detected NNI ports, create corresponding physical and
-            # logical ports on the device and logical device.
-            for port in self.asfvolt_device_info.sfp_device_presence_map.iterkeys():
-                if not self._valid_nni_port(port):
-                    continue
-                # We support only one NNI port.
-                self.nni_intf_id = (port -
-                                    self.asfvolt_device_info.
-                                    asfvolt16_device_topology.num_of_pon_ports)
-                break
-            self.add_port(port_no=self.nni_intf_id +
-                          MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM,
-                          port_type=Port.ETHERNET_NNI,
-                          label='NNI facing Ethernet port')
-            self.add_logical_port(port_no=self.nni_intf_id + \
-                                  MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM,
-                                  port_type=Port.ETHERNET_NNI,
-                                  device_id=device.id,
-                                  logical_device_id=self.logical_device_id,
-                                  port_state=OFPPS_LIVE)
-
-            self.log.info('OLT-activation-complete')
+            # We retrieve the access terminal configuration and
+            # create the ports the first time when device is provisioned
+            # and enabled.
+            yield self._retrieve_access_term_config()
+            self._create_device_ports()
 
             # heart beat - To health checkup of OLT
             if self.is_heartbeat_started == 0:
                 self.log.info('Heart-beat-is-not-yet-started-starting-now')
                 self.start_heartbeat()
 
-                self.pm_metrics=Asfvolt16OltPmMetrics(device, self.log)
+                self.pm_metrics = Asfvolt16OltPmMetrics(device, self.log)
                 pm_config = self.pm_metrics.make_proto()
                 self.log.info("initial-pm-config", pm_config=pm_config)
-                self.adapter_agent.update_device_pm_config(pm_config,init=True)
+                self.adapter_agent.update_device_pm_config(pm_config, init=True)
 
                 # Apply the PM configuration
                 self.update_pm_config(device, pm_config)
 
+                self.is_device_reachable = True
                 # Request PM counters(for NNI) from OLT device.
                 # intf_id:nni_port
-                self._handle_pm_counter_req_towards_device(device)
+                reactor.callInThread(self._handle_pm_counter_req_towards_device)
 
             device.connect_status = ConnectStatus.REACHABLE
             device.oper_status = OperStatus.ACTIVE
             device.reason = 'OLT activated successfully'
             self.adapter_agent.update_device(device)
+            self.is_device_reachable = True
+
+            self.log.info('OLT-activation-complete')
 
         elif ind_info['deactivation_successful'] is True:
             device.oper_status = OperStatus.FAILED
@@ -1029,7 +1209,6 @@
             device.reason = 'Failed to Intialize OLT'
             self.adapter_agent.update_device(device)
             reactor.callLater(15, self.activate, device)
-        return
 
     def start_heartbeat(self):
         reactor.callLater(0, self.heartbeat)
@@ -1042,8 +1221,8 @@
             # ENABLED and operation state is in Failed or Unkown
             self.log.info('Not-Yet-handled', olt_id=self.olt_id,
                           pon_ni=ind_info['_pon_id'], onu_data=ind_info)
-        elif ind_info['_sub_group_type'] == 'sub_term_indication' and \
-             ind_info['activation_successful'] == True:
+        elif ind_info['_sub_group_type'] == 'sub_term_op_state' and \
+                ind_info['activation_successful'] is True:
             pon_id = ind_info['_pon_id']
             self.log.info('handle_activated_onu', olt_id=self.olt_id,
                           pon_ni=pon_id, onu_data=ind_info)
@@ -1073,36 +1252,48 @@
         self.adapter_agent.publish_inter_adapter_message(child_device.id,
                                                          msg)
 
-    def handle_discovered_onu(self, child_device, ind_info):
+    @inlineCallbacks
+    def handle_sub_tem_oper_status_change_onu(self, child_device, ind_info,
+                                              sub_term_cfg=None):
         pon_id = ind_info['_pon_id']
         if ind_info['_sub_group_type'] == 'onu_discovery':
             self.log.info('Activation-is-in-progress', olt_id=self.olt_id,
                           pon_ni=pon_id, onu_data=ind_info,
                           onu_id=child_device.proxy_address.onu_id)
 
-        elif ind_info['_sub_group_type'] == 'sub_term_indication':
+        if ind_info['_sub_group_type'] == 'sub_term_op_state':
             self.log.info('ONU-activation-is-completed', olt_id=self.olt_id,
                           pon_ni=pon_id, onu_data=ind_info)
 
-            msg = {'proxy_address': child_device.proxy_address,
-                   'event': 'activation-completed', 'event_data': ind_info}
-
-            balSubTermInd = {}
-            serial_number=(ind_info['_vendor_id'] +
-                           ind_info['_vendor_specific'])
-            balSubTermInd["serial_number"] = serial_number.__str__()
-            balSubTermInd["registration_id"] = ind_info['registration_id'].__str__()
-            self.log.info('onu_activated:registration_id',balSubTermInd["registration_id"])
-            balSubTermInd["device_id"] = (self.device_id).__str__()
-
-            # Send the event message to the ONU adapter
-            self.adapter_agent.publish_inter_adapter_message(child_device.id,
-                                                             msg)
             if ind_info['activation_successful'] is True:
-                self.handle_alarms(self.device_id,"onu",\
-                       ind_info['_pon_id'],\
-                       "ONU_ACTIVATED",1,"high",\
-                       balSubTermInd)
+                if sub_term_cfg is None:
+                    sub_term_cfg = yield self.bal.get_subscriber_terminal_cfg(
+                        ind_info['onu_id'],
+                        ind_info['_pon_id']
+                    )
+
+                balSubTermInd = dict()
+                serial_number = sub_term_cfg.terminal.data.serial_number.vendor_id +\
+                                sub_term_cfg.terminal.data.serial_number.vendor_specific
+                balSubTermInd["serial_number"] = serial_number.__str__()
+                balSubTermInd["registration_id"] =\
+                    sub_term_cfg.terminal.data.registration_id[:36].__str__()
+                self.log.info('onu_activated:registration_id',
+                              balSubTermInd["registration_id"])
+                balSubTermInd["device_id"] = self.device_id.__str__()
+                if self.logical_device_id:
+                    balSubTermInd["datapath_id"] = self.get_datapath_id()
+
+                msg = {'proxy_address': child_device.proxy_address,
+                       'event': 'activation-completed', 'event_data': ind_info}
+                # Send the event message to the ONU adapter
+                self.adapter_agent.publish_inter_adapter_message(child_device.id,
+                                                                 msg)
+
+                self.handle_alarms(self.device_id, "onu",
+                                   ind_info['_pon_id'],
+                                   "ONU_ACTIVATED", 1, "medium",
+                                   balSubTermInd)
                 for key, v_ont_ani in self.v_ont_anis.items():
                     if v_ont_ani.v_ont_ani.data.onu_id == \
                             child_device.proxy_address.onu_id:
@@ -1123,17 +1314,37 @@
             self.log.info('Invalid-ONU-event', olt_id=self.olt_id,
                           pon_ni=ind_info['_pon_id'], onu_data=ind_info)
 
+    @inlineCallbacks
+    def handle_sub_term_oper_status_change(self, ind_info):
+        if ind_info['activation_successful'] is True:
+            sub_term_cfg = yield self.bal.get_subscriber_terminal_cfg(
+                ind_info['onu_id'],
+                ind_info['_pon_id']
+            )
+            serial_number = sub_term_cfg.terminal.data.serial_number.vendor_id + \
+                            sub_term_cfg.terminal.data.serial_number.vendor_specific
+            child_device = self.adapter_agent.get_child_device(
+                self.device_id,
+                serial_number=serial_number)
+            if child_device is None:
+                self.log.info('Onu-is-not-configured', olt_id=self.olt_id,
+                              pon_ni=ind_info['_pon_id'], onu_data=ind_info)
+                return
+            yield self.handle_sub_tem_oper_status_change_onu(child_device, ind_info,
+                                                             sub_term_cfg)
+
     onu_handlers = {
         OperStatus.UNKNOWN: handle_not_started_onu,
         OperStatus.FAILED: handle_not_started_onu,
         OperStatus.ACTIVATING: handle_activating_onu,
         OperStatus.ACTIVE: handle_activated_onu,
-        OperStatus.DISCOVERED: handle_discovered_onu,
+        OperStatus.DISCOVERED: handle_sub_tem_oper_status_change_onu,  # this never gets
+                                                                       # invoked.
     }
 
-    def handle_sub_term_ind(self, ind_info):
-        serial_number=(ind_info['_vendor_id'] +
-                           ind_info['_vendor_specific'])
+    def handle_sub_term_discovery(self, ind_info):
+        serial_number = (ind_info['_vendor_id'] +
+                         ind_info['_vendor_specific'])
         child_device = self.adapter_agent.get_child_device(
             self.device_id,
             serial_number=serial_number)
@@ -1141,13 +1352,15 @@
             self.log.info('Onu-is-not-configured', olt_id=self.olt_id,
                           pon_ni=ind_info['_pon_id'], onu_data=ind_info)
             if ind_info['_sub_group_type'] == 'onu_discovery':
-                balSubTermDisc = {}
+                balSubTermDisc = dict()
                 balSubTermDisc["serial_number"] = serial_number.__str__()
-                balSubTermDisc["device_id"] = (self.device_id).__str__()
-                self.handle_alarms(self.device_id,"onu",\
-                               ind_info['_pon_id'],\
-                               "ONU_DISCOVERED",1,"high",\
-                               balSubTermDisc)
+                balSubTermDisc["device_id"] = self.device_id.__str__()
+                if self.logical_device_id:
+                    balSubTermDisc["datapath_id"] = self.get_datapath_id()
+                self.handle_alarms(self.device_id, "onu",
+                                   ind_info['_pon_id'],
+                                   "ONU_DISCOVERED", 1, "medium",
+                                   balSubTermDisc)
             return
 
         handler = self.onu_handlers.get(child_device.oper_status)
@@ -1179,18 +1392,19 @@
             self.log.exception('', exc=str(e))
         return
 
-    def hex_format(self, regid):
+    @staticmethod
+    def hex_format(regid):
         ascii_regid = map(ord, regid)
-        size=len(ascii_regid)
+        size = len(ascii_regid)
         if size > 36:
             del ascii_regid[36:]
         else:
-            ascii_regid += (36-size) * [0]
+            ascii_regid += (36 - size) * [0]
         return ''.join('{:02x}'.format(e) for e in ascii_regid)
 
     def get_registration_id(self, data):
         if data.data.expected_registration_id is not None and \
-           len(data.data.expected_registration_id) > 0:
+                len(data.data.expected_registration_id) > 0:
             return self.hex_format(data.data.expected_registration_id)
         # default reg id
         return '202020202020202020202020202020202020202020202020202020202020202020202020'
@@ -1221,31 +1435,46 @@
                           onu_id=child_device.proxy_address.onu_id,
                           serial_number=serial_number)
 
+    @inlineCallbacks
     def delete_v_ont_ani(self, data):
-        serial_number = data.data.expected_serial_number
-        registration_id = self.get_registration_id(data)
-        child_device = self.adapter_agent.get_child_device(
-            self.device_id,
-            serial_number=serial_number)
-        if child_device is None:
-            self.log.info('Failed-to-find-ONU-Info',
-                          serial_number=serial_number)
-        elif child_device.admin_state == AdminState.ENABLED:
-            self.log.info('Deactivating ONU',
-                          serial_number=serial_number,
-                          onu_id=child_device.proxy_address.onu_id,
-                          pon_id=child_device.parent_port_no)
-            onu_info = dict()
-            onu_info['pon_id'] = child_device.parent_port_no
-            onu_info['onu_id'] = child_device.proxy_address.onu_id
-            onu_info['vendor'] = child_device.vendor_id
-            onu_info['vendor_specific'] = serial_number[4:]
-            onu_info['reg_id'] = registration_id
-            self.bal.deactivate_onu(onu_info)
-        else:
-            self.log.info('Invalid-ONU-state-to-deactivate',
-                          onu_id=child_device.proxy_address.onu_id,
-                          serial_number=serial_number)
+        try:
+            serial_number = data.data.expected_serial_number
+            registration_id = self.get_registration_id(data)
+            child_device = self.adapter_agent.get_child_device(
+                self.device_id,
+                serial_number=serial_number)
+            if child_device is None:
+                self.log.info('Failed-to-find-ONU-Info',
+                              serial_number=serial_number)
+            elif child_device.admin_state == AdminState.ENABLED:
+                self.log.info('deleteing-onu',
+                              serial_number=serial_number)
+                while self.kv_store.is_reference_found_for_key_value(
+                        self.device_id, "onu_id",
+                        child_device.proxy_address.onu_id):
+                    self.log.info("reference-still-found-for-onu-id")
+                    yield asleep(0.1)
+                self.log.info('Deactivating ONU',
+                              serial_number=serial_number,
+                              onu_id=child_device.proxy_address.onu_id,
+                              pon_id=child_device.parent_port_no)
+                onu_info = dict()
+                onu_info['pon_id'] = child_device.parent_port_no
+                onu_info['onu_id'] = child_device.proxy_address.onu_id
+                onu_info['vendor'] = child_device.vendor_id
+                onu_info['vendor_specific'] = serial_number[4:]
+                onu_info['reg_id'] = registration_id
+                yield asleep(2)
+                yield self.bal.deactivate_onu(onu_info)
+                yield asleep(2)
+                yield self.bal.delete_onu(onu_info)
+            else:
+                self.log.info('Invalid-ONU-state-to-deactivate',
+                              onu_id=child_device.proxy_address.onu_id,
+                              serial_number=serial_number)
+        except Exception as e:
+            self.log.exception('delete-vont-ani-failed', exc=str(e))
+        return
 
     @inlineCallbacks
     def create_interface(self, data):
@@ -1253,7 +1482,7 @@
             if isinstance(data, ChannelgroupConfig):
                 if data.name in self.channel_groups:
                     self.log.info('Channel-Group-already-present',
-                             channel_group=data)
+                                  channel_group=data)
                 else:
                     channel_group_config = ChannelgroupConfig()
                     channel_group_config.CopyFrom(data)
@@ -1261,7 +1490,7 @@
             if isinstance(data, ChannelpartitionConfig):
                 if data.name in self.channel_partitions:
                     self.log.info('Channel-partition-already-present',
-                             channel_partition=data)
+                                  channel_partition=data)
                 else:
                     channel_partition_config = ChannelpartitionConfig()
                     channel_partition_config.CopyFrom(data)
@@ -1270,16 +1499,16 @@
             if isinstance(data, ChannelpairConfig):
                 if data.name in self.channel_pairs:
                     self.log.info('Channel-pair-already-present',
-                             channel_pair=data)
+                                  channel_pair=data)
                 else:
                     channel_pair_config = ChannelpairConfig()
                     channel_pair_config.CopyFrom(data)
                     self.channel_pairs[data.name] = channel_pair_config
             if isinstance(data, ChannelterminationConfig):
-                max_pon_ports = self.asfvolt_device_info.\
-                        asfvolt16_device_topology.num_of_pon_ports
+                max_pon_ports = self.asfvolt_device_info. \
+                    asfvolt16_device_topology.num_of_pon_ports
                 if data.data.xgs_ponid > max_pon_ports:
-                    raise ValueError\
+                    raise ValueError \
                         ("pon_id-%u-is-greater-than-%u"
                          % (data.data.xgs_ponid, max_pon_ports))
 
@@ -1292,37 +1521,34 @@
                 if not self.reconcile_in_progress:
                     self.log.info('Activating-PON-port-at-OLT',
                                   pon_id=data.data.xgs_ponid)
+                    try:
+                        yield self.bal.activate_pon_port(
+                                   self.olt_id, data.data.xgs_ponid,
+                                   self.transceiver_type)
+                        yield self._add_port_config_to_queue(data)
+                    except Exception as e:
+                        self.log.exception("error-activating-pon-port", e=e)
+                        # Remove if by any chance we created an entry on the queue
+                        self._remove_port_config_from_queue()
+                        return
+                    else:
+                        self.add_port(port_no=data.data.xgs_ponid,
+                                      port_type=Port.PON_OLT,
+                                      label=data.name)
+                        if data.name in self.channel_terminations:
+                            self.log.info('Channel-termination-already-present',
+                                          channel_termination=data)
+                        else:
+                            channel_termination_config = ChannelterminationConfig()
+                            channel_termination_config.CopyFrom(data)
+                            self.channel_terminations[data.name] = \
+                                channel_termination_config
+                            self.log.info('channel-termnination-data',
+                                          data=data,
+                                          chan_term=self.channel_terminations)
 
-                    # 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)
-                    self.bal.activate_pon_port(self.olt_id, data.data.xgs_ponid,
-                                               self.transceiver_type)
-
-                if data.name in self.channel_terminations:
-                    self.log.info('Channel-termination-already-present',
-                                  channel_termination=data)
-                else:
-                    channel_termination_config = ChannelterminationConfig()
-                    channel_termination_config.CopyFrom(data)
-                    self.channel_terminations[data.name] = \
-                        channel_termination_config
-                    self.log.info('channel-termnination-data',
-                                   data=data,chan_term=self.channel_terminations)
             if isinstance(data, VOntaniConfig):
-                if data.data.onu_id > MAX_ONU_ID_PER_PON_PORT:
+                if data.data.onu_id >= MAX_ONU_ID_PER_PON_PORT:
                     self.log.error("invalid-onu-id", onu_id=data.data.onu_id)
                     raise Exception("onu-id-greater-than-{}-not-supported".
                                     format(data.data.onu_id))
@@ -1351,12 +1577,12 @@
                     # Add the port only if it didnt already exist. Each port
                     # has a unique label
                     self.adapter_agent.add_port(self.device_id, Port(
-                                                port_no=self._get_next_uni_port(),
-                                                label=data.interface.name,
-                                                type=Port.ETHERNET_UNI,
-                                                admin_state=AdminState.ENABLED,
-                                                oper_status=OperStatus.ACTIVE
-                                                ))
+                        port_no=self._get_next_uni_port(),
+                        label=data.interface.name,
+                        type=Port.ETHERNET_UNI,
+                        admin_state=AdminState.ENABLED,
+                        oper_status=OperStatus.ACTIVE
+                    ))
                 else:
                     # Usually happens during xpon replay after voltha reboot.
                     # The port already exists in vcore. We will not create again.
@@ -1384,11 +1610,13 @@
         return
 
     def update_interface(self, data):
-        self.log.info('Not-Implemented-yet')
+        self.log.info('Not-Implemented-yet', data=data)
         return
 
+    @inlineCallbacks
     def remove_interface(self, data):
         try:
+            self.log.info("remove_interface",data=data)
             if isinstance(data, ChannelgroupConfig):
                 if data.name in self.channel_groups:
                     del self.channel_groups[data.name]
@@ -1396,26 +1624,36 @@
                 if data.name in self.channel_partitions:
                     del self.channel_partitions[data.name]
             if isinstance(data, ChannelpairConfig):
-                    del self.channel_pairs[data.name]
+                del self.channel_pairs[data.name]
             if isinstance(data, ChannelterminationConfig):
                 if data.name in self.channel_terminations:
                     self.log.info('Deativating-PON-port-at-OLT',
                                   pon_id=data.data.xgs_ponid)
-                    self.del_port(label=data.name,
-                                  port_type=Port.PON_OLT,
-                                  port_no=data.data.xgs_ponid)
-                    self.bal.deactivate_pon_port(self.olt_id, data.data.xgs_ponid,
-                                                 self.transceiver_type)
-                    del self.channel_terminations[data.name]
+                    try:
+                        yield self.bal.deactivate_pon_port(
+                                           self.olt_id, data.data.xgs_ponid,
+                                           self.transceiver_type)
+                        yield self._add_port_config_to_queue(data)
+                    except Exception as e:
+                        self.log.exception("error-deactivating-pon-port", e=e)
+                        # Remove if by any chance we created an entry on the queue
+                        self._remove_port_config_from_queue()
+                    finally:
+                        # Delete the channel termination data anyway
+                        self.del_port(label=data.name,
+                                      port_type=Port.PON_OLT,
+                                      port_no=data.data.xgs_ponid)
+                        del self.channel_terminations[data.name]
             if isinstance(data, VOntaniConfig):
                 if data.name in self.v_ont_anis:
+                    self.log.info("deleting-vont-ani")
                     self.delete_v_ont_ani(data)
                     del self.v_ont_anis[data.name]
             if isinstance(data, VEnetConfig):
                 if data.name in self.v_enets:
                     self.log.info("deleting-port-at-olt")
                     self.del_port(label=data.interface.name,
-                                  port_type = Port.ETHERNET_UNI)
+                                  port_type=Port.ETHERNET_UNI)
                     del self.v_enets[data.name]
             if isinstance(data, OntaniConfig):
                 if data.name in self.ont_anis:
@@ -1432,14 +1670,15 @@
                 traffic_descriptor
         if tcont_data.interface_reference in self.v_ont_anis:
             v_ont_ani = self.v_ont_anis[tcont_data.interface_reference]
-            pon_port = self._get_pon_port_from_pref_chanpair_ref(\
-                          v_ont_ani.v_ont_ani.data.preferred_chanpair)
+            pon_port = self._get_pon_port_from_pref_chanpair_ref(
+                v_ont_ani.v_ont_ani.data.preferred_chanpair)
             onu_device = self.adapter_agent.get_child_device(
                 self.device_id,
                 onu_id=v_ont_ani.v_ont_ani.data.onu_id,
                 parent_port_no=pon_port)
-            if (onu_device is not None and
-                        onu_device.oper_status == OperStatus.ACTIVE):
+            self.log.debug("create-tcont-oper-status",
+                           oper_status=onu_device.oper_status)
+            if onu_device is not None:
                 owner_info = dict()
                 # To-Do: Right Now use alloc_id as schduler ID. Need to
                 # find way to generate uninqe number.
@@ -1448,7 +1687,52 @@
                 owner_info['intf_id'] = onu_device.proxy_address.channel_id
                 owner_info['onu_id'] = onu_device.proxy_address.onu_id
                 owner_info['alloc_id'] = tcont_data.alloc_id
+
+                # Enable the below code for Default Traffic Shaping
+                rate_info = dict()
+                rate_info['cir'] = traffic_descriptor_data.assured_bandwidth
+                rate_info['pir'] = traffic_descriptor_data.maximum_bandwidth
+                rate_info['burst'] = ASFVOLT16_MAX_BURST_BYTES_AT_PBR
+                priority = traffic_descriptor_data.priority
+                weight = traffic_descriptor_data.weight
+                ds_scheduler_id = self.get_sched_id('downstream',
+                                                    onu_device.proxy_address.channel_id)
+                queue_id = self.get_queue_id(onu_device.proxy_address.onu_id)
+
+                if ((traffic_descriptor_data.assured_bandwidth != 0) and
+                        (traffic_descriptor_data.maximum_bandwidth != 0)):
+                    self.bal.create_scheduler(id, 'upstream', owner_info, 8, rate_info)
+                    self.log.info('Creating-Queues with tdp data', queue_id=queue_id,
+                                  ds_scheduler_id=ds_scheduler_id)
+                    self.bal.create_queue(queue_id,
+                                          'downstream',
+                                          ds_scheduler_id,
+                                          priority=priority,
+                                          weight=weight,
+                                          rate_info=rate_info)
+                else:
+                    self.bal.create_scheduler(id, 'upstream', owner_info, 8)
+                    # Create the Queue for Downstream with Traffic Shaping Profile
+                    # To-Do: The rate_info for DS will be different from US,
+                    # would be considered when VOLTHA supports it
+                    self.bal.create_queue(queue_id,
+                                          'downstream',
+                                          ds_scheduler_id,
+                                          priority=priority,
+                                          weight=weight)
+                '''
+                #Disable the below code for Default Traffic Shaping
                 self.bal.create_scheduler(id, 'upstream', owner_info, 8)
+                weight = traffic_descriptor_data.weight
+                ds_scheduler_id = self.get_sched_id('downstream')
+                queue_id = self.get_queue_id(onu_device.proxy_address.onu_id)
+                self.log.info('Creating-Queues', queue_id=queue_id,
+                              ds_scheduler_id=ds_scheduler_id)
+                self.bal.create_queue(queue_id,
+                                     'downstream',
+                                      ds_scheduler_id,
+                                      weight=weight)
+                '''
             else:
                 self.log.info('Onu-is-not-configured', olt_id=self.olt_id,
                               intf_id=onu_device.proxy_address.channel_id,
@@ -1461,26 +1745,113 @@
                 tcont.CopyFrom(tcont_data)
                 v_ont_ani.tconts[tcont_data.name] = tcont
 
+    @inlineCallbacks
     def update_tcont(self, tcont_data, traffic_descriptor_data):
-        raise NotImplementedError()
+        if traffic_descriptor_data.name in self.traffic_descriptors:
+            traffic_descriptor = TrafficDescriptorProfileData()
+            traffic_descriptor.CopyFrom(traffic_descriptor_data)
+            self.traffic_descriptors[traffic_descriptor_data.name] = \
+                traffic_descriptor
+        if tcont_data.interface_reference in self.v_ont_anis:
+            v_ont_ani = self.v_ont_anis[tcont_data.interface_reference]
+            pon_port = self._get_pon_port_from_pref_chanpair_ref(
+                v_ont_ani.v_ont_ani.data.preferred_chanpair)
+            onu_device = self.adapter_agent.get_child_device(
+                self.device_id,
+                onu_id=v_ont_ani.v_ont_ani.data.onu_id,
+                parent_port_no=pon_port)
 
+            dba_sched_id = tcont_data.alloc_id
+            ds_scheduler_id = self.get_sched_id('downstream',
+                                                onu_device.proxy_address.channel_id)
+
+            queue_id = self.get_queue_id(onu_device.proxy_address.onu_id)
+
+            # As delete flow will be called as part of onos flow delete
+            # yield self.del_flow(onu_device, ASFVOLT_HSIA_ID,
+            #                     dba_sched_id=dba_sched_id,
+            #                     us_scheduler_id=us_scheduler_id,
+            #                     ds_scheduler_id=ds_scheduler_id,
+            #                     queue_id=queue_id)
+
+            owner_info = dict()
+            # To-Do: Right Now use alloc_id as schduler ID. Need to
+            # find way to generate uninqe number.
+            id = tcont_data.alloc_id
+            owner_info['type'] = 'agg_port'
+            owner_info['intf_id'] = onu_device.proxy_address.channel_id
+            owner_info['onu_id'] = onu_device.proxy_address.onu_id
+            owner_info['alloc_id'] = tcont_data.alloc_id
+
+            # Enable the below code for Default Traffic Shaping
+            rate_info = dict()
+            rate_info['cir'] = traffic_descriptor_data.assured_bandwidth
+            rate_info['pir'] = traffic_descriptor_data.maximum_bandwidth
+            rate_info['burst'] = ASFVOLT16_MAX_BURST_BYTES_AT_PBR
+
+            priority = traffic_descriptor_data.priority
+            weight = traffic_descriptor_data.weight
+
+            # Delete the Queue for Downstream
+            self.log.info('deleting-queue with tdp data', queue_id=queue_id,
+                          ds_scheduler_id=ds_scheduler_id)
+            yield self.bal.delete_queue(queue_id, 'downstream', ds_scheduler_id)
+            yield asleep(0.1)
+            self.log.info('creating-queue with tdp data', queue_id=queue_id,
+                          ds_scheduler_id=ds_scheduler_id)
+            yield self.bal.create_queue(queue_id,
+                                        'downstream',
+                                        ds_scheduler_id,
+                                        priority=priority,
+                                        weight=weight,
+                                        rate_info=rate_info)
+            yield asleep(0.1)
+            yield self.bal.delete_scheduler(dba_sched_id, 'upstream')
+            yield asleep(0.1)
+            yield self.bal.create_scheduler(id, 'upstream', owner_info, 8, rate_info)
+
+            '''
+            #Disable the below code for Default Traffic Shaping
+            yield self.bal.create_scheduler(id, 'upstream', owner_info, 8)
+
+            # Delete the Queue for Downstream
+            yield self.bal.delete_queue(queue_id, 'downstream', ds_scheduler_id)
+            yield asleep(0.1)
+            yield self.bal.create_queue(queue_id,
+                                       'downstream',
+                                        ds_scheduler_id,
+                                        weight=weight)
+            '''
+
+    @inlineCallbacks
     def remove_tcont(self, tcont_data, traffic_descriptor_data):
         if traffic_descriptor_data.name in self.traffic_descriptors:
             del self.traffic_descriptors[traffic_descriptor_data.name]
         if tcont_data.interface_reference in self.v_ont_anis:
             v_ont_ani = self.v_ont_anis[tcont_data.interface_reference]
-            pon_port = self._get_pon_port_from_pref_chanpair_ref(\
-                          v_ont_ani.v_ont_ani.data.preferred_chanpair)
+            pon_port = self._get_pon_port_from_pref_chanpair_ref(
+                v_ont_ani.v_ont_ani.data.preferred_chanpair)
             onu_device = self.adapter_agent.get_child_device(
                 self.device_id,
                 onu_id=v_ont_ani.v_ont_ani.data.onu_id,
                 parent_port_no=pon_port)
             # To-Do: Right Now use alloc_id as schduler ID. Need to
-            # find way to generate uninqe number.
+            # find way to generate unique number.
+
             id = tcont_data.alloc_id
+            while self.kv_store.is_reference_found_for_key_value(
+                    self.device_id, "dba_sched_id", id):
+                self.log.info("reference-still-found-for-dba-sched-id")
+                yield asleep(0.1)
+
             self.bal.delete_scheduler(id, 'upstream')
-            self.log.info('tcont-deleted-successfully',
-                          tcont_name=tcont_data.name)
+            ds_scheduler_id = self.get_sched_id('downstream',
+                                                onu_device.proxy_address.channel_id)
+            queue_id = self.get_queue_id(onu_device.proxy_address.onu_id)
+
+            # Delete the Queue for Downstream
+            self.bal.delete_queue(queue_id, 'downstream', ds_scheduler_id)
+
             if tcont_data.name in v_ont_ani.tconts:
                 del v_ont_ani.tconts[tcont_data.name]
 
@@ -1515,9 +1886,9 @@
                 self.delete_pon_id_and_gem_port_to_uni_port_map(
                     gem_port.gemport_id, v_enet
                 )
-                self.del_all_flow(v_enet)
+                # self.del_all_flow(v_enet)
                 del v_enet.gem_ports[data.name]
-                #To-Do Need to know what to do with flows.
+                # To-Do Need to know what to do with flows.
         else:
             self.log.info('VEnet-is-not-configured-yet.',
                           gem_port_info=data)
@@ -1528,22 +1899,22 @@
         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)
+            try:
+                yield self.bal.deactivate_pon_port(olt_no=self.olt_id,
+                                                   pon_port=pon_port,
+                                                   transceiver_type=
+                                                   self.transceiver_type)
+                yield self._add_port_config_to_queue(channel_termination)
+            except Exception as e:
+                self.log.exception("error-deactivating-pon-port", e=e)
+                # Remove if by any chance we created an entry on the queue
+                self._remove_port_config_from_queue()
+            else:
+                # Nothing to do
+                pass
 
         # deactivate olt
-        yield self.bal.deactivate_olt()
+        # yield self.bal.deactivate_olt()
 
         # disable all ports on the device
         self.adapter_agent.disable_all_ports(self.device_id)
@@ -1551,6 +1922,7 @@
         device.admin_state = AdminState.DISABLED
         device.oper_status = OperStatus.FAILED
         device.connect_status = ConnectStatus.UNREACHABLE
+
         self.adapter_agent.update_device(device)
         # deactivate nni port
         self.update_logical_port(self.nni_intf_id + MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM,
@@ -1558,12 +1930,12 @@
                                  OFPPS_LINK_DOWN)
 
         # disable child devices(onus)
-        for child_device in self.adapter_agent.\
+        for child_device in self.adapter_agent. \
                 get_child_devices(self.device_id):
             msg = {'proxy_address': child_device.proxy_address,
                    'event': 'olt-disabled'}
             if child_device.oper_status == OperStatus.ACTIVE and \
-               child_device.connect_status == ConnectStatus.REACHABLE:
+                    child_device.connect_status == ConnectStatus.REACHABLE:
                 self.adapter_agent.publish_inter_adapter_message(child_device.id,
                                                                  msg)
 
@@ -1576,18 +1948,16 @@
         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)
+            try:
+                yield self.bal.activate_pon_port(olt_no=self.olt_id,
+                                                 pon_port=pon_port,
+                                                 transceiver_type=
+                                                 self.transceiver_type)
+                yield self._add_port_config_to_queue(channel_termination)
+            except Exception as e:
+                self.log.exception("error-activating-pon-port", e=e)
+                # Remove if by any chance we created an entry on the queue
+                self._remove_port_config_from_queue()
 
         device.oper_status = OperStatus.ACTIVE
         device.connect_status = ConnectStatus.REACHABLE
@@ -1601,33 +1971,48 @@
                                  Port.ETHERNET_NNI,
                                  OFPPS_LIVE)
 
+        self.is_device_reachable = True
         # enable child devices(onus)
-        for child_device in self.adapter_agent.\
+        for child_device in self.adapter_agent. \
                 get_child_devices(self.device_id):
             msg = {'proxy_address': child_device.proxy_address,
                    'event': 'olt-enabled'}
             if child_device.oper_status == OperStatus.ACTIVE and \
-               child_device.connect_status == ConnectStatus.UNREACHABLE:
+                    child_device.connect_status == ConnectStatus.UNREACHABLE:
                 # Send the event message to the ONU adapter
                 self.adapter_agent.publish_inter_adapter_message(child_device.id,
                                                                  msg)
 
     def delete(self):
+        # Remove the logical device
+        logical_device = self.adapter_agent.get_logical_device(
+            self.logical_device_id)
+        if logical_device is not None:
+            self.adapter_agent.delete_logical_device(logical_device)
         super(Asfvolt16Handler, self).delete()
 
     def handle_packet_in(self, ind_info):
         self.log.info('Received-Packet-In', ind_info=ind_info)
-        logical_port = self.get_logical_port_from_pon_id_and_gem_port(
-            ind_info['intf_id'],
-            ind_info['svc_port'])
-        if not logical_port:
-            self.log.error("uni-logical_port-not-found")
-            return
+        # LLDP packet trap from the NNI port is a special case.
+        # The logical port cannot be derived from the pon_id and
+        # gem_port. But, the BAL flow_id for the LLDP packet is
+        # fixed. Hence, check this flow_id and do the necessary
+        # handling.
+        if ind_info['flow_id'] == ASFVOLT16_LLDP_DL_FLOW_ID:
+            logical_port = MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM + \
+                           ind_info['intf_id']
+        else:
+            logical_port = self.get_logical_port_from_pon_id_and_gem_port(
+                ind_info['intf_id'],
+                ind_info['svc_port'])
+            if not logical_port:
+                self.log.error("uni-logical_port-not-found")
+                return
         pkt = Ether(ind_info['packet'])
         kw = dict(
-                  logical_device_id=self.logical_device_id,
-                  logical_port_no=logical_port,
-                  )
+            logical_device_id=self.logical_device_id,
+            logical_port_no=logical_port,
+        )
         self.log.info('sending-packet-in', **kw)
         self.adapter_agent.send_packet_in(packet=str(pkt), **kw)
 
@@ -1641,10 +2026,9 @@
         if pkt.haslayer(Dot1Q):
             outer_shim = pkt.getlayer(Dot1Q)
             if isinstance(outer_shim.payload, Dot1Q):
-                inner_shim = outer_shim.payload
                 payload = (
-                    Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
-                    outer_shim.payload
+                        Ether(src=pkt.src, dst=pkt.dst, type=outer_shim.type) /
+                        outer_shim.payload
                 )
             else:
                 payload = pkt
@@ -1656,8 +2040,8 @@
                       packet=str(payload).encode("HEX"))
         send_pkt = binascii.unhexlify(str(payload).encode("HEX"))
 
-        if egress_port >= MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM and \
-           egress_port <= MAX_ASFVOLT_NNI_LOGICAL_PORT_NUM:
+        if MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM <= egress_port \
+                <= MAX_ASFVOLT_NNI_LOGICAL_PORT_NUM:
             pkt_info['dest_type'] = 'nni'
             # BAL expects NNI intf_id to be between 0 to 15.
             pkt_info['intf_id'] = egress_port - MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM
@@ -1665,7 +2049,6 @@
             send_pkt = binascii.unhexlify(str(pkt).encode("HEX"))
         else:
             port_id = 'uni-{}'.format(egress_port)
-            logical_port = None
             logical_port = \
                 self.adapter_agent.get_logical_port(self.logical_device_id,
                                                     port_id)
@@ -1687,156 +2070,344 @@
 
         self.bal.packet_out(send_pkt, pkt_info)
 
-    def update_flow_table(self, flows):
-        device = self.adapter_agent.get_device(self.device_id)
-        self.log.info('bulk-flow-update', device_id=self.device_id)
+    @inlineCallbacks
+    def add_bal_flow(self, flow):
+        self.log.debug('bal-flow-to-add', device_id=self.device_id, flow=flow)
+        classifier_info = dict()
+        action_info = dict()
+        is_down_stream = None
+        _in_port = None
+        try:
+            _in_port = fd.get_in_port(flow)
+            assert _in_port is not None
+            # Right now there is only one NNI port. Get the NNI PORT and compare
+            # with IN_PUT port number. Need to find better way.
+            ports = self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_NNI)
+            for port in ports:
+                if port.port_no == _in_port:
+                    self.log.info('downstream-flow')
+                    is_down_stream = True
+                    break
+            if is_down_stream is None:
+                is_down_stream = False
+                self.log.info('upstream-flow')
 
-        for flow in flows:
-            self.log.info('flow-details', device_id=self.device_id, flow=flow)
-            classifier_info = dict()
-            action_info = dict()
-            is_down_stream = None
-            _in_port = None
-            try:
-                _in_port = fd.get_in_port(flow)
-                assert _in_port is not None
-                # Right now there is only one NNI port. Get the NNI PORT and compare
-                # with IN_PUT port number. Need to find better way.
-                ports = self.adapter_agent.get_ports(device.id, Port.ETHERNET_NNI)
+            _out_port = fd.get_out_port(flow)  # may be None
+            self.log.info('out-port', out_port=_out_port)
 
+            for field in fd.get_ofb_fields(flow):
+                classifier_info['cookie'] = flow.cookie
+
+                if field.type == fd.ETH_TYPE:
+                    classifier_info['eth_type'] = field.eth_type
+                    self.log.info('field-type-eth-type',
+                                  eth_type=classifier_info['eth_type'])
+
+                elif field.type == fd.IP_PROTO:
+                    classifier_info['ip_proto'] = field.ip_proto
+                    self.log.info('field-type-ip-proto',
+                                  ip_proto=classifier_info['ip_proto'])
+
+                elif field.type == fd.IN_PORT:
+                    classifier_info['in_port'] = field.port
+                    self.log.info('field-type-in-port',
+                                  in_port=classifier_info['in_port'])
+
+                elif field.type == fd.VLAN_VID:
+                    classifier_info['vlan_vid'] = field.vlan_vid & 0xfff
+                    self.log.info('field-type-vlan-vid',
+                                  vlan=classifier_info['vlan_vid'])
+
+                elif field.type == fd.VLAN_PCP:
+                    classifier_info['vlan_pcp'] = field.vlan_pcp
+                    self.log.info('field-type-vlan-pcp',
+                                  pcp=classifier_info['vlan_pcp'])
+
+                elif field.type == fd.UDP_DST:
+                    classifier_info['udp_dst'] = field.udp_dst
+                    self.log.info('field-type-udp-dst',
+                                  udp_dst=classifier_info['udp_dst'])
+
+                elif field.type == fd.UDP_SRC:
+                    classifier_info['udp_src'] = field.udp_src
+                    self.log.info('field-type-udp-src',
+                                  udp_src=classifier_info['udp_src'])
+
+                elif field.type == fd.IPV4_DST:
+                    classifier_info['ipv4_dst'] = field.ipv4_dst
+                    self.log.info('field-type-ipv4-dst',
+                                  ipv4_dst=classifier_info['ipv4_dst'])
+
+                elif field.type == fd.IPV4_SRC:
+                    classifier_info['ipv4_src'] = field.ipv4_src
+                    self.log.info('field-type-ipv4-src',
+                                  ipv4_dst=classifier_info['ipv4_src'])
+
+                elif field.type == fd.METADATA:
+                    classifier_info['metadata'] = field.table_metadata
+                    self.log.info('field-type-metadata',
+                                  metadata=classifier_info['metadata'])
+
+                else:
+                    raise NotImplementedError('field.type={}'.format(
+                        field.type))
+
+            for action in fd.get_actions(flow):
+                if action.type == fd.OUTPUT:
+                    action_info['output'] = action.output.port
+                    self.log.info('action-type-output',
+                                  output=action_info['output'],
+                                  in_port=classifier_info['in_port'])
+
+                elif action.type == fd.POP_VLAN:
+                    action_info['pop_vlan'] = True
+                    self.log.info('action-type-pop-vlan', in_port=_in_port)
+
+                elif action.type == fd.PUSH_VLAN:
+                    action_info['push_vlan'] = True
+                    action_info['tpid'] = action.push.ethertype
+                    self.log.info('action-type-push-vlan',
+                                  push_tpid=action_info['tpid'],
+                                  in_port=_in_port)
+                    if action.push.ethertype != 0x8100:
+                        self.log.error('unhandled-tpid',
+                                       ethertype=action.push.ethertype)
+
+                elif action.type == fd.SET_FIELD:
+                    # action_info['action_type'] = 'set_field'
+                    _field = action.set_field.field.ofb_field
+                    assert (action.set_field.field.oxm_class ==
+                            OFPXMC_OPENFLOW_BASIC)
+                    self.log.info('action-type-set-field',
+                                  field=_field, in_port=_in_port)
+                    if _field.type == fd.VLAN_VID:
+                        self.log.info('set-field-type-vlan-vid',
+                                      vlan_vid=_field.vlan_vid & 0xfff)
+                        action_info['vlan_vid'] = (_field.vlan_vid & 0xfff)
+                    else:
+                        self.log.error('unsupported-action-set-field-type',
+                                       field_type=_field.type)
+                else:
+                    self.log.error('unsupported-action-type',
+                                   action_type=action.type, in_port=_in_port)
+
+            if is_down_stream is False:
+                found = False
+                ports = self.adapter_agent.get_ports(self.device_id,
+                                                     Port.ETHERNET_UNI)
                 for port in ports:
-                    if (port.port_no == _in_port):
-                        self.log.info('downstream-flow')
-                        is_down_stream = True
+                    if port.port_no == classifier_info['in_port']:
+                        found = True
                         break
-                if is_down_stream is None:
-                    is_down_stream = False
-                    self.log.info('upstream-flow')
+                if found is True:
+                    v_enet = self.get_venet(name=port.label)
+                else:
+                    self.log.error('Failed-to-get-v_enet-info',
+                                   in_port=classifier_info['in_port'])
+                    return
+                yield self.divide_and_add_flow(v_enet, classifier_info,
+                                               action_info, flow.priority)
+            elif is_down_stream:
+                yield self.add_downstream_only_flow(classifier_info, action_info)
 
-                _out_port = fd.get_out_port(flow)  # may be None
-                self.log.info('out-port', out_port=_out_port)
+        except Exception as e:
+            self.log.exception('failed-to-add-bal-flow', e=e, flow=flow)
 
-                for field in fd.get_ofb_fields(flow):
+    @inlineCallbacks
+    def remove_bal_flow(self, flow):
+        self.log.debug('bal-flow-to-remove', device_id=self.device_id, flow=flow)
 
-                    if field.type == fd.ETH_TYPE:
-                        classifier_info['eth_type'] = field.eth_type
-                        self.log.info('field-type-eth-type',
-                                      eth_type=classifier_info['eth_type'])
+        try:
+            if flow['direction'] == "BIDIRECTIONAL":
+                flow_id = flow['bal_flow_id']
+                onu_id = flow['onu_id']
+                intf_id = flow['intf_id']
+                gemport_id = flow['gemport_id']
+                priority = flow['priority']
+                queue_id = flow['queue_id']
+                ds_scheduler_id = flow['ds_scheduler_id']
+                us_scheduler_id = flow['us_scheduler_id']
+                dba_sched_id = flow['dba_sched_id']
+                stag = flow['stag']
+                ctag = flow['ctag']
 
-                    elif field.type == fd.IP_PROTO:
-                        classifier_info['ip_proto'] = field.ip_proto
-                        self.log.info('field-type-ip-proto',
-                                      ip_proto=classifier_info['ip_proto'])
+                # Deactivating and deleting downlink flow
+                is_down_stream = True
+                yield self.bal.deactivate_flow(flow_id,
+                                               is_down_stream,
+                                               onu_id=onu_id, intf_id=intf_id,
+                                               network_int_id=self.nni_intf_id,
+                                               gemport_id=gemport_id,
+                                               priority=priority,
+                                               stag=stag, ctag=ctag,
+                                               ds_scheduler_id=ds_scheduler_id,
+                                               queue_id=queue_id)
+                yield asleep(0.1)
+                yield self.bal.delete_flow(flow_id, is_down_stream)
+                yield asleep(0.1)
 
-                    elif field.type == fd.IN_PORT:
-                        classifier_info['in_port'] = field.port
-                        self.log.info('field-type-in-port',
-                                      in_port=classifier_info['in_port'])
+                # Deactivating and deleting uplink flow
+                is_down_stream = False
+                yield self.bal.deactivate_flow(flow_id,
+                                               is_down_stream, onu_id=onu_id,
+                                               intf_id=intf_id,
+                                               network_int_id=self.nni_intf_id,
+                                               gemport_id=gemport_id,
+                                               priority=priority,
+                                               stag=stag, ctag=ctag,
+                                               dba_sched_id=dba_sched_id,
+                                               us_scheduler_id=us_scheduler_id)
+                yield asleep(0.1)
+                yield self.bal.delete_flow(flow_id, is_down_stream)
+                yield asleep(0.1)
 
-                    elif field.type == fd.VLAN_VID:
-                        classifier_info['vlan_vid'] = field.vlan_vid & 0xfff
-                        self.log.info('field-type-vlan-vid',
-                                      vlan=classifier_info['vlan_vid'])
+            elif flow['direction'] == "DOWNSTREAM":
+                flow_id = flow['bal_flow_id']
+                is_down_stream = True
+                # deactivate_flow has generic flow deactivation handling
+                # Used this to deactivate LLDP flow
+                yield self.bal.deactivate_flow(flow_id=flow_id,
+                                               is_downstream=is_down_stream,
+                                               network_int_id=self.nni_intf_id)
+                yield asleep(0.1)
+                yield self.bal.delete_flow(flow_id, is_down_stream)
+                yield asleep(0.1)
+            else:
+                self.log.debug("flow-currently-not-supported")
 
-                    elif field.type == fd.VLAN_PCP:
-                        classifier_info['vlan_pcp'] = field.vlan_pcp
-                        self.log.info('field-type-vlan-pcp',
-                                      pcp=classifier_info['vlan_pcp'])
+        except Exception as e:
+            self.log.exception("error-removing-flows", e=e)
 
-                    elif field.type == fd.UDP_DST:
-                        classifier_info['udp_dst'] = field.udp_dst
-                        self.log.info('field-type-udp-dst',
-                                      udp_dst=classifier_info['udp_dst'])
+    @inlineCallbacks
+    def add_to_flow_table(self, flows):
+        # Twisted code is not inherently thread safe. This API could
+        # be invoked again by reactor while previous one is in progress.
+        # Since we maintain some stateful information here, we better
+        # synchronize parallel invocations on this API.
+        yield self._wait_for_previous_flow_config_to_finish()
+        self.flow_config_in_progress = True
 
-                    elif field.type == fd.UDP_SRC:
-                        classifier_info['udp_src'] = field.udp_src
-                        self.log.info('field-type-udp-src',
-                                      udp_src=classifier_info['udp_src'])
+        try:
+            self.log.debug('incremental-add-flow-update', device_id=self.device_id, flows=flows)
 
-                    elif field.type == fd.IPV4_DST:
-                        classifier_info['ipv4_dst'] = field.ipv4_dst
-                        self.log.info('field-type-ipv4-dst',
-                                      ipv4_dst=classifier_info['ipv4_dst'])
+            # Add the flows
+            flows_to_add = self.kv_store.get_flows_to_add(self.device_id, flows)
+            self.log.debug("incremental-flows-to-add", flows_to_add=flows_to_add)
+            for flow in flows:
+                if flow.cookie not in flows_to_add:
+                    continue
 
-                    elif field.type == fd.IPV4_SRC:
-                        classifier_info['ipv4_src'] = field.ipv4_src
-                        self.log.info('field-type-ipv4-src',
-                                      ipv4_dst=classifier_info['ipv4_src'])
+                self.log.debug("incremental-flow-to-add", flow_to_add=flow)
+                yield self.add_bal_flow(flow)
 
-                    elif field.type == fd.METADATA:
-                        classifier_info['metadata'] = field.table_metadata
-                        self.log.info('field-type-metadata',
-                                      metadata=classifier_info['metadata'])
+        except Exception as e:
+            self.log.exception("error-flow-adding-to-flowtable", e=e)
 
-                    else:
-                        raise NotImplementedError('field.type={}'.format(
-                            field.type))
+        try:
+            self.kv_store.add_to_kv_store(self.device_id, self.flow_mapping_list)
+            del self.flow_mapping_list[:]
+        except Exception as e:
+            self.log.exception("error-flow-adding-to-kv-store", e=e)
 
-                for action in fd.get_actions(flow):
+        self.flow_config_in_progress = False
 
-                    if action.type == fd.OUTPUT:
-                        action_info['output'] = action.output.port
-                        self.log.info('action-type-output',
-                                      output=action_info['output'],
-                                      in_port=classifier_info['in_port'])
+    @inlineCallbacks
+    def remove_from_flow_table(self, flows):
+        # Twisted code is not inherently thread safe. This API could
+        # be invoked again by reactor while previous one is in progress.
+        # Since we maintain some stateful information here, we better
+        # synchronize parallel invocations on this API.
+        yield self._wait_for_previous_flow_config_to_finish()
+        self.flow_config_in_progress = True
+        flows_to_remove_cookie_list = list()
 
-                    elif action.type == fd.POP_VLAN:
-                        action_info['pop_vlan'] = True
-                        self.log.info('action-type-pop-vlan',
-                                      in_port=_in_port)
+        try:
+            self.log.debug('incremental-remove-flow-update', device_id=self.device_id, flows=flows)
 
-                    elif action.type == fd.PUSH_VLAN:
-                        action_info['push_vlan'] = True
-                        action_info['tpid'] = action.push.ethertype
-                        self.log.info('action-type-push-vlan',
-                                      push_tpid=action_info['tpid'],
-                                      in_port=_in_port)
-                        if action.push.ethertype != 0x8100:
-                            self.log.error('unhandled-tpid',
-                                           ethertype=action.push.ethertype)
+            # Getting the flows to remove from kv, to get other details 
+            flows_to_remove = self.kv_store.get_flows_to_remove_info(self.device_id, flows)
+            self.log.debug("incremental-flows-to-remove", flow_to_remove=flows_to_remove)
+            # for each flow in flows_to_remove execute a command towards bal
+            for flow in flows_to_remove:
+                flows_to_remove_cookie_list.append(flow.keys()[0])
+                yield self.remove_bal_flow(flow.values()[0])
+                yield asleep(0.2)
+        except Exception as e:
+            self.log.exception("error-flow-removing-from-flowtable", e=e)
 
-                    elif action.type == fd.SET_FIELD:
-                        # action_info['action_type'] = 'set_field'
-                        _field = action.set_field.field.ofb_field
-                        assert (action.set_field.field.oxm_class ==
-                                OFPXMC_OPENFLOW_BASIC)
-                        self.log.info('action-type-set-field',
-                                      field=_field, in_port=_in_port)
-                        if _field.type == fd.VLAN_VID:
-                            self.log.info('set-field-type-vlan-vid',
-                                          vlan_vid=_field.vlan_vid & 0xfff)
-                            action_info['vlan_vid'] = (_field.vlan_vid & 0xfff)
-                        else:
-                            self.log.error('unsupported-action-set-field-type',
-                                           field_type=_field.type)
-                    else:
-                        self.log.error('unsupported-action-type',
-                                       action_type=action.type, in_port=_in_port)
+        try:
+            self.log.debug("flows-to-remove-cookie-list",
+                           flows_to_remove_cookie_list=flows_to_remove_cookie_list)
+            self.kv_store.remove_from_kv_store(self.device_id, flows_to_remove_cookie_list)
+        except Exception as e:
+            self.log.exception("error-flow-removing-from-kv-store", e=e)
 
-                if is_down_stream is False:
-                    found = False
-                    ports = self.adapter_agent.get_ports(self.device_id,
-                                                         Port.ETHERNET_UNI)
-                    for port in ports:
-                        if port.port_no == classifier_info['in_port']:
-                            found = True
-                            break
-                    if found is True:
-                        v_enet = self.get_venet(name=port.label)
-                    else:
-                        self.log.error('Failed-to-get-v_enet-info',
-                                       in_port=classifier_info['in_port'])
-                        return
-                    self.divide_and_add_flow(v_enet, classifier_info, action_info)
-            except Exception as e:
-                self.log.exception('failed-to-install-flow', e=e, flow=flow)
+        self.flow_config_in_progress = False
+
+    @inlineCallbacks
+    def update_flow_table(self, flows):
+        # Twisted code is not inherently thread safe. This API could
+        # be invoked again by reactor while previous one is in progress.
+        # Since we maintain some stateful information here, we better
+        # synchronize parallel invocations on this API.
+        yield self._wait_for_previous_flow_config_to_finish()
+        self.flow_config_in_progress = True
+
+        try:
+            device = self.adapter_agent.get_device(self.device_id)
+            self.log.debug('bulk-flow-update', device_id=self.device_id, flows=flows)
+            bulk_update_flow_cookie_list = [flow.cookie for flow in flows]
+            self.log.debug('bulk-flow-update-cookie', flows_cookie=bulk_update_flow_cookie_list)
+
+        except Exception as e:
+            self.log.exception("error-computing-flows", e=e)
+            self.flow_config_in_progress = False
+            return
+
+        # Removing the flows
+        try:
+            # for each flow in flows_to_remove execute a command towards bal
+            flows_to_remove = self.kv_store.get_flows_to_remove(self.device_id, flows)
+            self.log.debug("bulks-flows-to-remove", flows_to_remove=flows_to_remove)
+            for flow in flows_to_remove:
+                yield self.remove_bal_flow(flow)
+
+        except Exception as e:
+            self.log.exception("error-removing-bal-flows", e=e)
+
+        # Add the flows
+        try:
+            flows_to_add = self.kv_store.get_flows_to_add(self.device_id, flows)
+            self.log.debug("bulk-flows-to-add", flows_to_add=flows_to_add)
+            for flow in flows:
+                if flow.cookie not in flows_to_add:
+                    continue
+
+                self.log.debug("bulk-flow-to-add", flow_to_add=flow)
+                yield self.add_bal_flow(flow)
+
+        except Exception as e:
+            self.log.exception("error-adding-bal-flows", e=e)
+
+        self.kv_store.update_kv_store(self.device_id, self.flow_mapping_list, flows)
+
+        del self.flow_mapping_list[:]
+        self.flow_config_in_progress = False
 
     # This function will divide the upstream flow into both
     # upstreand and downstream flow, as broadcom devices
     # expects down stream flows to be added to handle
     # packet_out messge from controller.
     @inlineCallbacks
-    def divide_and_add_flow(self, v_enet, classifier, action):
+    def divide_and_add_flow(self, v_enet, classifier, action, priority):
+        flow_classifier_set = set(classifier.keys())
+        flow_action_set = set(action.keys())
+
+        self.log.debug('flow_classifier_set',
+                       flow_classifier_set=flow_classifier_set)
+        self.log.debug('flow_action_set',
+                       flow_action_set=flow_action_set)
+
         if 'ip_proto' in classifier:
             if classifier['ip_proto'] == 17:
                 yield self.prepare_and_add_dhcp_flow(classifier, action, v_enet,
@@ -1860,13 +2431,28 @@
                                     ASFVOLT_DOWNLINK_EAPOL_ID,
                                     ASFVOLT16_DEFAULT_VLAN)
         elif 'push_vlan' in action:
-            yield self.del_eapol_flow(v_enet, ASFVOLT_EAPOL_ID,
-                                ASFVOLT_DOWNLINK_EAPOL_ID,
-                                ASFVOLT16_DEFAULT_VLAN)
-            yield self.prepare_and_add_eapol_flow(classifier, action, v_enet,
-                                           ASFVOLT_EAPOL_ID_DATA_VLAN,
-                                           ASFVOLT_DOWNLINK_EAPOL_ID_DATA_VLAN)
-            yield self.add_data_flow(classifier, action, v_enet)
+            if classifier['vlan_vid'] != RESERVED_VLAN_ID:
+                yield self.del_eapol_flow(v_enet, ASFVOLT_EAPOL_ID,
+                                          ASFVOLT_DOWNLINK_EAPOL_ID,
+                                          ASFVOLT16_DEFAULT_VLAN)
+                yield self.prepare_and_add_eapol_flow(classifier, action, v_enet,
+                                                      ASFVOLT_EAPOL_ID_DATA_VLAN,
+                                                      ASFVOLT_DOWNLINK_EAPOL_ID_DATA_VLAN)
+            yield self.add_data_flow(classifier, action, v_enet, priority)
+        else:
+            self.log.info('Invalid-flow-type-to-handle',
+                          classifier=classifier,
+                          action=action)
+
+    @inlineCallbacks
+    def add_downstream_only_flow(self, classifier, action):
+        if 'ip_proto' in classifier:
+            pass
+        elif 'eth_type' in classifier:
+            if classifier['eth_type'] == 35020:  # 0x88cc
+                yield self.add_lldp_downstream_flow(classifier, action)
+        elif 'push_vlan' in action:
+            pass
         else:
             self.log.info('Invalid-flow-type-to-handle',
                           classifier=classifier,
@@ -1884,7 +2470,7 @@
         eapol_action['push_vlan'] = True
         eapol_action['vlan_vid'] = data_action['vlan_vid']
         yield self.add_eapol_flow(eapol_classifier, eapol_action, v_enet,
-                           eapol_id, downlink_eapol_id, data_classifier['vlan_vid'])
+                                  eapol_id, downlink_eapol_id, data_classifier['vlan_vid'])
 
     @inlineCallbacks
     def add_eapol_flow(self, uplink_classifier, uplink_action,
@@ -1913,8 +2499,8 @@
             self.log.info('Failed-to-get-tcont-info',
                           tcont=gem_port.tcont_ref)
             return
-        pon_port = self._get_pon_port_from_pref_chanpair_ref(\
-                      v_ont_ani.v_ont_ani.data.preferred_chanpair)
+        pon_port = self._get_pon_port_from_pref_chanpair_ref(
+            v_ont_ani.v_ont_ani.data.preferred_chanpair)
         onu_device = self.adapter_agent.get_child_device(
             self.device_id, onu_id=v_ont_ani.v_ont_ani.data.onu_id,
             parent_port_no=pon_port)
@@ -1922,7 +2508,8 @@
             self.log.info('Failed-to-get-onu-device',
                           onu_id=v_ont_ani.v_ont_ani.data.onu_id)
             return
-
+        queue_id = ASFVOLT16_DEFAULT_QUEUE_ID_START
+        scheduler_id = self.get_sched_id('upstream', self.nni_intf_id)
         flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
                                    onu_device.proxy_address.channel_id,
                                    uplink_eapol_id)
@@ -1940,11 +2527,13 @@
                           flow_id=flow_id,
                           sched_info=tcont.alloc_id)
             yield self.bal.add_flow(onu_device.proxy_address.onu_id,
-                              onu_device.proxy_address.channel_id, self.nni_intf_id,
-                              flow_id, gem_port.gemport_id,
-                              uplink_classifier, is_down_stream,
-                              action_info=uplink_action,
-                              sched_id=tcont.alloc_id)
+                                    onu_device.proxy_address.channel_id, self.nni_intf_id,
+                                    flow_id, gem_port.gemport_id,
+                                    uplink_classifier, is_down_stream,
+                                    action_info=uplink_action,
+                                    dba_sched_id=tcont.alloc_id,
+                                    queue_id=queue_id,
+                                    queue_sched_id=scheduler_id)
             # To-Do. While addition of one flow is in progress,
             # we cannot add an another flow. Right now use sleep
             # of 0.1 sec, assuming that addtion of flow is successful.
@@ -1957,6 +2546,7 @@
                                intf_id=onu_device.proxy_address.channel_id)
 
         # Add Downstream EAPOL Flow.
+        scheduler_id = self.get_sched_id('downstream', onu_device.proxy_address.channel_id)
         downlink_flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
                                             onu_device.proxy_address.channel_id,
                                             downlink_eapol_id)
@@ -1967,14 +2557,16 @@
         try:
             self.log.info('Adding-Downstream-EAPOL-flow',
                           classifier=downlink_classifier,
-                          action_info=downlink_action,
+                          action=downlink_action,
                           gem_port=gem_port,
                           flow_id=downlink_flow_id,
                           sched_info=tcont.alloc_id)
             yield self.bal.add_flow(onu_device.proxy_address.onu_id,
-                              onu_device.proxy_address.channel_id, self.nni_intf_id,
-                              downlink_flow_id, gem_port.gemport_id,
-                              downlink_classifier, is_down_stream)
+                                    onu_device.proxy_address.channel_id, self.nni_intf_id,
+                                    downlink_flow_id, gem_port.gemport_id,
+                                    downlink_classifier, is_down_stream,
+                                    queue_id=queue_id,
+                                    queue_sched_id=scheduler_id)
             # To-Do. While addition of one flow is in progress,
             # we cannot add an another flow. Right now use sleep
             # of 0.1 sec, assuming that addtion of flow is successful.
@@ -1987,8 +2579,56 @@
                                intf_id=onu_device.proxy_address.channel_id)
 
     @inlineCallbacks
+    def add_lldp_downstream_flow(self, downlink_classifier, downlink_action):
+        is_downstream = True
+
+        if downlink_action['output'] & 0x7fffffff == ofp.OFPP_CONTROLLER:
+            downlink_action['trap_to_host'] = True
+        else:
+            self.log.error("lldp-trap-to-host-rule-only-supported-now")
+            return
+
+        # TODO Is the below hard-coding OK?
+        # Currently this flow_id is dependent on ONU ID
+        # But, this flow is only for OLT and the ONU might
+        # yet be discovered and activated.
+        downlink_flow_id = ASFVOLT16_LLDP_DL_FLOW_ID
+        try:
+            self.log.info('Adding-Downstream-lldp-trap-flow',
+                          classifier=downlink_classifier,
+                          action=downlink_action,
+                          flow_id=downlink_flow_id)
+            # The below intf_id hardcoding will be removed when changes for
+            # consistent NNI port number are taken in (rebased from Voltha master)
+            in_port = downlink_classifier['in_port']
+            intf_id = in_port - MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM
+            yield self.bal.add_flow(network_int_id=self.nni_intf_id,
+                                    flow_id=downlink_flow_id,
+                                    classifier_info=downlink_classifier,
+                                    action_info=downlink_action,
+                                    is_downstream=is_downstream)
+            # To-Do. While addition of one flow is in progress,
+            # we cannot add an another flow. Right now use sleep
+            # of 0.1 sec, assuming that addition of flow is successful.
+            yield asleep(0.1)
+        except Exception as e:
+            self.log.exception('failed-to-install-downstream-lldp-trap-flow', e=e,
+                               classifier=downlink_classifier,
+                               action=downlink_action)
+
+        # Creating list of flows with flow id, bal id and direction info
+        flow_cookie_info = dict()
+        bal_id_dir_info = dict()
+        bal_id_dir_info["bal_flow_id"] = downlink_flow_id
+        bal_id_dir_info["direction"] = "DOWNSTREAM"
+        # hardcoding will be later removed when consistent NNI changes taken
+        flow_cookie_info[downlink_classifier['cookie']] = bal_id_dir_info
+        self.flow_mapping_list.append(flow_cookie_info)
+
+    @inlineCallbacks
     def prepare_and_add_dhcp_flow(self, data_classifier, data_action,
                                   v_enet, dhcp_id, downlink_dhcp_id):
+        self.log.info("preparing-custom-classifier-action-for-dhcp")
         dhcp_classifier = dict()
         dhcp_action = dict()
         dhcp_classifier['ip_proto'] = 17
@@ -1996,7 +2636,7 @@
         dhcp_classifier['udp_dst'] = 67
         dhcp_classifier['pkt_tag_type'] = 'single_tag'
         yield self.add_dhcp_flow(dhcp_classifier, dhcp_action, v_enet,
-                           dhcp_id, downlink_dhcp_id)
+                                 dhcp_id, downlink_dhcp_id)
 
     @inlineCallbacks
     def add_dhcp_flow(self, uplink_classifier, uplink_action,
@@ -2022,8 +2662,8 @@
             self.log.error('Failed-to-get-tcont-info',
                            tcont=gem_port.tcont_ref)
             return
-        pon_port = self._get_pon_port_from_pref_chanpair_ref(\
-                      v_ont_ani.v_ont_ani.data.preferred_chanpair)
+        pon_port = self._get_pon_port_from_pref_chanpair_ref(
+            v_ont_ani.v_ont_ani.data.preferred_chanpair)
         onu_device = self.adapter_agent.get_child_device(
             self.device_id, onu_id=v_ont_ani.v_ont_ani.data.onu_id,
             parent_port_no=pon_port)
@@ -2031,7 +2671,9 @@
             self.log.error('Failed-to-get-onu-device',
                            onu_id=v_ont_ani.v_ont_ani.data.onu_id)
             return
+        queue_id = ASFVOLT16_DEFAULT_QUEUE_ID_START
 
+        scheduler_id = self.get_sched_id('upstream', self.nni_intf_id)
         flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
                                    onu_device.proxy_address.channel_id,
                                    dhcp_id)
@@ -2046,11 +2688,13 @@
                           flow_id=flow_id,
                           sched_info=tcont.alloc_id)
             yield self.bal.add_flow(onu_device.proxy_address.onu_id,
-                              onu_device.proxy_address.channel_id, self.nni_intf_id,
-                              flow_id, gem_port.gemport_id,
-                              uplink_classifier, is_down_stream,
-                              action_info=uplink_action,
-                              sched_id=tcont.alloc_id)
+                                    onu_device.proxy_address.channel_id, self.nni_intf_id,
+                                    flow_id, gem_port.gemport_id,
+                                    uplink_classifier, is_down_stream,
+                                    action_info=uplink_action,
+                                    dba_sched_id=tcont.alloc_id,
+                                    queue_id=queue_id,
+                                    queue_sched_id=scheduler_id)
             # To-Do. While addition of one flow is in progress,
             # we cannot add an another flow. Right now use sleep
             # of 0.1 sec, assuming that addtion of flow is successful.
@@ -2068,21 +2712,12 @@
         downlink_classifier['udp_dst'] = 68
 
         if dhcp_id == ASFVOLT_DHCP_TAGGED_ID:
-            downlink_classifier['pkt_tag_type'] = 'double_tag'
-            # Copy O_OVID
-            downlink_classifier['vlan_vid'] = downlink_action['vlan_vid']
-            # Copy I_OVID
-            if uplink_classifier['vlan_vid'] != RESERVED_VLAN_ID:
-                # downlink_classifier['metadata'] is the I_VID, which is not required
-                # when we use transparent tagging
-                downlink_classifier['metadata'] = uplink_classifier['vlan_vid']
-            if 'push_vlan' in downlink_action:
-                downlink_action.pop('push_vlan')
             downlink_action['trap_to_host'] = True
         else:
-            downlink_classifier['pkt_tag_type'] =  'untagged'
+            downlink_classifier['pkt_tag_type'] = 'untagged'
             downlink_classifier.pop('vlan_vid')
 
+        scheduler_id = self.get_sched_id('downstream', onu_device.proxy_address.channel_id)
         downlink_flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
                                             onu_device.proxy_address.channel_id,
                                             downlink_dhcp_id)
@@ -2094,10 +2729,12 @@
                           flow_id=downlink_flow_id,
                           sched_info=tcont.alloc_id)
             yield self.bal.add_flow(onu_device.proxy_address.onu_id,
-                              onu_device.proxy_address.channel_id, self.nni_intf_id,
-                              downlink_flow_id, gem_port.gemport_id,
-                              downlink_classifier, is_down_stream,
-                              action_info=downlink_action)
+                                    onu_device.proxy_address.channel_id, self.nni_intf_id,
+                                    downlink_flow_id, gem_port.gemport_id,
+                                    downlink_classifier, is_down_stream,
+                                    action_info=downlink_action,
+                                    queue_id=queue_id,
+                                    queue_sched_id=scheduler_id)
             # To-Do. While addition of one flow is in progress,
             # we cannot add an another flow. Right now use sleep
             # of 5 sec, assuming that addtion of flow is successful.
@@ -2114,7 +2751,7 @@
         return
 
     @inlineCallbacks
-    def add_data_flow(self, uplink_classifier, uplink_action, v_enet):
+    def add_data_flow(self, uplink_classifier, uplink_action, v_enet, priority):
 
         downlink_classifier = dict(uplink_classifier)
         downlink_action = dict(uplink_action)
@@ -2138,17 +2775,21 @@
         # will take care of handling all the p bits.
         # We need to revisit when mulitple gem port per p bits is needed.
         yield self.add_hsia_flow(uplink_classifier, uplink_action,
-                          downlink_classifier, downlink_action,
-                          v_enet, ASFVOLT_HSIA_ID)
+                                 downlink_classifier, downlink_action,
+                                 v_enet, priority, ASFVOLT_HSIA_ID)
 
     @inlineCallbacks
     def add_hsia_flow(self, uplink_classifier, uplink_action,
-                     downlink_classifier, downlink_action,
-                     v_enet, hsia_id):
+                      downlink_classifier, downlink_action,
+                      v_enet, priority, hsia_id, l2_modification_flow=True):
         # Add Upstream Firmware Flow.
         # To-Do For a time being hard code the traffic class value.
         # Need to know how to get the traffic class info from flows.
-        gem_port = self.get_gem_port_info(v_enet, traffic_class=2)
+        if l2_modification_flow:
+            traffic_class = TRAFFIC_CLASS_2
+
+        queue_id = ASFVOLT16_DEFAULT_QUEUE_ID_START
+        gem_port = self.get_gem_port_info(v_enet, traffic_class=traffic_class)
         if gem_port is None:
             self.log.info('Failed-to-get-gemport')
             self.store_flows(uplink_classifier, uplink_action,
@@ -2164,8 +2805,8 @@
             self.log.info('Failed-to-get-tcont-info',
                           tcont=gem_port.tcont_ref)
             return
-        pon_port = self._get_pon_port_from_pref_chanpair_ref(\
-                      v_ont_ani.v_ont_ani.data.preferred_chanpair)
+        pon_port = self._get_pon_port_from_pref_chanpair_ref(
+            v_ont_ani.v_ont_ani.data.preferred_chanpair)
         onu_device = self.adapter_agent.get_child_device(
             self.device_id, onu_id=v_ont_ani.v_ont_ani.data.onu_id,
             parent_port_no=pon_port)
@@ -2174,11 +2815,22 @@
                           onu_id=v_ont_ani.v_ont_ani.data.onu_id)
             return
 
+        if l2_modification_flow:
+            # This is required to deactivate the flow during TDP
+            onu_device.vlan = uplink_action['vlan_vid']
+        else:
+            # This is required to deactivate the flow during TDP
+            onu_device.vlan = uplink_classifier['vlan_vid']
+        self.adapter_agent.update_device(onu_device)
+        self.log.info('Stag-is-stored-in-onu-device', stag=onu_device.vlan)
+
         flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
                                    onu_device.proxy_address.channel_id,
                                    hsia_id)
+
         try:
             is_down_stream = False
+            scheduler_id = self.get_sched_id('upstream', self.nni_intf_id)
             self.log.info('Adding-ARP-upstream-flow',
                           classifier=uplink_classifier,
                           action=uplink_action,
@@ -2186,11 +2838,14 @@
                           flow_id=flow_id,
                           sched_info=tcont.alloc_id)
             yield self.bal.add_flow(onu_device.proxy_address.onu_id,
-                              onu_device.proxy_address.channel_id, self.nni_intf_id,
-                              flow_id, gem_port.gemport_id,
-                              uplink_classifier, is_down_stream,
-                              action_info=uplink_action,
-                              sched_id=tcont.alloc_id)
+                                    onu_device.proxy_address.channel_id, self.nni_intf_id,
+                                    flow_id, gem_port.gemport_id,
+                                    uplink_classifier, is_down_stream,
+                                    action_info=uplink_action,
+                                    priority=priority,
+                                    dba_sched_id=tcont.alloc_id,
+                                    queue_id=queue_id,
+                                    queue_sched_id=scheduler_id)
             # To-Do. While addition of one flow is in progress,
             # we cannot add an another flow. Right now use sleep
             # of 0.1 sec, assuming that addtion of flow is successful.
@@ -2204,21 +2859,30 @@
             return
         is_down_stream = True
         # To-Do: For Now hard code the p-bit values.
-        #downlink_classifier['vlan_pcp'] = 7
+        # downlink_classifier['vlan_pcp'] = 7
         downlink_flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
                                             onu_device.proxy_address.channel_id,
                                             hsia_id)
         try:
+            # To assign TDP value to queue in downstream
+            if l2_modification_flow:
+                queue_id = self.get_queue_id(onu_device.proxy_address.onu_id)
+
+            scheduler_id = self.get_sched_id('downstream',
+                                             onu_device.proxy_address.channel_id)
             self.log.info('Adding-ARP-downstream-flow',
                           classifier=downlink_classifier,
                           action=downlink_action,
                           gem_port=gem_port,
                           flow_id=downlink_flow_id)
             yield self.bal.add_flow(onu_device.proxy_address.onu_id,
-                              onu_device.proxy_address.channel_id, self.nni_intf_id,
-                              downlink_flow_id, gem_port.gemport_id,
-                              downlink_classifier, is_down_stream,
-                              action_info=downlink_action)
+                                    onu_device.proxy_address.channel_id, self.nni_intf_id,
+                                    downlink_flow_id, gem_port.gemport_id,
+                                    downlink_classifier, is_down_stream,
+                                    action_info=downlink_action,
+                                    priority=priority,
+                                    queue_id=queue_id,
+                                    queue_sched_id=scheduler_id)
             # To-Do. While addition of one flow is in progress,
             # we cannot add an another flow. Right now use sleep
             # of 0.1 sec, assuming that addtion of flow is successful.
@@ -2231,22 +2895,37 @@
                                intf_id=onu_device.proxy_address.channel_id)
             return
 
-    @inlineCallbacks
-    def del_all_flow(self, v_enet):
-        # Currently this got called whenever we delete a gemport, but
-        # del_flow will not work properly as suffcient parameters are not
-        # present for deleting a flow.
-        # Deleting a flow is of two steps process.
-        # 1. Deactivate the flow, making ADMIN_STATE Down
-        # 2. Deleting the flow, making BalCfgClear
-        # Need to implement deactivate flow, before deleting a flow
-        # for HSIA, DHCP and other flow types.
-        # For EAPOL it's implemented, check del_eapol_flow method
-        yield self.del_flow(v_enet, ASFVOLT_HSIA_ID, ASFVOLT_HSIA_ID)
-        yield self.del_flow(v_enet, ASFVOLT_DHCP_TAGGED_ID,
-                      ASFVOLT_DOWNLINK_DHCP_TAGGED_ID)
-        yield self.del_flow(v_enet, ASFVOLT_EAPOL_ID_DATA_VLAN,
-                      ASFVOLT_DOWNLINK_EAPOL_ID_DATA_VLAN)
+        # Creating list of flows with flow id, bal id and direction info
+        flow_cookie_info = dict()
+        bal_id_dir_info = dict()
+        bal_id_dir_info["bal_flow_id"] = flow_id
+        bal_id_dir_info["direction"] = "BIDIRECTIONAL"
+        bal_id_dir_info["onu_id"] = onu_device.proxy_address.onu_id
+        bal_id_dir_info["intf_id"] = onu_device.proxy_address.channel_id
+        bal_id_dir_info["gemport_id"] = gem_port.gemport_id
+        bal_id_dir_info["priority"] = priority
+        bal_id_dir_info["queue_id"] = queue_id
+        bal_id_dir_info["queue_sched_id"] = scheduler_id
+        bal_id_dir_info["dba_sched_id"] = tcont.alloc_id
+        bal_id_dir_info["ds_scheduler_id"] = \
+            self.get_sched_id('downstream',
+                              onu_device.proxy_address.channel_id)
+        bal_id_dir_info["us_scheduler_id"] = self.get_sched_id('upstream',
+                                                               self.nni_intf_id)
+        if l2_modification_flow:
+            bal_id_dir_info["stag"] = uplink_action["vlan_vid"]
+        else:
+            bal_id_dir_info["stag"] = uplink_classifier["vlan_vid"]
+
+        bal_id_dir_info["ctag"] = RESERVED_VLAN_ID
+        try:
+            if uplink_classifier['vlan_vid'] != RESERVED_VLAN_ID:
+                bal_id_dir_info["ctag"] = uplink_classifier['vlan_vid']
+        except KeyError as err:
+            self.log.debug('vlan_vid-not-found-in-uplink-classifier')
+
+        flow_cookie_info[uplink_classifier["cookie"]] = bal_id_dir_info
+        self.flow_mapping_list.append(flow_cookie_info)
 
     @inlineCallbacks
     def del_eapol_flow(self, v_enet, uplink_id, downlink_id, vlan_id):
@@ -2276,6 +2955,9 @@
             self.log.info('Failed-to-get-onu-device',
                           onu_id=v_ont_ani.v_ont_ani.data.onu_id)
             return
+        queue_id = ASFVOLT16_DEFAULT_QUEUE_ID_START
+
+        scheduler_id = self.get_sched_id('downstream', onu_device.proxy_address.channel_id)
         downlink_flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
                                             onu_device.proxy_address.channel_id,
                                             downlink_id)
@@ -2289,7 +2971,9 @@
                                                  intf_id=onu_device.proxy_address.channel_id,
                                                  network_int_id=self.nni_intf_id,
                                                  gemport_id=gem_port.gemport_id,
-                                                 stag=vlan_id)
+                                                 stag=vlan_id,
+                                                 queue_id=queue_id,
+                                                 queue_sched_id=scheduler_id)
             # While deletion of one flow is in progress,
             # we cannot delete an another flow. Right now use sleep
             # of 0.1 sec, assuming that deletion of flow is successful.
@@ -2305,6 +2989,7 @@
                                onu_id=onu_device.proxy_address.onu_id,
                                intf_id=onu_device.proxy_address.channel_id)
 
+        scheduler_id = self.get_sched_id('upstream', self.nni_intf_id)
         uplink_flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
                                           onu_device.proxy_address.channel_id,
                                           uplink_id)
@@ -2324,7 +3009,9 @@
                                                  network_int_id=self.nni_intf_id,
                                                  gemport_id=gem_port.gemport_id,
                                                  stag=vlan_id,
-                                                 sched_id=tcont.alloc_id)
+                                                 dba_sched_id=tcont.alloc_id,
+                                                 queue_id=queue_id,
+                                                 queue_sched_id=scheduler_id)
             # While deletion of one flow is in progress,
             # we cannot delete an another flow. Right now use sleep
             # of 0.1 sec, assuming that deletion of flow is successful.
@@ -2341,16 +3028,14 @@
                                intf_id=onu_device.proxy_address.channel_id)
 
     @inlineCallbacks
-    def del_flow(self, v_enet, uplink_id, downlink_id):
-        # To-Do For a time being hard code the traffic class value.
-        # Need to know how to get the traffic class info from flows.
-        v_ont_ani = self.get_v_ont_ani(v_enet.v_enet.data.v_ontani_ref)
+    def del_all_flow(self, v_enet):
+        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)
             return
-        pon_port = self._get_pon_port_from_pref_chanpair_ref(\
-                      v_ont_ani.v_ont_ani.data.preferred_chanpair)
+        pon_port = self._get_pon_port_from_pref_chanpair_ref(
+            v_ont_ani.v_ont_ani.data.preferred_chanpair)
         onu_device = self.adapter_agent.get_child_device(
             self.device_id, onu_id=v_ont_ani.v_ont_ani.data.onu_id,
             parent_port_no=pon_port)
@@ -2359,46 +3044,94 @@
                           onu_id=v_ont_ani.v_ont_ani.data.onu_id)
             return
 
-        downlink_flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
-                                            onu_device.proxy_address.channel_id,
-                                            downlink_id)
+        us_scheduler_id = self.get_sched_id('upstream',
+                                            self.nni_intf_id)
+        ds_scheduler_id = self.get_sched_id('downstream',
+                                            onu_device.proxy_address.channel_id)
+        queue_id = self.get_queue_id(onu_device.proxy_address.onu_id)
+
+        gem_port = self.get_gem_port_info(v_enet, traffic_class=2)
+        dba_sched_id = gem_port.gemport_id
+
+        yield self.del_flow(onu_device, ASFVOLT_HSIA_ID,
+                            dba_sched_id=dba_sched_id,
+                            us_scheduler_id=us_scheduler_id,
+                            ds_scheduler_id=ds_scheduler_id,
+                            queue_id=queue_id)
+        yield self.bal.delete_queue(queue_id, 'downstream', ds_scheduler_id)
+        yield self.bal.delete_scheduler(dba_sched_id, 'upstream')
+        '''
+        #DT - Not required
+        yield self.del_flow(v_enet, ASFVOLT_DHCP_TAGGED_ID)
+        yield self.del_flow(v_enet, ASFVOLT_EAPOL_ID_DATA_VLAN)
+        yield self.del_flow(v_enet, ASFVOLT_EAPOL_ID)
+        '''
+
+    @inlineCallbacks
+    def del_flow(self, onu_device, flow_id,
+                 dba_sched_id=None, us_scheduler_id=None,
+                 ds_scheduler_id=None, queue_id=None):
+
+        onu_id = onu_device.proxy_address.onu_id
+        intf_id = onu_device.proxy_address.channel_id
+
+        uni_port = self.get_uni_port(onu_device.id)
+        ports = self.adapter_agent.get_ports(self.device_id,
+                                             Port.ETHERNET_UNI)
+        found = False
+        v_enet = None
+        for port in ports:
+            if port.port_no == uni_port.port_no:
+                found = True
+                v_enet = self.get_venet(name=port.label)
+                break
+
+        if found is False:
+            self.log.error('Failed-to-get-v_enet-info')
+            return
+
+        gem_port = self.get_gem_port_info(v_enet, traffic_class=2)
+
+        downlink_flow_id = self.get_flow_id(onu_id, intf_id, flow_id)
         is_down_stream = True
-        try:
-            self.log.info('Deleting-Downstream-flow',
-                          flow_id=downlink_flow_id)
-            # Need to implement deactivate HSIA flow ,currently only
-            # Delete is called, so hsia flow deletion will not work properly
-            yield self.bal.delete_flow(downlink_flow_id, is_down_stream)
-            # While deletion of one flow is in progress,
-            # we cannot delete an another flow. Right now use sleep
-            # of 0.1 sec, assuming that deletion of flow is successful.
-            yield asleep(0.1)
-        except Exception as e:
-            self.log.exception('failed-to-install-downstream-flow', e=e,
-                               flow_id=downlink_flow_id,
-                               onu_id=onu_device.proxy_address.onu_id,
-                               intf_id=onu_device.proxy_address.channel_id)
+        self.log.info('Deleting-Downstream-flow', flow_id=downlink_flow_id)
 
-        uplink_flow_id = self.get_flow_id(onu_device.proxy_address.onu_id,
-                                   onu_device.proxy_address.channel_id,
-                                   uplink_id)
-        try:
-            is_down_stream = False
-            self.log.info('deleting-Upstream-flow',
-                          flow_id=uplink_flow_id)
-            # Need to implement deactivate HSIA flow ,currently only
-            # Delete is called, so hsia flow deletion will not work properly
+        self.log.info('Retrieving-stored-stag', stag=onu_device.vlan)
+        yield self.bal.deactivate_flow(downlink_flow_id,
+                                       is_down_stream,
+                                       onu_id=onu_id, intf_id=intf_id,
+                                       network_int_id=self.nni_intf_id,
+                                       gemport_id=gem_port.gemport_id,
+                                       stag=onu_device.vlan,
+                                       queue_id=queue_id,
+                                       ds_scheduler_id=ds_scheduler_id)
 
-            yield self.bal.delete_flow(uplink_flow_id, is_down_stream)
-            # While deletion of one flow is in progress,
-            # we cannot delete an another flow. Right now use sleep
-            # of 0.1 sec, assuming that deletion of flow is successful.
-            yield asleep(0.1)
-        except Exception as e:
-            self.log.exception('failed-to-delete-Upstream-flow', e=e,
-                               flow_id=uplink_flow_id,
-                               onu_id=onu_device.proxy_address.onu_id,
-                               intf_id=onu_device.proxy_address.channel_id)
+        # While deletion of one flow is in progress,
+        # we cannot delete an another flow. Right now use sleep
+        # of 0.1 sec, assuming that deletion of flow is successful.
+        yield asleep(0.1)
+        yield self.bal.delete_flow(downlink_flow_id, is_down_stream)
+        yield asleep(0.1)
+
+        uplink_flow_id = self.get_flow_id(onu_id, intf_id, flow_id)
+        is_down_stream = False
+        self.log.info('deleting-Upstream-flow',
+                      flow_id=uplink_flow_id)
+        yield self.bal.deactivate_flow(uplink_flow_id,
+                                       is_down_stream, onu_id=onu_id,
+                                       intf_id=intf_id,
+                                       network_int_id=self.nni_intf_id,
+                                       gemport_id=gem_port.gemport_id,
+                                       stag=onu_device.vlan,
+                                       dba_sched_id=dba_sched_id,
+                                       us_scheduler_id=us_scheduler_id)
+
+        # While deletion of one flow is in progress,
+        # we cannot delete an another flow. Right now use sleep
+        # of 0.1 sec, assuming that deletion of flow is successful.
+        yield asleep(0.1)
+        yield self.bal.delete_flow(uplink_flow_id, is_down_stream)
+        yield asleep(0.1)
 
     def parse_provisioning_options(self, extra_args):
         parser = MyArgumentParser(add_help=False)
@@ -2438,7 +3171,7 @@
     def _get_next_uni_port(self):
         uni_ports = self.adapter_agent.get_ports(self.device_id,
                                                  Port.ETHERNET_UNI)
-        uni_port_nums = set([uni_port.port_no for uni_port in uni_ports])
+        uni_port_nums = set(uni_port.port_no for uni_port in uni_ports)
         # We need to start allocating port numbers from ONU_UNI_PORT_START_ID.
         # Find the first unused port number.
         next_port_num = next(ifilterfalse(uni_port_nums.__contains__,
@@ -2450,23 +3183,72 @@
 
     def _valid_nni_port(self, port):
         if port < self.asfvolt_device_info.asfvolt16_device_topology.num_of_pon_ports or \
-            port >= (self.asfvolt_device_info.asfvolt16_device_topology.num_of_pon_ports +
-                     self.asfvolt_device_info.asfvolt16_device_topology.num_of_nni_ports):
+                port >= (self.asfvolt_device_info.asfvolt16_device_topology.num_of_pon_ports +
+                         self.asfvolt_device_info.asfvolt16_device_topology.num_of_nni_ports):
             return False
         return True
 
-    def _get_pon_port_from_pref_chanpair_ref(self, chanpair_ref):
-        pon_id = -1
-        # return the pon port corresponding to the channel_termination
-        # whose chanpair_ref mathes the passed channelpair_ref
-        for channel_termination in self.channel_terminations.itervalues():
-            if channel_termination.data.channelpair_ref == chanpair_ref:
-                self.log.debug("channel-termination-entry-found",
-                                pon_id=channel_termination.data.xgs_ponid,
-                                chanpair_ref=chanpair_ref)
-                return channel_termination.data.xgs_ponid
+    @inlineCallbacks
+    def _wait_for_previous_flow_config_to_finish(self):
+        while self.flow_config_in_progress:
+            # non-blocking wait for 200ms
+            yield asleep(0.2)
+        return
 
-        if pon_id < 0:
-            raise Exception("pon-id-not-found-for-chanpair-ref {}".\
-                             format(chanpair_ref))
+    def _get_flow_id(self, flow_id):
+        return flow_id & ((2**self.FLOW_ID_BITS) - 1)
 
+    @inlineCallbacks
+    def _retrieve_access_term_config(self):
+        access_term_config = yield self.bal.get_access_terminal_cfg()
+        self.asfvolt_device_info.update_device_topology(access_term_config.cfg)
+        self.asfvolt_device_info.update_device_software_info(access_term_config.cfg)
+        self.asfvolt_device_info.read_and_build_device_sfp_presence_map()
+
+    def _create_device_ports(self):
+        # For all the detected NNI ports, create corresponding physical and
+        # logical ports on the device and logical device.
+        self._update_nni_port()
+
+        self.add_port(port_no=self.nni_intf_id +
+                      MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM,
+                      port_type=Port.ETHERNET_NNI,
+                      label='NNI facing Ethernet port')
+        self.add_logical_port(port_no=self.nni_intf_id +
+                              MIN_ASFVOLT_NNI_LOGICAL_PORT_NUM,
+                              port_type=Port.ETHERNET_NNI,
+                              device_id=self.device_id,
+                              logical_device_id=self.logical_device_id,
+                              port_state=OFPPS_LIVE)
+
+    def _update_nni_port(self):
+        # Updating NNI interface id
+        for port in self.asfvolt_device_info.sfp_device_presence_map.iterkeys():
+            if not self._valid_nni_port(port):
+                continue
+            # We support only one NNI port.
+            self.nni_intf_id = (port -
+                                self.asfvolt_device_info.
+                                asfvolt16_device_topology.num_of_pon_ports)
+            break
+
+    @inlineCallbacks
+    def _add_port_config_to_queue(self, data):
+        # We put the transaction in a Queue
+        # Only one transaction can exist in the queue
+        # at a given time. We do this we enable the pon
+        # ports sequentially.
+        while True and self.is_device_reachable:
+            try:
+                self.pon_port_config_resp.put_nowait(data)
+                break
+            except Full:
+                self.log.info('another-pon-port-enable-pending')
+                yield asleep(0.3)
+        return
+
+    def _remove_port_config_from_queue(self):
+        try:
+            self.pon_port_config_resp.get_nowait()
+        except Empty:
+            self.log.error("no-data-in-queue")
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_ind_handler.py b/voltha/adapters/asfvolt16_olt/asfvolt16_ind_handler.py
index ea6269d..7929067 100644
--- a/voltha/adapters/asfvolt16_olt/asfvolt16_ind_handler.py
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_ind_handler.py
@@ -29,42 +29,41 @@
     def __init__(self, log):
         self.log = log
 
-    def bal_acc_term_oper_sta_cng_ind(self, indication, device_handler):
+    def bal_acc_term_oper_sta_cng(self, indication, device_handler):
+        self.log.info("access-term-oper-status-change", indication=indication)
         ind_info = dict()
-        ind_info['_object_type'] = 'access_terminal_indication'
+        ind_info['_object_type'] = 'access_term_ind'
         ind_info['_sub_group_type'] = 'oper_state_change'
-        bal_err = bal_pb2.BalErr()
-        return bal_err
-
-    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'
         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
+        if indication.access_term_ind_op_state.data.admin_state is \
+                bal_model_types_pb2.BAL_STATE_UP and \
+                indication.access_term_ind_op_state.data.new_oper_status is \
+                bal_model_types_pb2.BAL_STATUS_UP:
+            ind_info['activation_successful'] = True
+        elif indication.access_term_ind_op_state.data.admin_state is \
+                bal_model_types_pb2.BAL_STATE_DOWN and \
+                indication.access_term_ind_op_state.data.new_oper_status is \
+                bal_model_types_pb2.BAL_STATUS_DOWN:
+            ind_info['deactivation_successful'] = True
 
         reactor.callLater(0,
-                          device_handler.handle_access_term_ind,
-                          ind_info,
-                          indication.access_term_ind)
+                          device_handler.handle_access_term_oper_status_change,
+                          ind_info)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    def bal_acc_term_processing_error(self, indication, device_handler):
+        # TODO: No error handling currently.
+        self.log.error("access-term-processing-error", indication=indication)
+        # return a dummy response
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
     def bal_flow_oper_sts_cng(self, indication, device_handler):
+        self.log.debug("flow-oper-status-change", indication=indication)
         ind_info = dict()
         ind_info['_object_type'] = 'flow_indication'
         ind_info['_sub_group_type'] = 'oper_state_change'
@@ -74,18 +73,10 @@
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
-    def bal_flow_ind(self, indication, device_handler):
-        ind_info = dict()
-        ind_info['_object_type'] = 'flow_indication'
-        ind_info['_sub_group_type'] = 'flow_indication'
-        bal_err = bal_pb2.BalErr()
-        bal_err.err = bal_errno_pb2.BAL_ERR_OK
-        return bal_err
-
-    def bal_group_ind(self, indication, device_handler):
-        ind_info = dict()
-        ind_info['_object_type'] = 'group_indication'
-        ind_info['_sub_group_type'] = 'group_indication'
+    def bal_flow_processing_error(self, indication, device_handler):
+        # TODO: No error handling.
+        self.log.debug("flow-processing-error", indication=indication)
+        # dummy response
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
@@ -94,6 +85,19 @@
         ind_info = dict()
         ind_info['_object_type'] = 'interface_indication'
         ind_info['_sub_group_type'] = 'oper_state_change'
+        ind_info['activation_successful'] = False
+        if indication.interface_op_state.data.new_oper_status is \
+                bal_model_types_pb2.BAL_STATUS_UP and \
+                indication.interface_op_state.data.admin_state is \
+                bal_model_types_pb2.BAL_STATUS_UP:
+            ind_info['activation_successful'] = True
+            self.log.info("Awaiting-ONU-discovery")
+
+        reactor.callLater(0,
+                          device_handler.BalIfaceOperStatusChange,
+                          indication.interface_op_state.key.intf_id,
+                          ind_info)
+
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
@@ -101,39 +105,35 @@
     def bal_iface_los(self, indication, device_handler):
         los_status = indication.interface_los.data.status
         if los_status != bal_model_types_pb2.BAL_ALARM_STATUS_NO__CHANGE:
-            balIfaceLos_dict = {}
+            balIfaceLos_dict = dict()
             balIfaceLos_dict["los_status"] = los_status.__str__()
-            reactor.callLater(0, \
-                              device_handler.BalIfaceLosAlarm, \
-                              indication.device_id, \
-                              indication.interface_los.key.intf_id, \
+            reactor.callLater(0,
+                              device_handler.BalIfaceLosAlarm,
+                              indication.device_id,
+                              indication,
                               los_status, balIfaceLos_dict)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
-    def bal_iface_ind(self, indication, device_handler):
-        self.log.info('Awaiting-ONU-discovery')
-        reactor.callLater(0,\
-                          device_handler.BalIfaceIndication,\
-                          indication.device_id.decode('unicode-escape'),\
-                          indication.interface_ind.key.intf_id)
-        bal_err = bal_pb2.BalErr()
-        bal_err.err = bal_errno_pb2.BAL_ERR_OK
-        return bal_err
-
-    def bal_iface_stat(self, indication, device_handler):
-        ind_info = dict()
-        ind_info['_object_type'] = 'interface_indication'
-        ind_info['_sub_group_type'] = 'stat_indication'
-        bal_err = bal_pb2.BalErr()
-        bal_err.err = bal_errno_pb2.BAL_ERR_OK
-        return bal_err
-
     def bal_subs_term_oper_sts_cng(self, indication, device_handler):
+        onu_data = indication.terminal_op_state
         ind_info = dict()
         ind_info['_object_type'] = 'sub_term_indication'
-        ind_info['_sub_group_type'] = 'oper_state_change'
+        ind_info['_sub_group_type'] = 'sub_term_op_state'
+        ind_info['_pon_id'] = onu_data.key.intf_id
+        ind_info['onu_id'] = onu_data.key.sub_term_id
+        ind_info['activation_successful'] = False
+        if onu_data.data.admin_state is bal_model_types_pb2.BAL_STATE_DOWN or \
+                onu_data.data.new_oper_status is bal_model_types_pb2.BAL_STATUS_DOWN:
+            ind_info['activation_successful'] = False
+        elif onu_data.data.admin_state is bal_model_types_pb2.BAL_STATE_UP and \
+                onu_data.data.new_oper_status is bal_model_types_pb2.BAL_STATUS_UP:
+            ind_info['activation_successful'] = True
+
+        reactor.callLater(0,
+                          device_handler.handle_sub_term_oper_status_change,
+                          ind_info)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
@@ -157,7 +157,7 @@
         ind_info['_vendor_specific'] = \
             onu_data.data.serial_number.vendor_specific
         reactor.callLater(0,
-                          device_handler.handle_sub_term_ind,
+                          device_handler.handle_sub_term_discovery,
                           ind_info)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
@@ -173,34 +173,34 @@
         # Loss of PLOAM channel
         lopc_mic_error = indication.terminal_alarm.data.alarm.lopc_mic_error
 
-        balSubTermAlarm_Dict = {}
+        balSubTermAlarm_Dict = dict()
         balSubTermAlarm_Dict["LOS Status"] = los.__str__()
         balSubTermAlarm_Dict["LOB Status"] = lob.__str__()
         balSubTermAlarm_Dict["LOPC MISS Status"] = lopc_miss.__str__()
         balSubTermAlarm_Dict["LOPC MIC ERROR Status"] = lopc_mic_error.__str__()
 
         if los != bal_model_types_pb2.BAL_ALARM_STATUS_NO__CHANGE:
-            reactor.callLater(0, device_handler.BalSubsTermLosAlarm, \
-                              indication.device_id, \
-                              indication.terminal_alarm.key.intf_id, \
+            reactor.callLater(0, device_handler.BalSubsTermLosAlarm,
+                              indication.device_id,
+                              indication.terminal_alarm.key.intf_id,
                               los, balSubTermAlarm_Dict)
 
         if lob != bal_model_types_pb2.BAL_ALARM_STATUS_NO__CHANGE:
-            reactor.callLater(0, device_handler.BalSubsTermLobAlarm, \
-                              indication.device_id, \
-                              indication.terminal_alarm.key.intf_id, \
+            reactor.callLater(0, device_handler.BalSubsTermLobAlarm,
+                              indication.device_id,
+                              indication.terminal_alarm.key.intf_id,
                               lob, balSubTermAlarm_Dict)
 
         if lopc_miss != bal_model_types_pb2.BAL_ALARM_STATUS_NO__CHANGE:
-            reactor.callLater(0, device_handler.BalSubsTermLopcMissAlarm, \
-                              indication.device_id, \
-                              indication.terminal_alarm.key.intf_id, \
+            reactor.callLater(0, device_handler.BalSubsTermLopcMissAlarm,
+                              indication.device_id,
+                              indication.terminal_alarm.key.intf_id,
                               lopc_miss, balSubTermAlarm_Dict)
 
         if lopc_mic_error != bal_model_types_pb2.BAL_ALARM_STATUS_NO__CHANGE:
-            reactor.callLater(0, device_handler.BalSubsTermLopcMicErrorAlarm, \
-                              indication.device_id, \
-                              indication.terminal_alarm.key.intf_id, \
+            reactor.callLater(0, device_handler.BalSubsTermLopcMicErrorAlarm,
+                              indication.device_id,
+                              indication.terminal_alarm.key.intf_id,
                               lopc_mic_error, balSubTermAlarm_Dict)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
@@ -220,63 +220,67 @@
             ind_info['_object_type'] = 'sub_term_indication'
             ind_info['_sub_group_type'] = 'dgi_indication'
 
-            balSubTermDgi_Dict = {}
+            balSubTermDgi_Dict = dict()
             balSubTermDgi_Dict["dgi_status"] = dgi_status.__str__()
             reactor.callLater(0,
-                              device_handler.BalSubsTermDgiAlarm, \
-                              indication.device_id, \
-                              indication.terminal_dgi.key.intf_id,\
-                              indication.terminal_dgi.key.sub_term_id, \
-                              dgi_status,balSubTermDgi_Dict, ind_info)
+                              device_handler.BalSubsTermDgiAlarm,
+                              indication.device_id,
+                              indication.terminal_dgi.key.intf_id,
+                              indication.terminal_dgi.key.sub_term_id,
+                              dgi_status, balSubTermDgi_Dict, ind_info)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
-    def bal_subs_term_ind(self, indication, device_handler):
-        #     ind_info: {'_object_type': <str>
-        #                '_sub_group_type': <str>
-        #                '_device_id': <str>
-        #                '_pon_id' : <int>
-        #                'onu_id' : <int>
-        #                '_vendor_id' : <str>
-        #                '__vendor_specific' : <str>
-        #                'activation_successful':[True or False]}
-        onu_data = indication.terminal_ind
-        ind_info = dict()
-        ind_info['_object_type'] = 'sub_term_indication'
-        ind_info['_sub_group_type'] = 'sub_term_indication'
-        ind_info['_pon_id'] = onu_data.key.intf_id
-        ind_info['onu_id'] = onu_data.key.sub_term_id
-        ind_info['_vendor_id'] = onu_data.data.serial_number.vendor_id
-        ind_info['_vendor_specific'] = \
-            onu_data.data.serial_number.vendor_specific
-        self.log.info('registration-id-in-bal-subs-term-ind-is',\
-                       registration_id=onu_data.data.registration_id[:36])
-        ind_info['registration_id'] = onu_data.data.registration_id[:36]
-        ind_info['activation_successful'] = None
-        if (bal_model_types_pb2.BAL_STATE_DOWN == onu_data.data.admin_state or
-            bal_model_types_pb2.BAL_STATUS_UP != onu_data.data.oper_status):
-            ind_info['activation_successful'] = False
-        elif (bal_model_types_pb2.BAL_STATE_UP == onu_data.data.admin_state and
-            bal_model_types_pb2.BAL_STATUS_UP == onu_data.data.oper_status):
-            ind_info['activation_successful'] = True
-
-        reactor.callLater(0,
-                          device_handler.handle_sub_term_ind,
-                          ind_info)
+    def bal_subs_term_dowi_ind(self, indication, device_handler):
+        self.log.debug("sub-term-dowi-ind", indication=indication)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
-    def bal_tm_queue_ind_info(self, indication, device_handler):
-        ind_info = dict()
-        ind_info['_object_type'] = 'tm_q_indication'
-        ind_info['_sub_group_type'] = 'tm_q_indication'
+    def bal_subs_term_looci_ind(self, indication, device_handler):
+        self.log.debug("sub-term-looci-ind", indication=indication)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
-    def bal_tm_sched_ind_info(self, indication, device_handler):
+    def bal_subs_term_processing_error(self, indication, device_handler):
+        self.log.debug("sub-term-processing-error", indication=indication)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    def bal_subs_term_sdi_ind(self, indication, device_handler):
+        self.log.debug("sub-term-sdi-ind", indication=indication)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    def bal_subs_term_sfi_ind(self, indication, device_handler):
+        self.log.debug("sub-term-sfi-ind", indication=indication)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    def bal_subs_term_activation_fail(self, indication, device_handler):
+        self.log.debug("sub-term-activation-fail", indication=indication)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    def bal_subs_term_sufi_ind(self, indication, device_handler):
+        self.log.debug("sub-term-sufi-ind", indication=indication)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    def bal_subs_term_tiwi_ind(self, indication, device_handler):
+        self.log.debug("sub-term-tiwi-ind", indication=indication)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    def bal_tm_sched_oper_status_change(self, indication, device_handler):
         ind_info = dict()
         ind_info['_object_type'] = 'tm_sched_indication'
         ind_info['_sub_group_type'] = 'tm_sched_indication'
@@ -305,7 +309,7 @@
         ind_info['_object_type'] = 'packet_in_indication'
         ind_info['_sub_group_type'] = 'omci_message'
         ind_info['intf_id'] = \
-        indication.balOmciResp.key.packet_send_dest.itu_omci_channel.intf_id
+            indication.balOmciResp.key.packet_send_dest.itu_omci_channel.intf_id
         packet_data = indication.balOmciResp.key.packet_send_dest
         ind_info['onu_id'] = packet_data.itu_omci_channel.sub_term_id
         ind_info['packet'] = indication.balOmciResp.data.pkt
@@ -318,7 +322,8 @@
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
-    def bal_pkt_ieee_oam_channel_rx_ind(self, indication, device_handler):
+    @staticmethod
+    def bal_pkt_ieee_oam_channel_rx_ind(indication, device_handler):
         ind_info = dict()
         ind_info['_object_type'] = 'packet_in_indication'
         ind_info['_sub_group_type'] = 'ieee_oam_message'
@@ -332,33 +337,26 @@
                                                               None)
         if indication_handler is None:
             self.log.debug('No handler', objType=bal_ind.objType,
-                                         sub_group=bal_ind.sub_group)
+                           sub_group=bal_ind.sub_group)
             pass  # no-op
         else:
             indication_handler(self, bal_ind, device_handler)
 
     indication_handler_map = {
         (bal_model_ids_pb2.BAL_OBJ_ID_ACCESS_TERMINAL,
-         bal_model_ids_pb2.BAL_ACCESS_TERMINAL_AUTO_ID_IND):
-            bal_acc_term_ind,
-        (bal_model_ids_pb2.BAL_OBJ_ID_ACCESS_TERMINAL,
          bal_model_ids_pb2.BAL_ACCESS_TERMINAL_AUTO_ID_OPER_STATUS_CHANGE):
-            bal_acc_term_oper_sta_cng_ind,
+            bal_acc_term_oper_sta_cng,
+        (bal_model_ids_pb2.BAL_OBJ_ID_ACCESS_TERMINAL,
+         bal_model_ids_pb2.BAL_ACCESS_TERMINAL_AUTO_ID_PROCESSING_ERROR):
+            bal_acc_term_processing_error,
 
         (bal_model_ids_pb2.BAL_OBJ_ID_FLOW,
          bal_model_ids_pb2.BAL_FLOW_AUTO_ID_OPER_STATUS_CHANGE):
             bal_flow_oper_sts_cng,
         (bal_model_ids_pb2.BAL_OBJ_ID_FLOW,
-         bal_model_ids_pb2.BAL_FLOW_AUTO_ID_IND):
-            bal_flow_ind,
+         bal_model_ids_pb2.BAL_FLOW_AUTO_ID_PROCESSING_ERROR):
+            bal_flow_processing_error,
 
-        (bal_model_ids_pb2.BAL_OBJ_ID_GROUP,
-         bal_model_ids_pb2.BAL_GROUP_AUTO_ID_IND):
-            bal_group_ind,
-
-        (bal_model_ids_pb2.BAL_OBJ_ID_INTERFACE,
-         bal_model_ids_pb2.BAL_INTERFACE_AUTO_ID_IND):
-            bal_iface_ind,
         (bal_model_ids_pb2.BAL_OBJ_ID_INTERFACE,
          bal_model_ids_pb2.BAL_INTERFACE_AUTO_ID_LOS):
             bal_iface_los,
@@ -367,33 +365,57 @@
             bal_iface_oper_sts_cng,
 
         (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
-         bal_model_ids_pb2.\
+         bal_model_ids_pb2.
          BAL_SUBSCRIBER_TERMINAL_AUTO_ID_OPER_STATUS_CHANGE):
             bal_subs_term_oper_sts_cng,
         (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
-         bal_model_ids_pb2.\
+         bal_model_ids_pb2.
          BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUB_TERM_DISC):
             bal_subs_term_discovery_ind,
         (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
-         bal_model_ids_pb2.\
+         bal_model_ids_pb2.
          BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUB_TERM_ALARM):
             bal_subs_term_alarm_ind,
         (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
-         bal_model_ids_pb2.\
+         bal_model_ids_pb2.
          BAL_SUBSCRIBER_TERMINAL_AUTO_ID_DGI):
             bal_subs_term_dgi_ind,
         (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
-         bal_model_ids_pb2.\
-         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_IND):
-            bal_subs_term_ind,
-
-        (bal_model_ids_pb2.BAL_OBJ_ID_TM_QUEUE,
-         bal_model_ids_pb2.BAL_TM_QUEUE_AUTO_ID_IND):
-            bal_tm_queue_ind_info,
+         bal_model_ids_pb2.
+         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_DOWI):
+            bal_subs_term_dowi_ind,
+        (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
+         bal_model_ids_pb2.
+         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_LOOCI):
+            bal_subs_term_looci_ind,
+        (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
+         bal_model_ids_pb2.
+         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_PROCESSING_ERROR):
+            bal_subs_term_processing_error,
+        (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
+         bal_model_ids_pb2.
+         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SDI):
+            bal_subs_term_sdi_ind,
+        (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
+         bal_model_ids_pb2.
+         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SFI):
+            bal_subs_term_sfi_ind,
+        (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
+         bal_model_ids_pb2.
+         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUB_TERM_ACT_FAIL):
+            bal_subs_term_activation_fail,
+        (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
+         bal_model_ids_pb2.
+         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUFI):
+            bal_subs_term_sufi_ind,
+        (bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL,
+         bal_model_ids_pb2.
+         BAL_SUBSCRIBER_TERMINAL_AUTO_ID_TIWI):
+            bal_subs_term_tiwi_ind,
 
         (bal_model_ids_pb2.BAL_OBJ_ID_TM_SCHED,
-         bal_model_ids_pb2.BAL_TM_SCHED_AUTO_ID_IND):
-            bal_tm_sched_ind_info,
+         bal_model_ids_pb2.BAL_TM_SCHED_AUTO_ID_OPER_STATUS_CHANGE):
+            bal_tm_sched_oper_status_change,
 
         (bal_model_ids_pb2.BAL_OBJ_ID_PACKET,
          bal_model_ids_pb2.BAL_PACKET_AUTO_ID_BEARER_CHANNEL_RX):
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_kv_store.py b/voltha/adapters/asfvolt16_olt/asfvolt16_kv_store.py
new file mode 100755
index 0000000..eb578a2
--- /dev/null
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_kv_store.py
@@ -0,0 +1,266 @@
+#
+# Copyright 2017 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""
+Implementation for the interface of KV store of flow and bal flow mapping
+"""
+import structlog
+import json
+from zope.interface import implementer
+from voltha.adapters.asfvolt16_olt.kv_store_interface import KvStoreInterface
+from voltha.core.config.config_backend import ConsulStore
+from voltha.core.config.config_backend import EtcdStore
+
+# KV store uses this prefix to store flows info
+PATH_PREFIX = 'asfvolt16_flow_store'
+
+log = structlog.get_logger()
+
+@implementer(KvStoreInterface)
+class Asfvolt16KvStore(object):
+
+    def __init__(self, backend, host, port):
+        """
+        based on backend ('consul' and 'etcd' use the host and port
+        to create of the respective object
+        :param backend: Type of backend storage (etcd or consul)
+        :param host: host ip info for backend storage
+        :param port: port for the backend storage
+        """
+        try:
+            if backend == 'consul':
+                self.kv_store = ConsulStore(host, port, PATH_PREFIX)
+            elif backend == 'etcd':
+                self.kv_store = EtcdStore(host, port, PATH_PREFIX)
+            else:
+                log.error('Invalid-backend')
+                raise Exception("Invalid-backend-for-kv-store")
+        except Exception as e:
+            log.exception("exception-in-init", e=e)
+
+    # Used for incremental flow, as we are getting remove flow cookies,
+    # So instead of evaluating, we are just getting the mapping info
+    # from kv store
+    def get_flows_to_remove_info(self, device_id, flows):
+        # store flows to be removed
+        flows_to_remove_list = []
+        id = device_id.encode('ascii', 'ignore')
+
+        try:
+            # Preparing cookie info list from received remove flow
+            for flow in flows:
+                cookie_info = self.kv_store[id + '/' + str(flow.cookie)]
+                if cookie_info:
+                    log.debug("cookie-info-exist", cookie=flow.cookie,
+                              cookie_info=cookie_info)
+                    flows_to_remove_list.append(json.loads(cookie_info))
+                else:
+                    log.debug("cookie-info-does-not-exist", cookie=flow.cookie)
+
+        except Exception as e:
+            log.exception("evaulating-flows-to-remove-info", e=e)
+
+        return flows_to_remove_list
+
+    # Used for bulk flow update, as we are getting bulk flow cookies,
+    # So we evalute based on the curent flows present in kv store
+    def get_flows_to_remove(self, device_id, flows):
+        # store the flows present in the db
+        current_flows_list = []
+
+        # store flows to be removed
+        flows_to_remove_list = []
+        id = device_id.encode('ascii', 'ignore')
+
+        # Get all the flows already present in the consul
+        try:
+            # Get all the flows already present in the consul
+            # Preparing cookie list from flows present in the KV store
+            kv_store_flows = self.kv_store._kv_get(PATH_PREFIX + '/' + id,
+                                                   recurse=True)
+            if kv_store_flows is None:
+                return flows_to_remove_list
+
+            for kv_store_flow in kv_store_flows:
+                value = kv_store_flow['Value']
+                current_flows_list.append(json.loads(value))
+
+            # Preparing cookie list from bulk flow received
+            bulk_update_flow_cookie_list = [flow.cookie for flow in flows]
+
+            # Evaluating the flows need to be removed
+            # current_flows not present in bulk_flow
+            for current_flow in current_flows_list:
+                cookie = current_flow.keys()[0]
+                if long(cookie) not in bulk_update_flow_cookie_list:
+                    flows_to_remove_list.append(current_flow[cookie])
+
+        except Exception as e:
+            log.exception("evaulating-flows-to-remove", e=e)
+
+        return flows_to_remove_list
+
+    def get_flows_to_add(self, device_id, flows):
+        # store the flows present in the db
+        current_flows_list = []
+        id = device_id.encode('ascii', 'ignore')
+
+        try:
+            # Get all the flows already present in the consul
+            # Preparing cookie set from flows present in the KV store
+            kv_store_flows = self.kv_store._kv_get(PATH_PREFIX + '/' + id,
+                                                   recurse=True)
+            if kv_store_flows is not None:
+                for kv_store_flow in kv_store_flows:
+                    value = kv_store_flow['Value']
+                    current_flows_list.append(json.loads(value))
+
+            current_flow_cookie_set = set(long(current_flow.keys()[0])
+                                          for current_flow in current_flows_list)
+            # Preparing cookie set from bulk flow received
+            bulk_update_flow_cookie_set = set(flow.cookie for flow in flows)
+
+            # Evaluating the list of flows newly to be added
+            flow_to_add_set = bulk_update_flow_cookie_set.difference \
+                                             (current_flow_cookie_set)
+            flows_to_add_list = list(flow_to_add_set)
+
+        except Exception as e:
+            log.exception("evaluating-flows-to-add", e=e)
+
+        return flows_to_add_list
+
+    def add_to_kv_store(self, device_id, new_flow_mapping_list):
+        # store the flows present in the db
+        current_flows_list = []
+        id = device_id.encode('ascii', 'ignore')
+
+        try:
+            log.debug("incremental-flows-to-be-added-to-kv-store",
+                      flows=new_flow_mapping_list)
+            # Key is the cookie id, extracted from the key stored in new_flow_mapping_list
+            for flow in new_flow_mapping_list:
+                self.kv_store[id + '/' + str(flow.keys()[0])] = json.dumps(flow)
+
+        except Exception as e:
+            log.exception("incremental-flow-add-to-kv-store", e=e)
+
+    def remove_from_kv_store(self, device_id, flows_to_remove):
+        id = device_id.encode('ascii', 'ignore')
+
+        try:
+            log.debug("incremental-flows-to-be-removed-from-kv-store",
+                      flows=flows_to_remove)
+            # remove the flows based on cookie id from kv store
+            for cookie in flows_to_remove:
+                del self.kv_store[id + '/' + str(cookie)]
+
+        except Exception as e:
+            log.exception("incremental-flow-remove-from-kv-store", e=e)
+
+    def update_kv_store(self, device_id, new_flow_mapping_list, flows):
+        # store the flows present in the db
+        current_flows_list = []
+        id = device_id.encode('ascii', 'ignore')
+
+        try:
+            # Get all the flows already present in the consul
+            # Preparing cookie set from flows present in the KV store
+            kv_store_flows = self.kv_store._kv_get(PATH_PREFIX + '/' + id,
+                                                   recurse=True)
+            if kv_store_flows is not None:
+                for kv_store_flow in kv_store_flows:
+                    value = kv_store_flow['Value']
+                    current_flows_list.append(json.loads(value))
+
+            current_flow_cookie_set = set(long(current_flow.keys()[0])
+                                          for current_flow in current_flows_list)
+
+            # Preparing cookie set from flows added newly
+            new_flow_added_cookie_set = set(new_flow.keys()[0]
+                                            for new_flow in new_flow_mapping_list)
+
+            # Preparing cookie set from bulk flow received
+            bulk_update_flow_cookie_set = set(flow.cookie for flow in flows)
+
+            # Evaluating flows to be removed, remove from KV store
+            remove_flows_list = list(current_flow_cookie_set.difference \
+                                              (bulk_update_flow_cookie_set))
+            log.debug("bulk-flows-to-be-removed-from-kv-store",
+                      flows=remove_flows_list)
+
+            for cookie in remove_flows_list:
+                del self.kv_store[id + '/' + str(cookie)]
+
+            # Evaluating flows need to be added newly to KV, add to KV
+            new_flows_list = list(new_flow_added_cookie_set.difference \
+                                            (current_flow_cookie_set))
+            log.debug("bulk-flows-to-be-added-to-kv-store", flows=new_flows_list)
+
+            for new_flow in new_flows_list:
+                for fl in new_flow_mapping_list:
+                    if fl.keys()[0] == new_flow:
+                        self.kv_store[id + '/' + str(new_flow)] = json.dumps(fl)
+
+        except Exception as e:
+            log.exception("bulk-flow-update-kv-store", e=e)
+
+
+    def clear_kv_store(self, device_id):
+        id = device_id.encode('ascii', 'ignore')
+        try:
+            # Recurse flow is not working as cache is not getting cleared
+            # So extracting all flows using GET and deleting each flow
+            #kv_store_clear_flows = self.kv_store._kv_delete(PATH_PREFIX + '/' \
+            #                                                + id, recurse=True)
+
+            # Get all the flows present in the consul
+            kv_store_flows = self.kv_store._kv_get(PATH_PREFIX + '/' + id,
+                                                   recurse=True)
+            if kv_store_flows is not None:
+                for kv_store_flow in kv_store_flows:
+                    # Extracting cookie id from the kv store flow details
+                    # and deleting each flows
+                    flow = json.loads(kv_store_flow['Value'])
+                    cookie = flow.keys()[0]
+                    del self.kv_store[id + '/' + str(cookie)]
+                log.debug("kv-store-flows-cleared-successfully")
+            else:
+                log.debug("no-flows-found-in-kv-store")
+                return
+
+        except Exception as e:
+            log.exception("clear-kv-store", e=e)
+
+    def is_reference_found_for_key_value(self, device_id, key, value):
+        id = device_id.encode('ascii', 'ignore')
+        try:
+            # Get all the flows present in the consul
+            kv_store_flows = self.kv_store._kv_get(PATH_PREFIX + '/' + id,
+                                                   recurse=True)
+            if kv_store_flows is not None:
+                for kv_store_flow in kv_store_flows:
+                    flow = json.loads(kv_store_flow['Value'])
+                    cookie = flow.keys()[0]
+                    flow_data = flow[cookie]
+                    if key in flow_data.keys():
+                        # Check if have reference for the Key in the flow
+                        # with the given value
+                        if flow_data[key] == value:
+                            return True
+        except Exception as e:
+            log.exception("excepting-finding-refernece-for-kv", e=e)
+
+        return False
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py b/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
index 3e91fc9..86e2df0 100644
--- a/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
@@ -34,7 +34,8 @@
                                                name='asfvolt16_olt',
                                                vendor='Edgecore',
                                                version='0.98',
-                                               device_type='asfvolt16_olt')
+                                               device_type='asfvolt16_olt',
+                                               accepts_add_remove_flow_updates = True)
         # register for adapter messages
         self.port = 60001
         self.rx_handler = Asfvolt16RxHandler(self, self.port, log)
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_rx_handler.py b/voltha/adapters/asfvolt16_olt/asfvolt16_rx_handler.py
index 2b65da7..2ef2eb6 100644
--- a/voltha/adapters/asfvolt16_olt/asfvolt16_rx_handler.py
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_rx_handler.py
@@ -57,12 +57,12 @@
         return bal_err
 
     @twisted_async
-    def BalAccTermInd(self, request, context):
+    def BalAccTermProcErr(self, request, context):
         device_id = request.device_id.decode('unicode-escape')
-        self.log.info('Received-access-terminal-Indication',
+        self.log.info('Received-access-terminal-Processing-Error',
                       device_id=device_id, obj_type=request.objType)
         device_handler = self.adapter.devices_handlers[device_id]
-        self.ind_handler.bal_acc_term_ind(request, device_handler)
+        self.ind_handler.bal_acc_term_processing_error(request, device_handler)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
@@ -79,12 +79,12 @@
         return bal_err
 
     @twisted_async
-    def BalFlowInd(self, request, context):
+    def BalFlowProcErr(self, request, context):
         device_id = request.device_id.decode('unicode-escape')
-        self.log.info('Not-implemented-yet',
+        self.log.info('Received-bal-flow-processing-error',
                       device_id=device_id, obj_type=request.objType)
         device_handler = self.adapter.devices_handlers[device_id]
-        self.ind_handler.bal_flow_ind(request, device_handler)
+        self.ind_handler.bal_flow_processing_error(request, device_handler)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
@@ -189,34 +189,100 @@
         return bal_err
 
     @twisted_async
-    def BalSubsTermInd(self, request, context):
+    def BalSubsTermDowiInd(self, request, context):
         device_id = request.device_id.decode('unicode-escape')
-        self.log.info('Subscriber-terminal-indication-received',
+        self.log.info('Subscriber-terminal-dowi', \
                       device_id=device_id, obj_type=request.objType)
         device_handler = self.adapter.devices_handlers[device_id]
-        self.ind_handler.bal_subs_term_ind(request, device_handler)
+        self.ind_handler.bal_subs_term_dowi_ind(request, device_handler)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
     @twisted_async
-    def BalTmQueueIndInfo(self, request, context):
+    def BalSubsTermLoociInd(self, request, context):
         device_id = request.device_id.decode('unicode-escape')
-        self.log.info('Not-implemented-yet',
+        self.log.info('Subscriber-terminal-looci', \
                       device_id=device_id, obj_type=request.objType)
         device_handler = self.adapter.devices_handlers[device_id]
-        self.ind_handler.bal_tm_queue_ind_info(request, device_handler)
+        self.ind_handler.bal_subs_term_looci_ind(request, device_handler)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
 
     @twisted_async
-    def BalTmSchedIndInfo(self, request, context):
+    def BalSubsTermProcErr(self, request, context):
         device_id = request.device_id.decode('unicode-escape')
-        self.log.info('Not-implemented-yet',
+        self.log.info('Subscriber-terminal-processing-error-received',
                       device_id=device_id, obj_type=request.objType)
         device_handler = self.adapter.devices_handlers[device_id]
-        self.ind_handler.bal_tm_sched_ind_info(request, device_handler)
+        self.ind_handler.bal_subs_term_processing_error(request, device_handler)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    @twisted_async
+    def BalSubsTermSdiInd(self, request, context):
+        device_id = request.device_id.decode('unicode-escape')
+        self.log.info('Subscriber-terminal-sdi-received',
+                      device_id=device_id, obj_type=request.objType)
+        device_handler = self.adapter.devices_handlers[device_id]
+        self.ind_handler.bal_subs_term_sdi_ind(request, device_handler)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    @twisted_async
+    def BalSubsTermSfiInd(self, request, context):
+        device_id = request.device_id.decode('unicode-escape')
+        self.log.info('Subscriber-terminal-sfi-received',
+                      device_id=device_id, obj_type=request.objType)
+        device_handler = self.adapter.devices_handlers[device_id]
+        self.ind_handler.bal_subs_term_sfi_ind(request, device_handler)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    @twisted_async
+    def BalSubsTermSufiInd(self, request, context):
+        device_id = request.device_id.decode('unicode-escape')
+        self.log.info('Subscriber-terminal-sufi-received',
+                      device_id=device_id, obj_type=request.objType)
+        device_handler = self.adapter.devices_handlers[device_id]
+        self.ind_handler.bal_subs_term_sufi_ind(request, device_handler)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    @twisted_async
+    def BalSubsTermTiwiInd(self, request, context):
+        device_id = request.device_id.decode('unicode-escape')
+        self.log.info('Subscriber-terminal-tiwi-received',
+                      device_id=device_id, obj_type=request.objType)
+        device_handler = self.adapter.devices_handlers[device_id]
+        self.ind_handler.bal_subs_term_tiwi_ind(request, device_handler)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    @twisted_async
+    def BalSubTermActFailInd(self, request, context):
+        device_id = request.device_id.decode('unicode-escape')
+        self.log.info('Subscriber-terminal-activation-fail-received',
+                      device_id=device_id, obj_type=request.objType)
+        device_handler = self.adapter.devices_handlers[device_id]
+        self.ind_handler.bal_subs_term_activation_fail(request, device_handler)
+        bal_err = bal_pb2.BalErr()
+        bal_err.err = bal_errno_pb2.BAL_ERR_OK
+        return bal_err
+
+    @twisted_async
+    def BalTmSchedOperStatsChange(self, request, context):
+        device_id = request.device_id.decode('unicode-escape')
+        self.log.info('Tm-Scheduler-Operation-status-change-received',
+                      device_id=device_id, obj_type=request.objType)
+        device_handler = self.adapter.devices_handlers[device_id]
+        self.ind_handler.bal_tm_sched_oper_status_change(request, device_handler)
         bal_err = bal_pb2.BalErr()
         bal_err.err = bal_errno_pb2.BAL_ERR_OK
         return bal_err
diff --git a/voltha/adapters/asfvolt16_olt/bal.py b/voltha/adapters/asfvolt16_olt/bal.py
index ae8dcf0..33d3deb 100644
--- a/voltha/adapters/asfvolt16_olt/bal.py
+++ b/voltha/adapters/asfvolt16_olt/bal.py
@@ -27,12 +27,16 @@
 import time
 import os
 
-# ASFVOLT Adapter port is 60001
+"""
+ASFVOLT Adapter port is 60001
+"""
 ADAPTER_PORT = 60001
 
 GRPC_TIMEOUT = 5
 GRPC_HEARTBEAT_TIMEOUT = 2
 
+RESERVED_VLAN_ID = 4095
+
 
 class Bal(object):
     def __init__(self, olt, log):
@@ -76,6 +80,7 @@
             self.log.info('connecting-olt', host_and_port=host_and_port,
                           init_details=init)
             yield self.stub.BalApiInit(init, timeout=GRPC_TIMEOUT)
+            yield asleep(0.2)
 
     def activate_olt(self):
         self.log.info('activating-olt')
@@ -98,6 +103,33 @@
         yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
 
     @inlineCallbacks
+    def get_access_terminal_cfg(self):
+        try:
+            obj = bal_pb2.BalKey()
+            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_ACCESS_TERMINAL
+            obj.access_term_key.access_term_id = 0
+            access_term_cfg = yield self.stub.BalCfgGet(obj, timeout=GRPC_TIMEOUT)
+            self.log.debug("rxed-access-term-cfg", access_term_cfg=access_term_cfg)
+            returnValue(access_term_cfg)
+        except Exception as e:
+            self.log.info('get-access-terminal-cfg-exception', exc=str(e))
+            return
+
+    @inlineCallbacks
+    def get_subscriber_terminal_cfg(self, sub_term_id, intf_id):
+        try:
+            obj = bal_pb2.BalKey()
+            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL
+            obj.terminal_key.sub_term_id = sub_term_id
+            obj.terminal_key.intf_id = intf_id
+            sub_term_cfg = yield self.stub.BalCfgGet(obj, timeout=GRPC_TIMEOUT)
+            self.log.debug("rxed-sub-term-cfg", sub_term_cfg=sub_term_cfg)
+            returnValue(sub_term_cfg)
+        except Exception as e:
+            self.log.info('get-subscriber-terminal-cfg-exception', exc=str(e))
+            return
+
+    @inlineCallbacks
     def activate_pon_port(self, olt_no, pon_port, transceiver_type):
         try:
             obj = bal_pb2.BalCfg()
@@ -176,7 +208,7 @@
             obj.terminal.data.serial_number.vendor_id = onu_info['vendor']
             obj.terminal.data.serial_number.vendor_specific = \
                 onu_info['vendor_specific']
-            obj.terminal.data.registration_id = onu_info['reg_id']
+            #obj.terminal.data.registration_id = onu_info['reg_id']
             self.log.info('activating-ONU-in-olt',
                           onu_details=obj)
             yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
@@ -226,9 +258,9 @@
 
     @inlineCallbacks
     def add_flow(self, onu_id=None, intf_id=None, network_int_id=None,
-                 flow_id=None, gem_port=None,
-                 classifier_info=None, is_downstream=False,
-                 action_info=None, sched_id=None):
+                 flow_id=None, gem_port=None, classifier_info=None,
+                 is_downstream=None, action_info=None, priority=None,
+                 dba_sched_id=None, queue_id=None, queue_sched_id=None):
         try:
             obj = bal_pb2.BalCfg()
             # Fill Header details
@@ -240,11 +272,16 @@
             if is_downstream is False:
                 obj.flow.key.flow_type = \
                     bal_model_types_pb2.BAL_FLOW_TYPE_UPSTREAM
-                obj.flow.data.dba_tm_sched_id = sched_id
+                obj.flow.data.dba_tm_sched_id = dba_sched_id
             else:
                 obj.flow.key.flow_type = \
                     bal_model_types_pb2.BAL_FLOW_TYPE_DOWNSTREAM
 
+            if queue_sched_id:
+                obj.flow.data.queue.sched_id = queue_sched_id
+            if queue_id:
+                obj.flow.data.queue.queue_id = queue_id
+
             obj.flow.data.admin_state = bal_model_types_pb2.BAL_STATE_UP
             if intf_id is not None:
                 obj.flow.data.access_int_id = intf_id
@@ -254,6 +291,8 @@
                 obj.flow.data.sub_term_id = onu_id
             if gem_port:
                 obj.flow.data.svc_port_id = gem_port
+            if priority:
+                obj.flow.data.priority = priority
             obj.flow.data.classifier.presence_mask = 0
 
             if classifier_info is None:
@@ -320,10 +359,7 @@
                 obj.flow.data.classifier.presence_mask |= \
                     bal_model_types_pb2.BAL_CLASSIFIER_ID_PKT_TAG_TYPE
 
-            # Action field is not mandatory in Downstream
-            # If the packet matches the classifiers, the packet is put
-            # on the gem port specified.
-            if action_info is not None:
+            if action_info:
                 obj.flow.data.action.presence_mask = 0
                 obj.flow.data.action.cmds_bitmask = 0
                 if 'pop_vlan' in action_info:
@@ -348,9 +384,9 @@
                     obj.flow.data.action.presence_mask |= \
                         bal_model_types_pb2.BAL_ACTION_ID_CMDS_BITMASK
                 else:
-                    self.log.info('invalid-action', action_info=action_info)
+                    self.log.info('Invalid-action-field',
+                                 action_info=action_info)
                     return
-
             self.log.info('adding-flow-to-OLT-Device',
                           flow_details=obj)
             yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
@@ -359,8 +395,101 @@
                           flow_id, onu_id, exc=str(e))
         return
 
-    # Note: Bal_2.4 version expects expects all the classifier and action
-    # in deactivate flow that was used during flow activation.
+    @inlineCallbacks
+    def deactivate_flow(self, flow_id,
+                        is_downstream,
+                        onu_id=None,
+                        intf_id=None,
+                        network_int_id=None,
+                        gemport_id=None,
+                        priority=None,
+                        stag=None,
+                        ctag=None,
+                        dba_sched_id=None,
+                        us_scheduler_id=None,
+                        ds_scheduler_id=None,
+                        queue_id=None):
+        try:
+            obj = bal_pb2.BalCfg()
+            # Fill Header details
+            obj.device_id = self.device_id.encode('ascii', 'ignore')
+            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_FLOW
+            # Fill Access Terminal Details
+            # To-DO flow ID need to be retrieved from flow details
+            obj.flow.key.flow_id = flow_id
+            obj.flow.data.admin_state = bal_model_types_pb2.BAL_STATE_DOWN
+            if intf_id is not None:
+                obj.flow.data.access_int_id = intf_id
+            if network_int_id is not None:
+                obj.flow.data.network_int_id = network_int_id
+            if onu_id is not None:
+                obj.flow.data.sub_term_id = onu_id
+            if gemport_id is not None:
+                obj.flow.data.svc_port_id = gemport_id
+            if priority is not None:
+                obj.flow.data.priority = priority
+
+            if is_downstream is True:
+                obj.flow.key.flow_type = \
+                    bal_model_types_pb2.BAL_FLOW_TYPE_DOWNSTREAM
+                if stag is not None:
+                    obj.flow.data.classifier.o_vid = stag
+                    obj.flow.data.classifier.presence_mask |= \
+                        bal_model_types_pb2.BAL_CLASSIFIER_ID_O_VID
+                    obj.flow.data.classifier.pkt_tag_type = \
+                        bal_model_types_pb2.BAL_PKT_TAG_TYPE_DOUBLE_TAG
+                    obj.flow.data.classifier.presence_mask |= \
+                        bal_model_types_pb2.BAL_CLASSIFIER_ID_PKT_TAG_TYPE
+                    obj.flow.data.action.cmds_bitmask |= \
+                        bal_model_types_pb2.BAL_ACTION_CMD_ID_REMOVE_OUTER_TAG
+                    obj.flow.data.action.presence_mask |= \
+                        bal_model_types_pb2.BAL_ACTION_ID_CMDS_BITMASK
+                    obj.flow.data.action.o_vid = stag
+                    obj.flow.data.action.presence_mask |= \
+                        bal_model_types_pb2.BAL_ACTION_ID_O_VID
+                if ctag != RESERVED_VLAN_ID:
+                    obj.flow.data.classifier.i_vid = ctag
+                    obj.flow.data.classifier.presence_mask |= \
+                        bal_model_types_pb2.BAL_CLASSIFIER_ID_I_VID
+            else:
+                obj.flow.key.flow_type = \
+                    bal_model_types_pb2.BAL_FLOW_TYPE_UPSTREAM
+                obj.flow.data.classifier.pkt_tag_type = \
+                    bal_model_types_pb2.BAL_PKT_TAG_TYPE_SINGLE_TAG
+                obj.flow.data.classifier.presence_mask |= \
+                    bal_model_types_pb2.BAL_CLASSIFIER_ID_PKT_TAG_TYPE
+                obj.flow.data.action.cmds_bitmask |= \
+                    bal_model_types_pb2.BAL_ACTION_CMD_ID_ADD_OUTER_TAG
+                obj.flow.data.action.presence_mask |= \
+                    bal_model_types_pb2.BAL_ACTION_ID_CMDS_BITMASK
+                obj.flow.data.action.o_vid = stag
+                obj.flow.data.action.presence_mask |= \
+                    bal_model_types_pb2.BAL_ACTION_ID_O_VID
+                if ctag != RESERVED_VLAN_ID:
+                    obj.flow.data.classifier.o_vid = ctag
+                    obj.flow.data.classifier.presence_mask |= \
+                        bal_model_types_pb2.BAL_CLASSIFIER_ID_O_VID
+
+            if dba_sched_id is not None:
+                obj.flow.data.dba_tm_sched_id = dba_sched_id
+
+            if queue_id is not None:
+                obj.flow.data.queue.queue_id = queue_id
+                if ds_scheduler_id is not None:
+                    obj.flow.data.queue.sched_id = ds_scheduler_id
+            else:
+                obj.flow.data.queue.queue_id = 0
+                if us_scheduler_id is not None:
+                    obj.flow.data.queue.sched_id = us_scheduler_id
+
+            self.log.info('deactivating-flows-from-OLT-Device',
+                          flow_details=obj)
+            yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
+        except Exception as e:
+            self.log.exception('deactivate_flow-exception',
+                          flow_id, onu_id, exc=str(e))
+        return
+
     @inlineCallbacks
     def deactivate_eapol_flow(self, flow_id, is_downstream,
                               onu_id=None,
@@ -368,7 +497,9 @@
                               network_int_id=None,
                               gemport_id=None,
                               stag=None,
-                              sched_id=None):
+                              dba_sched_id=None,
+                              queue_id=None,
+                              queue_sched_id=None):
         try:
             obj = bal_pb2.BalCfg()
             # Fill Header details
@@ -405,9 +536,12 @@
                 bal_model_types_pb2.BAL_ACTION_CMD_ID_TRAP_TO_HOST
             obj.flow.data.action.presence_mask |= \
                 bal_model_types_pb2.BAL_ACTION_ID_CMDS_BITMASK
-            if sched_id is not None:
-                obj.flow.data.dba_tm_sched_id = sched_id
-
+            if dba_sched_id:
+                obj.flow.data.dba_tm_sched_id = dba_sched_id
+            if queue_id:
+                obj.flow.data.queue.queue_id = queue_id
+            if queue_sched_id:
+                obj.flow.data.queue.sched_id = queue_sched_id
             self.log.info('deactivating-eapol-flows-from-OLT-Device',
                           flow_details=obj)
             yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
@@ -417,29 +551,8 @@
         return
 
     @inlineCallbacks
-    def delete_flow(self, flow_id, is_downstream):
-        try:
-            obj = bal_pb2.BalKey()
-            # Fill Header details
-            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_FLOW
-            obj.flow_key.flow_id = flow_id
-            if is_downstream is False:
-                obj.flow_key.flow_type = \
-                    bal_model_types_pb2.BAL_FLOW_TYPE_UPSTREAM
-            else:
-                obj.flow_key.flow_type = \
-                    bal_model_types_pb2.BAL_FLOW_TYPE_DOWNSTREAM
-
-            self.log.info('deleting-flows-from-OLT-Device',
-                          flow_details=obj)
-            resp = yield self.stub.BalCfgClear(obj, timeout=GRPC_TIMEOUT)
-        except Exception as e:
-            self.log.exception('delete_flow-exception',
-                          flow_id, e=e)
-        return
-
-    @inlineCallbacks
-    def create_scheduler(self, id, direction, owner_info, num_priority):
+    def create_scheduler(self, id, direction, owner_info, num_priority,
+                         rate_info=None):
         try:
             obj = bal_pb2.BalCfg()
             # Fill Header details
@@ -474,9 +587,16 @@
                 self.log.error('Not-supported-scheduling-type',
                                sched_type=owner_info['type'])
                 return
-            obj.tm_sched_cfg.data.sched_type = \
-                bal_model_types_pb2.BAL_TM_SCHED_TYPE_SP_WFQ
-            obj.tm_sched_cfg.data.num_priorities = num_priority
+            #obj.tm_sched_cfg.data.sched_type = \
+            #    bal_model_types_pb2.BAL_TM_SCHED_TYPE_SP_WFQ
+            #obj.tm_sched_cfg.data.num_priorities = num_priority
+            if rate_info is not None:
+                obj.tm_sched_cfg.data.rate.presence_mask = \
+                    bal_model_types_pb2.BAL_TM_SHAPING_ID_ALL
+                obj.tm_sched_cfg.data.rate.cir = rate_info['cir']
+                obj.tm_sched_cfg.data.rate.pir = rate_info['pir']
+                obj.tm_sched_cfg.data.rate.burst = rate_info['burst']
+
             self.log.info('Creating-Scheduler',
                           scheduler_details=obj)
             yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
@@ -486,10 +606,10 @@
                           sched_id=id,
                           direction=direction,
                           owner=owner_info,
+                          rate=rate_info,
                           exc=str(e))
         return
 
-
     @inlineCallbacks
     def deactivate_onu(self, onu_info):
         try:
@@ -514,6 +634,22 @@
         return
 
     @inlineCallbacks
+    def delete_onu(self, onu_info):
+        try:
+            obj = bal_pb2.BalKey()
+            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_SUBSCRIBER_TERMINAL
+            # Fill Access Terminal Details
+            obj.terminal_key.sub_term_id = onu_info['onu_id']
+            obj.terminal_key.intf_id = onu_info['pon_id']
+            self.log.info('delete-ONU-in-olt',
+                          onu_details=obj)
+            yield self.stub.BalCfgClear(obj, timeout=5)
+        except Exception as e:
+            self.log.info('delete-ONU-exception',
+                          onu_info['onu_id'], exc=str(e))
+        return
+
+    @inlineCallbacks
     def delete_scheduler(self, id, direction):
         try:
             obj = bal_pb2.BalKey()
@@ -538,6 +674,52 @@
         return
 
     @inlineCallbacks
+    def delete_scheduler(self, id, direction):
+        try:
+            obj = bal_pb2.BalKey()
+            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_TM_SCHED
+            # Fill Access Terminal Details
+            if direction == 'downstream':
+                obj.tm_sched_key.dir =\
+                    bal_model_types_pb2.BAL_TM_SCHED_DIR_DS
+            else:
+                obj.tm_sched_key.dir = \
+                    bal_model_types_pb2.BAL_TM_SCHED_DIR_US
+            obj.tm_sched_key.id = id
+            self.log.info('Deleting Scheduler',
+                          scheduler_details=obj)
+            yield self.stub.BalCfgClear(obj, timeout=GRPC_TIMEOUT)
+        except Exception as e:
+            self.log.info('creat-scheduler-exception',
+                          olt=self.olt.olt_id,
+                          sched_id=id,
+                          direction=direction,
+                          exc=str(e))
+        return
+
+    @inlineCallbacks
+    def delete_flow(self, flow_id, is_downstream):
+        try:
+            obj = bal_pb2.BalKey()
+            # Fill Header details
+            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_FLOW
+            obj.flow_key.flow_id = flow_id
+            if is_downstream is False:
+                obj.flow_key.flow_type = \
+                    bal_model_types_pb2.BAL_FLOW_TYPE_UPSTREAM
+            else:
+                obj.flow_key.flow_type = \
+                    bal_model_types_pb2.BAL_FLOW_TYPE_DOWNSTREAM
+
+            self.log.info('deleting-flows-from-OLT-Device',
+                          flow_details=obj)
+            resp = yield self.stub.BalCfgClear(obj, timeout=5)
+        except Exception as e:
+            self.log.exception('delete_flow-exception',
+                          flow_id, e=e)
+        return
+
+    @inlineCallbacks
     def get_bal_interface_stats(self, intf_id, interface_type):
         # This happens too often and the below log is unnecessary.
         # The status are anyway available on kafka
@@ -619,12 +801,90 @@
                 obj.device_id = str(device_id)
                 bal_ind = self.ind_stub.BalGetIndFromDevice(obj, timeout=GRPC_TIMEOUT)
                 if bal_ind.ind_present == True:
-                    # self.log.info('Indication-received',
-                    #               device=device_id, bal_ind=bal_ind)
                     self.ind_obj.handle_indication_from_bal(bal_ind, self.olt)
             except Exception as e:
                 self.log.info('Failed-to-get-indication-info', exc=str(e))
-            finally:
-                time.sleep(self.interval)
+
+            time.sleep(self.interval)
 
         self.log.debug('stop-indication-receive-thread')
+
+    @inlineCallbacks
+    def create_queue(self, id, direction, sched_id,
+                     priority=None, weight=None, rate_info=None):
+        try:
+            obj = bal_pb2.BalCfg()
+            # Fill Header details
+            obj.device_id = self.device_id.encode('ascii', 'ignore')
+            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_TM_QUEUE
+            # Fill Queue Cfg Details
+            if direction == 'downstream':
+                obj.tm_queue_cfg.key.sched_dir = \
+                    bal_model_types_pb2.BAL_TM_SCHED_DIR_DS
+            else:
+                obj.tm_queue_cfg.key.sched_dir = \
+                    bal_model_types_pb2.BAL_TM_SCHED_DIR_US
+            obj.tm_queue_cfg.key.id = id
+            obj.tm_queue_cfg.key.sched_id = sched_id
+            '''
+            TO-DO:By default the schedular created is of type sp_wfq,
+            which requires either priority or weight but not both.
+            Need to fetch schd_type then assign either one of them
+            '''
+            if weight is not None:
+                #obj.tm_queue_cfg.data.priority = priority
+                obj.tm_queue_cfg.data.weight = weight
+
+            if rate_info is not None:
+                obj.tm_queue_cfg.data.rate.presence_mask = \
+                    bal_model_types_pb2.BAL_TM_SHAPING_ID_ALL
+                obj.tm_queue_cfg.data.rate.cir = rate_info['cir']
+                obj.tm_queue_cfg.data.rate.pir = rate_info['pir']
+                obj.tm_queue_cfg.data.rate.burst = rate_info['burst']
+            else:
+                obj.tm_queue_cfg.data.rate.presence_mask = \
+                    bal_model_types_pb2.BAL_TM_SHAPING_ID_NONE
+            obj.tm_queue_cfg.data.creation_mode = \
+                    bal_model_types_pb2.BAL_TM_CREATION_MODE_MANUAL
+            obj.tm_queue_cfg.data.ref_count = 0
+
+            self.log.info('Creating-Queue',
+                          scheduler_details=obj)
+            yield self.stub.BalCfgSet(obj, timeout=GRPC_TIMEOUT)
+        except Exception as e:
+            self.log.info('create-queue-exception',
+                          olt=self.olt.olt_id,
+                          queue_id=id,
+                          direction=direction,
+                          sched_id=sched_id,
+                          priority=priority,
+                          weight=weight,
+                          rate_info=rate_info,
+                          exc=str(e))
+        return
+
+    @inlineCallbacks
+    def delete_queue(self, id, direction, sched_id):
+        try:
+            obj = bal_pb2.BalKey()
+            obj.hdr.obj_type = bal_model_ids_pb2.BAL_OBJ_ID_TM_QUEUE
+            # Fill Queue Key Details
+            if direction == 'downstream':
+                obj.tm_queue_key.sched_dir =\
+                    bal_model_types_pb2.BAL_TM_SCHED_DIR_DS
+            else:
+                obj.tm_queue_key.sched_dir = \
+                    bal_model_types_pb2.BAL_TM_SCHED_DIR_US
+            obj.tm_queue_key.id = id
+            obj.tm_queue_key.sched_id = sched_id
+            self.log.info('Deleting-Queue',
+                          queue_details=obj)
+            yield self.stub.BalCfgClear(obj, timeout=GRPC_TIMEOUT)
+        except Exception as e:
+            self.log.info('delete-queue-exception',
+                          olt=self.olt.olt_id,
+                          queue_id=id,
+                          direction=direction,
+                          sched_id=sched_id,
+                          exc=str(e))
+        return
diff --git a/voltha/adapters/asfvolt16_olt/kv_store_interface.py b/voltha/adapters/asfvolt16_olt/kv_store_interface.py
new file mode 100755
index 0000000..d3d4d05
--- /dev/null
+++ b/voltha/adapters/asfvolt16_olt/kv_store_interface.py
@@ -0,0 +1,98 @@
+#
+# Copyright 2017 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+Interface definition for KV Store interface for ASFvOLT16 adapter
+"""
+from zope.interface import Interface
+
+
+class KvStoreInterface(Interface):
+    """
+    KV Store Interface for ASFvOLT16 adapter
+    """
+     
+    def get_flows_to_remove_info(device_id, flows):
+        """
+        Use this API to get the list of info of flows to be removed 
+        This is used for incremental flow update
+        We extract the bal flow info from kv store for the received flows
+        :param device_id: A OLT device id
+        :param flows : Incremntal flows to be removed received at the adapter 
+                       from higher layer as part of incremental flow update
+        :return: list of info of flows to be removed
+        """
+    
+    def get_flows_to_remove(device_id, flows):
+        """
+        Use this API to get the list of info of flows to be deleted by comparing
+        with current flow in kv and received bulk flow
+        This is used for bulk flow update
+        :param device_id: A OLT device id
+        :param flows : Flows received at the adapter from higher layer
+                       as part of bulk flow update
+        :return: list of info of flows to be deleted (bal_flow_id, direction etc)
+        """
+
+    def get_flows_to_add(device_id, flows):
+        """
+        Use this API to get the list of cookies of the new OpenFlow rules
+        that need to be installed on the device
+        :param device_id: A OLT device id
+        :param flows : Flows received at the adapter from higher layers as
+                       part of bulks flow/incremantal flow update 
+        :return: list of OpenFlow cookies
+        """
+
+    def add_to_kv_store(device_id, new_flow_mapping_list, flows):
+        """
+        Use this API to add new bal flow id mapping info to the KV store
+        Used for incremental flow update 
+        :param device_id: A OLT device id
+        :param new_flow_mapping_list: It contains the flows and its mapping to bal flows
+                                      to be added newly to KV store and bal
+        :param flows : Flows received at the adapter from higher layers as
+                       part of incremental flow to add update
+        :return: None
+        """
+
+    def remove_from_kv_store(device_id, flows):
+        """
+        Use this API to remove bal flow id mapping info from the KV store
+        Used for incremental flow update 
+        :param device_id: A OLT device id
+        :param flows : Flows received at the adapter from higher layers as
+                       part of incremental flow to remove update
+        :return: None
+        """
+
+    def update_kv_store(device_id, new_flow_mapping_list, flows):
+        """
+        Use this API to update(add and remove) the bal flow id mapping info to the KV store
+        :param device_id: A OLT device id
+        :param new_flow_mapping_list: It contains the flows and its mapping to bal flows
+                                      to be added newly to KV store and bal
+        :param flows : Flows received at the adapter from higher layers as
+                       part of update_flows_bulk
+        :return: None
+        """
+
+    def clear_kv_store(device_id):
+        """
+        Use this API to clear all the bal flow id mapping info from the KV store
+        :param device_id: A OLT device id
+        :return: None
+        """
diff --git a/voltha/adapters/asfvolt16_olt/protos/bal_indications.proto b/voltha/adapters/asfvolt16_olt/protos/bal_indications.proto
index a6255ae..8ee38ec 100644
--- a/voltha/adapters/asfvolt16_olt/protos/bal_indications.proto
+++ b/voltha/adapters/asfvolt16_olt/protos/bal_indications.proto
@@ -24,55 +24,65 @@
 
 message BalIndications{
    BalObjId     objType = 1; //type of object for which the indications have been received
-   uint32       sub_group = 22; //Its a new parameter introduced by broadcom to indicate
+   uint32       sub_group = 26; //Its a new parameter introduced by broadcom to indicate
                                 //type of an indication within the object Type.
    oneof u {
-         BalAccessTerminalInd access_term_ind                        = 2;  // Access Terminal
-         BalAccessTerminalOperStatusChange access_term_ind_op_state  = 3;  // Access Terminal Operational State Change
+         BalAccessTerminalOperStatusChange access_term_ind_op_state  = 2;  // Access Terminal Operational State Change
+         BalAccessTerminalProcessingError access_term_proc_err       = 3;  // Access Terminal - general processing error
          BalFlowOperStatusChange flow_op_state                       = 4;  // Flow Operational State Change
-         BalFlowInd flow_ind                                         = 5;  // Flow
-         BalGroupInd group_ind                                       = 6;  // Group
+         BalFlowProcessingError flow_proc_err                        = 5;  // Flow - general processing error
+         BalInterfaceLos interface_los                               = 6;  // OLT alarms
          BalInterfaceOperStatusChange interface_op_state             = 7;  // Interface Operational State Change
-         BalInterfaceLos interface_los                               = 8;  // OLT alarms
-         BalInterfaceInd interface_ind                               = 9;  // Interface
-         BalInterfaceStat interface_stats                            = 10; // NNI statistics
-         BalSubscriberTerminalOperStatusChange terminal_op_state     = 11; // Subscriber Terminal Operational State Change
-         BalSubscriberTerminalSubTermDisc terminal_disc              = 12; // Subscriber discovery
-         BalSubscriberTerminalSubTermAlarm terminal_alarm            = 13; // Subscriber alarm
-         BalSubscriberTerminalDgi terminal_dgi                       = 14; // Subscriber dgi
-         BalSubscriberTerminalInd terminal_ind                       = 15; // Subscriber
-         BalTmQueueInd tm_queue_Ind                                  = 16; // TmQueue Ind
-         BalTmSchedInd tm_sched_Ind                                  = 17; // TmScheduler Ind
-         BalPacketBearerChannelRx  pktData                           = 18; // packet data
-         BalPacketItuOmciChannelRx balOmciResp                       = 19; // OMCI response
-         BalPacketIeeeOamChannelRx balOamResp                        = 20; // PLOAM response
+         BalPacketBearerChannelRx  pktData                           = 8; // packet data
+         BalPacketIeeeOamChannelRx balOamResp                        = 9; // PLOAM response
+         BalPacketItuOmciChannelRx balOmciResp                       = 10; // OMCI response
+         BalSubscriberTerminalDgi terminal_dgi                       = 11; // Subscriber dgi
+         BalSubscriberTerminalDowi terminal_dowi                     = 12; // Subscriber dowi
+         BalSubscriberTerminalLooci terminal_looci                   = 13; // Subscriber dowi
+         BalSubscriberTerminalOperStatusChange terminal_op_state     = 14;  // Subscriber Terminal Operational State Change
+         BalSubscriberTerminalProcessingError terminal_proc_err      = 15;  // Subscriber Terminal Processing Error
+         BalSubscriberTerminalSdi terminal_sdi                       = 16; // Subscriber Sdi
+         BalSubscriberTerminalSfi terminal_sfi                       = 17; // Subscriber Sfi
+         BalSubscriberTerminalSubTermActFail terminal_sub_term_act_fail = 18; // Subscriber Termial act Fail
+         BalSubscriberTerminalSubTermAlarm terminal_alarm            = 19; // Subscriber alarm
+         BalSubscriberTerminalSubTermDisc terminal_disc              = 20; // Subscriber discovery
+         BalSubscriberTerminalSufi terminal_sufi                     = 21; // Subscriber Sufi
+         BalSubscriberTerminalTiwi terminal_tiwi                     = 22; // Subscriber Tiwi
+         BalTmSchedOperStatusChange tm_sched_oper_stats_change       = 23; // TmScheduler Oper Status Change
+	/* We are not supporting BalSysChannelProfileInd as of now. */
+         //BalSysChannelProfileInd bal_profile_ind                     = 24; // Sys Channel Profile Indication
       }
-      string device_id                                               = 21; //Deviced Id
-      uint32 ind_present                                             = 23;
+      string device_id                                               = 25; //Deviced Id
+      uint32 ind_present                                             = 27;
 }
 
 service BalInd {
 
       //Handling of bal indications from the device
-      rpc BalAccTermInd(BalIndications) returns(BalErr) {}
       rpc BalAccTermOperStsCngInd(BalIndications) returns(BalErr) {}
+      rpc BalAccTermProcErr(BalIndications) returns(BalErr) {}
       rpc BalFlowOperStsCng(BalIndications) returns(BalErr) {}
-      rpc BalFlowInd(BalIndications) returns(BalErr) {}
-      rpc BalGroupInd(BalIndications) returns(BalErr) {}
-      rpc BalIfaceOperStsCng(BalIndications) returns(BalErr) {}
+      rpc BalFlowProcErr(BalIndications) returns(BalErr) {}
       rpc BalIfaceLos(BalIndications) returns(BalErr) {}
-      rpc BalIfaceInd(BalIndications) returns(BalErr) {}
-      rpc BalIfaceStat(BalIndications) returns(BalErr) {}
-      rpc BalSubsTermOperStsCng(BalIndications) returns(BalErr) {}
-      rpc BalSubsTermDiscoveryInd(BalIndications) returns(BalErr) {}
-      rpc BalSubsTermAlarmInd(BalIndications) returns(BalErr) {}
-      rpc BalSubsTermDgiInd(BalIndications) returns(BalErr) {}
-      rpc BalSubsTermInd(BalIndications) returns(BalErr) {}
-      rpc BalTmQueueIndInfo(BalIndications) returns(BalErr) {}
-      rpc BalTmSchedIndInfo(BalIndications) returns(BalErr) {}
+      rpc BalIfaceOperStsCng(BalIndications) returns(BalErr) {}
       rpc BalPktBearerChannelRxInd(BalIndications) returns(BalErr) {}
-      rpc BalPktOmciChannelRxInd(BalIndications) returns(BalErr) {}
       rpc BalPktIeeeOamChannelRxInd(BalIndications) returns(BalErr) {}
+      rpc BalPktOmciChannelRxInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermDgiInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermDowiInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermLoociInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermOperStsCng(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermProcErr(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermSdiInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermSfiInd(BalIndications) returns(BalErr) {}
+      rpc BalSubTermActFailInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermAlarmInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermDiscoveryInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermSufiInd(BalIndications) returns(BalErr) {}
+      rpc BalSubsTermTiwiInd(BalIndications) returns(BalErr) {}
+      rpc BalTmSchedOperStatsChange(BalIndications) returns(BalErr) {}
+      /* We are not supporting BalSysProfileInd as of now. */
+      //rpc BalSysProfileInd(BalIndications) returns(BalErr) {}
 }
 
 service BalGetInd {
diff --git a/voltha/adapters/asfvolt16_olt/protos/bal_model_ids.proto b/voltha/adapters/asfvolt16_olt/protos/bal_model_ids.proto
index a3a0259..ea6030a 100644
--- a/voltha/adapters/asfvolt16_olt/protos/bal_model_ids.proto
+++ b/voltha/adapters/asfvolt16_olt/protos/bal_model_ids.proto
@@ -27,17 +27,7 @@
     BAL_ACCESS_TERMINAL_CFG_ID_IWF_MODE      = 2;    /**< Interworking function mode. */
     BAL_ACCESS_TERMINAL_CFG_ID_TOPOLOGY      = 3;    /**< Topology mode. */
     BAL_ACCESS_TERMINAL_CFG_ID_SW_VERSION    = 4;    /**< Software version mode. */
-}
-
-/** Identifiers for all properties contained in the access_terminal_ind group.
- */
-enum BalAccessTerminalIndId
-{
-    BAL_ACCESS_TERMINAL_IND_ID_ADMIN_STATE   = 0;    /**< Administrative state. */
-    BAL_ACCESS_TERMINAL_IND_ID_OPER_STATUS   = 1;    /**< Operational status. */
-    BAL_ACCESS_TERMINAL_IND_ID_IWF_MODE      = 2;    /**< Interworking function mode. */
-    BAL_ACCESS_TERMINAL_IND_ID_TOPOLOGY      = 3;    /**< Topology mode */
-    BAL_ACCESS_TERMINAL_IND_ID_SW_VERSION    = 4;    /**< Software version mode */
+    BAL_ACCESS_TERMINAL_CFG_ID_CONN_ID       = 5;    /**< Connection ID. */
 }
 
 /** Identifiers for all properties contained in the access_terminal_key group.
@@ -66,37 +56,15 @@
     BAL_FLOW_CFG_ID_ACCESS_INT_ID            = 2;    /**< Access Interface ID. */
     BAL_FLOW_CFG_ID_NETWORK_INT_ID           = 3;    /**< Network Interface ID. */
     BAL_FLOW_CFG_ID_SUB_TERM_ID              = 4;    /**< Subscriber Terminal ID. */
-    BAL_FLOW_CFG_ID_SUB_TERM_UNI_IDX         = 5;    /**< Subscriber Terminal uni port index. */
-    BAL_FLOW_CFG_ID_SVC_PORT_ID              = 6;    /**< Service Port ID. */
-    BAL_FLOW_CFG_ID_RESOLVE_MAC              = 7;    /**< Resolve mac. */
-    BAL_FLOW_CFG_ID_CLASSIFIER               = 8;    /**< Classifier. */
-    BAL_FLOW_CFG_ID_ACTION                   = 9;    /**< Action. */
-    BAL_FLOW_CFG_ID_COOKIE                   = 10;   /**< Cookie. */
-    BAL_FLOW_CFG_ID_PRIORITY                 = 11;   /**< Priority. */
-    BAL_FLOW_CFG_ID_GROUP_ID                 = 12;   /**< Group ID. */
-    BAL_FLOW_CFG_ID_QUEUE                    = 13;   /**< Egress queue. */
-    BAL_FLOW_CFG_ID_DBA_TM_SCHED_ID          = 14;   /**< Tm Sched. */
-}
-
-/** Identifiers for all properties contained in the flow_ind group.
- */
-enum BalFlowIndId
-{
-    BAL_FLOW_IND_ID_ADMIN_STATE              = 0;    /**< Administrative state. */
-    BAL_FLOW_IND_ID_OPER_STATUS              = 1;    /**< Operational status. */
-    BAL_FLOW_IND_ID_ACCESS_INT_ID            = 2;    /**< Access interface ID. */
-    BAL_FLOW_IND_ID_NETWORK_INT_ID           = 3;    /**< Network Interface ID. */
-    BAL_FLOW_IND_ID_SUB_TERM_ID              = 4;    /**< Subscriber terminal ID. */
-    BAL_FLOW_IND_ID_SUB_TERM_UNI_IDX         = 5;    /**< Subscriber terminal UNI ID. */
-    BAL_FLOW_IND_ID_SVC_PORT_ID              = 6;    /**< Service port ID. */
-    BAL_FLOW_IND_ID_RESOLVE_MAC              = 7;    /**< Resolve mac. */
-    BAL_FLOW_IND_ID_CLASSIFIER               = 8;    /**< Classifier. */
-    BAL_FLOW_IND_ID_ACTION                   = 9;   /**< Action. */
-    BAL_FLOW_IND_ID_COOKIE                   = 10;   /**< Cookie. */
-    BAL_FLOW_IND_ID_PRIORITY                 = 11;   /**< Priority. */
-    BAL_FLOW_IND_ID_GROUP_ID                 = 12;   /**< Group ID. */
-    BAL_FLOW_IND_ID_QUEUE                    = 13;   /**< Egress queue. */
-    BAL_FLOW_IND_ID_DBA_TM_SCHED_ID          = 14;   /**< Tm Sched. */
+    BAL_FLOW_CFG_ID_SVC_PORT_ID              = 5;    /**< Service Port ID. */
+    BAL_FLOW_CFG_ID_RESOLVE_MAC              = 6;    /**< Resolve mac. */
+    BAL_FLOW_CFG_ID_CLASSIFIER               = 7;    /**< Classifier. */
+    BAL_FLOW_CFG_ID_ACTION                   = 8;    /**< Action. */
+    BAL_FLOW_CFG_ID_COOKIE                   = 9;    /**< Cookie. */
+    BAL_FLOW_CFG_ID_PRIORITY                 = 10;   /**< Priority. */
+    BAL_FLOW_CFG_ID_GROUP_ID                 = 11;   /**< Group ID. */
+    BAL_FLOW_CFG_ID_QUEUE                    = 12;   /**< Egress queue. */
+    BAL_FLOW_CFG_ID_DBA_TM_SCHED_ID          = 13;   /**< Tm Sched. */
 }
 
 /** Identifiers for all properties contained in the flow_key group.
@@ -119,16 +87,6 @@
    BAL_FLOW_OPER_STATUS_CHANGE_ID_COOKIE                    = 5;
 }
 
-/** Identifiers for all properties contained in the flow_stat group.
- */
-enum BalFlowStatId
-{
-    BAL_FLOW_STAT_ID_RX_PACKETS              = 0;    /**< Received packets. */
-    BAL_FLOW_STAT_ID_RX_BYTES                = 1;    /**< Received bytes. */
-    BAL_FLOW_STAT_ID_TX_PACKETS              = 2;    /**< Transmitted packets. */
-    BAL_FLOW_STAT_ID_TX_BYTES                = 3;    /**< Transmitted bytes. */
-}
-
 /** Identifiers for all properties contained in the group_cfg group.
  */
 enum BalGroupCfgId
@@ -137,18 +95,7 @@
     BAL_GROUP_CFG_ID_MEMBERS                 = 1;    /**< Member. */
     BAL_GROUP_CFG_ID_COOKIE                  = 2;    /**< Application cookie. */
     BAL_GROUP_CFG_ID_FLOWS                   = 3;    /**< List of flows associated with the group . */
-    BAL_GROUP_CFG_ID_OWNER                   = 4;    /**< Owner of the group. */
-}
-
-/** Identifiers for all properties contained in the group_ind group.
-    */
-enum BalGroupIndId
-{
-   BAL_GROUP_IND_ID_MEMBERS_CMD              = 0;
-   BAL_GROUP_IND_ID_MEMBERS                  = 1;
-   BAL_GROUP_IND_ID_COOKIE                   = 2;
-   BAL_GROUP_IND_ID_FLOWS                    = 3;
-   BAL_GROUP_IND_ID_OWNER                    = 4;
+    BAL_GROUP_CFG_ID_TYPE                    = 4;    /**< type of the group. */
 }
 
 /** Identifiers for all properties contained in the group_key group.
@@ -167,37 +114,15 @@
     BAL_INTERFACE_CFG_ID_MIN_DATA_AGG_PORT_ID= 2;            /**< Minimum aggregate port ID. */
     BAL_INTERFACE_CFG_ID_MIN_DATA_SVC_PORT_ID= 3;            /**< Minimum service port ID. */
     BAL_INTERFACE_CFG_ID_TRANSCEIVER_TYPE    = 4;            /**< Transceiver type. */
-    BAL_INTERFACE_CFG_ID_DS_MISS_MODE        = 5;            /**< Downstream unknown packet action. */
-    BAL_INTERFACE_CFG_ID_MTU                 = 6;            /**< MTU. */
-    BAL_INTERFACE_CFG_ID_FLOW_CONTROL        = 7;            /**< Flow control. */
-    BAL_INTERFACE_CFG_ID_DS_TM               = 8;            /**< Downstream scheduler and shaper. */
-    BAL_INTERFACE_CFG_ID_US_TM               = 9;            /**< Upstream scheduler and shaper. */
-    BAL_INTERFACE_CFG_ID_SUB_TERM_ID_LIST    = 10;           /**< Sub-term id list. */
-    BAL_INTERFACE_CFG_ID_PON_DISTANCE        = 11;           /**< pon_distance. */
-    BAL_INTERFACE_CFG_ID_BER_MONITOR         = 12;           /**< ber_monitor. */
-    BAL_INTERFACE_CFG_ID_US_BANDWIDTH_LIMIT  = 13;           /**< us_bandwidth_limit. */
-    BAL_INTERFACE_CFG_ID_DS_FEC              = 14;           /**< ds_fec. */
-}
-
-/** Identifiers for all properties contained in the interface_ind group.
- */
-enum BalInterfaceIndId
-{
-    BAL_INTERFACE_IND_ID_ADMIN_STATE         = 0;            /**< Administrative state. */
-    BAL_INTERFACE_IND_ID_OPER_STATUS         = 1;            /**< Operational status. */
-    BAL_INTERFACE_IND_ID_MIN_DATA_AGG_PORT_ID= 2;            /**< Minimum aggregate port ID. */
-    BAL_INTERFACE_IND_ID_MIN_DATA_SVC_PORT_ID= 3;            /**< Minimum service port ID. */
-    BAL_INTERFACE_IND_ID_TRANSCEIVER_TYPE    = 4;            /**< Transceiver type. */
-    BAL_INTERFACE_IND_ID_DS_MISS_MODE        = 5;            /**< Downstream unknown packet action. */
-    BAL_INTERFACE_IND_ID_MTU                 = 6;            /**< MTU. */
-    BAL_INTERFACE_IND_ID_FLOW_CONTROL        = 7;            /**< Flow control. */
-    BAL_INTERFACE_IND_ID_DS_TM               = 8;            /**< Downstream scheduler and shaper. */
-    BAL_INTERFACE_IND_ID_US_TM               = 9;            /**< Upstream scheduler and shaper. */
-    BAL_INTERFACE_IND_ID_SUB_TERM_ID_LIST    = 10;           /**< Sub term id list */
-    BAL_INTERFACE_IND_ID_PON_DISTANCE        = 11;           /**< pon_distance. */
-    BAL_INTERFACE_IND_ID_BER_MONITOR         = 12;           /**< ber_monitor. */
-    BAL_INTERFACE_IND_ID_US_BANDWIDTH_LIMIT  = 13;           /**< us_bandwidth_limit. */
-    BAL_INTERFACE_IND_ID_DS_FEC              = 14;           /**< ds_fec. */
+    BAL_INTERFACE_CFG_ID_MTU                 = 5;            /**< MTU. */
+    BAL_INTERFACE_CFG_ID_DS_TM               = 6;            /**< Downstream scheduler and shaper. */
+    BAL_INTERFACE_CFG_ID_US_TM               = 7;            /**< Upstream scheduler and shaper. */
+    BAL_INTERFACE_CFG_ID_SUB_TERM_ID_LIST    = 8;            /**< Sub-term id list. */
+    BAL_INTERFACE_CFG_ID_PON_DISTANCE        = 9;            /**< pon_distance. */
+    BAL_INTERFACE_CFG_ID_BER_MONITOR         = 10;           /**< ber_monitor. */
+    BAL_INTERFACE_CFG_ID_US_BANDWIDTH_LIMIT  = 11;           /**< us_bandwidth_limit. */
+    BAL_INTERFACE_CFG_ID_DS_FEC              = 12;           /**< ds_fec. */
+    BAL_INTERFACE_CFG_ID_NGPON_2             = 13;           /**< ngpon2. */
 }
 
 /** Identifiers for all properties contained in the interface_key group.
@@ -231,19 +156,49 @@
 {
     BAL_INTERFACE_STAT_ID_RX_BYTES                           = 0;    /**< Received bytes. */
     BAL_INTERFACE_STAT_ID_RX_PACKETS                         = 1;    /**< Recieved packets. */
-    BAL_INTERFACE_STAT_ID_RX_UCAST_PACKETS                   = 2;    /**< Received unicast packets. */
-    BAL_INTERFACE_STAT_ID_RX_MCAST_PACKETS                   = 3;    /**< Received multicast packets. */
-    BAL_INTERFACE_STAT_ID_RX_BCAST_PACKETS                   = 4;    /**< Received broadcast packets. */
-    BAL_INTERFACE_STAT_ID_RX_ERROR_PACKETS                   = 5;    /**< Received error packets. */
-    BAL_INTERFACE_STAT_ID_RX_UNKNOWN_PROTOS                  = 6;    /**< Received unknown-proto packets. */
-    BAL_INTERFACE_STAT_ID_TX_BYTES                           = 7;    /**< Transmitted bytes. */
-    BAL_INTERFACE_STAT_ID_TX_PACKETS                         = 8;    /**< Transmitted packets. */
-    BAL_INTERFACE_STAT_ID_TX_UCAST_PACKETS                   = 9;    /**< Transmitted unicast packets. */
-    BAL_INTERFACE_STAT_ID_TX_MCAST_PACKETS                   = 10;   /**< Transmitted multicast packets. */
-    BAL_INTERFACE_STAT_ID_TX_BCAST_PACKETS                   = 11;   /**< Transmitted broadcast packets. */
-    BAL_INTERFACE_STAT_ID_TX_ERROR_PACKETS                   = 12;   /**< Transmitted error packets. */
-    BAL_INTERFACE_STAT_ID_RX_CRC_ERRORS                      = 13;   /**< Received packets with CRC error. */
-    BAL_INTERFACE_STAT_ID_BIP_ERRORS                         = 14;   /**< Received bip errors (bip8 for gpon, bip32 for xgpon). */
+    BAL_INTERFACE_STAT_ID_RX_DATA_BYTES                      = 2;    /**< Received data bytes. */
+    BAL_INTERFACE_STAT_ID_RX_UCAST_PACKETS                   = 3;    /**< Received unicast packets. */
+    BAL_INTERFACE_STAT_ID_RX_MCAST_PACKETS                   = 4;    /**< Received multicast packets. */
+    BAL_INTERFACE_STAT_ID_RX_BCAST_PACKETS                   = 5;    /**< Received broadcast packets. */
+    BAL_INTERFACE_STAT_ID_RX_64_PACKETS                      = 6;    /**< Received 64 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_65_127_PACKETS                  = 7;    /**< Received 65-127 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_128_255_PACKETS                 = 8;    /**< Received 128-255 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_256_511_PACKETS                 = 9;    /**< Received 256-511 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_512_1023_PACKETS                = 10;   /**< Received 512-1023 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_1024_1518_PACKETS               = 11;   /**< Received 1024-1518 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_1519_2047_PACKETS               = 12;   /**< Received 1519-2047 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_2048_4095_PACKETS               = 13;   /**< Received 2048-4095 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_4096_9216_PACKETS               = 14;   /**< Received 4096-9216 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_9217_16383_PACKETS              = 15;   /**< Received 9217-16383 byte packets. */
+    BAL_INTERFACE_STAT_ID_RX_ERROR_PACKETS                   = 16;   /**< Received error packets. */
+    BAL_INTERFACE_STAT_ID_RX_UNKNOWN_PROTOS                  = 17;   /**< Received unknown-proto packets. */
+    BAL_INTERFACE_STAT_ID_RX_CRC_ERRORS                      = 18;   /**< Received packets with CRC error. */
+    BAL_INTERFACE_STAT_ID_BIP_ERRORS                         = 19;   /**< Received bip errors (bip8 for gpon, bip32 for xgpon). */
+    BAL_INTERFACE_STAT_ID_RX_MPCP                            = 20;   /**< Received MPCP packets. */
+    BAL_INTERFACE_STAT_ID_RX_REPORT                          = 21;   /**< Received report packets. */
+    BAL_INTERFACE_STAT_ID_RX_OAM_BYTES                       = 22;   /**< Received OAM bytes. */
+    BAL_INTERFACE_STAT_ID_RX_OAM_PACKETS                     = 23;   /**< Received OAM packets. */
+    BAL_INTERFACE_STAT_ID_TX_BYTES                           = 24;   /**< Transmitted bytes. */
+    BAL_INTERFACE_STAT_ID_TX_PACKETS                         = 25;   /**< Transmitted packets. */
+    BAL_INTERFACE_STAT_ID_TX_DATA_BYTES                      = 26;   /**< Transmitted data bytes. */
+    BAL_INTERFACE_STAT_ID_TX_UCAST_PACKETS                   = 27;   /**< Transmitted unicast packets. */
+    BAL_INTERFACE_STAT_ID_TX_MCAST_PACKETS                   = 28;   /**< Transmitted multicast packets. */
+    BAL_INTERFACE_STAT_ID_TX_BCAST_PACKETS                   = 29;   /**< Transmitted broadcast packets. */
+    BAL_INTERFACE_STAT_ID_TX_64_PACKETS                      = 30;   /**< Transmitted 64 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_65_127_PACKETS                  = 31;   /**< Transmitted 65-127 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_128_255_PACKETS                 = 32;   /**< Transmitted 128-255 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_256_511_PACKETS                 = 33;   /**< Transmitted 256-511 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_512_1023_PACKETS                = 34;   /**< Transmitted 512-1023 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_1024_1518_PACKETS               = 35;   /**< Transmitted 1024-1518 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_1519_2047_PACKETS               = 36;   /**< Transmitted 1519-2047 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_2048_4095_PACKETS               = 37;   /**< Transmitted 2048-4095 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_4096_9216_PACKETS               = 38;   /**< Transmitted 4096-9216 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_9217_16383_PACKETS              = 39;   /**< Transmitted 9217-16383 byte packets. */
+    BAL_INTERFACE_STAT_ID_TX_ERROR_PACKETS                   = 40;   /**< Transmitted error packets. */
+    BAL_INTERFACE_STAT_ID_TX_MPCP                            = 41;   /**< Transmitted MPCP packets. */
+    BAL_INTERFACE_STAT_ID_TX_GATE                            = 42;   /**< Transmitted gate packets. */
+    BAL_INTERFACE_STAT_ID_TX_OAM_BYTES                       = 43;   /**< Transmitted OAM bytes. */
+    BAL_INTERFACE_STAT_ID_TX_OAM_PACKETS                     = 44;   /**< Transmitted OAM packets. */
 }
 
 /** Identifiers for all properties contained in the packet_bearer_channel_rx
@@ -333,26 +288,6 @@
     BAL_SUBSCRIBER_TERMINAL_DOWI_ID_NEW_EQD                  = 2;    /**< new_eqd. */
 }
 
-/** Identifiers for all properties contained in the subscriber_terminal_ind
- * group.
- */
-enum BalSubscriberTerminalIndId
-{
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_ADMIN_STATE               = 0;    /**< Administrative state. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_OPER_STATUS               = 1;    /**< Operational status. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_SERIAL_NUMBER             = 2;    /**< Serial number. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_PASSWORD                  = 3;    /**< Password. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_REGISTRATION_ID           = 4;    /**< Registration id. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_SVC_PORT_ID               = 5;    /**< Service port ID. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_MAC_ADDRESS               = 6;    /**< MAC address. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_DS_TM                     = 7;    /**< Downstream scheduler and shaper. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_US_TM                     = 8;    /**< Upstream scheduler and shaper. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_SVC_PORT_ID_LIST          = 9;    /**< svc_port_id list. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_AGG_PORT_ID_LIST          = 10;   /**< agg_port_id list. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_SUB_TERM_RATE             = 11;   /**< sub_term_rate. */
-    BAL_SUBSCRIBER_TERMINAL_IND_ID_US_EFC                    = 12;   /**< us_fec. */
-}
-
 /** Identifiers for all properties contained in the subscriber_terminal_key
  * group.
  */
@@ -398,15 +333,12 @@
     BAL_SUBSCRIBER_TERMINAL_SFI_ID_BER                           = 1;    /**< ber. */
 }
 
-/** Identifiers for all properties contained in the subscriber_terminal_stat
- * group.
+/** Identifiers for all properties contained in the
+ * subscriber_terminal_sub_term_act_fail group.
  */
-enum BalSubscriberTerminalStatId
+enum BalSubscriberTerminalSubTermFailId
 {
-    BAL_SUBSCRIBER_TERMINAL_STAT_ID_RX_PACKETS       = 0;    /**< Received  packets. */
-    BAL_SUBSCRIBER_TERMINAL_STAT_ID_RX_BYTES         = 1;    /**< Received bytes. */
-    BAL_SUBSCRIBER_TERMINAL_STAT_ID_TX_PACKETS       = 2;    /**< Transmitted packets. */
-    BAL_SUBSCRIBER_TERMINAL_STAT_ID_TX_BYTES         = 3;    /**< Transmitted bytes. */
+    BAL_SUBSCRIBER_TERMINAL_SUB_TERM_ACT_FAIL_ID_FAIL_REASON     = 0;    /**< Fail Reason. */
 }
 
 /** Identifiers for all properties contained in the
@@ -414,7 +346,7 @@
  */
 enum BalSubscriberTerminalSubTermAlarmId
 {
-    BCMBAL_SUBSCRIBER_TERMINAL_SUB_TERM_ALARM_ID_ALARM              = 0;    /**< Alarm. */
+    BAL_SUBSCRIBER_TERMINAL_SUB_TERM_ALARM_ID_ALARM              = 0;    /**< Alarm. */
 }
 
 /** Identifiers for all properties contained in the
@@ -422,7 +354,8 @@
  */
 enum BalSubscriberTerminalSubTermDiscId
 {
-    BCMBAL_SUBSCRIBER_TERMINAL_SUB_TERM_DISC_ID_SERIAL_NUMBER       = 0;    /**< Serial number. */
+    BAL_SUBSCRIBER_TERMINAL_SUB_TERM_DISC_ID_SERIAL_NUMBER       = 0;    /**< Serial number. */
+    BAL_SUBSCRIBER_TERMINAL_SUB_TERM_DISC_ID_ONU_MAC             = 1;    /**< ONU Mac Address. */
 }
 
 /** Identifiers for all properties contained in the subscriber_terminal_sufi
@@ -442,6 +375,34 @@
     BAL_SUBSCRIBER_TERMINAL_TIWI_ID_DRIFT_VALUE                  = 1;    /**< drift_value. */
 }
 
+/** Identifiers for all properties contained in the sys_channel_profile_cfg
+ * group.
+ */
+enum BalSysChannelProfileCfgId
+{
+    BAL_SYS_CHANNEL_PROFILE_CFG_ID_SYSTEM_PROFILE                = 0;    /**< System profile. */
+    BAL_SYS_CHANNEL_PROFILE_CFG_ID_CHANNEL_PROFILE               = 1;    /**< Channel profile. */
+    BAL_SYS_CHANNEL_PROFILE_CFG_ID_REF_COUNT                     = 2;    /**< ref_count. */
+}
+
+/** Identifiers for all properties contained in the sys_channel_profile_ind
+ * group.
+ */
+enum BalSysChannelProfileIndId
+{
+    BAL_SYS_CHANNEL_PROFILE_IND_ID_SYSTEM_PROFILE                = 0;    /**< system profile. */
+    BAL_SYS_CHANNEL_PROFILE_IND_ID_CHANNEL_PROFILE               = 1;    /**< channel profile. */
+    BAL_SYS_CHANNEL_PROFILE_IND_ID_REF_COUNT                     = 2;    /**< ref_count. */
+}
+
+/** Identifiers for all properties contained in the sys_channel_profile_key
+ * group.
+ */
+enum BalSysChannelProfileKeyId
+{
+    BAL_SYS_CHANNEL_PROFILE_KEY_ID_SYS_ID                        = 0;    /**< system id. */
+}
+
 /** Identifiers for all properties contained in the tm_queue_cfg group.
  */
 enum BalTmQueueCfgId
@@ -454,18 +415,6 @@
     BAL_TM_QUEUE_CFG_ID_REF_COUNT                    = 5;    /**< ref_count. */
 }
 
-/** Identifiers for all properties contained in the tm_queue_ind group.
- */
-enum BalTmQueueIndId
-{
-    BAL_TM_QUEUE_IND_ID_PRIORITY                     = 0;    /**< priority. */
-    BAL_TM_QUEUE_IND_ID_WEIGHT                       = 1;    /**< weight. */
-    BAL_TM_QUEUE_IND_ID_RATE                         = 2;    /**< rate. */
-    BAL_TM_QUEUE_IND_ID_BAC                          = 3;    /**< bac. */
-    BAL_TM_QUEUE_IND_ID_CREATE_MODE                  = 4;    /**< create_mode. */
-    BAL_TM_QUEUE_IND_ID_REF_COUNT                    = 5;    /**< ref_count. */
-}
-
 /** Identifiers for all properties contained in the tm_queue_key group.
  */
 enum BalTmQueueKeyId
@@ -475,16 +424,6 @@
     BAL_TM_QUEUE_KEY_ID_ID                           = 2;    /**< id. */
 }
 
-/** Identifiers for all properties contained in the tm_queue_stat group.
- */
-enum BalTmQueueStatId
-{
-    BAL_TM_QUEUE_STAT_ID_PACKETS_OK                  = 0;    /**< packets_ok. */
-    BAL_TM_QUEUE_STAT_ID_BYTES_OK                    = 1;    /**< bytes_ok. */
-    BAL_TM_QUEUE_STAT_ID_PACKETS_DISCARDED           = 2;    /**< packets_discarded. */
-    BAL_TM_QUEUE_STAT_ID_BYTES_DISCARDED             = 3;    /**< bytes_discarded. */
-}
-
 /** Identifiers for all properties contained in the tm_sched_cfg group.
  */
 enum BalTmSchedCfgId
@@ -492,31 +431,14 @@
     BAL_TM_SCHED_CFG_ID_OWNER                                    = 0;    /**< owner. */
     BAL_TM_SCHED_CFG_ID_SCHED_TYPE                               = 1;    /**< type. */
     BAL_TM_SCHED_CFG_ID_SCHED_PARENT                             = 2;    /**< parent. */
-    BAL_TM_SCHED_CFG_ID_SCHED_CHILD_TYPE                         = 3;    /**< child_type. */
-    BAL_TM_SCHED_CFG_ID_NUM_PRIORITIES                           = 4;    /**< num_priorities. */
-    BAL_TM_SCHED_CFG_ID_RATE                                     = 5;    /**< rate. */
-    BAL_TM_SCHED_CFG_ID_EXT_ITU_DBA                              = 6;    /**< extended itu dba. */
-    BAL_TM_SCHED_CFG_ID_EXT_EPON_DBA                             = 7;    /**< extended epon dba. */
-    BAL_TM_SCHED_CFG_ID_CREATION_MODE                            = 8;    /**< creation_mode. */
-    BAL_TM_SCHED_CFG_ID_QUEUES                                   = 9;    /**< queues. */
-    BAL_TM_SCHED_CFG_ID_SUB_SCHEDS                               = 10;   /**< sub_scheds. */
-}
-
-/** Identifiers for all properties contained in the tm_sched_ind group.
- */
-enum BalTmSchedIndId
-{
-    BAL_TM_SCHED_IND_ID_OWNER                                    = 0;    /**< owner. */
-    BAL_TM_SCHED_IND_ID_SCHED_TYPE                               = 1;    /**< type. */
-    BAL_TM_SCHED_IND_ID_SCHED_PARENT                             = 2;    /**< parent. */
-    BAL_TM_SCHED_IND_ID_SCHED_CHILD_TYPE                         = 3;    /**< child_type. */
-    BAL_TM_SCHED_IND_ID_NUM_PRIORITIES                           = 4;    /**< num_priorities. */
-    BAL_TM_SCHED_IND_ID_RATE                                     = 5;    /**< rate. */
-    BAL_TM_SCHED_IND_ID_EXT_ITU_DBA                              = 6;    /**< extended itu dba. */
-    BAL_TM_SCHED_IND_ID_EXT_EPON_DBA                             = 7;    /**< extended epon dba. */
-    BAL_TM_SCHED_IND_ID_CREATION_MODE                            = 8;    /**< creation_mode. */
-    BAL_TM_SCHED_IND_ID_QUEUES                                   = 9;    /**< queues. */
-    BAL_TM_SCHED_IND_ID_SUB_SCHEDS                               = 10;   /**< sub_scheds. */
+    BAL_TM_SCHED_CFG_ID_NUM_PRIORITIES                           = 3;    /**< num_priorities. */
+    BAL_TM_SCHED_CFG_ID_RATE                                     = 4;    /**< rate. */
+    BAL_TM_SCHED_CFG_ID_EXT_ITU_DBA                              = 5;    /**< extended itu dba. */
+    BAL_TM_SCHED_CFG_ID_EXT_EPON_DBA                             = 6;    /**< extended epon dba. */
+    BAL_TM_SCHED_CFG_ID_CREATION_MODE                            = 7;    /**< creation_mode. */
+    BAL_TM_SCHED_CFG_ID_QUEUE_LIST                               = 8;    /**< queue list. */
+    BAL_TM_SCHED_CFG_ID_SUB_SCHED_LIST                           = 9;    /**< sub_scheds. */
+    BAL_TM_SCHED_CFG_ID_OPER_STATUS                              = 10;   /**< oper status. */
 }
 
 /** Identifiers for all properties contained in the tm_sched_key group.
@@ -527,18 +449,29 @@
     BAL_TM_SCHED_KEY_ID_ID                           = 1;    /**< id. */
 }
 
+/** Identifiers for all properties contained in the tm_sched_oper_status_change
+ * group.
+ */
+enum BalTmSchedOperStatusChangeId
+{
+    BAL_TM_SCHED_OPER_STATUS_CHANGE_ID_NEW_OPER_STATUS           = 0;    /**< new oper status. */
+    BAL_TM_SCHED_OPER_STATUS_CHANGE_ID_OLD_OPER_STATUS           = 1;    /**< old oper status. */
+}
+
 /** Identifiers for all objects in the system.
  */
 enum BalObjId
 {
-    BAL_OBJ_ID_ACCESS_TERMINAL                       = 0;    /**< BAL Access Terminal */
-    BAL_OBJ_ID_FLOW                                  = 1;    /**< BAL Flow */
-    BAL_OBJ_ID_GROUP                                 = 2;    /**< BAL Group */
-    BAL_OBJ_ID_INTERFACE                             = 3;    /**< BAL Interface */
-    BAL_OBJ_ID_PACKET                                = 4;    /**< packet */
-    BAL_OBJ_ID_SUBSCRIBER_TERMINAL                   = 5;    /**< BAL Subscriber Terminal */
-    BAL_OBJ_ID_TM_QUEUE                              = 6;    /**< tm_queue */
-    BAL_OBJ_ID_TM_SCHED                              = 7;    /**< tm_sched */
+    BAL_OBJ_ID_ACCESS_TERMINAL                                   = 0;    /**< BAL Access Terminal */
+    BAL_OBJ_ID_FLOW                                              = 1;    /**< BAL Flow */
+    BAL_OBJ_ID_GROUP                                             = 2;    /**< BAL Group */
+    BAL_OBJ_ID_INTERFACE                                         = 3;    /**< BAL Interface */
+    BAL_OBJ_ID_PACKET                                            = 4;    /**< packet */
+    BAL_OBJ_ID_SUBSCRIBER_TERMINAL                               = 5;    /**< BAL Subscriber Terminal */
+    BAL_OBJ_ID_SYS_CHANNEL_PROFILE                               = 6;    /**< sys_channel_profile  */
+    BAL_OBJ_ID_TM_QUEUE                                          = 7;    /**< tm_queue */
+    BAL_OBJ_ID_TM_SCHED                                          = 8;    /**< tm_sched */
+
 }
 
 /** Identifiers for all possible groups under all objects in the system.
@@ -547,80 +480,71 @@
 {
     BAL_OBJ_GROUP_ID_ACCESS_TERMINAL_KEY                         = 0;    /**< BAL Access Terminal - key */
     BAL_OBJ_GROUP_ID_ACCESS_TERMINAL_CFG                         = 1;    /**< BAL Access Terminal - cfg */
-    BAL_OBJ_GROUP_ID_ACCESS_TERMINAL_IND                         = 2;    /**< BAL Access Terminal - Access Terminal Indication */
-    BAL_OBJ_GROUP_ID_ACCESS_TERMINAL_OPER_STATUS_CHANGE          = 3;    /**< BAL Access Terminal - Change of operational status */
+    BAL_OBJ_GROUP_ID_ACCESS_TERMINAL_OPER_STATUS_CHANGE          = 2;    /**< BAL Access Terminal - Change of operational status */
+    BAL_OBJ_GROUP_ID_ACCESS_TERMINAL_PROCESSING_ERROR            = 3;    /**< BAL Access Terminal - general processing error */
     BAL_OBJ_GROUP_ID_FLOW_KEY                                    = 4;    /**< BAL Flow - key */
     BAL_OBJ_GROUP_ID_FLOW_CFG                                    = 5;    /**< BAL Flow - cfg */
-    BAL_OBJ_GROUP_ID_FLOW_STAT                                   = 6;    /**< BAL Flow - stat */
-    BAL_OBJ_GROUP_ID_FLOW_IND                                    = 7;    /**< BAL Flow - Flow Indication */
-    BAL_OBJ_GROUP_ID_FLOW_OPER_STATUS_CHANGE                     = 8;    /**< BAL Flow - Change of operational status */
-    BAL_OBJ_GROUP_ID_GROUP_KEY                                   = 9;    /**< BAL Group - key */
-    BAL_OBJ_GROUP_ID_GROUP_CFG                                   = 10;   /**< BAL Group - cfg */
-    BAL_OBJ_GROUP_ID_GROUP_IND                                   = 11;   /**< BAL Group - Group indication */
-    BAL_OBJ_GROUP_ID_INTERFACE_KEY                               = 12;   /**< BAL Interface - key */
-    BAL_OBJ_GROUP_ID_INTERFACE_CFG                               = 13;   /**< BAL Interface - cfg */
-    BAL_OBJ_GROUP_ID_INTERFACE_STAT                              = 14;   /**< BAL Interface - stat */
-    BAL_OBJ_GROUP_ID_INTERFACE_IND                               = 15;   /**< BAL Interface - Interface Indication */
-    BAL_OBJ_GROUP_ID_INTERFACE_LOS                               = 16;   /**< BAL Interface - LOS */
-    BAL_OBJ_GROUP_ID_INTERFACE_OPER_STATUS_CHANGE                = 17;   /**< BAL Interface - Change of operational status */
-    BAL_OBJ_GROUP_ID_PACKET_KEY                                  = 18;   /**< packet - key */
-    BAL_OBJ_GROUP_ID_PACKET_CFG                                  = 19;   /**< packet - cfg */
-    BAL_OBJ_GROUP_ID_PACKET_BEARER_CHANNEL_RX                    = 20;   /**< packet - Bearer channel rx packet indication */
-    BAL_OBJ_GROUP_ID_PACKET_IEEE_OAM_CHANNEL_RX                  = 21;   /**< packet - IEEE OAM channel rx packet indication */
-    BAL_OBJ_GROUP_ID_PACKET_ITU_OMCI_CHANNEL_RX                  = 22;   /**< packet - ITU OMCI channel rx packet indication */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_KEY                     = 23;   /**< BAL Subscriber Terminal - key */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_CFG                     = 24;   /**< BAL Subscriber Terminal - cfg */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_STAT                    = 25;   /**< BAL Subscriber Terminal - stat */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_DGI                     = 26;   /**< BAL Subscriber Terminal - Receive Dying-Gasp of subscriber terminal */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_DOWI                    = 27;   /**< BAL Subscriber Terminal - dowi */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_IND                     = 28;   /**< BAL Subscriber Terminal - Subscriber Terminal Indication */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_LOOCI                   = 29;   /**< BAL Subscriber Terminal - looci */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_OPER_STATUS_CHANGE      = 30;   /**< BAL Subscriber Terminal - Change of operational status */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SDI                     = 31;   /**< BAL Subscriber Terminal - sdi */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SFI                     = 32;   /**< BAL Subscriber Terminal - sfi */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SUB_TERM_ALARM          = 33;   /**< BAL Subscriber Terminal - Subscriber Terminal Alarm Indication */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SUB_TERM_DISC           = 34;   /**< BAL Subscriber Terminal - Subscriber Terminal Discovery Indication */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SUFI                    = 35;   /**< BAL Subscriber Terminal - sufi */
-    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_TIWI                    = 36;   /**< BAL Subscriber Terminal - tiwi */
+    BAL_OBJ_GROUP_ID_FLOW_OPER_STATUS_CHANGE                     = 6;    /**< BAL Flow - Change of operational status */
+    BAL_OBJ_GROUP_ID_FLOW_PROCESSING_ERROR                       = 7;    /**< BAL Flow - general processing error */
+    BAL_OBJ_GROUP_ID_GROUP_KEY                                   = 8;    /**< BAL Group - key */
+    BAL_OBJ_GROUP_ID_GROUP_CFG                                   = 9;    /**< BAL Group - cfg */
+    BAL_OBJ_GROUP_ID_INTERFACE_KEY                               = 10;   /**< BAL Interface - key */
+    BAL_OBJ_GROUP_ID_INTERFACE_CFG                               = 11;   /**< BAL Interface - cfg */
+    BAL_OBJ_GROUP_ID_INTERFACE_STAT                              = 12;   /**< BAL Interface - stat */
+    BAL_OBJ_GROUP_ID_INTERFACE_LOS                               = 13;   /**< BAL Interface - LOS */
+    BAL_OBJ_GROUP_ID_INTERFACE_OPER_STATUS_CHANGE                = 14;   /**< BAL Interface - Change of operational status */
+    BAL_OBJ_GROUP_ID_PACKET_KEY                                  = 15;   /**< packet - key */
+    BAL_OBJ_GROUP_ID_PACKET_CFG                                  = 16;   /**< packet - cfg */
+    BAL_OBJ_GROUP_ID_PACKET_BEARER_CHANNEL_RX                    = 17;   /**< packet - Bearer channel rx packet indication */
+    BAL_OBJ_GROUP_ID_PACKET_IEEE_OAM_CHANNEL_RX                  = 18;   /**< packet - IEEE OAM channel rx packet indication */
+    BAL_OBJ_GROUP_ID_PACKET_ITU_OMCI_CHANNEL_RX                  = 19;   /**< packet - ITU OMCI channel rx packet indication */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_KEY                     = 20;   /**< BAL Subscriber Terminal - key */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_CFG                     = 21;   /**< BAL Subscriber Terminal - cfg */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_DGI                     = 22;   /**< BAL Subscriber Terminal - Receive Dying-Gasp of subscriber terminal */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_DOWI                    = 23;   /**< BAL Subscriber Terminal - dowi */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_LOOCI                   = 24;   /**< BAL Subscriber Terminal - looci */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_OPER_STATUS_CHANGE      = 25;   /**< BAL Subscriber Terminal - Change of operational status */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_PROCESSING_ERROR        = 26;   /**< BAL Subscriber Terminal - general processing error */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SDI                     = 27;   /**< BAL Subscriber Terminal - sdi */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SFI                     = 28;   /**< BAL Subscriber Terminal - sfi */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SUB_TERM_ACT_FAIL       = 29;   /**< BAL Subscriber Terminal - Subscriber Terminal Activation Failure Indication */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SUB_TERM_ALARM          = 30;   /**< BAL Subscriber Terminal - Subscriber Terminal Alarm Indication */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SUB_TERM_DISC           = 31;   /**< BAL Subscriber Terminal - Subscriber Terminal Discovery Indication */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_SUFI                    = 32;   /**< BAL Subscriber Terminal - sufi */
+    BAL_OBJ_GROUP_ID_SUBSCRIBER_TERMINAL_TIWI                    = 33;   /**< BAL Subscriber Terminal - tiwi */
+    BAL_OBJ_GROUP_ID_SYS_CHANNEL_PROFILE_KEY                     = 34;   /**< sys_channel_profile  - key */
+    BAL_OBJ_GROUP_ID_SYS_CHANNEL_PROFILE_CFG                     = 35;   /**< sys_channel_profile  - cfg */
+    BAL_OBJ_GROUP_ID_SYS_CHANNEL_PROFILE_IND                     = 36;   /**< sys_channel_profile  - channel indication */
     BAL_OBJ_GROUP_ID_TM_QUEUE_KEY                                = 37;   /**< tm_queue - key */
     BAL_OBJ_GROUP_ID_TM_QUEUE_CFG                                = 38;   /**< tm_queue - cfg */
-    BAL_OBJ_GROUP_ID_TM_QUEUE_STAT                               = 39;   /**< tm_queue - stat */
-    BAL_OBJ_GROUP_ID_TM_QUEUE_IND                                = 40;   /**< tm_queue - tm queue indication */
-    BAL_OBJ_GROUP_ID_TM_SCHED_KEY                                = 41;   /**< tm_sched - key */
-    BAL_OBJ_GROUP_ID_TM_SCHED_CFG                                = 42;   /**< tm_sched - cfg */
-    BAL_OBJ_GROUP_ID_TM_SCHED_IND                                = 43;   /**< tm_sched - Tm Sched Indication */
+    BAL_OBJ_GROUP_ID_TM_SCHED_KEY                                = 39;   /**< tm_sched - key */
+    BAL_OBJ_GROUP_ID_TM_SCHED_CFG                                = 40;   /**< tm_sched - cfg */
+    BAL_OBJ_GROUP_ID_TM_SCHED_OPER_STATUS_CHANGE                 = 41;   /**< tm_sched - Operational Status Change Indication */
+
 }
 
 /** List of all access_terminal groups of type auto.
  */
 enum BalAccessTerminalAutoId
 {
-    BAL_ACCESS_TERMINAL_AUTO_ID_IND                  = 0;    /**< Access Terminal Indication. */
-    BAL_ACCESS_TERMINAL_AUTO_ID_OPER_STATUS_CHANGE   = 1;    /**< Change of operational status. */
+    BAL_ACCESS_TERMINAL_AUTO_ID_OPER_STATUS_CHANGE   = 0;    /**< Change of operational status. */
+    BAL_ACCESS_TERMINAL_AUTO_ID_PROCESSING_ERROR     = 1;    /**< general processing error. */
 }
 
 /** List of all flow groups of type auto.
  */
 enum BalFlowAutoId
 {
-    BAL_FLOW_AUTO_ID_IND                             = 0;    /**< Flow Indication. */
-    BAL_FLOW_AUTO_ID_OPER_STATUS_CHANGE              = 1;    /**< Change of operational status. */
-}
-
-/** List of all group groups of type auto.
- */
-enum BalGroupAutoId
-{
-    BAL_GROUP_AUTO_ID_IND                        = 0;    /**< Group indication. */
+    BAL_FLOW_AUTO_ID_OPER_STATUS_CHANGE                      = 0;    /**< Change of operational status. */
+    BAL_FLOW_AUTO_ID_PROCESSING_ERROR                        = 1;    /**< general processing error. */
 }
 
 /** List of all interface groups of type auto.
  */
 enum BalInterfaceAutoId
 {
-    BAL_INTERFACE_AUTO_ID_IND                    = 0;    /**< Interface Indication. */
-    BAL_INTERFACE_AUTO_ID_LOS                    = 1;    /**< LOS. */
-    BAL_INTERFACE_AUTO_ID_OPER_STATUS_CHANGE     = 2;    /**< Change of operational status. */
+    BAL_INTERFACE_AUTO_ID_LOS                    = 0;    /**< LOS. */
+    BAL_INTERFACE_AUTO_ID_OPER_STATUS_CHANGE     = 1;    /**< Change of operational status. */
 }
 
 /** List of all packet groups of type auto.
@@ -636,29 +560,31 @@
  */
 enum BalSubscriberTerminalAutoId
 {
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_DGI                 = 0;    /**< Receive Dying-Gasp of subscriber terminal. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_DOWI                = 1;    /**< dowi. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_IND                 = 2;    /**< Subscriber Terminal Indication. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_LOOCI               = 3;    /**< looci. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_OPER_STATUS_CHANGE  = 4;    /**< Change of operational status. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SDI                 = 5;    /**< sdi. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SFI                 = 6;    /**< sfi. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUB_TERM_ALARM      = 7;    /**< Subscriber Terminal Alarm Indication. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUB_TERM_DISC       = 8;    /**< Subscriber Terminal Discovery Indication. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUFI                = 9;    /**< sufi. */
-    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_TIWI                = 10;   /**< tiwi. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_DGI                = 0;    /**< Receive Dying-Gasp of subscriber terminal. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_DOWI               = 1;    /**< dowi. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_LOOCI              = 2;    /**< looci. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_OPER_STATUS_CHANGE = 3;    /**< Change of operational status. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_PROCESSING_ERROR   = 4;    /**< general processing error. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SDI                = 5;    /**< sdi. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SFI                = 6;    /**< sfi. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUB_TERM_ACT_FAIL  = 7;    /**< Subscriber Terminal Activation Failure Indication. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUB_TERM_ALARM     = 8;    /**< Subscriber Terminal Alarm Indication. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUB_TERM_DISC      = 9;    /**< Subscriber Terminal Discovery Indication. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_SUFI               = 10;   /**< sufi. */
+    BAL_SUBSCRIBER_TERMINAL_AUTO_ID_TIWI               = 11;   /**< tiwi. */
+
 }
 
-/** List of all tm_queue groups of type auto.
+/** List of all sys_channel_profile groups of type auto.
  */
-enum BalTmQueueAutoId
+enum BalSysChannelProfileAutoId
 {
-    BAL_TM_QUEUE_AUTO_ID_IND                         = 0;    /**< Tm Queue Indication. */
+    BAL_SYS_CHANNEL_PROFILE_AUTO_ID_IND  = 0;    /**< channel indication. */
 }
 
 /** List of all tm_sched groups of type auto.
  */
 enum BalTmSchedAutoId
 {
-    BAL_TM_SCHED_AUTO_ID_IND                         = 0;    /**< Tm Sched Indication. */
+    BAL_TM_SCHED_AUTO_ID_OPER_STATUS_CHANGE  = 0;    /**< Operational Status Change Indication. */
 }
diff --git a/voltha/adapters/asfvolt16_olt/protos/bal_model_types.proto b/voltha/adapters/asfvolt16_olt/protos/bal_model_types.proto
index 5e81d59..020d98b 100644
--- a/voltha/adapters/asfvolt16_olt/protos/bal_model_types.proto
+++ b/voltha/adapters/asfvolt16_olt/protos/bal_model_types.proto
@@ -37,20 +37,19 @@
 /** actionCmdId.
  */
 enum BalActionCmdId {
-    BAL_ACTION_CMD_ID_NONE               = 0;
-    BAL_ACTION_CMD_ID_ADD_OUTER_TAG      = 0x0001;   /**< Add outer tag. */
-    BAL_ACTION_CMD_ID_REMOVE_OUTER_TAG   = 0x0002;   /**< Remove outer tag. */
-    BAL_ACTION_CMD_ID_XLATE_OUTER_TAG    = 0x0004;   /**< Translate outer tag. */
-    BAL_ACTION_CMD_ID_XLATE_TWO_TAGS     = 0x0008;   /**< Translate two tags. */
-    BAL_ACTION_CMD_ID_DISCARD_DS_BCAST   = 0x0010;   /**< Used to satisfy TR-156 Issue 3 R-111 */
-    BAL_ACTION_CMD_ID_DISCARD_DS_UNKNOWN = 0x0020;   /**< Used to satisfy TR-156 Issue 3 R-109 */
-    BAL_ACTION_CMD_ID_ADD_TWO_TAGS       = 0x0040;   /**< Add two tags. */
-    BAL_ACTION_CMD_ID_REMOVE_TWO_TAGS    = 0x0080;   /**< Remove two tags. */
-    BAL_ACTION_CMD_ID_REMARK_PBITS       = 0x0100;   /**< Set the outer tag pbits */
-    BAL_ACTION_CMD_ID_COPY_PBITS         = 0x0200;   /**< Copy the inner pbits to outer pbits */
-    BAL_ACTION_CMD_ID_REVERSE_COPY_PBITS = 0x0400;   /**< Copy the outer pbits to inner pbits */
-    BAL_ACTION_CMD_ID_DSCP_TO_PBITS      = 0x0800;   /**< Copy the L4 DSCP to outer pbits */
-    BAL_ACTION_CMD_ID_TRAP_TO_HOST       = 0x1000;   /**< Not a valid action for a group object member */
+    BAL_ACTION_CMD_ID_NONE                           = 0;
+    BAL_ACTION_CMD_ID_XLATE_OUTER_TAG                = 0x0001;     /**< Translate outer tag. */
+    BAL_ACTION_CMD_ID_ADD_OUTER_TAG                  = 0x0002;     /**< Add outer tag. */
+    BAL_ACTION_CMD_ID_REMOVE_OUTER_TAG               = 0x0004;     /**< Remove outer tag. */
+    BAL_ACTION_CMD_ID_XLATE_INNER_TAG                = 0x0010;     /**< Translate inner tag. */
+    BAL_ACTION_CMD_ID_ADD_INNER_TAG                  = 0x0020;     /**< Add inner tag. */
+    BAL_ACTION_CMD_ID_REMOVE_INNER_TAG               = 0x0040;     /**< Remove inner tag. */
+    BAL_ACTION_CMD_ID_REMARK_OUTER_PBITS             = 0x0100;     /**< Set the outer tag pbits */
+    BAL_ACTION_CMD_ID_COPY_INNER_PBITS_TO_OUTER_PBITS= 0x0200;     /**< Copy the inner pbits to outer pbits */
+    BAL_ACTION_CMD_ID_REMARK_INNER_PBITS             = 0x1000;     /**< Set the outer tag pbits */
+    BAL_ACTION_CMD_ID_COPY_OUTER_PBITS_TO_INNER_PBITS= 0x2000;     /**< Copy the outer pbits to inner pbits */
+    BAL_ACTION_CMD_ID_DISCARD_DS_BCAST               = 0x00010000; /**< drop downstream broadcast packets. */
+    BAL_ACTION_CMD_ID_TRAP_TO_HOST                   = 0x00020000; /**< Not a valid action for a group object member */
 }
 
 /** alarm status.
@@ -62,6 +61,57 @@
     BAL_ALARM_STATUS_NO__CHANGE          = 2;        /**< alarm status should not be changed */
 }
 
+/** alloc type.
+ */
+enum BalAllocType
+{
+    BAL_ALLOC_TYPE_NONE                   = 0;    /**< none. */
+    BAL_ALLOC_TYPE_NSR                    = 1;    /**< no status report. */
+    BAL_ALLOC_TYPE_SR                     = 2;    /**< status report. */
+    BAL_ALLOC_TYPE__NUM_OF                = 3;    /**< Number of enum entries, not an entry itself. */
+}
+
+/** Sign.
+ */
+enum BalSign
+{
+    BAL_SIGN_POSITIVE                     = 0;    /**< Positive. */
+    BAL_SIGN_NEGATIVE                     = 1;    /**< Negative. */
+    BAL_SIGN__NUM_OF                      = 2;    /**< Number of enum entries, not an entry itself. */
+}
+
+/**  XGPON ni upstream line rate capabilities
+ */
+enum BalUpstreamLineRateCapabilities
+{
+    BAL_UPSTREAM_LINE_RATE_CAPABILITIES_RATE_2_P_5_G               = 0;   /**< 2.5G Upstream line rate capability. */
+    BAL_UPSTREAM_LINE_RATE_CAPABILITIES_RATE_10_G                  = 1;    /**< 10g upstream line rate capability . */
+    BAL_UPSTREAM_LINE_RATE_CAPABILITIES_RATE_DUAL_2_P_5_G_AND_10_G = 2;    /**< dual 2.5g and 10g upstream line rate capability . */
+    BAL_UPSTREAM_LINE_RATE_CAPABILITIES__NUM_OF                    = 3;    /**< Number of enum entries, not an entry itself. */
+}
+
+/** Link Type.
+ */
+enum BalLinkType
+{
+    BAL_LINK_TYPE_UNSPECIFIED          = 0;    /**<  link type unspecified  */
+    BAL_LINK_TYPE_B                    = 1;    /**< link type a is not supported, link type b is supported */
+    BAL_LINK_TYPE_A                    = 2;    /**< link type a is supported, link type b is not supported */
+    BAL_LINK_TYPE_A_AND_B              = 3;    /**< both link types a and b are supported  */
+    BAL_LINK_TYPE__NUM_OF              = 4;    /**< Number of enum entries, not an entry itself. */
+}
+
+/** Calibration record.
+ */
+enum BalCalibrationRecord
+{
+    BAL_CALIBRATION_RECORD_UNSPECIFIED   = 0;    /**< Unspecified. */
+    BAL_CALIBRATION_RECORD_UNCALIBRATED  = 1;    /**< Uncalibrated. */
+    BAL_CALIBRATION_RECORD_LOOSE         = 2;    /**< Loose. */
+    BAL_CALIBRATION_RECORD_SUFFICIENT    = 3;    /**< Sufficient. */
+    BAL_CALIBRATION_RECORD__NUM_OF       = 4;    /**< Number of enum entries, not an entry itself. */
+}
+
 /** classifier ID.
  */
 enum BalClassifierId {
@@ -118,7 +168,9 @@
     BAL_DS_MISS_MODE_DISCARD             = 0;        /**< Discard. */
     BAL_DS_MISS_MODE_BROADCAST           = 1;        /**< Broadcast. */
     BAL_DS_MISS_MODE_VID                 = 2;        /**< Vid. */
+    BAL_DS_MISS_MODE__NUM_OF             = 3;        /**< Number of enum entries, not an entry itself. */
 }
+
 /** extended epon dba ID.
  */
 enum BalExtendedEponDbaId
@@ -158,7 +210,8 @@
     BAL_EXTENDED_ITU_DBA_ID_RT_CBR                   = 0x0004;   /**< RT_CBR */
     BAL_EXTENDED_ITU_DBA_ID_RT_PROFILE               = 0x0008;   /**< RT Profile */
     BAL_EXTENDED_ITU_DBA_ID_NRT_PROFILE              = 0x0010;   /**< NRT Profile */
-    BAL_EXTENDED_ITU_DBA_ID_ALL                      = 0x001F;   /**< All fields */
+    BAL_EXTENDED_ITU_DBA_ID_ALLOC_TYPE               = 0x0020;   /**< alloc_type. */
+    BAL_EXTENDED_ITU_DBA_ID_ALL                      = 0x003F;   /**< All fields */
 }
 
 /** Extra BW Eligibility Type
@@ -191,14 +244,77 @@
     BAL_GROUP_MEMBER_CMD_SET_MEMBERS         = 3;    /**< Replace members with new set. */
 }
 
-/** owner of the group
+/** Interface type in DS direction.
  */
-enum BalGroupOwner
+enum BalIntfTypeDs
 {
-    BAL_GROUP_OWNER_NONE                     = 0;    /**< no owner */
-    BAL_GROUP_OWNER_MULTICAST                = 1;    /**< used as multicast group */
-    BAL_GROUP_OWNER_UNICAST                  = 2;    /**< used as unicast group */
-    BAL_GROUP_OWNER__NUM_OF                  = 3;    /**< Number of enum entries, not an entry itself. */
+    BAL_INTF_TYPE_DS_INVALID                  = 0;
+    BAL_INTF_TYPE_DS_PON                      = 1;    /**< PON Interface. */
+    BAL_INTF_TYPE_DS_EPON_1G_PATH             = 2;    /**< EPON 1G Path. */
+    BAL_INTF_TYPE_DS_EPON_10G_PATH            = 3;     /**< EPON 10G Path. */
+}
+
+/** typeof the group
+ */
+enum BalGroupType
+{
+    BAL_GROUP_TYPE_NONE             = 0;    /**< no type set */
+    BAL_GROUP_TYPE_MULTICAST        = 1;    /**< used as multicast group */
+    BAL_GROUP_TYPE_N_TO_1           = 2;    /**< used as n:1 group */
+    BAL_GROUP_TYPE__NUM_OF          = 3;    /**< Number of enum entries, not an entry itself. */
+}
+
+/** interface_ngpon2 ID.
+ */
+enum BalInterfaceNgpon2Id
+{
+    BAL_INTERFACE_NGPON_2_ID_NONE              = 0;
+    BAL_INTERFACE_NGPON_2_ID_SYS_ID            = 0x0001;   /**< 20-bit identifier of the NGPON2 system,
+                                                            should match a key of exysting sys_channel_profile object */
+    BAL_INTERFACE_NGPON_2_ID_OPERATION_CONTROL = 0x0002;   /**< operation_control. */
+    BAL_INTERFACE_NGPON_2_ID_TOL               = 0x0004;   /**< Transmit Optical Level.
+                                                            An indication of the current OLT CT transceiver channel
+                                                            launch power into the ODN */
+    BAL_INTERFACE_NGPON_2_ID_ALL               = 0x0007;   /**< All fields */
+}
+
+/** Operation control ID.
+ */
+enum BalOperationControlId
+{
+    BAL_OPERATION_CONTROL_ID_NONE           = 0;
+    BAL_OPERATION_CONTROL_ID_RE             = 0x0001;   /**<  Indicates whether the Transmit Optical Level (TOL)
+                                                         contains the launch power of the OTL (RE=0)
+                                                         or of a reach extender (RE=1) */
+    BAL_OPERATION_CONTROL_ID_ODN_CLASS      = 0x0002;   /**<  Identifies the nominal optical parameters of the
+                                                         transceiver according to the ODN Optical Path Loss (OPL) */
+    BAL_OPERATION_CONTROL_ID_DS_FEC_MODE    = 0x0004;   /**<  Enable/Disable the downstream FEC. Default is Enable.
+                                                         Attribute can be set only when PON NI state is Inactive */
+    BAL_OPERATION_CONTROL_ID_PROTOCOL       = 0x0008;   /**< When system mode is NGPON2, this parameter Indicate the
+                                                         TC layer protocol: ITU-T G.989.3 or ITU-T G.987.3 */
+    BAL_OPERATION_CONTROL_ID_DS_LINK_TYPE   = 0x0010;   /**<  Optical link type (Unspecified, A, B, Both) */
+    BAL_OPERATION_CONTROL_ID_PON_ID         = 0x0020;   /**<  Identifies the TWDM channel termination within a certain domain  */
+    BAL_OPERATION_CONTROL_ID_C              = 0x0040;   /**< Transmit optical level (TOL) reference point indicator: S/R-CG or S/R-CP  */
+    BAL_OPERATION_CONTROL_ID_ALL            = 0x007F;    /**< All fields */
+}
+
+/** ODN Class.
+ */
+enum BalOdnClass
+{
+    BAL_ODN_CLASS_N_1        = 0;        /**< N1. */
+    BAL_ODN_CLASS_N_2        = 4;        /**< N2. */
+    BAL_ODN_CLASS_E_1        = 2;        /**< E1. */
+    BAL_ODN_CLASS_E_2        = 3;         /**< E2. */
+}
+
+/** TC protocol.
+ */
+enum BalTcProtocol
+{
+    BAL_TC_PROTOCOL_TC_LAYER_PROTOCOL_G_987_P_3             = 0;        /**< TC layer protocol G.987.3. */
+    BAL_TC_PROTOCOL_TC_LAYER_PROTOCOL_G_989_P_3             = 1;        /**< TC layer protocol G.989.3 . */
+    BAL_TC_PROTOCOL__NUM_OF                                 = 3;  /**< Number of enum entries, not an entry itself. */
 }
 
 /** Interface type.
@@ -215,25 +331,42 @@
 enum BalIwfMode {
     BAL_IWF_MODE_DIRECT_MAPPING              = 0;    /**< Direct mapping. */
     BAL_IWF_MODE_PER_FLOW                    = 1;    /**< Per flow . */
+    BAL_IWF_MODE__NUM_OF                     = 2;    /**< Number of enum entries, not an entry itself. */
 }
 
 /** The PON family
  */
 enum BalPonFamily
 {
-    BAL_PON_FAMILY_GPON                      = 0;    /**< GPON family. */
-    BAL_PON_FAMILY_EPON                      = 1;    /**< EPON family. */
-    BAL_PON_FAMILY_INVALID                   = 2;    /**< INVALID . */
+    BAL_PON_FAMILY_ITU        = 0;    /**< ITU family. */
+    BAL_PON_FAMILY_IEEE       = 1;    /**< IEEE family. */
+    BAL_PON_FAMILY_INVALID    = 2;    /**< INVALID . */
+    BAL_PON_FAMILY__NUM_OF    = 3;    /**< Number of enum entries, not an entry itself. */
 }
 
 /** The PON sub-family
  */
 enum BalPonSubFamily
 {
-    BAL_PON_SUB_FAMILY_GPON                  = 0;    /**< GPON. */
-    BAL_PON_SUB_FAMILY_XGPON                 = 1;    /**< XGPON. */
-    BAL_PON_SUB_FAMILY_EPON                  = 2;    /**< EPON. */
-    BAL_PON_SUB_FAMILY_INVALID               = 3;    /**< INVALID. */
+    BAL_PON_SUB_FAMILY_GPON             = 0;    /**< GPON. */
+    BAL_PON_SUB_FAMILY_XGPON            = 1;    /**< XGPON. */
+    BAL_PON_SUB_FAMILY_XGS              = 2;    /**< XGS. */
+    BAL_PON_SUB_FAMILY_EPON_TDMA        = 3;    /**<  EPON_TDMA. */
+    BAL_PON_SUB_FAMILY_EPON_1_G         = 4;    /**< EPON_1G. */
+    BAL_PON_SUB_FAMILY_EPON_10_G        = 5;    /**< EPON_10G. */
+    BAL_PON_SUB_FAMILY_XGS_XGPON_TDMA   = 6;    /**< XGS_XGPON_TDMA. */
+    BAL_PON_SUB_FAMILY_NGPON_2          = 7;    /**< NGPON2. */
+    BAL_PON_SUB_FAMILY_INVALID          = 8;    /**< INVALID. */
+    BAL_PON_SUB_FAMILY__NUM_OF          = 9;    /**< Number of enum entries, not an entry itself. */
+}
+
+/** Result.
+ */
+enum BalResult
+{
+    BAL_RESULT_SUCCESS           = 0;    /**< Success. */
+    BAL_RESULT_FAIL              = 1;    /**< Failure. */
+    BAL_RESULT__NUM_OF           = 2;    /**< Number of enum entries, not an entry itself. */
 }
 
 /** SLA ID.
@@ -248,31 +381,41 @@
 /** Admin state values for access terminal object
  */
 enum BalState {
-    BAL_STATE_INVALID                        = 0;
-    BAL_STATE_UP                             = 1;        /**< Admin state up */
-    BAL_STATE_DOWN                           = 2;        /**< Admin state down */
-    BAL_STATE_TESTING                        = 3;        /**< Admin state testing */
+    BAL_STATE_UP                             = 0;        /**< Admin state up */
+    BAL_STATE_DOWN                           = 1;        /**< Admin state down */
+    BAL_STATE__NUM_OF                        = 2;        /**< Number of enum entries, not an entry itself. */
 }
 
 /** Oper status values
  */
 enum BalStatus {
-    BAL_STATUS_INVALID                       = 0;
-    BAL_STATUS_UP                            = 1;        /**< Oper status up */
-    BAL_STATUS_DOWN                          = 2;        /**< Oper status down */
-    BAL_STATUS_TESTING                       = 3;        /**< Oper status testing */
-    BAL_STATUS_NOT_PRESENT                   = 4;        /**< Oper status not present */
-    BAL_STATUS_LOWER_LAYER_DOWN              = 5;        /**< Oper status lower layer down */
-    BAL_STATUS_UNKNOWN                       = 6;        /**< Oper status unknown */
+    BAL_STATUS_UP                            = 0;    /**< Oper status up */
+    BAL_STATUS_DOWN                          = 1;    /**< Oper status down */
+    BAL_STATUS_NOT_PRESENT                   = 2;    /**< Oper status not present */
+    BAL_STATUS__NUM_OF                       = 3;    /**< Number of enum entries, not an entry itself. */
+}
+
+/** Sub Term Act Fail Reason.
+ */
+enum BalSubTermActFailReason
+{
+    BAL_SUB_TERM_ACT_FAIL_REASON_NONE                        = 0;    /**< Reason not set */
+    BAL_SUB_TERM_ACT_FAIL_REASON_RANGING                     = 1;    /**< ITU Ranging Failed */
+    BAL_SUB_TERM_ACT_FAIL_REASON_PASSWORD_AUTHENTICATION     = 2;    /**< ITU Authentication Failed */
+    BAL_SUB_TERM_ACT_FAIL_REASON_LOS                         = 3;    /**< ITU LOS */
+    BAL_SUB_TERM_ACT_FAIL_REASON_ONU_ALARM                   = 4;    /**< ITU ONU Alarm */
+    BAL_SUB_TERM_ACT_FAIL_REASON_SWITCH_OVER                 = 5;    /**< ITU Protection Switch Over */
+    BAL_SUB_TERM_ACT_FAIL_REASON__NUM_OF                     = 6;    /**< Number of enum entries, not an entry itself. */
 }
 
 /** sub_term_rate.
  */
 enum BalSubTermRate
 {
-    BAL_SUB_TERM_RATE_NONE                           = 0;        /**< none. */
-    BAL_SUB_TERM_RATE_RATE_10_G                      = 1;        /**< rate_10_g. */
-    BAL_SUB_TERM_RATE_RATE_2_5_G                     = 2;        /**< rate_2_5_g. */
+    BAL_SUB_TERM_RATE_SYMMETRIC_10_G          = 0;    /**< ITU: XGS-PON */
+    BAL_SUB_TERM_RATE_ASYMMETRIC_10_G         = 1;    /**< ITU: XG-PON1 */
+    BAL_SUB_TERM_RATE_SYMMETRIC_1_G           = 2;    /**< ITU: GPON */
+    BAL_SUB_TERM_RATE__NUM_OF                 = 3;    /**< Number of enum entries, not an entry itself. */
 }
 
 /** The type of release version
@@ -284,6 +427,41 @@
     BAL_VERSION_TYPE_DEVELOPMENT                     = 2;    /**< debug version */
 }
 
+/** System profile ID.
+ */
+enum BalSystemProfileId
+{
+    BAL_SYSTEM_PROFILE_ID_NONE                           = 0;
+    BAL_SYSTEM_PROFILE_ID_VERSION                        = 0x0001;   /**< System profile version. */
+    BAL_SYSTEM_PROFILE_ID_CHANNEL_SPACING                = 0x0002;   /**< An integer indicating the channel spacing in units of 1GHz  */
+    BAL_SYSTEM_PROFILE_ID_US_OPERATING_WAVELENGTH_BANDS  = 0x0004;   /**< US  operating wavelength bands. */
+    BAL_SYSTEM_PROFILE_ID_US_MSE                         = 0x0008;   /**<  Upstream Maximum Spectral Excursion (MSE)
+                                                                      represented as an unsigned integer indicating the
+                                                                      value in units of 1GHz */
+    BAL_SYSTEM_PROFILE_ID_LOOSE_CALIBRATION_BOUND        = 0x0010;   /**< Spectral excursion bound below which a TWDM
+                                                                      ONU can be considered as loosely calibrated  */
+    BAL_SYSTEM_PROFILE_ID_FSR                            = 0x0020;   /**<  If a cyclic WM is used in the upstream,
+                                                                      Free Spectral Range indicates the value in units of 0.1 GHz */
+    BAL_SYSTEM_PROFILE_ID_TWDM_CHANNEL_COUNT             = 0x0040;   /**<  The number of Channel_Profile PLOAM messages
+                                                                      with distinct Channel Profile indices that an ONU
+                                                                      can expect to receive while listening to this
+                                                                      downstream wavelength channel */
+    BAL_SYSTEM_PROFILE_ID_ALL                            = 0x007F;   /**< All fields */
+}
+
+/** US  operating wavelength bands.
+ */
+enum BalUsOperatingWavelengthBands
+{
+    BAL_US_OPERATING_WAVELENGTH_BANDS_EXPANDED_SPECTRUM_WIDE_BAND    = 0;        /**< expanded spectrum wide band option . */
+    BAL_US_OPERATING_WAVELENGTH_BANDS_EXPANDED_SPECTRUM_REDUCED_BAND = 1;        /**< expanded spectrum reduced band option. */
+    BAL_US_OPERATING_WAVELENGTH_BANDS_EXPANDED_SPECTRUM_NARROW_BAND  = 2;        /**< expanded spectrum narrow band option. */
+    BAL_US_OPERATING_WAVELENGTH_BANDS_SHARED_SPECTRUM_WIDE_BAND      = 3;        /**< shared spectrum wide band option. */
+    BAL_US_OPERATING_WAVELENGTH_BANDS_SHARED_SPECTRUM_REDUCED_BAND   = 4;        /**< shared spectrum reduced band option . */
+    BAL_US_OPERATING_WAVELENGTH_BANDS_SHARED_SPECTRUM_NARROW_BAND    = 5;        /**< shared spectrum wide narrow option . */
+    BAL_US_OPERATING_WAVELENGTH_BANDS__NUM_OF                        = 6;        /**< Number of enum entries, not an entry itself. */
+}
+
 /** Buffer Admission Control Type
  */
 enum BalTmBacType {
@@ -300,13 +478,6 @@
     BAL_TM_CREATION_MODE_AUTO                = 1;            /**< tm object created automatically */
 }
 
-/** Scheduling Level for the Children TM
- */
-enum BalTmSchedChildType {
-    BAL_TM_SCHED_CHILD_TYPE_QUEUE            = 0;            /**< Queue-level scheduler */
-    BAL_TM_SCHED_CHILD_TYPE_SCHED            = 1;            /**< Scheduler-level scheduler */
-}
-
 /** Traffic Direction
  */
 enum BalTmSchedDir {
@@ -319,13 +490,12 @@
  */
 enum BalTmSchedOwnerType
 {
-    BAL_TM_SCHED_OWNER_TYPE_UNDEFINED        = 0;            /**< Undefined */
-    BAL_TM_SCHED_OWNER_TYPE_INTERFACE        = 1;            /**< Interface */
-    BAL_TM_SCHED_OWNER_TYPE_SUB_TERM         = 2;            /**< Subscriber terminal */
-    BAL_TM_SCHED_OWNER_TYPE_AGG_PORT         = 3;            /**< TM scheduler is owned by aggregation port */
-    BAL_TM_SCHED_OWNER_TYPE_UNI              = 4;            /**< TM scheduler is owned by UNI port */
-    BAL_TM_SCHED_OWNER_TYPE_VIRTUAL          = 5;            /**< Other unspecified owner */
-    BAL_TM_SCHED_OWNER_TYPE__NUM_OF          = 6;            /**< Number of enum entries, not an entry itself. */
+    BAL_TM_SCHED_OWNER_TYPE_UNDEFINED        = 0;    /**< Undefined */
+    BAL_TM_SCHED_OWNER_TYPE_INTERFACE        = 1;    /**< Interface */
+    BAL_TM_SCHED_OWNER_TYPE_SUB_TERM         = 2;    /**< Subscriber terminal */
+    BAL_TM_SCHED_OWNER_TYPE_AGG_PORT         = 3;    /**< TM scheduler is owned by aggregation port */
+    BAL_TM_SCHED_OWNER_TYPE_VIRTUAL          = 4;    /**< Other unspecified owner */
+    BAL_TM_SCHED_OWNER_TYPE__NUM_OF          = 5;    /**< Number of enum entries, not an entry itself. */
 }
 
 /** TmSchedOwner aggPort ID.
@@ -358,7 +528,6 @@
     BAL_TM_SCHED_TYPE_WFQ                        = 1;        /**< Weighted Fair Queue */
     BAL_TM_SCHED_TYPE_SP                         = 2;        /**< Strict Priority */
     BAL_TM_SCHED_TYPE_SP_WFQ                     = 3;        /**< Hybrid SP + WFQ */
-    BAL_TM_SCHED_TYPE__NUM_OF                    = 4;        /**< Number of enum entries, not an entry itself. */
 }
 
 /** TmShaping ID.
@@ -366,8 +535,8 @@
 enum BalTmShapingId
 {
     BAL_TM_SHAPING_ID_NONE                       = 0;
-    BAL_TM_SHAPING_ID_SBR                        = 0x0001;   /**< Sustained Bit Rate (kbps) */
-    BAL_TM_SHAPING_ID_PBR                        = 0x0002;   /**< Peak Bit Rate (kbps) */
+    BAL_TM_SHAPING_ID_CIR                        = 0x0001;   /**< Committed Information Rate (kbps) */
+    BAL_TM_SHAPING_ID_PIR                        = 0x0002;   /**< Peak Information Rate (kbps) */
     BAL_TM_SHAPING_ID_BURST                      = 0x0004;   /**< Max Burst Bytes at Peak Bit Rate */
     BAL_TM_SHAPING_ID_ALL                        = 0x0007;   /**< All fields */
 }
@@ -385,6 +554,9 @@
     BAL_TRX_TYPE_XGPON_LTH_7226_PC               = 6;        /**< xgpon_lth_7226_pc. */
     BAL_TRX_TYPE_XGPON_LTH_5302_PC               = 7;        /**< xgpon_lth_5302_pc. */
     BAL_TRX_TYPE_XGPON_LTH_7226_A_PC_PLUS        = 8;        /**< xgpon_lth_7226_a_pc_plus. */
+    BAL_TRX_TYPE_XGPON_LTW_627_X_PC              = 9;        /**< xgpon_ltw_627_x_pc. */
+    BAL_TRX_TYPE_XGPON_XPP_XE_R_3_CDFB           = 10;       /**< xgpon_xpp_xe_r_3_cdfb. */
+    BAL_TRX_TYPE__NUM_OF                         = 11;       /**< Number of enum entries, not an entry itself. */
 }
 
 /** action.
@@ -401,6 +573,52 @@
     uint32 i_tpid = 8;                    /**< Inner tpid. */
 }
 
+/** Variable-length list of aggregation_port_id.
+ */
+message BalAggregationPortIdList
+{
+    repeated uint32  val = 1;               /**< List contents. */
+}
+
+/** DS frequency offset.
+ */
+message BalDsFrequencyOffset
+{
+    BalSign sign = 1;   /**< Sign. */
+    uint32 value = 2;   /**< Value. */
+}
+
+/** Channel Profile.
+ */
+message BalChannelProfile
+{
+    uint32 version                            = 1;   /**< Channel profile version . */
+    uint32 channel_index                      = 2;   /**< Channel profile index . */
+    BalDsFrequencyOffset ds_frequency_offset  = 3;   /**< The difference between the actual OLT CT Tx frequency
+                                                      and the nominal central frequency for the given DWLCH ID,
+                                                      expressed in units of 0.1GHz */
+    uint32 channel_partition                  = 4;   /**< channel partition. */
+    uint32 uwlch_id                           = 5;   /**<  The assigned upstream wavelength channel ID */
+    uint32 us_frequency                       = 6;   /**< The nominal central frequency of the upstream wavelength
+                                                      channel or a root frequency of the cyclic set of central
+                                                      frequencies forming an upstream wavelength channel,
+                                                      indicates the value in units of 0.1 GHz. */
+    BalUpstreamLineRateCapabilities us_rate   = 7;   /**<  US rate. */
+    uint32 default_onu_attenuation            = 8;   /**<  The default ONU attenuation level in steps of 3dB  */
+    uint32 response_threshold                 = 9;   /**< Threshold represent the maximum number of Ploams the ONU
+                                                      can transmit at non-zero attenuation level while attempting to
+                                                      establish communication with OLT CT */
+    BalLinkType us_link_type                  = 10;  /**< US link type. */
+    bool is_valid                             = 11;  /**< Is Valid. */
+}
+
+/** Fixed-Length list: 8x channel_profile.
+ */
+message BalArrChannelProfile8
+{
+    repeated BalChannelProfile arr = 1;  /**< Array. */
+}
+
 /** ber monitor parameters.
  */
 message BalBerMonitorParams
@@ -482,7 +700,7 @@
     uint32 grant_threshold_tq              = 3;          /**< Used to determine the maximum grant size that will be issued to this LLID (in TQ; rounded up to the nearest 128TQ; 1TQ = 16ns = 2Bytes@1G or 20Bytes@10G). */
     uint32 cir_priority                    = 4;                   /**< The priority of the CIR scheduling element. */
     uint32 cir_weight_tq                   = 5;       /**< The weight of the CIR scheduler (in TQ rounded up to nearest 128). Must be greater than or equal to Grant Threshold. */
-    uint32 pir_priority                     = 6;                   /**< The priority of the PIR scheduling element. */
+    uint32 pir_priority                    = 6;                   /**< The priority of the PIR scheduling element. */
     uint32 pir_weight_tq                   = 7;       /**< The weight of the PIR scheduler (in TQ rounded up to nearest 128). Must be greater than or equal to Grant Threshold. */
     uint32 tdm_grant_size_tq               = 8;   /**< Size of TDM grants (in TQ). */
     uint32 tdm_grant_interval_us           = 9;         /**< Interval between TDM grants (in us). */
@@ -498,8 +716,15 @@
     uint32 rt_cbr                         = 4; /**< RT_CBR */
     uint32 rt_profile                     = 5; /**< RT Profile */
     uint32  nrt_profile                    = 6;/**< NRT Profile */
+    BalAllocType alloc_type               = 7; /**< alloc_type. */
 }
 
+/** Variable-length list of flow_id.
+ */
+message BalIdList
+{
+    repeated uint32 val  = 2;    /**< List contents. */
+}
 
 /** Queue Reference
  */
@@ -513,10 +738,12 @@
  */
 message BalGroupMemberInfo
 {
-    uint32 intf_id = 1;             /**< Access interface id for this member */
-    uint32 svc_port_id = 2;         /**< GPON/XGPON - The multicast "GEM" for this member. EPON - The multicast link identifier. */
-    BalAction action = 3;               /**< VLAN actions */
-    BalTmQueueRef queue = 4;          /**< Egress queue */
+    uint32 intf_id             = 1;           /**< Access interface id for this member */
+    BalIntfTypeDs intf_type    = 2;           /**< Type of interface. Usually PON, or a specific data path for
+                                               interfaces with multiple downstream channels. */
+    uint32 svc_port_id         = 3;           /**< GPON/XGPON - The multicast "GEM" for this member.
+                                               EPON - The multicast link identifier. */
+    BalTmQueueRef queue        = 4;           /**< Egress queue */
 }
 
 /** Variable-length list of groupMemberInfo.
@@ -526,6 +753,57 @@
     repeated BalGroupMemberInfo val = 1;  /**< List contents. */
 }
 
+/** Identifies the TWDM channel termination within a certain domain
+ */
+message BalPonId
+{
+    uint32 administrative_label       = 1;  /**< MSB 28 bit of the PON ID */
+    uint32 dwlch_id                   = 2;   /**< LSB 4 bits of the PON ID */
+}
+
+/** Operation control.
+ */
+message BalOperationControl
+{
+    BalOperationControlId presence_mask    = 1;  /**< Presence Mask. */
+    uint32 re                              = 2;  /**<  Indicates whether the Transmit Optical Level (TOL) contains the
+                                                  launch power of the OTL (RE=0) or of a reach extender (RE=1) */
+    BalOdnClass odn_class                  = 3;  /**<  Identifies the nominal optical parameters of the transceiver
+                                                  according to the ODN Optical Path Loss (OPL) */
+    BalControl ds_fec_mode                 = 4;  /**<  Enable/Disable the downstream FEC. Default is Enable.
+                                                  Attribute can be set only when PON NI state is Inactive */
+    BalTcProtocol protocol                 = 5;  /**< When system mode is NGPON2, this parameter Indicate the
+                                                  TC layer protocol: ITU-T G.989.3 or ITU-T G.987.3 */
+    BalLinkType ds_link_type               = 6;  /**<  Optical link type (Unspecified, A, B, Both) */
+    BalPonId pon_id                        = 7;  /**<  Identifies the TWDM channel termination within a certain domain  */
+    uint32 c                               = 8;  /**< Transmit optical level (TOL) reference point indicator: S/R-CG or S/R-CP  */
+}
+
+/** interface ngpon2 related attributes
+ */
+message BalInterfaceNgpon2
+{
+    BalInterfaceNgpon2Id presence_mask     = 1;  /**< Presence Mask. */
+    uint32 sys_id                          = 2;  /**< 20-bit identifier of the NGPON2 system, should match a key of
+                                                  existing sys_channel_profile object */
+    BalOperationControl operation_control  = 3; /**< operation_control. */
+    uint32 tol                             = 4;   /**< Transmit Optical Level. An indication of the current OLT CT transceiver channel launch power into the ODN */
+}
+
+/** Password.
+ */
+message BalPassword
+{
+    string arr   = 1;    /**< Array. */
+}
+
+/** Registration id.
+ */
+message BalRegistrationId
+{
+    string arr    = 1;    /**< ONU registration ID */
+}
+
 /** Serial number.
  */
 message BalSerialNumber
@@ -534,11 +812,12 @@
     string vendor_specific = 2; /**< vendor specific. */
 }
 
-/** Variable-length list of servicePortId.
+
+/** Variable-length list of service_port_id.
  */
-message BalIdList
+message BalServicePortIdList
 {
-    repeated uint32 val = 1;    /**< List contents. */
+    repeated uint32 val     = 1;    /**< List contents. */
 }
 
 /** SLA.
@@ -550,6 +829,13 @@
     uint32 max_rate = 3;              /**< The maximum rate for this flow, in kilobits per second (optional) */
 }
 
+/** Variable-length list of sub_id.
+ */
+message BalSubIdList
+{
+    repeated uint32 val    = 1;        /**< List contents. */
+}
+
 /** Subscriber Terminal Alarms.
  */
 message BalSubscriberTerminalAlarms
@@ -558,6 +844,8 @@
     BalAlarmStatus lob           = 2;  /**< LOB. */
     BalAlarmStatus lopc_miss     = 3;  /**< LOPC miss. */
     BalAlarmStatus lopc_mic_error= 4;  /**< LOPC mic error. */
+    BalAlarmStatus lof           = 5;  /**< ITU GPON LOF Alarm. */
+    BalAlarmStatus loam          = 6;  /**< ITU GPON LOAM Alarm. */
 }
 
 /** Software version information
@@ -567,11 +855,30 @@
     BalVersionType      version_type = 1;   /**< Release or debug version */
     uint32 major_rev                 = 2;   /**< Major rev */
     uint32 minor_rev                 = 3;   /**< Minor rev */
-    uint32 patch_rev                 = 4;   /**< Patch number */
+    uint32 release_rev               = 4;   /**< Release number */
     uint32 om_version                = 5;   /**< BAL API Object Model version */
     uint32 dev_point                 = 6;   /**< Development point - only valid for development versions, 0 otherwise */
 }
 
+/** System profile.
+ */
+message BalSystemProfile
+{
+    BalSystemProfileId presence_mask      = 1;   /**< Presence Mask. */
+    uint32 version                        = 2;   /**< System profile version. */
+    uint32 channel_spacing                = 3;   /**< An integer indicating the channel spacing in units of 1GHz  */
+    BalUsOperatingWavelengthBands us_operating_wavelength_bands = 4;   /**< US  operating wavelength bands. */
+    uint32 us_mse                         = 5;   /**<  Upstream Maximum Spectral Excursion (MSE) represented as an
+                                                  ansigned integer indicating the value in units of 1GHz */
+    BalCalibrationRecord loose_calibration_bound   = 6;   /**< Spectral excursion bound below which a TWDM ONU can
+                                                           be considered as loosely calibrated  */
+    uint32 fsr                            = 7;   /**<  If a cyclic WM is used in the upstream, Free Spectral
+                                                  Range indicates the value in units of 0.1 GHz */
+    uint32 twdm_channel_count             = 8;   /**<  The number of Channel_Profile PLOAM messages with distinct
+                                                  Channel Profile indices that an ONU can expect to receive while
+                                                  listening to this downstream wavelength channel */
+}
+
 /** Random Early Discard Configuration
  */
 message BalTmred
@@ -608,6 +915,20 @@
     }
 }
 
+/** Variable-length list of tm_queue_id.
+ */
+message BalTmQueueIdList
+{
+    repeated uint32 val  = 1;       /**< List contents. */
+}
+
+/** Variable-length list of tm_sched_id.
+ */
+message BalTmSchedIdList
+{
+    repeated uint32 val   = 1;      /**< List contents. */
+}
+
 /** TM Scheduler Owner
  */
 message BalTmSchedOwnerInterface
@@ -630,13 +951,6 @@
     uint32 agg_port_id = 4; /**< Aggregation port id */
 }
 
-message BalTmSchedOwnerUni
-{
-    uint32 intf_id = 1;                        /**< PON interface id */
-    uint32 sub_term_id = 2;              /**< Subscriber terminal id */
-    uint32 idx = 3;    /**< Index at subscriber terminal */
-}
-
 message BalTmSchedOwnerVirtual
 {
     uint32 idx = 1;   /**< Owner index */
@@ -649,7 +963,6 @@
         BalTmSchedOwnerInterface interface = 2;
         BalTmSchedOwnerSubTerm sub_term = 3;
         BalTmSchedOwnerAggPort agg_port = 4;
-        BalTmSchedOwnerUni uni = 5;
         BalTmSchedOwnerVirtual virtual = 6;
     }
 }
@@ -686,6 +999,13 @@
     BalPonSubFamily pon_sub_family = 6; /**< The PON sub-family for the access_terminal */
 }
 
+/** Variable-length list of U8.
+ */
+message BalU8ListU32Max2048
+{
+    repeated uint32 val  = 1;   /**< List contents. */
+}
+
 /** Structure definition for the "key" group of the "access_terminal" object.
  */
 message BalAccessTerminalKey
@@ -697,38 +1017,21 @@
  */
 message BalAccessTerminalCfgData
 {
-    BalState admin_state = 1;   /**< Administrative state */
-    BalStatus oper_status = 2;  /**< Operational status */
+    BalState admin_state = 1;   /**< Current administrative state */
+    BalStatus oper_status = 2;  /**< Current operational status */
     BalIwfMode iwf_mode = 3;   /**< The interworking mode */
+    BalTopology topology = 4;       /**< Topology. */
+    BalSwVersion sw_version = 5;   /**< Software version information */
+    uint32 conn_id = 6;           /**< Connection id uniquely identifying BAL core */
 }
 
 /** Transport message definition for "cfg" group of "access_terminal" object.
  */
 message BalAccessTerminalCfg
 {
-    BalAccessTerminalKey key = 1; /**< Object key. */
-    BalAccessTerminalCfgData data = 2;   /**< All properties that must be set by the user. */
-}
-
-/** Structure definition for the "ind" group of the "access_terminal" object.
- */
-message BalAccessTerminalIndData
-{
-    BalState admin_state = 1;   /**< Current administrative state */
-    BalStatus oper_status = 2;  /**< Current operational status */
-    BalIwfMode iwf_mode = 3;   /**< The interworking mode */
-    BalTopology topology = 4;       /**< Topology. */
-    BalSwVersion sw_version = 5;   /**< Software version information */
-
-}
-
-/** Transport message definition for "ind" group of "access_terminal" object.
- */
-message BalAccessTerminalInd
-{
-    BalObj hdr = 1;                        /**< Transport header. */
-    BalAccessTerminalKey key = 2;         /**< Object key. */
-    BalAccessTerminalIndData data = 3;   /**< All properties that must be set by the user. */
+    BalApiCfg hdr = 1;               /**< Transport header. */
+    BalAccessTerminalKey key = 2; /**< Object key. */
+    BalAccessTerminalCfgData data = 3;   /**< All properties that must be set by the user. */
 }
 
 /** Structure definition for the "oper_status_change" group of the
@@ -748,11 +1051,20 @@
  */
 message BalAccessTerminalOperStatusChange
 {
-    BalObj hdr = 1;                /**< Transport header. */
+    BalAuto              hdr = 1;  /**< Transport header. */
     BalAccessTerminalKey key = 2; /**< Object key. */
     BalAccessTerminalOperStatusChangeData data = 3;    /**< All properties that must be set by the user. */
 }
 
+/** Transport message definition for "processing_error" group of
+ * "access_terminal" object.
+ */
+message BalAccessTerminalProcessingError
+{
+    BalAuto hdr = 1;                /**< Transport header. */
+    BalAccessTerminalKey key = 2;   /**< Object key. */
+}
+
 /** Structure definition for the "key" group of the "flow" object.
  */
 message BalFlowKey
@@ -770,77 +1082,26 @@
     uint32 access_int_id = 3;           /**< The ID of the subscriber side interface; i.e. PON */
     uint32 network_int_id = 4;          /**< The ID of the network side interface; i.e. NNI */
     uint32 sub_term_id = 5;              /**< The ID of the subsccriber terminal device */
-    uint32 sub_term_uni_idx = 6;               /**< The index of the subsccriber terminal uni port the flow is related to */
-    uint32 svc_port_id = 7;     /**< The ID of the service port (for GPON/XGPON - GEM ID) */
-    bool resolve_mac = 8;                 /**< A flag indicating if the MAC address table should be used in DS GEM resolution */
-    BalClassifier classifier = 9;           /**< The classifier for this flow */
-    BalAction action = 10;                   /**< The action associated with the flow */
-    uint64 cookie = 11;       /**< Application cookie */
-    uint32 priority = 12;          /**< Priority for this flow in case of multiple match. */
-    uint32 group_id = 13;   /**< RW - The multicast group associated with this flow, valid for type MULTICAST only */
-    BalTmQueueRef queue = 14;  /**< Egress queue */
-    uint32 dba_tm_sched_id = 15; /**< A reference to an us tm_sched used for us dba for this flow */
+    uint32 svc_port_id = 6;     /**< The ID of the service port (for GPON/XGPON - GEM ID) */
+    bool resolve_mac = 7;                 /**< A flag indicating if the MAC address table should be used in DS GEM resolution */
+    BalClassifier classifier = 8;           /**< The classifier for this flow */
+    BalAction action = 9;                   /**< The action associated with the flow */
+    uint64 cookie = 10;       /**< Application cookie */
+    uint32 priority = 11;          /**< Priority for this flow in case of multiple match. */
+    uint32 group_id = 12;   /**< RW - The multicast group associated with this flow, valid for type MULTICAST only */
+    BalTmQueueRef queue = 13;  /**< Egress queue */
+    uint32 dba_tm_sched_id = 14; /**< A reference to an us tm_sched used for us dba for this flow */
 }
 
 /** Transport message definition for "cfg" group of "flow" object.
  */
 message BalFlowCfg
 {
-    BalObj hdr = 1;            /**< Transport header. */
+    BalApiCfg hdr = 1;            /**< Transport header. */
     BalFlowKey key = 2;        /**< Object key. */
     BalFlowCfgData data = 3;  /**< All properties that must be set by the user. */
 }
 
-/** Structure definition for the "stat" group of the "flow" object.
- */
-message BalFlowStatData
-{
-    uint64 rx_packets = 1;    /**< Received packets. */
-    uint64 rx_bytes = 2;      /**< Received bytes. */
-    uint64 tx_packets = 3;    /**< Transmitted packets. */
-    uint64 tx_bytes = 4;      /**< Transmitted bytes. */
-}
-
-/** Transport message definition for "stat" group of "flow" object.
- */
-message BalFlowStat
-{
-    BalObj hdr = 1;            /**< Transport header. */
-    BalFlowKey key = 2;        /**< Object key. */
-    BalFlowStatData data = 3; /**< All properties that must be set by the user. */
-}
-
-/** Structure definition for the "ind" group of the "flow" object.
- */
-message BalFlowIndData
-{
-    BalState admin_state = 1;       /**< Administrative state */
-    BalStatus oper_status = 2;      /**< Operational Status */
-    uint32 access_int_id = 3;         /**< The ID of the subscriber side interface; i.e. PON */
-    uint32 network_int_id = 4;        /**< The ID of the network side interface; i.e. NNI */
-    uint32 sub_term_id = 5;           /**< The ID of the subsccriber terminal device */
-    uint32 sub_term_uni_idx = 6;           /**< The index of the subsccriber terminal uni port the flow is related to */
-    uint32 svc_port_id = 7;           /**< The ID of the service port (for GPON/XGPON - GEM ID) */
-    bool resolve_mac = 8;         /**< A flag indicating if the MAC address table should be used in DS GEM resolution */
-    BalClassifier classifier = 9;   /**< The classifier for this flow */
-    BalAction action = 10;           /**< The action associated with the flow */
-    uint32 cookie = 11;                /**< Application cookie */
-    uint32 priority = 12;              /**< Priority for this flow in case of multiple match. */
-    uint32 group_id = 13;           /**< RW - The multicast group associated with this flow, valid for type MULTICAST only */
-    BalTmQueueRef queue = 14;          /**< Egress queue */
-    uint32 dba_tm_sched_id = 15; /**< A reference to an us tm_sched used for us dba for this flow */
-
-}
-
-/** Transport message definition for "ind" group of "flow" object.
- */
-message BalFlowInd
-{
-    BalObj hdr = 1;            /**< Transport header. */
-    BalFlowKey key = 2;        /**< Object key. */
-    BalFlowIndData data = 3;  /**< All properties that must be set by the user. */
-}
-
 /** Structure definition for the "oper_status_change" group of the "flow"
  * object.
  *
@@ -861,11 +1122,19 @@
  */
 message BalFlowOperStatusChange
 {
-    BalObj hdr = 1;        /**< Transport header. */
+    BalAuto hdr = 1;       /**< Transport header. */
     BalFlowKey key = 2;    /**< Object key. */
     BalFlowOperStatusChangeData data = 3;   /**< All properties that must be set by the user. */
 }
 
+/** Transport message definition for "processing_error" group of "flow" object.
+ */
+message BalFlowProcessingError
+{
+    BalAuto hdr = 1;        /**< Transport header. */
+    BalFlowKey key = 2;    /**< Object key. */
+}
+
 /** Structure definition for the "key" group of the "group" object.
  */
 message BalGroupKey
@@ -877,39 +1146,20 @@
  */
 message BalGroupCfgData
 {
-    BalGroupMemberCmd members_cmd = 1;        /**< Membership operation commands. */
-    BalGroupMemberInfoList members = 2;  /**< The list of members associated with this group */
-    uint64 cookie = 3;                       /**< Application cookie */
-    BalIdList flows = 4;              /**< List of flows associated with this group */
-    BalGroupOwner owner = 5;                   /**< Owner of the group. */
+    BalGroupMemberCmd members_cmd =  1;        /**< Membership operation commands. */
+    BalGroupMemberInfoList members  = 2;    /**< The list of members associated with this group */
+    uint64 cookie = 3;                         /**< Application cookie */
+    BalIdList flows = 4;                /**< List of flows associated with this group */
+    BalGroupType type = 5;                     /**< Owner of the group. */
 }
 
 /** Transport message definition for "cfg" group of "group" object.
  */
 message BalGroupCfg
 {
-    BalGroupKey key = 1;       /**< Object key. */
-    BalGroupCfgData data = 2; /**< All properties that must be set by the user. */
-}
-
-/** Structure definition for the "ind" group of the "group" object.
- */
-message BalGroupIndData
-{
-    BalGroupMemberCmd members_cmd = 1;        /**< Membership operation commands. */
-    BalGroupMemberInfoList members = 2;  /**< The list of members associated with this group */
-    uint64 cookie = 3;                       /**< Application cookie */
-    BalIdList flows = 4;              /**< List of flows associated with this group */
-    BalGroupOwner owner = 5;                   /**< Owner of the group. */
-}
-
-/** Transport message definition for "ind" group of "group" object.
- */
-message BalGroupInd
-{
-    BalObj hdr = 1;            /**< Transport header. */
+    BalApiCfg hdr      = 1;       /**< Transport header. */
     BalGroupKey key = 2;       /**< Object key. */
-    BalGroupIndData data = 3; /**< All properties that must be set by the user. */
+    BalGroupCfgData data = 3;  /**< All properties that must be set by the user. */
 }
 
 /** Structure definition for the "key" group of the "interface" object.
@@ -929,86 +1179,86 @@
     uint32 min_data_agg_port_id = 3;    /**< The minimum agg_portId that is allowed in the system */
     uint32 min_data_svc_port_id = 4;        /**< The minimum svc_portId that is allowed in the system */
     BalTrxType transceiver_type = 5;                   /**< The transceiver type used on an interface. N/A for EPON.*/
-    BalDsMissMode ds_miss_mode = 6;                   /**< Defines the action to take for unknown downstream packets */
-    uint32 mtu = 7;                   /**< The MTU for an interface */
-    BalControl flow_control = 8;    /**< Flow control enable or disable */
-    uint32 ds_tm = 9;       /**< Downstream scheduler and shaper */
-    uint32 us_tm = 10;       /**< Upstream scheduler and shaper */
-    BalIdList sub_term_id_list = 11;    /**< A list of subscriber terminal ids configured on this interface */
-    balPonDistance pon_distance = 12;           /**< pon inetrface distance parameters */
-    BalBerMonitorParams ber_monitor = 13;      /**< BER monitor process configuration */
-    uint32 us_bandwidth_limit = 14;                /**< us_bandwidth_limit. */
-    BalControl ds_fec = 15;                      /**< enable/disable  ds fec (gpon only) */
+    uint32 mtu = 6;                   /**< The MTU for an interface */
+    uint32 ds_tm = 7;       /**< Downstream scheduler and shaper */
+    uint32 us_tm = 8;       /**< Upstream scheduler and shaper */
+    BalSubIdList sub_term_id_list = 9;    /**< A list of subscriber terminal ids configured on this interface */
+    balPonDistance pon_distance = 10;           /**< pon inetrface distance parameters */
+    BalBerMonitorParams ber_monitor = 11;      /**< BER monitor process configuration */
+    uint32 us_bandwidth_limit = 12;                /**< us_bandwidth_limit. */
+    BalControl ds_fec = 13;                      /**< enable/disable  ds fec (gpon only) */
+    BalInterfaceNgpon2 ngpon_2 =14;            /**< ngpon_2 attributes of the interface */
 }
 
 /** Transport message definition for "cfg" group of "interface" object.
  */
 message BalInterfaceCfg
 {
-    BalInterfaceKey key = 1;       /**< Object key. */
-    BalInterfaceCfgData data = 2; /**< All properties that must be set by the user. */
+    BalApiCfg hdr     = 1;           /**< Transport header. */
+    BalInterfaceKey key = 2;       /**< Object key. */
+    BalInterfaceCfgData data = 3; /**< All properties that must be set by the user. */
 }
 
 /** Structure definition for the "stat" group of the "interface" object.
  */
 message BalInterfaceStatData
 {
-    uint64 rx_bytes = 1;          /**< RFC 2233 */
-    uint64 rx_packets = 2;        /**< RFC 1213 ucast + none-ucast */
-    uint64 rx_ucast_packets = 3;  /**< RFC 2233 */
-    uint64 rx_mcast_packets = 4;  /**< RFC 2233 */
-    uint64 rx_bcast_packets = 5;  /**< RFC 2233 */
-    uint64 rx_error_packets = 6;  /**< RFC 1213 */
-    uint64 rx_unknown_protos = 7; /**< RFC 1213 */
-    uint64 tx_bytes = 8;          /**< RFC 2233 */
-    uint64 tx_packets = 9;        /**< RFC 1213 ucast + none-ucast */
-    uint64 tx_ucast_packets = 10;  /**< RFC 2233 */
-    uint64 tx_mcast_packets = 11;  /**< RFC 2233 */
-    uint64 tx_bcast_packets = 12;  /**< RFC 2233 */
-    uint64 tx_error_packets = 13;  /**< RFC 1213 */
-    uint64 rx_crc_errors = 14;     /**< Received packets with CRC error. */
-    uint64 bip_errors = 15;        /**< Received bip errors (bip8 for gpon, bip32 for xgpon). */
+    uint64 rx_bytes                = 1;              /**< RFC 2233 */
+    uint64 rx_packets              = 2;              /**< RFC 1213 ucast + none-ucast */
+    uint64 rx_data_bytes           = 3;              /**< IEEE only: received bytes excluding MPCP/OAM */
+    uint64 rx_ucast_packets        = 4;              /**< RFC 2233 */
+    uint64 rx_mcast_packets        = 5;              /**< RFC 2233 */
+    uint64 rx_bcast_packets        = 6;              /**< RFC 2233 */
+    uint64 rx_64_packets           = 7;              /**< IEEE only: 64 byte packets received, excluding reports */
+    uint64 rx_65_127_packets       = 8;              /**< IEEE only: 65-127 byte packets received */
+    uint64 rx_128_255_packets      = 9;              /**< IEEE only: 128-255 byte packets received */
+    uint64 rx_256_511_packets      = 10;             /**< IEEE only: 256-511 byte packets received */
+    uint64 rx_512_1023_packets     = 11;             /**< IEEE only: 512-1023 byte packets received */
+    uint64 rx_1024_1518_packets    = 12;             /**< IEEE only: 1024-1518 byte packets received */
+    uint64 rx_1519_2047_packets    = 13;             /**< IEEE only: 1519-2047 byte packets received */
+    uint64 rx_2048_4095_packets    = 14;             /**< IEEE only: 2048-4095 byte packets received */
+    uint64 rx_4096_9216_packets    = 15;             /**< IEEE only: 4096-9216 byte packets received */
+    uint64 rx_9217_16383_packets   = 16;             /**< IEEE only: 9217-16383 byte packets received */
+    uint64 rx_error_packets        = 17;             /**< RFC 1213 */
+    uint64 rx_unknown_protos       = 18;             /**< RFC 1213 */
+    uint64 rx_crc_errors           = 19;             /**< ITU only */
+    uint64 bip_errors              = 20;             /**< ITU only */
+    uint64 rx_mpcp                 = 21;             /**< IEEE only: MPCP packets received, excluding reports */
+    uint64 rx_report               = 22;             /**< IEEE only: MPCP reports received */
+    uint64 rx_oam_bytes            = 23;             /**< IEEE only: OAM bytes received */
+    uint64 rx_oam_packets          = 24;             /**< IEEE only: OAM packets received */
+    uint64 tx_bytes                = 25;             /**< RFC 2233 */
+    uint64 tx_packets              = 26;             /**< RFC 1213 ucast + none-ucast */
+    uint64 tx_data_bytes           = 27;             /**< IEEE only: transmitted bytes excluding MPCP/OAM */
+    uint64 tx_ucast_packets        = 28;             /**< RFC 2233 */
+    uint64 tx_mcast_packets        = 29;             /**< RFC 2233 */
+    uint64 tx_bcast_packets        = 30;             /**< RFC 2233 */
+    uint64 tx_64_packets           = 31;             /**< IEEE only: 64 byte packets transmitted, excluding gates */
+    uint64 tx_65_127_packets       = 32;             /**< IEEE only: 65-127 byte packets transmitted */
+    uint64 tx_128_255_packets      = 33;             /**< IEEE only: 128-255 byte packets transmitted */
+    uint64 tx_256_511_packets      = 34;             /**< IEEE only: 256-511 byte packets transmitted */
+    uint64 tx_512_1023_packets     = 35;             /**< IEEE only: 512-1023 byte packets transmitted */
+    uint64 tx_1024_1518_packets    = 36;             /**< IEEE only: 1024-1518 byte packets transmitted */
+    uint64 tx_1519_2047_packets    = 37;             /**< IEEE only: 1519-2047 byte packets transmitted */
+    uint64 tx_2048_4095_packets    = 38;             /**< IEEE only: 2048-4095 byte packets transmitted */
+    uint64 tx_4096_9216_packets    = 39;             /**< IEEE only: 4096-9216 byte packets transmitted */
+    uint64 tx_9217_16383_packets   = 40;             /**< IEEE only: 9217-16383 byte packets transmitted */
+    uint64 tx_error_packets        = 41;             /**< RFC 1213 */
+    uint64 tx_mpcp                 = 42;             /**< IEEE only: MPCP packets transmitted, excluding gates */
+    uint64 tx_gate                 = 43;             /**< IEEE only: MPCP gates transmitted */
+    uint64 tx_oam_bytes            = 44;             /**< IEEE only: OAM bytes transmitted */
+    uint64 tx_oam_packets          = 45;             /**< IEEE only: OAM packets transmitted */
 }
 
 /** Transport message definition for "stat" group of "interface" object.
  */
 message BalInterfaceStat
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalStat hdr = 1;                    /**< Transport header. */
     BalInterfaceKey key = 2;           /**< Object key. */
     BalInterfaceStatData data = 3;    /**< All properties that must be set by the user. */
 }
 
-/** Structure definition for the "ind" group of the "interface" object.
- */
-message BalInterfaceIndData
-{
-    BalState admin_state = 1;           /**< Current administrative state */
-    BalStatus oper_status = 2;          /**< Current operational state */
-    uint32 min_data_agg_port_id = 3;      /**< The minimum agg_port_id that is allowed in the system */
-    uint32 min_data_svc_port_id = 4;      /**< The minimum svc_port_id that is allowed in the system */
-    BalTrxType transceiver_type = 5;   /**< The transceiver type used on an interface */
-    BalDsMissMode ds_miss_mode = 6;   /**< Defines the action to take for DS unknown packets */
-    uint32 mtu = 7;                       /**< The MTU for an interface */
-    BalControl flow_control = 8;        /**< Flow control enable or disable */
-    uint32 ds_tm = 9;           /**< Downstream scheduler and shaper */
-    uint32 us_tm = 10;           /**< Upstream scheduler and shaper */
-    BalIdList sub_term_id_list = 11;    /**< A list of subscriber terminal ids configured on this interface */
-    balPonDistance pon_distance = 12;           /**< pon inetrface distance parameters */
-    BalBerMonitorParams ber_monitor = 13;      /**< BER monitor process configuration */
-    uint32 us_bandwidth_limit = 14;                /**< us_bandwidth_limit. */
-    BalControl ds_fec = 15;                      /**< enable/disable  ds fec (gpon only) */
-}
-
-/** Transport message definition for "ind" group of "interface" object.
- */
-message BalInterfaceInd
-{
-    BalObj hdr = 1;                /**< Transport header. */
-    BalInterfaceKey key = 2;       /**< Object key. */
-    BalInterfaceIndData data = 3; /**< All properties that must be set by the user. */
-}
-
 /** Structure definition for the "los" group of the "interface" object.
  *
  * An indication of a change olt los alarm
@@ -1022,7 +1272,7 @@
  */
 message BalInterfaceLos
 {
-    BalObj hdr = 1;                /**< Transport header. */
+    BalAuto hdr = 1;                /**< Transport header. */
     BalInterfaceKey key = 2;       /**< Object key. */
     BalInterfaceLosData data = 3; /**< All properties that must be set by the user. */
 }
@@ -1044,7 +1294,7 @@
  */
 message BalInterfaceOperStatusChange
 {
-    BalObj hdr = 1;            /**< Transport header. */
+    BalAuto hdr = 1;            /**< Transport header. */
     BalInterfaceKey key = 2;   /**< Object key. */
     BalInterfaceOperStatusChangeData data = 3;  /**< All properties that must be set by the user. */
 }
@@ -1067,14 +1317,14 @@
     BalIntfType intf_type = 4;         /**< Interface Type. */
     uint32 svc_port = 5;    /**< N/A for sending a packet */
     uint64 flow_cookie = 6;          /**< N/A for sending a packet */
-    bytes pkt = 7;             /**< Packet Data. */
+    bytes pkt = 7;    /**< Packet Data. */
 }
 
 /** Transport message definition for "cfg" group of "packet" object.
  */
 message BalPacketCfg
 {
-    BalObj hdr = 1;                /**< Transport header. */
+    BalApiCfg hdr = 1;                /**< Transport header. */
     BalPacketKey key = 2;          /**< Object key. */
     BalPacketCfgData data = 3;    /**< All properties that must be set by the user. */
 }
@@ -1089,7 +1339,7 @@
     BalIntfType intf_type = 4;         /**< Interface Type. */
     uint32 svc_port = 5;    /**< N/A for sending a packet */
     uint64 flow_cookie = 6;          /**< N/A for sending a packet */
-    bytes pkt = 7;             /**< Packet Data. */
+    bytes pkt = 7;    /**< Packet Data. */
 }
 
 /** Transport message definition for "bearer_channel_rx" group of "packet"
@@ -1097,7 +1347,7 @@
  */
 message BalPacketBearerChannelRx
 {
-    BalObj hdr = 1;        /**< Transport header. */
+    BalAuto hdr = 1;        /**< Transport header. */
     BalPacketKey key = 2;  /**< Object key. */
     BalPacketBearerChannelRxData data = 3;  /**< All properties that must be set by the user. */
 }
@@ -1109,7 +1359,7 @@
  */
 message BalPacketIeeeOamChannelRxData
 {
-    bytes pkt = 1;    /**< Packet Data. */
+    bytes pkt   = 1;    /**< Packet Data. */
 }
 
 /** Transport message definition for "ieee_oam_channel_rx" group of "packet"
@@ -1117,7 +1367,7 @@
  */
 message BalPacketIeeeOamChannelRx
 {
-    BalObj hdr = 1;        /**< Transport header. */
+    BalAuto hdr = 1;        /**< Transport header. */
     BalPacketKey key = 2;  /**< Object key. */
     BalPacketIeeeOamChannelRxData data = 3;    /**< All properties that must be set by the user. */
 }
@@ -1136,7 +1386,7 @@
  */
 message BalPacketItuOmciChannelRx
 {
-    BalObj hdr = 1;                /**< Transport header. */
+    BalAuto hdr = 1;                /**< Transport header. */
     BalPacketKey key = 2;          /**< Object key. */
     BalPacketItuOmciChannelRxData data = 3;    /**< All properties that must be set by the user. */
 }
@@ -1172,10 +1422,10 @@
     bytes mac_address = 7;                          /**< The Ethernet MAC address of an EPON subscriber terminal */
     uint32 ds_tm = 8;                               /**< Downstream scheduler and shaper */
     uint32 us_tm = 9;                               /**< Upstream scheduler and shaper */
-    BalIdList svc_port_id_list = 10;        /**< A list of bearer traffic svc_port_ids associated with this subscriber terminal */
-    BalIdList agg_port_id_list = 11;    /**< A list of aggrPort_ids associated with this subscriber terminal */
+    BalServicePortIdList svc_port_id_list = 10;        /**< A list of bearer traffic svc_port_ids associated with this subscriber terminal */
+    BalAggregationPortIdList agg_port_id_list = 11;    /**< A list of aggrPort_ids associated with this subscriber terminal */
     BalSubTermRate sub_term_rate = 12;                     /**< sub_term_rate. */
-    BalControl ds_fec = 13;                      /**< enable/disable  ds fec (gpon only) */
+    BalControl us_fec = 13;     /**< enable/disable us fec */
 }
 
 /** Transport message definition for "cfg" group of "subscriber_terminal"
@@ -1183,31 +1433,12 @@
  */
 message BalSubscriberTerminalCfg
 {
-    BalSubscriberTerminalKey key = 1; /**< Object key. */
-    BalSubscriberTerminalCfgData data = 2;   /**< All properties that must be set by the user. */
-}
-
-/** Structure definition for the "stat" group of the "subscriber_terminal"
- * object.
- */
-message BalSubscriberTerminalStatData
-{
-    uint64 rx_packets = 1;    /**< Received packets on specified object */
-    uint64 rx_bytes = 2;      /**< Received bytes on specified object */
-    uint64 tx_packets = 3;    /**< Transmitted packets on specified object */
-    uint64 tx_bytes = 4;      /**< Transmittted bytes on specified object */
-}
-
-/** Transport message definition for "stat" group of "subscriber_terminal"
- * object.
- */
-message BalSubscriberTerminalStat
-{
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalApiCfg hdr = 1;      /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
-    BalSubscriberTerminalStatData data = 3;  /**< All properties that must be set by the user. */
+    BalSubscriberTerminalCfgData data = 3;   /**< All properties that must be set by the user. */
 }
 
+
 /** Structure definition for the "dgi" group of the "subscriber_terminal"
  * object.
  */
@@ -1221,7 +1452,7 @@
  */
 message BalSubscriberTerminalDgi
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalAuto hdr = 1;                    /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
     BalSubscriberTerminalDgiData data = 3;   /**< All properties that must be set by the user. */
 }
@@ -1241,39 +1472,11 @@
  */
 message BalSubscriberTerminalDowi
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalAuto hdr = 1;                    /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
     BalSubscriberTerminalDowiData data = 3;   /**< All properties that must be set by the user. */
 }
 
-/** Structure definition for the "ind" group of the "subscriber_terminal"
- * object.
- */
-message BalSubscriberTerminalIndData
-{
-    BalState admin_state = 1;               /**< Current administrative state */
-    BalStatus oper_status = 2;              /**< Current operational status */
-    BalSerialNumber serial_number = 3;     /**< The serial number of an  ITU PON (GPON/XG-PON1/XGS-PON/NG-PON2) subscriber terminal */
-    string password = 4;               /**< The password of a GPON subscriber terminal */
-    string registration_id = 5; /**< ONU registration ID of an  ITU PON (XG-PON1/XGS-PON/NG-PON2) subscriber terminal */
-    uint32 svc_port_id = 6;                   /**< The service port ID (for PON, the ONU ID) */
-    bytes mac_address = 7;          /**< The Ethernet MAC address of an epon subscriber terminal */
-    uint32 ds_tm = 8;               /**< Downstream scheduler and shaper */
-    uint32 us_tm = 9;               /**< Upstream scheduler and shaper */
-    BalIdList agg_port_id_list = 10;    /**< A list of aggr_port_ids associated with this subscriber terminal */
-    BalSubTermRate sub_term_rate = 11;                     /**< sub_term_rate. */
-    BalControl us_efc = 13;                      /**< enable/disable  ds fec (gpon only) */
-}
-
-/** Transport message definition for "ind" group of "subscriber_terminal"
- * object.
- */
-message BalSubscriberTerminalInd
-{
-    BalObj hdr = 1;                    /**< Transport header. */
-    BalSubscriberTerminalKey key = 2; /**< Object key. */
-    BalSubscriberTerminalIndData data = 3;   /**< All properties that must be set by the user. */
-}
 
 /** Structure definition for the "looci" group of the "subscriber_terminal"
  * object.
@@ -1288,7 +1491,7 @@
  */
 message BalSubscriberTerminalLooci
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalAuto hdr = 1;                    /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
     BalSubscriberTerminalLoociData data = 3;   /**< All properties that must be set by the user. */
 }
@@ -1310,11 +1513,20 @@
  */
 message BalSubscriberTerminalOperStatusChange
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalAuto hdr = 1;                    /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
     BalSubscriberTerminalOperStatusChangeData data = 4;    /**< All properties that must be set by the user. */
 }
 
+/** Transport message definition for "processing_error" group of
+ * "subscriber_terminal" object.
+ */
+message BalSubscriberTerminalProcessingError
+{
+    BalAuto hdr                   = 1; /**< Transport header. */
+    BalSubscriberTerminalKey key = 2; /**< Object key. */
+}
+
 /** Structure definition for the "sdi" group of the "subscriber_terminal"
  * object.
  */
@@ -1329,7 +1541,7 @@
  */
 message BalSubscriberTerminalSdi
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalAuto hdr = 1;                    /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
     BalSubscriberTerminalSdiData data = 3;   /**< All properties that must be set by the user. */
 }
@@ -1348,11 +1560,29 @@
  */
 message BalSubscriberTerminalSfi
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalAuto hdr = 1;                    /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
     BalSubscriberTerminalSfiData data = 3;   /**< All properties that must be set by the user. */
 }
 
+/** Structure definition for the "sub_term_act_fail" group of the
+ * "subscriber_terminal" object.
+ */
+message BalSubscriberTerminalSubTermActFailData
+{
+    BalSubTermActFailReason fail_reason       = 1;    /**< Subscriber Terminal Activation Failure reason code. */
+}
+
+/** Transport message definition for "sub_term_act_fail" group of
+ * "subscriber_terminal" object.
+ */
+message BalSubscriberTerminalSubTermActFail
+{
+    BalAuto hdr                      = 1; /**< Transport header. */
+    BalSubscriberTerminalKey key    = 2; /**< Object key. */
+    BalSubscriberTerminalSubTermActFailData data  = 3;   /**< All properties that must be set by the user. */
+}
+
 /** Structure definition for the "sub_term_alarm" group of the
  * "subscriber_terminal" object.
  */
@@ -1366,11 +1596,30 @@
  */
 message BalSubscriberTerminalSubTermAlarm
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalAuto hdr = 1;                    /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
     BalsubscriberTerminalSubTermAlarmData data = 3;    /**< All properties that must be set by the user. */
 }
 
+/** Structure definition for the "sub_term_disc" group of the
+ * "subscriber_terminal" object.
+ */
+message BalSubscriberTerminalSubTermDiscData
+{
+    BalSerialNumber serial_number = 1; /**< The serial number of an  ITU PON (GPON/XG-PON1/XGS-PON/NG-PON2) subscriber terminal */
+}
+
+
+/** Transport message definition for "sub_term_disc" group of
+ * "subscriber_terminal" object.
+ */
+message BalSubscriberTerminalSubTermDisc
+{
+    BalAuto hdr = 1;                    /**< Transport header. */
+    BalSubscriberTerminalKey key = 2; /**< Object key. */
+    BalSubscriberTerminalSubTermDiscData data = 3; /**< All properties that must be set by the user. */
+}
+
 /** Structure definition for the "sufi" group of the "subscriber_terminal"
  * object.
  */
@@ -1384,46 +1633,78 @@
  */
 message BalSubscriberTerminalSufi
 {
-    BalObj hdr = 1;                    /**< Transport header. */
+    BalAuto hdr = 1;                    /**< Transport header. */
     BalSubscriberTerminalKey key = 2; /**< Object key. */
     BalSubscriberTerminalSufiData data = 3;   /**< All properties that must be set by the user. */
 }
 
-/** Structure definition for the "tifi" group of the "subscriber_terminal"
+/** Structure definition for the "tiwi" group of the "subscriber_terminal"
+ * object.
+ *
+ * transmission interference
+ */
+message BalSubscriberTerminalTiwiData
+{
+    BalAlarmStatus tiwi_status      = 1;    /**< tiwi alarm status */
+    uint32 drift_value = 2;               /**<  Calculated amount of drift (positive + negative as a signed value). */
+}
+
+/** Transport message definition for "tiwi" group of "subscriber_terminal"
  * object.
  */
-message BalSubscriberTerminalTifiData
+message BalSubscriberTerminalTiwi
 {
-    BalAlarmStatus tifi_status = 1;    /**< sufi alarm status */
-    uint32 drift_value = 2;            /**<  Calculated amount of drift (positive + negative as a signed value). */
+    BalAuto hdr      = 1;                    /**< Transport header. */
+    BalSubscriberTerminalKey key = 2;       /**< Object key. */
+    BalSubscriberTerminalTiwiData data = 3; /**< All properties that must be set by the user. */
 }
 
-/** Transport message definition for "tifi" group of "subscriber_terminal"
+/** Structure definition for the "key" group of the "sys_channel_profile"
  * object.
  */
-message BalSubscriberTerminalTifi
+message BalSysChannelProfileKey
 {
-    BalObj hdr = 1;                    /**< Transport header. */
-    BalSubscriberTerminalKey key = 2; /**< Object key. */
-    BalSubscriberTerminalTifiData data = 3;   /**< All properties that must be set by the user. */
+    int32 sys_id     = 1; /**< StateManager::gentable_handlers.c */
 }
 
-/** Structure definition for the "sub_term_disc" group of the
- * "subscriber_terminal" object.
+/** Structure definition for the "cfg" group of the "sys_channel_profile"
+ * object.
  */
-message BalSubscriberTerminalSubTermDiscData
+message BalSysChannelProfileCfgData
 {
-    BalSerialNumber serial_number = 1; /**< The serial number of an  ITU PON (GPON/XG-PON1/XGS-PON/NG-PON2) subscriber terminal */
+    BalSystemProfile system_profile       = 1;   /**< System profile. */
+    BalArrChannelProfile8 channel_profile = 2;   /**< Channel profile. */
+    uint32 ref_count                      = 3;   /**< reference count */
 }
 
-/** Transport message definition for "sub_term_disc" group of
- * "subscriber_terminal" object.
+/** Transport message definition for "cfg" group of "sys_channel_profile"
+ * object.
  */
-message BalSubscriberTerminalSubTermDisc
+message BalSysChannelProfileCfg
 {
-    BalObj hdr = 1;                    /**< Transport header. */
-    BalSubscriberTerminalKey key = 2; /**< Object key. */
-    BalSubscriberTerminalSubTermDiscData data = 3; /**< All properties that must be set by the user. */
+    BalApiCfg hdr                           = 1;    /**< Transport header. */
+    BalSysChannelProfileKey key          = 2;    /**< Object key. */
+    BalSysChannelProfileCfgData data     = 3;    /**< All properties that must be set by the user. */
+}
+
+/** Structure definition for the "ind" group of the "sys_channel_profile"
+ * object.
+ */
+message BalSysChannelProfileIndData
+{
+    BalSystemProfile system_profile            = 1;     /**< system profile. */
+    BalArrChannelProfile8 channel_profile      = 2;     /**< channel profile. */
+    uint32 ref_count                           = 3;     /**< ref_count. */
+}
+
+/** Transport message definition for "ind" group of "sys_channel_profile"
+ * object.
+ */
+message BalSysChannelProfileInd
+{
+    BalAuto hdr                            = 1;        /**< Transport header. */
+    BalSysChannelProfileKey key           = 2;        /**< Object key. */
+    BalSysChannelProfileIndData data      = 3;        /**< All properties that must be set by the user. */
 }
 
 /** Structure definition for the "key" group of the "TmQueue" object.
@@ -1451,50 +1732,9 @@
  */
 message BalTmQueueCfg
 {
-    BalTmQueueKey key = 1;        /**< Object key. */
-    BalTmQueueCfgData data = 2;  /**< All properties that must be set by the user. */
-}
-
-/** Structure definition for the "stat" group of the "TmQueue" object.
- */
-message BalTmQueueStatData
-{
-    uint64 packets_ok = 1;        /**< Packets transmitted succewssfully */
-    uint64 bytes_ok = 2;          /**< Bytes transmitted successfully */
-    uint64 packets_discarded = 3; /**< Packets discarded */
-    uint64 bytes_discarded = 4;   /**< Bytes discarded */
-}
-
-/** Transport message definition for "stat" group of "TmQueue" object.
- */
-message BalTmQueueStat
-{
-    BalObj hdr = 1;                /**< Transport header. */
+    BalApiCfg hdr = 1; /**< Transport header. */
     BalTmQueueKey key = 2;        /**< Object key. */
-    BalTmQueueStatData data = 3; /**< All properties that must be set by the user. */
-}
-
-/** Structure definition for the "ind" group of the "TmQueue" object.
- *
- * Tm Queue Indication
- */
-message BalTmQueueIndData
-{
-    uint32 priority = 1;    /**< priority. */
-    uint32 weight = 2;        /**< weight. */
-    BalTmShaping rate = 3;         /**< rate. */
-    BalTmBac bac = 4;              /**< bac. */
-    BalTmCreationMode create_mode = 5;    /**< create_mode. */
-    uint32 ref_count = 6;                      /**< ref_count. */
-}
-
-/** Transport message definition for "ind" group of "TmQueue" object.
- */
-message BalTmQueueInd
-{
-    BalObj hdr = 1;                /**< Transport header. */
-    BalTmQueueKey key = 2;        /**< Object key. */
-    BalTmQueueIndData data = 3;  /**< All properties that must be set by the user. */
+    BalTmQueueCfgData data = 3;  /**< All properties that must be set by the user. */
 }
 
 /** Structure definition for the "key" group of the "TmSched" object.
@@ -1505,55 +1745,50 @@
     uint32 id = 2;      /**< ID */
 }
 
-/** Structure definition for the "cfg" group of the "TmSched" object.
+/** Structure definition for the "TmSchedCfgData" object.
+ *
+ * Tm Sched Configuration Data
  */
 message BalTmSchedCfgData
 {
-    BalTmSchedOwner owner = 1;        /**< The owner of the tm_sched object instance*/
-    BalTmSchedType sched_type = 2;    /**< Scheduler type */
-    BalTmSchedParent sched_parent = 3;            /**< Scheduling parameters for parent scheduler */
-    BalTmSchedChildType sched_child_type = 4;    /**< Scheduling level for children tm  */
-    uint32 num_priorities = 5;                 /**< Max number of strict priority scheduling elements */
-    BalTmShaping rate = 6;                 /**< Rate shaping parameters */
-    BalExtendedItuDba ext_itu_dba = 7;    /**< Extended itu dba parameters for an agg_port owned tm_sched */
-    BalExtendedEponDba ext_epon_dba = 8;  /**< epon dba parameters for an agg_port owned tm_sched */
-    BalTmCreationMode creation_mode = 9;  /**< Creation mode */
-    BalIdList queues = 10;      /**< Subsidiary queues */
-    BalIdList sub_scheds = 11;  /**< Subsidiary schedulers */
-}
-
-/** Transport message definition for "cfg" group of "Tmsched" object.
- */
-message BalTmSchedCfg
-{
-    BalTmSchedKey key = 1;        /**< Object key. */
-    BalTmSchedCfgData data = 2;  /**< All properties that must be set by the user. */
-}
-
-/** Structure definition for the "ind" group of the "TmSched" object.
- *
- * Tm Sched Indication
- */
-message BalTmSchedIndData
-{
     BalTmSchedOwner owner = 1;        /**< The owner of the tm_sched object instance */
     BalTmSchedType sched_type = 2;    /**< Scheduler type */
     BalTmSchedParent sched_parent = 3;            /**< Scheduling parameters for parent scheduler */
-    BalTmSchedChildType sched_child_type= 4;    /**< Scheduling type of all child tm objects */
-    uint32 num_priorities = 5;                 /**< Max number of strict priority scheduling elements */
-    BalTmShaping rate = 6;                 /**< Rate shaping parameters */
-    BalExtendedItuDba ext_itu_dba = 7;    /**< Extended itu dba parameters for an agg_port owned tm_sched */
-    BalExtendedEponDba ext_epon_dba = 8;  /**< epon dba parameters for an agg_port owned tm_sched */
-    BalTmCreationMode creation_moden= 9;  /**< Creation mode */
-    BalIdList queues = 10;      /**< Subsidiary queues */
-    BalIdList sub_scheds = 11;  /**< Subsidiary schedulers */
+    uint32 num_priorities = 4;                 /**< Max number of strict priority scheduling elements */
+    BalTmShaping rate = 5;                 /**< Rate shaping parameters */
+    BalExtendedItuDba ext_itu_dba = 6;    /**< Extended itu dba parameters for an agg_port owned tm_sched */
+    BalExtendedEponDba ext_epon_dba = 7;  /**< epon dba parameters for an agg_port owned tm_sched */
+    BalTmCreationMode creation_mode = 8;  /**< Creation mode */
+    BalTmQueueIdList queues   = 9;      /**< Subsidiary queues */
+    BalTmSchedIdList sub_scheds = 10;  /**< Subsidiary schedulers */
+    BalStatus oper_status = 11;                  /**< Current Agg Port oper status */
 }
 
-/** Transport message definition for "ind" group of "TmSched" object.
+/** Transport message definition for "TmSchedCfg" object.
  */
-message BalTmSchedInd
+message BalTmSchedCfg
 {
-    BalObj hdr = 1;                /**< Transport header. */
-    BalTmSchedKey key = 2;        /**< Object key. */
-    BalTmSchedIndData data = 3;  /**< All properties that must be set by the user. */
+    BalApiCfg hdr = 1;              /**< Transport header. */
+    BalTmSchedKey key = 2;       /**< Object key. */
+    BalTmSchedCfgData data = 3;  /**< All properties that must be set by the user. */
+}
+
+/** Structure definition for the "oper_status_change" group of the "tm_sched"
+ * object.
+ */
+message BalTmSchedOperStatusChangeData
+{
+    BalStatus new_oper_status = 1;  /**< new oper status. */
+    BalStatus old_oper_status = 2;  /**< old oper status. */
+}
+
+/** Transport message definition for "oper_status_change" group of "tm_sched"
+ * object.
+ */
+message BalTmSchedOperStatusChange
+{
+    BalAuto                         hdr = 1;  /**< Transport header. */
+    BalTmSchedKey                   key = 2;  /**< Object key. */
+    BalTmSchedOperStatusChangeData data = 3;  /**< All properties that must be set by the user. */
+
 }
diff --git a/voltha/adapters/asfvolt16_olt/protos/bal_obj.proto b/voltha/adapters/asfvolt16_olt/protos/bal_obj.proto
index 1e5b28c..ae62d68 100644
--- a/voltha/adapters/asfvolt16_olt/protos/bal_obj.proto
+++ b/voltha/adapters/asfvolt16_olt/protos/bal_obj.proto
@@ -79,4 +79,24 @@
     BalObj_msg_dir       dir = 7;           /**< Direction - request / response */
     BalErrno		 status = 8;        /**< BAL status code (BCM_ERR_OK–success, error code otherwise) */
     uint64               presence_mask = 9; /**< Indicates which attribute parameters are present */
+    uint32               err_field_index = 10;  /**< if status != BCM_ERR_OK: index of erroneous attribute or BCMBAL_ERR_FIELD_NONE */
+    string               err_text = 11;     /**< if status != BCM_ERR_OK: Error text */
+}
+
+/**< Information structure for use with BAL configuration API (get/set/clear)*/
+message BalApiCfg
+{
+    BalObj               bal_obj = 1;
+}
+
+/** Information structure for BAL indication configuration API */
+message BalAuto
+{
+    BalObj               bal_obj = 1;
+}
+
+/** Information structure for BAL statistics API */
+message BalStat
+{
+    BalObj               bal_obj = 1;
 }
diff --git a/voltha/adapters/broadcom_onu/broadcom_onu.py b/voltha/adapters/broadcom_onu/broadcom_onu.py
index 5053142..3cfde23 100644
--- a/voltha/adapters/broadcom_onu/broadcom_onu.py
+++ b/voltha/adapters/broadcom_onu/broadcom_onu.py
@@ -24,6 +24,7 @@
 from twisted.internet.defer import DeferredQueue, inlineCallbacks, returnValue
 from zope.interface import implementer
 
+from common.utils.asleep import asleep
 from voltha.adapters.interface import IAdapterInterface
 from voltha.core.logical_device_agent import mac_str_to_tuple
 import voltha.core.flow_decomposer as fd
@@ -53,10 +54,12 @@
 log = structlog.get_logger()
 
 
+MANAGEMENT_VLAN = 4090
 BRDCM_DEFAULT_VLAN = 4091
 ADMIN_STATE_LOCK = 1
 ADMIN_STATE_UNLOCK = 0
 RESERVED_VLAN_ID = 4095
+FLOW_TYPE_EAPOL = 34958
 
 @implementer(IAdapterInterface)
 class BroadcomOnuAdapter(object):
@@ -68,7 +71,8 @@
             id=name,
             vendor_ids=['NONE'],
             adapter=name,
-            accepts_bulk_flow_update=True
+            accepts_bulk_flow_update=True,
+            accepts_add_remove_flow_updates=True
         )
     ]
 
@@ -173,9 +177,7 @@
             if handler is not None:
                 log.debug('calling-handler-delete', handler=handler)
                 handler.delete(device)
-                del self.devices_handlers[device.id]
-        else:
-            log.warn('device-not-found-in-handlers', device=device, device_handlers=self.devices_handlers)
+            del self.devices_handlers[device.id]
         return
 
     def get_device_details(self, device):
@@ -194,7 +196,20 @@
         return handler.update_flow_table(device, flows.items)
 
     def update_flows_incrementally(self, device, flow_changes, group_changes):
-        raise NotImplementedError()
+        log.info('incremental-flow-update', device_id=device.id,
+                 flows=flow_changes, groups=group_changes)
+        # For now, there is no support for group changes
+        assert len(group_changes.to_add.items) == 0
+        assert len(group_changes.to_remove.items) == 0
+
+        handler = self.devices_handlers[device.id]
+        # Remove flows
+        if len(flow_changes.to_remove.items) != 0:
+            handler.remove_from_flow_table(flow_changes.to_remove.items)
+
+        # Add flows
+        if len(flow_changes.to_add.items) != 0:
+            handler.add_to_flow_table(flow_changes.to_add.items)
 
     def send_proxied_message(self, proxy_address, msg):
         log.debug('send-proxied-message', proxy_address=proxy_address, msg=msg)
@@ -260,7 +275,7 @@
                 handler.create_tcont(tcont_data, traffic_descriptor_data)
 
     def update_tcont(self, device, tcont_data, traffic_descriptor_data):
-        raise NotImplementedError()
+        log.info('update_tcont not implemented in onu')
 
     def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
         log.debug('remove-tcont', device_id=device.id)
@@ -326,14 +341,12 @@
         self.event_messages = DeferredQueue()
         self.proxy_address = None
         self.tx_id = 0
-
-        # Proxy for api calls
-        self.core = registry('core')
-        self.proxy = self.core.get_proxy('/')
+        self.flow_map = dict()
 
         # Need to query ONU for number of supported uni ports
         # For now, temporarily set number of ports to 1 - port #2
         self.uni_ports = (1, 2, 3, 4, 5)
+        self.flow_config_in_progress = False
 
         # Handle received ONU event messages
         reactor.callLater(0, self.handle_onu_events)
@@ -362,6 +375,7 @@
                 device.connect_status = ConnectStatus.UNREACHABLE
                 device.oper_status = OperStatus.FAILED
                 self.adapter_agent.update_device(device)
+                self.flow_map.clear()
 
         elif event_msg['event'] == 'deactivation-completed':
             device = self.adapter_agent.get_device(self.device_id)
@@ -374,11 +388,13 @@
             device.connect_status = ConnectStatus.UNREACHABLE
             device.oper_status = OperStatus.DISCOVERED
             self.adapter_agent.update_device(device)
+            self.flow_map.clear()
 
         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)
+            self.flow_map.clear()
 
         elif event_msg['event'] == 'ranging-completed':
 
@@ -397,6 +413,7 @@
             device = self.adapter_agent.get_device(self.device_id)
             device.connect_status = ConnectStatus.UNREACHABLE
             self.adapter_agent.update_device(device)
+            self.flow_map.clear()
 
         elif event_msg['event'] == 'olt-enabled':
             self.adapter_agent.enable_all_ports(self.device_id)
@@ -499,7 +516,6 @@
         except Exception as e:
             self.log.exception("exception-updating-port",e=e)
 
-    @inlineCallbacks
     def delete(self, device):
         self.log.info('delete-onu', device=device)
 
@@ -516,179 +532,104 @@
 
     @inlineCallbacks
     def update_flow_table(self, device, flows):
+
+        # Twisted code is not inherently thread safe. This API could
+        # be invoked again by reactor while previous one is in progress.
+        # Since we maintain some stateful information here, we better
+        # synchronize parallel invocations on this API.
+        yield self._wait_for_previous_update_flow_to_finish()
+        self.flow_config_in_progress = True
+
         #
         # We need to proxy through the OLT to get to the ONU
         # Configuration from here should be using OMCI
         #
-        #self.log.info('bulk-flow-update', device_id=device.id, flows=flows)
+        try:
+            # Calculates flows_to_adds and flows_to_delete using
+            # incoming_flows and current_flows.
+            current_flows = set(self.flow_map.keys())
 
-        def is_downstream(port):
-            return port == 100  # Need a better way
+            # Only adding those flows to incoming_flows which are having cookie.
+            incoming_flows = set(flow.cookie for flow in flows if flow.cookie)
+            flows_to_add = incoming_flows.difference(current_flows)
+            flows_to_delete = current_flows.difference(incoming_flows)
 
-        def is_upstream(port):
-            return not is_downstream(port)
+            # Sends request to delete flows for ONU flows in flows_to_delete list.
+            for cookie in flows_to_delete:
+                if cookie in self.flow_map:
+                    c_tag = self.flow_map[cookie]["vlan_id"]
+                    self.log.debug("flow-to-delete-cookie",
+                                   cookie=cookie, c_tag=c_tag)
 
-        for flow in flows:
-            _type = None
-            _port = None
-            _vlan_vid = None
-            _udp_dst = None
-            _udp_src = None
-            _ipv4_dst = None
-            _ipv4_src = None
-            _metadata = None
-            _output = None
-            _push_tpid = None
-            _field = None
-            _set_vlan_vid = None
-            self.log.debug('bulk-flow-update', device_id=device.id, flow=flow)
-            try:
-                _in_port = fd.get_in_port(flow)
-                assert _in_port is not None
+                    # Deleting flow from ONU.
+                    yield self._delete_onu_flow(self.flow_map[cookie])
 
-                if is_downstream(_in_port):
-                    self.log.debug('downstream-flow')
-                elif is_upstream(_in_port):
-                    self.log.debug('upstream-flow')
+                    # Removing flow_map entry for deleted flow.
+                    del self.flow_map[cookie]
                 else:
-                    raise Exception('port should be 1 or 2 by our convention')
+                    self.log.info('ignoring-cookie_received', cookie=cookie)
 
-                _out_port = fd.get_out_port(flow)  # may be None
-                self.log.debug('out-port', out_port=_out_port)
-
-                for field in fd.get_ofb_fields(flow):
-                    if field.type == fd.ETH_TYPE:
-                        _type = field.eth_type
-                        self.log.debug('field-type-eth-type',
-                                      eth_type=_type)
-
-                    elif field.type == fd.IP_PROTO:
-                        _proto = field.ip_proto
-                        self.log.debug('field-type-ip-proto',
-                                      ip_proto=_proto)
-
-                    elif field.type == fd.IN_PORT:
-                        _port = field.port
-                        self.log.debug('field-type-in-port',
-                                      in_port=_port)
-
-                    elif field.type == fd.VLAN_VID:
-                        _vlan_vid = field.vlan_vid & 0xfff
-                        self.log.debug('field-type-vlan-vid',
-                                      vlan=_vlan_vid)
-
-                    elif field.type == fd.VLAN_PCP:
-                        _vlan_pcp = field.vlan_pcp
-                        self.log.debug('field-type-vlan-pcp',
-                                      pcp=_vlan_pcp)
-
-                    elif field.type == fd.UDP_DST:
-                        _udp_dst = field.udp_dst
-                        self.log.debug('field-type-udp-dst',
-                                      udp_dst=_udp_dst)
-
-                    elif field.type == fd.UDP_SRC:
-                        _udp_src = field.udp_src
-                        self.log.debug('field-type-udp-src',
-                                      udp_src=_udp_src)
-
-                    elif field.type == fd.IPV4_DST:
-                        _ipv4_dst = field.ipv4_dst
-                        self.log.debug('field-type-ipv4-dst',
-                                      ipv4_dst=_ipv4_dst)
-
-                    elif field.type == fd.IPV4_SRC:
-                        _ipv4_src = field.ipv4_src
-                        self.log.debug('field-type-ipv4-src',
-                                      ipv4_dst=_ipv4_src)
-
-                    elif field.type == fd.METADATA:
-                        _metadata = field.table_metadata
-                        self.log.debug('field-type-metadata',
-                                      metadata=_metadata)
-
-                    else:
-                        raise NotImplementedError('field.type={}'.format(
-                            field.type))
-
-                for action in fd.get_actions(flow):
-
-                    if action.type == fd.OUTPUT:
-                        _output = action.output.port
-                        self.log.debug('action-type-output',
-                                      output=_output, in_port=_in_port)
-
-                    elif action.type == fd.POP_VLAN:
-                        self.log.debug('action-type-pop-vlan',
-                                      in_port=_in_port)
-
-                    elif action.type == fd.PUSH_VLAN:
-                        _push_tpid = action.push.ethertype
-                        self.log.debug('action-type-push-vlan',
-                                 push_tpid=_push_tpid, in_port=_in_port)
-                        if action.push.ethertype != 0x8100:
-                            self.log.error('unhandled-tpid',
-                                           ethertype=action.push.ethertype)
-
-                    elif action.type == fd.SET_FIELD:
-                        _field = action.set_field.field.ofb_field
-                        assert (action.set_field.field.oxm_class ==
-                                OFPXMC_OPENFLOW_BASIC)
-                        self.log.debug('action-type-set-field',
-                                      field=_field, in_port=_in_port)
-                        if _field.type == fd.VLAN_VID:
-                            _set_vlan_vid = _field.vlan_vid & 0xfff
-                            self.log.debug('set-field-type-valn-vid', _set_vlan_vid)
-                        else:
-                            self.log.error('unsupported-action-set-field-type',
-                                           field_type=_field.type)
-                    else:
-                        self.log.error('unsupported-action-type',
-                                  action_type=action.type, in_port=_in_port)
-
-                if _type is not None:
+            # If flow is not in flow_to_add, no need to add flow to ONU.
+            for flow in flows:
+                if flow.cookie not in flows_to_add:
+                    self.log.debug("flow-not-to-be-added", cookie=flow.cookie)
                     continue
 
-                #
-                # All flows created from ONU adapter should be OMCI based
-                #
-                if _vlan_vid == 0 and _set_vlan_vid != None and _set_vlan_vid != 0:
-                    # allow priority tagged packets
-                    # Set AR - ExtendedVlanTaggingOperationConfigData
-                    #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
+                # Adding flow to ONU.
+                yield self._add_onu_flow(flow)
 
-                    self.send_delete_vlan_tagging_filter_data(0x2102)
-                    yield self.wait_for_response()
+        except Exception as e:
+            self.log.exception('failed-to-update-flow-table', e=e)
 
-                    # self.send_set_vlan_tagging_filter_data(0x2102, _set_vlan_vid)
-                    if _set_vlan_vid != RESERVED_VLAN_ID:
-                        # As per G.988 - Table 9.3.11-1 - Forward operation attribute values
-                        # Forward action of 0x10 allows VID Investigation
-                        self.send_create_vlan_tagging_filter_data(0x2102, _set_vlan_vid, 0x10)
-                        yield self.wait_for_response()
+        self.flow_config_in_progress = False
 
-                        for port_id in self.uni_ports:
+    @inlineCallbacks
+    def add_to_flow_table(self, flows):
+        """
+        This function is called for update_flows_incrementally to add
+        only delta flows to ONU.
+        :param flows: flows to add to ONU.
+        """
+        yield self._wait_for_previous_update_flow_to_finish()
+        self.flow_config_in_progress = True
+        self.log.debug('add-to-flow-table', flows=flows)
+        try:
+            for flow in flows:
+                # if incoming flow contains cookie, then add to ONU
+                if flow.cookie:
+                    # Adds flow to ONU.
+                    yield self._add_onu_flow(flow)
+        except Exception as e:
+            self.log.exception('failed-to-add-to-flow-table', e=e)
 
-                            self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(\
-                                                                     0x200 + port_id, 0x1000, _set_vlan_vid)
-                            yield self.wait_for_response()
+        self.flow_config_in_progress = False
 
-                            self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(0x200 + port_id, 8, 0, 0,
-                                                                                                             1, 8, _set_vlan_vid)
-                            yield self.wait_for_response()
-                    else:
-                        # As per G.988 - Table 9.3.11-1 - Forward operation attribute values
-                        # Forward action of 0x00 does not perform VID Investigation for transparent vlan case
-                        self.send_create_vlan_tagging_filter_data(0x2102, _set_vlan_vid, 0x00)
-                        yield self.wait_for_response()
-
-                        for port_id in self.uni_ports:
-                            self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(\
-                                                                       0x200 + port_id, 14, 4096, 0, 0, 15, 0)
-                            yield self.wait_for_response()
-
-            except Exception as e:
-                self.log.exception('failed-to-install-flow', e=e, flow=flow)
+    @inlineCallbacks
+    def remove_from_flow_table(self, flows):
+        """
+        This function is called for update_flow_incrementally to delete
+        only delta flows from ONU.
+        :param flows: flows to delete from ONU
+        """
+        yield self._wait_for_previous_update_flow_to_finish()
+        self.flow_config_in_progress = True
+        self.log.debug('remove-from-flow-table', flows=flows)
+        try:
+            cookies = [flow.cookie for flow in flows]
+            for cookie in cookies:
+                if cookie in self.flow_map:
+                    c_tag = self.flow_map[cookie]["vlan_id"]
+                    self.log.debug("remove-from-flow-table",
+                                   cookie=cookie, c_tag=c_tag)
+                    # Deleting flow from ONU.
+                    yield self._delete_onu_flow(self.flow_map[cookie])
+                    # Removing flow_map entry for deleted flow.
+                    del self.flow_map[cookie]
+                else:
+                    self.log.error('ignoring-cookie_received', cookie=cookie)
+        except Exception as e:
+            self.log.exception('failed-to-remove-from-flow-table', e=e)
+        self.flow_config_in_progress = False
 
     def get_tx_id(self):
         self.tx_id += 1
@@ -905,17 +846,17 @@
 
     def send_set_8021p_mapper_service_profile(self,
                                               entity_id,
-                                              interwork_tp_id):
-        data = dict(
-            interwork_tp_pointer_for_p_bit_priority_0=interwork_tp_id,
-            interwork_tp_pointer_for_p_bit_priority_1=interwork_tp_id,
-            interwork_tp_pointer_for_p_bit_priority_2=interwork_tp_id,
-            interwork_tp_pointer_for_p_bit_priority_3=interwork_tp_id,
-            interwork_tp_pointer_for_p_bit_priority_4=interwork_tp_id,
-            interwork_tp_pointer_for_p_bit_priority_5=interwork_tp_id,
-            interwork_tp_pointer_for_p_bit_priority_6=interwork_tp_id,
-            interwork_tp_pointer_for_p_bit_priority_7=interwork_tp_id
-        )
+                                              interwork_tp_id=None):
+        data = dict()
+        data['interwork_tp_pointer_for_p_bit_priority_0']=interwork_tp_id
+        data['interwork_tp_pointer_for_p_bit_priority_1']=interwork_tp_id
+        data['interwork_tp_pointer_for_p_bit_priority_2']=interwork_tp_id
+        data['interwork_tp_pointer_for_p_bit_priority_3']=interwork_tp_id
+        data['interwork_tp_pointer_for_p_bit_priority_4']=interwork_tp_id
+        data['interwork_tp_pointer_for_p_bit_priority_5']=interwork_tp_id
+        data['interwork_tp_pointer_for_p_bit_priority_6']=interwork_tp_id
+        data['interwork_tp_pointer_for_p_bit_priority_7']=interwork_tp_id
+
         frame = OmciFrame(
             transaction_id=self.get_tx_id(),
             message_type=OmciSet.message_id,
@@ -1092,6 +1033,18 @@
         )
         self.send_omci_message(frame)
 
+    def send_delete_extended_vlan_tagging_operation_vlan_configuration_data_untagged(self,
+                                                                                     entity_id):
+        frame = OmciFrame(
+            transaction_id=self.get_tx_id(),
+            message_type=OmciDelete.message_id,
+            omci_message=OmciDelete(
+                entity_class=ExtendedVlanTaggingOperationConfigurationData.class_id,
+                entity_id=entity_id
+            )
+        )
+        self.send_omci_message(frame)
+
     def send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(self,
                                                                                     entity_id,
                                                                                     filter_inner_priority,
@@ -1137,6 +1090,62 @@
         )
         self.send_omci_message(frame)
 
+    def send_set_extended_vlan_tagging_operation_vlan_configuration_data_double_tag(self,
+                                                                                    entity_id,
+                                                                                    filter_outer_vid,
+                                                                                    filter_inner_vid,
+                                                                                    treatment_tags_to_remove
+                                                                                    ):
+        # Note: The default values below are meaningful if transparent handling is
+        # needed for double vlan tagged packets with matching inner and outer vlans.
+        # If any other handling is needed for double vlan tagged packets, the default
+        # values may not work and the function needs to be adapted accordingly.
+        data = dict(
+            received_frame_vlan_tagging_operation_table=
+                VlanTaggingOperation(
+                    filter_outer_priority=14,
+                    filter_outer_vid=filter_outer_vid,
+                    filter_outer_tpid_de=0,
+                    filter_inner_priority=14,
+                    filter_inner_vid=filter_inner_vid,
+                    filter_inner_tpid_de=0,
+                    filter_ether_type=0,
+                    treatment_tags_to_remove=treatment_tags_to_remove,
+                    treatment_outer_priority=15,
+                    treatment_outer_vid=0,  # N/A
+                    treatment_outer_tpid_de=0,  # N/A
+                    treatment_inner_priority=15,
+                    treatment_inner_vid=0,  # N/A
+                    treatment_inner_tpid_de=0  # N/A
+                )
+        )
+        frame = OmciFrame(
+            transaction_id=self.get_tx_id(),
+            message_type=OmciSet.message_id,
+            omci_message=OmciSet(
+                entity_class=
+                ExtendedVlanTaggingOperationConfigurationData.class_id,
+                entity_id=entity_id,
+                attributes_mask=
+                ExtendedVlanTaggingOperationConfigurationData.mask_for(
+                        *data.keys()),
+                data=data
+            )
+        )
+        self.send_omci_message(frame)
+
+    def send_delete_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(self,
+                                                                                       entity_id):
+        frame = OmciFrame(
+            transaction_id=self.get_tx_id(),
+            message_type=OmciDelete.message_id,
+            omci_message=OmciDelete(
+                entity_class=ExtendedVlanTaggingOperationConfigurationData.class_id,
+                entity_id=entity_id
+            )
+        )
+        self.send_omci_message(frame)
+
     def send_create_multicast_operations_profile(self,
                                                  entity_id,
                                                  igmp_ver):
@@ -1361,6 +1370,7 @@
         self.send_omci_message(frame)
 
     def send_reboot(self):
+        self.log.info('send omci reboot message')
         frame = OmciFrame(
             transaction_id=self.get_tx_id(),
             message_type=OmciReboot.message_id,
@@ -1385,11 +1395,13 @@
             self.log.info('wait-for-response-exception', exc=str(e))
 
     @inlineCallbacks
-    def message_exchange(self, cvid=BRDCM_DEFAULT_VLAN):
+    def message_exchange(self):
         # reset incoming message queue
         while self.incoming_messages.pending:
             _ = yield self.incoming_messages.get()
 
+        mcvid = MANAGEMENT_VLAN
+        cvid = BRDCM_DEFAULT_VLAN
 
         # construct message
         # MIB Reset - OntData - 0
@@ -1442,12 +1454,6 @@
             self.send_create_mac_bridge_port_configuration_data(0x200 + port_id, 0x201, port_id, 1, 0x100 + port_id)
             yield self.wait_for_response()
 
-
-            # Set AR - ExtendedVlanTaggingOperationConfigData
-            #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
-            # self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(0x200 + port_id, 8, 0, 0, 1, 8, cvid)
-            # yield self.wait_for_response()
-
             # Set AR - ExtendedVlanTaggingOperationConfigData
             #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to untagged pkts - c-vid
             self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(0x200 + port_id, 0x1000, cvid)
@@ -1534,9 +1540,6 @@
                     curr_speed=OFPPF_1GB_FD,
                     max_speed=OFPPF_1GB_FD
                 ),
-                ofp_port_stats=ofp_port_stats(
-                    port_no=port_no
-                ),
                 device_id=device.id,
                 device_port_no=uni_port.port_no
             ))
@@ -1640,6 +1643,7 @@
 
     def remove_interface(self, data):
         if isinstance(data, VEnetConfig):
+            parent_port_num = None
             onu_device = self.adapter_agent.get_device(self.device_id)
             ports = self.adapter_agent.get_ports(onu_device.parent_id, Port.ETHERNET_UNI)
             parent_port_num = None
@@ -1684,8 +1688,9 @@
             # Mapper Service Profile config
             # Set AR - 802.1pMapperServiceProfile - Mapper_ profile_id -
             #                                       gem_port_tp pointer
-            self.send_set_8021p_mapper_service_profile(0x8001,
-                                                       gem_port.gemport_id)
+
+            self.send_set_8021p_mapper_service_profile(0x8001, interwork_tp_id=gem_port.gemport_id)
+               
             yield self.wait_for_response()
 
 
@@ -1699,8 +1704,7 @@
             self.log.error('device-unreachable')
             return
 
-        self.send_set_8021p_mapper_service_profile(0x8001,
-                                                  0xFFFF)
+        self.send_set_8021p_mapper_service_profile(0x8001, interwork_tp_id=0xFFFF)
         yield self.wait_for_response()
 
         self.send_delete_omci_mesage(GemInterworkingTp.class_id,
@@ -1747,6 +1751,7 @@
             # Disable all ports on that device
             self.disable_ports(device)
             device.oper_status = OperStatus.UNKNOWN
+            device.connect_status = ConnectStatus.UNREACHABLE
             self.adapter_agent.update_device(device)
         except Exception as e:
             log.exception('exception-in-onu-disable', exception=e)
@@ -1786,6 +1791,7 @@
                     device.oper_status = OperStatus.DISCOVERED
                     self.adapter_agent.update_device(device)
                     self.disable_ports(device)
+                    self.flow_map.clear()
                 else:
                     self.log.error("reboot-failed", success_code=success_code)
             else:
@@ -1806,7 +1812,13 @@
         ports = self.adapter_agent.get_ports(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_LINK_DOWN)
+            try:
+                lgcl_port = self.adapter_agent.get_logical_port(logical_device_id, port_id)
+                lgcl_port.ofp_port.state = OFPPS_LINK_DOWN
+                self.adapter_agent.update_logical_port(logical_device_id, lgcl_port)
+            except KeyError:
+                self.log.info('logical-port-not-found', device_id=self.device_id,
+                              portid=port_id)
 
     def enable_ports(self, device):
         self.log.info('enable-ports', device_id=self.device_id)
@@ -1821,4 +1833,229 @@
         ports = self.adapter_agent.get_ports(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)
+            try:
+                lgcl_port = self.adapter_agent.get_logical_port(logical_device_id, port_id)
+                lgcl_port.ofp_port.state = OFPPS_LIVE
+                self.adapter_agent.update_logical_port(logical_device_id, lgcl_port)
+            except KeyError:
+                self.log.info('logical-port-not-found', device_id=self.device_id,
+                              portid=port_id)
+
+    @inlineCallbacks
+    def _add_onu_flow(self, flow):
+        _type = None
+        _port = None
+        _vlan_vid = None
+        _udp_dst = None
+        _udp_src = None
+        _ipv4_dst = None
+        _ipv4_src = None
+        _metadata = None
+        _output = None
+        _push_tpid = None
+        _field = None
+        _set_vlan_vid = None
+        self.log.info('add-flow', flow=flow)
+
+        def is_downstream(port):
+            return port == 100  # Need a better way
+
+        def is_upstream(port):
+            return not is_downstream(port)
+
+        try:
+            _in_port = fd.get_in_port(flow)
+            assert _in_port is not None
+
+            if is_downstream(_in_port):
+                self.log.info('downstream-flow')
+            elif is_upstream(_in_port):
+                self.log.info('upstream-flow')
+            else:
+                raise Exception('port should be 1 or 2 by our convention')
+
+            _out_port = fd.get_out_port(flow)  # may be None
+            self.log.info('out-port', out_port=_out_port)
+
+            for field in fd.get_ofb_fields(flow):
+                if field.type == fd.ETH_TYPE:
+                    _type = field.eth_type
+                    self.log.info('field-type-eth-type',
+                                  eth_type=_type)
+
+                elif field.type == fd.IP_PROTO:
+                    _proto = field.ip_proto
+                    self.log.info('field-type-ip-proto',
+                                  ip_proto=_proto)
+
+                elif field.type == fd.IN_PORT:
+                    _port = field.port
+                    self.log.info('field-type-in-port',
+                                  in_port=_port)
+
+                elif field.type == fd.VLAN_VID:
+                    _vlan_vid = field.vlan_vid & 0xfff
+                    self.log.info('field-type-vlan-vid',
+                                  vlan=_vlan_vid)
+
+                elif field.type == fd.VLAN_PCP:
+                    _vlan_pcp = field.vlan_pcp
+                    self.log.info('field-type-vlan-pcp',
+                                  pcp=_vlan_pcp)
+
+                elif field.type == fd.UDP_DST:
+                    _udp_dst = field.udp_dst
+                    self.log.info('field-type-udp-dst',
+                                  udp_dst=_udp_dst)
+
+                elif field.type == fd.UDP_SRC:
+                    _udp_src = field.udp_src
+                    self.log.info('field-type-udp-src',
+                                  udp_src=_udp_src)
+
+                elif field.type == fd.IPV4_DST:
+                    _ipv4_dst = field.ipv4_dst
+                    self.log.info('field-type-ipv4-dst',
+                                  ipv4_dst=_ipv4_dst)
+
+                elif field.type == fd.IPV4_SRC:
+                    _ipv4_src = field.ipv4_src
+                    self.log.info('field-type-ipv4-src',
+                                  ipv4_dst=_ipv4_src)
+
+                elif field.type == fd.METADATA:
+                    _metadata = field.table_metadata
+                    self.log.info('field-type-metadata',
+                                  metadata=_metadata)
+
+                else:
+                    raise NotImplementedError('field.type={}'.format(
+                        field.type))
+
+            for action in fd.get_actions(flow):
+
+                if action.type == fd.OUTPUT:
+                    _output = action.output.port
+                    self.log.info('action-type-output',
+                                  output=_output, in_port=_in_port)
+
+                elif action.type == fd.POP_VLAN:
+                    self.log.info('action-type-pop-vlan',
+                                  in_port=_in_port)
+
+                elif action.type == fd.PUSH_VLAN:
+                    _push_tpid = action.push.ethertype
+                    self.log.info('action-type-push-vlan',
+                                  push_tpid=_push_tpid, in_port=_in_port)
+                    if action.push.ethertype != 0x8100:
+                        self.log.error('unhandled-tpid',
+                                       ethertype=action.push.ethertype)
+
+                elif action.type == fd.SET_FIELD:
+                    _field = action.set_field.field.ofb_field
+                    assert (action.set_field.field.oxm_class ==
+                            OFPXMC_OPENFLOW_BASIC)
+                    self.log.info('action-type-set-field',
+                                  field=_field, in_port=_in_port)
+                    if _field.type == fd.VLAN_VID:
+                        _set_vlan_vid = _field.vlan_vid & 0xfff
+                        self.log.info('set-field-type-vlan-vid',vlan=_set_vlan_vid)
+                    else:
+                        self.log.error('unsupported-action-set-field-type',
+                                       field_type=_field.type)
+                else:
+                    self.log.error('unsupported-action-type',
+                                   action_type=action.type, in_port=_in_port)
+
+            #
+            # All flows created from ONU adapter should be OMCI based
+            #
+            if _vlan_vid == 0 and _set_vlan_vid != None and _set_vlan_vid != 0:
+                # allow priority tagged packets
+                # Set AR - ExtendedVlanTaggingOperationConfigData
+                #          514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
+
+
+                if _set_vlan_vid != RESERVED_VLAN_ID:
+                    # As per G.988 - Table 9.3.11-1 - Forward operation attribute values
+                    # Forward action of 0x10 allows VID Investigation
+                    if _type != FLOW_TYPE_EAPOL:
+                        self.log.info("Triggering-extended-vlan-configurations",vlan=_set_vlan_vid,eth_type=_type)
+                        self.send_set_vlan_tagging_filter_data(0x2102, _set_vlan_vid)
+                        #self.send_create_vlan_tagging_filter_data(0x2102, _set_vlan_vid, 0x10)
+                        yield self.wait_for_response()
+
+                        for port_id in self.uni_ports:
+
+                            self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(0x200 + port_id, 0x1000, _set_vlan_vid)
+                            yield self.wait_for_response()
+
+                            self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(0x200 + port_id, 8, 0, 0, 1, 8, _set_vlan_vid)
+                            yield self.wait_for_response()
+                    else:
+                        self.log.info("Use-vlan-4091-for-eapol",eth_type=_type)
+
+                else:
+                    # As per G.988 - Table 9.3.11-1 - Forward operation attribute values
+                    # Forward action of 0x00 does not perform VID Investigation for transparent vlan case
+                    self.send_delete_vlan_tagging_filter_data(0x2102)
+                    yield self.wait_for_response()
+
+                    self.send_create_vlan_tagging_filter_data(0x2102, _set_vlan_vid, 0x00)
+                    yield self.wait_for_response()
+
+                    for port_id in self.uni_ports:
+                        self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(0x200 + port_id, 14, 4096, 0, 0, 15, 0)
+                        yield self.wait_for_response()
+                        #self.send_set_extended_vlan_tagging_operation_vlan_configuration_data_double_tag( \
+                        #    0x200 + port_id, 4096, 4096, 0)
+                        #yield self.wait_for_response()
+
+                # Create the entry in the internal flow table
+                self.flow_map[flow.cookie] = {"vlan_id": _set_vlan_vid,
+                                              "eth_type":_type,
+                                              "vlan_tagging_filter_data_entity_id": 0x2102,
+                                              "extended_vlan_tagging_filter_data": [0x200 + port_id for port_id in self.uni_ports]}
+        except Exception as e:
+            self.log.exception('failed-to-install-flow', e=e, flow=flow)
+
+    @inlineCallbacks
+    def _delete_onu_flow(self, flow_map_value):
+        # Deletes ONU flows.
+        try:
+            if flow_map_value["vlan_id"] != RESERVED_VLAN_ID:
+                for extended_vlan_tagging_filter_data in flow_map_value["extended_vlan_tagging_filter_data"]:
+                    if flow_map_value["eth_type"] != FLOW_TYPE_EAPOL:
+                        self.send_delete_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
+                            extended_vlan_tagging_filter_data)
+                        yield self.wait_for_response()
+
+                        self.send_delete_extended_vlan_tagging_operation_vlan_configuration_data_untagged(
+                            extended_vlan_tagging_filter_data)
+                        yield self.wait_for_response()
+
+            else:
+                for extended_vlan_tagging_filter_data in flow_map_value["extended_vlan_tagging_filter_data"]:
+                    self.send_delete_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
+                        extended_vlan_tagging_filter_data)
+                    yield self.wait_for_response()
+
+            for port_id in self.uni_ports:
+                # Extended VLAN Tagging Operation config
+                # Create AR - ExtendedVlanTaggingOperationConfigData - 514 - 2 - 0x102(Uni-Port-Num)
+                self.send_create_extended_vlan_tagging_operation_configuration_data(0x200 + port_id, 2, 0x100 + port_id)
+                yield self.wait_for_response()
+
+                # Set AR - ExtendedVlanTaggingOperationConfigData - 514 - 8100 - 8100
+                self.send_set_extended_vlan_tagging_operation_tpid_configuration_data(0x200 + port_id, 0x8100, 0x8100)
+                yield self.wait_for_response()
+
+        except Exception as e:
+            self.log.exception('failed-to-delete-flow', e=e, flow_map_value=flow_map_value)
+
+    @inlineCallbacks
+    def _wait_for_previous_update_flow_to_finish(self):
+        while self.flow_config_in_progress:
+            # non-blocking wait for 200ms
+            yield asleep(0.2)
+        return
diff --git a/voltha/core/core.py b/voltha/core/core.py
index 8978034..a7542a4 100644
--- a/voltha/core/core.py
+++ b/voltha/core/core.py
@@ -216,6 +216,24 @@
         path = '/devices/{}'.format(device.id)
         self.xpon_agent.register_interface(device.id, path, update=False)
 
+        try:
+            # Register for updates to '/tconts/{}'.
+            # Otherwise TrafficDescriptorProfile updates after VOLTHA restart
+            # are dropped at VOLTHA core.
+            tconts = self.local_root_proxy.get('/tconts')
+            for tcont in tconts:
+                try:
+                    olt_device = self.xpon_agent.get_device(tcont, 'olt')
+                except Exception as e:
+                    log.error("exception-getting-olt", e=e)
+                    return
+                if olt_device and olt_device.id == device.id:
+                    tcont_path = '/tconts/{}'.format(tcont.name)
+                    self.xpon_agent.register_interface(device.id, tcont_path)
+        except Exception as e:
+            log.exception("error-fetching-tcont--xpon-may-not-be-supported", e=e)
+
+
     @inlineCallbacks
     def _handle_remove_device(self, device):
         if device.id in self.device_agents:
diff --git a/voltha/core/logical_device_agent.py b/voltha/core/logical_device_agent.py
index f327310..87ebc7f 100644
--- a/voltha/core/logical_device_agent.py
+++ b/voltha/core/logical_device_agent.py
@@ -778,6 +778,13 @@
             downstream_ports = [
                 port for port in ports if port.type == Port.ETHERNET_UNI
             ]
+
+            # it is possible that the downstream ports are not
+            # created, but the flow_decomposition has already
+            # kicked in. In such scenarios, cut short the processing
+            # and return.
+            if len(downstream_ports) == 0:
+                return None, None
             # assert len(downstream_ports) == 1
             flows = OrderedDict((f.id, f) for f in [
                 mk_flow_stat(
diff --git a/voltha/protos/events.proto b/voltha/protos/events.proto
index ed7ac8f..725bb8c 100644
--- a/voltha/protos/events.proto
+++ b/voltha/protos/events.proto
@@ -123,6 +123,7 @@
         OLT = 1;
         ONT = 2;
         ONU = 3;
+        NNI = 4;
     }
 }