VOL-2502: Update README.md for openolt agent after BAL3.2.3.2 migration
VOL-2503: Provides test target for openolt-agent for Jenkins CI Integration
VOL-2504: Reorganize openolt-agent core.cc file

Change-Id: Id22fb881fcb9cc19d1f2ba044716731157d3a64e
diff --git a/.gitignore b/.gitignore
index 1ccc2a4..f20f213 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 # Autoconf files
-Makefile
+agent/Makefile
+agent/test/Makefile
 config.h
 config.log
 config.status
@@ -12,6 +13,9 @@
 # Protobuf intermediate files
 **/*.pb.*
 
+# Proto files
+**/*.proto
+
 # C++ output files
 **/*.o
 **/*.a
@@ -19,17 +23,14 @@
 # Build output
 build
 
-# BAL API 3.1.0
-**/bal-api-3.1.0
+# BAL API 3.x
+**/bal-api-3.*
 
 # Test binary
 **/test_openolt
 
 # Test report
-**/test_openolt_report.xml
-
-# Downloaded voltha-protos file
-voltha_protos
+**/test_openolt_report_xunit.xml
 
 # IntelliJ Files
 .idea
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d11a0c4
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
+#Copyright 2018-present Open Networking Foundation
+#
+#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.
+
+########################################################################
+
+# This Makefile provides hook for Jenkins to invoke the test target for
+# CI integration.
+# The main Makefile for product compilation is available at
+# agent/Makefile.in. Please see README.md for more details.
+
+# The unit tests require certain pre-requisite software for compilation
+# and execution. Please see agent/test/README.md for more details.
+
+.DEFAULT_GOAL := test
+
+prereqs-system:
+	cd agent/test && ./configure
+	make -C agent/test prereqs-system
+
+prereqs-local:
+	cd agent/test && ./configure
+	make -C agent/test prereqs-local
+
+# Invoke unit-tests
+test:
+	cd agent/test && ./configure
+	make -C agent/test test
diff --git a/README.md b/README.md
index 3db155f..6876893 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@
 Get access credentials for https://edgecore.quickconnect.to and then login and navigate to
 File_Station -> EdgecoreNAS, and then the folder /ASXvOLT16/OpenOLT_Agent/From_ONF_Distribution/
 and pick the right version of deb package required for your testing.
-voltha-2.2/openolt-2.2.0.deb is the latest version of package with support for BAL3.1.1.1.
+voltha-2.2/openolt-2.2.0.deb is the latest version of package with support for BAL3.2.3.2
 The pre-built debian packages have been tested on ONL-4.14. The ONL Installer required for
 voltha-2.2/openolt-2.2.0.deb is also available at in the same patch, i.e., voltha-2.2/.
 
@@ -72,7 +72,7 @@
 dpkg -i openolt.deb
 ```
 
-Note that ONL required for BAL3.1 is ONL `4.14`. This will be built as part of build procedure described `Build OpenOLT` section.
+Note that ONL required for BAL3.2.3.2 is ONL `4.14.109-OpenNetworkLinux`. This will be built as part of build procedure described `Build OpenOLT` section.
 
 ## Run OpenOLT as a Linux service
 
@@ -138,21 +138,21 @@
 
 ### Supported BAL API versions
 
-Currently, OpenOLT supports Broadcom's BAL API, version *3.1.1.1*.
+Currently, OpenOLT supports Broadcom's BAL API, version *3.2.3.2*.
 
 ### Proprietary software requirements
 
 The following proprietary source code is required to build the OpenOLT agent.
 
-* `SW-BCM68620_<BAL_VER>.zip` - Broadcom BAL source and Maple SDK
+* `SW-BCM686OLT_<BAL_VER>.tgz` - Broadcom BAL source and Maple SDK
 * `sdk-all-<SDK_VER>.tar.gz` - Broadcom Qumran SDK
 * `ACCTON_BAL_<BAL_VER>-<ACCTON_VER>.patch` - Accton/Edgecore's patch
 
 The versions currently supported by the OpenOLT agent are:
 
-* SW-BCM68620_3_1_1_1.tgz
+* SW-BCM686OLT_3_2_3_2.tgz
 * sdk-all-6.5.13.tar.gz
-* ACCTON_BAL_3.1.1.1-V201908010203.patch
+* ACCTON_BAL_3.2.3.2-V201912230101.patch
 
 > NOTE: the repository does not contain the above three source packages.  These
 > are needed to build the OpenOLT agent executable. Contact
@@ -197,7 +197,7 @@
 
 ```shell
 cd <dir containing Broadcom source and patch files>
-cp SW-BCM68620_3_1_1_1.tgz sdk-all-6.5.13.tar.gz ACCTON_BAL_3.1.1.1-V201908010203.patch <cloned openolt repo path>/agent/download
+cp ACCTON_BAL_3.2.3.2-V201912230101.patch SW-BCM686OLT_3_2_3_2.tgz sdk-all-6.5.13.tar.gz <cloned openolt repo path>/agent/download
 ```
 
 Run Autoconfig to generate the appropriate makefile scaffolding for the desired target
@@ -231,7 +231,7 @@
 make OPENOLTDEVICE=asfvolt16 OPENOLT_PROTO_VER=master
 ```
 
-By default, the OPENOLT_PROTO_VER defaults to git tag *v1.0.3* of https://github.com/opencord/voltha-protos repo.
+By default, the OPENOLT_PROTO_VER defaults to git tag *v3.1.0* of https://github.com/opencord/voltha-protos repo.
 
 If the build process succeeds, libraries and executables will be created in the
 *openolt/agent/build* directory.
@@ -265,14 +265,6 @@
 port ce128 sp=40000
 ```
 
-This change can also be made at run-time from the CLI of the dev_mgmt_daemon:
-
-```shell
-d/s/shell
-port ce128 speed=40000
-```
-(It is safe to ignore the error msgs.)
-
 ### Why does the Broadcom ONU not forward eapol packets?
 
 The firmware on the ONU is likely not setup to forward 802.1x on the linux bridge. Drop down to the shell in the Broadcom ONU's console and configure the Linux bridge to forward 802.1x.
@@ -396,8 +388,6 @@
 Navigate to `/opt/bcm68620` and execute the command `/broadcom/dev_mgmt_attach` to access the QAX
 diag shell. Note that you will not be able to access the QAX diag shell, you need to recompile the
 BAL SDK with `SW_UTIL_SHELL=y` option.
-There is also a known issue where `/broadcom/dev_mgmt_attach` does not work when openolt processes
-restart, and this will be fixed in BAL3.2.
 
 ### DBA Scheduler fail to create on the OLT with errors related to Bandwidth configuration
 
@@ -418,3 +408,12 @@
 
 [MEF Whitepaper - Bandwidth-Profiles-for-Ethernet-Services](https://www.mef.net/Assets/White_Papers/Bandwidth-Profiles-for-Ethernet-Services.pdf)
 [Technology Profile Implementation Note](https://www.opennetworking.org/wp-content/uploads/2019/09/2pm-Shaun-Missett-Technology-Profile-and-Speed-Profile-Implementation.pdf)
+
+
+## Known Issues
+
+* The Minimum BW that should be configured for ITU PON Alloc Object has changed from 16Kbps
+  to 32Kbps from BAL3.1 to BAL3.2 release. As per BAL3.x documents, when FEC is disabled,
+  the minimum BW is 16Kbps on the ITU PON Alloc Object. This seems to be a discrepency.
+  So, ensure that `cir` + `eir` value is greater than equal to *32000* for XGSPON use case.
+
diff --git a/VERSION b/VERSION
index 7c7e096..c212a7f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1,2 @@
-2.1.1-dev
+2.1.1
+
diff --git a/agent/Makefile.in b/agent/Makefile.in
index ad6d605..514dd3c 100644
--- a/agent/Makefile.in
+++ b/agent/Makefile.in
@@ -47,11 +47,19 @@
 #
 # Build directory
 BUILD_DIR = build
+
+# Protobuf installation
+PROTOBUF_VER = 3.5.0
+PROTOBUF_ADDR = https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOBUF_VER)/protobuf-cpp-$(PROTOBUF_VER).tar.gz
+PROTOBUF_DST = /tmp/protobuf-$(PROTOBUF_VER)
+protoc-bin = $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/bin/protoc
+
 #
 # GRPC installation
 GRPC_ADDR = https://github.com/grpc/grpc
 GRPC_DST = /tmp/grpc
 GRPC_VER = v1.10.x
+grpc-cpp-plugin-bin = $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/bin/grpc_cpp_plugin
 
 USER := $(shell echo $(USER))
 #
@@ -82,7 +90,7 @@
 CPPFLAGS += `pkg-config --cflags protobuf grpc`
 CPPFLAGS += -DVERSION=\"$(VERSION)\" -DBAL_VER=\"$(BAL_VER)\" -DLABEL_VCS_URL=\"$(LABEL_VCS_URL)\" \
             -DLABEL_VCS_REF=\"$(LABEL_VCS_REF)\" -DLABEL_BUILD_DATE=\"$(LABEL_BUILD_DATE)\" \
-            -DLABEL_COMMIT_DATE=\"$(LABEL_COMMIT_DATE)\"
+            -DLABEL_COMMIT_DATE=\"$(LABEL_COMMIT_DATE)\" -DFLOW_CHECKER
 CXXFLAGS += -std=c++11 -fpermissive -Wno-literal-suffix
 LDFLAGS += @LDFLAGS@
 LDFLAGS += `pkg-config --libs protobuf grpc++ grpc` -ldl -lgpr
@@ -90,21 +98,31 @@
 
 export CXX CXXFLAGS OPENOLT_PROTO_VER
 
-prereq:
+prereqs-system:
 	sudo apt-get -q -y install git pkg-config build-essential autoconf libtool libgflags-dev libgtest-dev clang libc++-dev unzip docker.io
 	sudo apt-get install -y build-essential autoconf libssl-dev gawk debhelper dh-systemd init-system-helpers curl cmake ccache g++-4.9
 
-	# Install GRPC, libprotobuf and protoc
+prereqs-local: $(protoc-bin) $(grpc-cpp-plugin-bin)
+
+$(protoc-bin):
+	# Install protobuf
+	rm -rf $(PROTOBUF_DST)
+	cd /tmp && wget $(PROTOBUF_ADDR)
+	cd /tmp && tar -zxvf protobuf-cpp-$(PROTOBUF_VER).tar.gz
+	cd $(PROTOBUF_DST) && ./autogen.sh
+	mkdir -p $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)
+	cd $(PROTOBUF_DST) && ./configure --prefix=$(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)
+	make -C $(PROTOBUF_DST)
+	make -C $(PROTOBUF_DST) install
+
+$(grpc-cpp-plugin-bin):
+	# Install GRPC, protoc
 	rm -rf $(GRPC_DST)
-	git clone -b $(GRPC_VER) $(GRPC_ADDR) $(GRPC_DST)
+	cd /tmp && git clone -b $(GRPC_VER) $(GRPC_ADDR) $(GRPC_DST)
 	cd $(GRPC_DST) && git submodule update --init
-	cd $(GRPC_DST)/third_party/protobuf && ./autogen.sh && ./configure
-	make -C $(GRPC_DST)/third_party/protobuf
-	sudo make -C $(GRPC_DST)/third_party/protobuf install
-	sudo ldconfig
+	mkdir -p $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)
 	make -C $(GRPC_DST)
-	sudo make -C $(GRPC_DST) install
-	sudo ldconfig
+	make -C $(GRPC_DST) install prefix=$(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)
 
 docker:
 	echo $(USER)
@@ -328,4 +346,4 @@
 distclean: clean-src clean
 	@rm -rf $(BUILD_DIR)
 
-.PHONY: onl sdk bal protos prereq sim .FORCE
+.PHONY: onl sdk bal protos prereqs-system prereqs-local sim .FORCE
diff --git a/agent/common/core.h b/agent/common/core.h
index dedc4c3..f73051e 100644
--- a/agent/common/core.h
+++ b/agent/common/core.h
@@ -23,6 +23,27 @@
 
 #include "state.h"
 
+extern "C"
+{
+#include <bcmolt_api.h>
+#include <bcmolt_api_model_supporting_enums.h>
+
+#include <bcmolt_api_conn_mgr.h>
+//CLI header files
+#include <bcmcli_session.h>
+#include <bcmcli.h>
+#include <bcm_api_cli.h>
+
+#include <bcmos_common.h>
+#include <bcm_config.h>
+// FIXME : dependency problem
+// #include <bcm_common_gpon.h>
+// #include <bcm_dev_log_task.h>
+}
+// ************************//
+// Macros used by the core //
+// ************************//
+
 #define NONE "\033[m"
 #define LIGHT_RED "\033[1;31m"
 #define BROWN "\033[0;33m"
@@ -38,83 +59,144 @@
         BCM_LOG(level, id, "%s" fmt "%s", LIGHT_GREEN, ##__VA_ARGS__, NONE); \
     else \
         BCM_LOG(INFO, id, fmt, ##__VA_ARGS__);
+
+
+#define ACL_LOG(level,msg,err) \
+    do { \
+    OPENOLT_LOG(level, openolt_log_id, "--------> %s (acl_id %d) err: %d <--------\n", msg, key.id, err); \
+    OPENOLT_LOG(level, openolt_log_id, "action_type %s\n", \
+        GET_ACL_ACTION_TYPE(action_type)); \
+    OPENOLT_LOG(level, openolt_log_id, "classifier(ether type %d), ip_proto %d, src_port %d, dst_port %d\n", \
+        acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port); \
+    } while(0)
+
+#define FLOW_LOG(level,msg,err) \
+    do { \
+    OPENOLT_LOG(level, openolt_log_id, "--------> %s (flow_id %d) err: %d <--------\n", msg, key.flow_id, err); \
+    OPENOLT_LOG(level, openolt_log_id, "intf_id %d, onu_id %d, uni_id %d, port_no %u, cookie %"PRIu64"\n", \
+        access_intf_id, onu_id, uni_id, port_no, cookie); \
+    OPENOLT_LOG(level, openolt_log_id, "flow_type %s, queue_id %d, sched_id %d\n", flow_type.c_str(), \
+        cfg.data.egress_qos.u.fixed_queue.queue_id, cfg.data.egress_qos.tm_sched.id); \
+    OPENOLT_LOG(level, openolt_log_id, "Ingress(intfd_type %s, intf_id %d), Egress(intf_type %s, intf_id %d)\n", \
+        GET_FLOW_INTERFACE_TYPE(cfg.data.ingress_intf.intf_type), cfg.data.ingress_intf.intf_id,  \
+        GET_FLOW_INTERFACE_TYPE(cfg.data.egress_intf.intf_type), cfg.data.egress_intf.intf_id); \
+    OPENOLT_LOG(level, openolt_log_id, "classifier(o_vid %d, o_pbits %d, i_vid %d, i_pbits %d, ether type 0x%x)\n", \
+        c_val.o_vid, c_val.o_pbits, c_val.i_vid, c_val.i_pbits,  classifier.eth_type()); \
+    OPENOLT_LOG(level, openolt_log_id, "classifier(ip_proto 0x%x, gemport_id %d, src_port %d, dst_port %d, pkt_tag_type %s)\n", \
+        c_val.ip_proto, gemport_id, c_val.src_port,  c_val.dst_port, GET_PKT_TAG_TYPE(c_val.pkt_tag_type)); \
+    OPENOLT_LOG(level, openolt_log_id, "action(cmds_bitmask %s, o_vid %d, o_pbits %d, i_vid %d, i_pbits %d)\n\n", \
+        get_flow_acton_command(a_val.cmds_bitmask), a_val.o_vid, a_val.o_pbits, a_val.i_vid, a_val.i_pbits); \
+    } while(0)
+
+#define FLOW_PARAM_LOG() \
+    do { \
+    OPENOLT_LOG(INFO, openolt_log_id, "--------> flow comparison (now before) <--------\n"); \
+    OPENOLT_LOG(INFO, openolt_log_id, "flow_id (%d %d)\n", \
+        key.flow_id, it->first.first); \
+    OPENOLT_LOG(INFO, openolt_log_id, "onu_id (%d %lu)\n", \
+        cfg.data.onu_id , get_flow_status(it->first.first, it->first.second, ONU_ID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "type (%d %lu)\n", \
+        key.flow_type, get_flow_status(it->first.first, it->first.second, FLOW_TYPE)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "svc_port_id (%d %lu)\n", \
+        cfg.data.svc_port_id, get_flow_status(it->first.first, it->first.second, SVC_PORT_ID));  \
+    OPENOLT_LOG(INFO, openolt_log_id, "priority (%d %lu)\n", \
+        cfg.data.priority, get_flow_status(it->first.first, it->first.second, PRIORITY)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "cookie (%lu %lu)\n", \
+        cfg.data.cookie, get_flow_status(it->first.first, it->first.second, COOKIE)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "ingress intf_type (%s %s)\n", \
+        GET_FLOW_INTERFACE_TYPE(cfg.data.ingress_intf.intf_type), \
+        GET_FLOW_INTERFACE_TYPE(get_flow_status(it->first.first, it->first.second, INGRESS_INTF_TYPE))); \
+    OPENOLT_LOG(INFO, openolt_log_id, "ingress intf id (%d %lu)\n", \
+        cfg.data.ingress_intf.intf_id , get_flow_status(it->first.first, it->first.second, INGRESS_INTF_ID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "egress intf_type (%d %lu)\n", \
+        cfg.data.egress_intf.intf_type , get_flow_status(it->first.first, it->first.second, EGRESS_INTF_TYPE)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "egress intf_id (%d %lu)\n", \
+        cfg.data.egress_intf.intf_id , get_flow_status(it->first.first, it->first.second, EGRESS_INTF_ID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier o_vid (%d %lu)\n", \
+        c_val.o_vid , get_flow_status(it->first.first, it->first.second, CLASSIFIER_O_VID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier o_pbits (%d %lu)\n", \
+        c_val.o_pbits , get_flow_status(it->first.first, it->first.second, CLASSIFIER_O_PBITS)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier i_vid (%d %lu)\n", \
+        c_val.i_vid , get_flow_status(it->first.first, it->first.second, CLASSIFIER_I_VID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier i_pbits (%d %lu)\n", \
+        c_val.i_pbits , get_flow_status(it->first.first, it->first.second, CLASSIFIER_I_PBITS)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier ether_type (0x%x 0x%lx)\n", \
+        c_val.ether_type , get_flow_status(it->first.first, it->first.second, CLASSIFIER_ETHER_TYPE));  \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier ip_proto (%d %lu)\n", \
+        c_val.ip_proto , get_flow_status(it->first.first, it->first.second, CLASSIFIER_IP_PROTO)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier src_port (%d %lu)\n", \
+        c_val.src_port , get_flow_status(it->first.first, it->first.second, CLASSIFIER_SRC_PORT)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier dst_port (%d %lu)\n", \
+        c_val.dst_port , get_flow_status(it->first.first, it->first.second, CLASSIFIER_DST_PORT)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier pkt_tag_type (%s %s)\n", \
+        GET_PKT_TAG_TYPE(c_val.pkt_tag_type), \
+        GET_PKT_TAG_TYPE(get_flow_status(it->first.first, it->first.second, CLASSIFIER_PKT_TAG_TYPE))); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier egress_qos type (%d %lu)\n", \
+        cfg.data.egress_qos.type , get_flow_status(it->first.first, it->first.second, EGRESS_QOS_TYPE)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier egress_qos queue_id (%d %lu)\n", \
+        cfg.data.egress_qos.u.fixed_queue.queue_id, \
+        get_flow_status(it->first.first, it->first.second, EGRESS_QOS_QUEUE_ID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier egress_qos sched_id (%d %lu)\n", \
+        cfg.data.egress_qos.tm_sched.id, \
+        get_flow_status(it->first.first, it->first.second, EGRESS_QOS_TM_SCHED_ID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "classifier cmds_bitmask (%s %s)\n", \
+        get_flow_acton_command(a_val.cmds_bitmask), \
+        get_flow_acton_command(get_flow_status(it->first.first, it->first.second, ACTION_CMDS_BITMASK))); \
+    OPENOLT_LOG(INFO, openolt_log_id, "action o_vid (%d %lu)\n", \
+        a_val.o_vid , get_flow_status(it->first.first, it->first.second, ACTION_O_VID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "action i_vid (%d %lu)\n", \
+        a_val.i_vid , get_flow_status(it->first.first, it->first.second, ACTION_I_VID)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "action o_pbits (%d %lu)\n", \
+        a_val.o_pbits , get_flow_status(it->first.first, it->first.second, ACTION_O_PBITS)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "action i_pbits (%d %lu)\n\n", \
+        a_val.i_pbits, get_flow_status(it->first.first, it->first.second, ACTION_I_PBITS)); \
+    OPENOLT_LOG(INFO, openolt_log_id, "group_id (%d %lu)\n\n", \
+        a_val.group_id, get_flow_status(it->first.first, it->first.second, GROUP_ID)); \
+    } while(0)
+
 #define COLLECTION_PERIOD 15 // in seconds
 #define BAL_DYNAMIC_LIST_BUFFER_SIZE (32 * 1024)
 #define MAX_REGID_LENGTH  36
 
+#define BAL_RSC_MANAGER_BASE_TM_SCHED_ID 16384
+#define MAX_TM_QMP_ID 16
+#define TMQ_MAP_PROFILE_SIZE 8
+#define MAX_TM_SCHED_ID 1023
+#define MAX_SUBS_TM_SCHED_ID (MAX_SUPPORTED_PON == 16 ? MAX_TM_SCHED_ID-4-16 : MAX_TM_SCHED_ID-10-64)
+#define EAP_ETHER_TYPE 34958
+#define XGS_BANDWIDTH_GRANULARITY 16000
+#define GPON_BANDWIDTH_GRANULARITY 32000
+#define NUM_OF_PRIORITIES 8
+#define NUMBER_OF_DEFAULT_INTERFACE_QUEUES 4 // <= NUM_OF_PRIORITIES
+#define FILL_ARRAY(ARRAY,START,END,VALUE) for(int i=START;i<END;ARRAY[i++]=VALUE);
+#define COUNT_OF(array) (sizeof(array) / sizeof(array[0]))
+
+#define GET_FLOW_INTERFACE_TYPE(type) \
+       (type == BCMOLT_FLOW_INTERFACE_TYPE_PON) ? "PON" : \
+       (type == BCMOLT_FLOW_INTERFACE_TYPE_NNI) ? "NNI" : \
+       (type == BCMOLT_FLOW_INTERFACE_TYPE_HOST) ? "HOST" : "unknown"
+#define GET_PKT_TAG_TYPE(type) \
+       (type == BCMOLT_PKT_TAG_TYPE_UNTAGGED) ? "UNTAG" : \
+       (type == BCMOLT_PKT_TAG_TYPE_SINGLE_TAG) ? "SINGLE_TAG" : \
+       (type == BCMOLT_PKT_TAG_TYPE_DOUBLE_TAG) ? "DOUBLE_TAG" : "unknown"
+#define GET_ACL_ACTION_TYPE(type) \
+       (type == BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_TRAP_TO_HOST) ? "trap_to_host" : \
+       (type == BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_DROP) ? "drop" : \
+       (type == BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_REDIRECT) ? "redirction" : "unknown"
+#define GET_ACL_MEMBERS_UPDATE_COMMAND(command) \
+       (command == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD) ? "add" : \
+       (command == BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE) ? "remove" : \
+       (command == BCMOLT_MEMBERS_UPDATE_COMMAND_SET) ? "set" : "unknown"
+#define GET_INTERFACE_TYPE(type) \
+       (type == BCMOLT_INTERFACE_TYPE_PON) ? "PON" : \
+       (type == BCMOLT_INTERFACE_TYPE_NNI) ? "NNI" : \
+       (type == BCMOLT_INTERFACE_TYPE_HOST) ? "HOST" : "unknown"
+
 extern State state;
 
-enum FLOW_CFG {
-    ONU_ID = 0,
-    FLOW_TYPE = 1,
-    SVC_PORT_ID = 2,
-    PRIORITY = 3,
-    COOKIE = 4,
-    INGRESS_INTF_TYPE= 5,
-    EGRESS_INTF_TYPE= 6,
-    INGRESS_INTF_ID = 7,
-    EGRESS_INTF_ID = 8,
-    CLASSIFIER_O_VID = 9,
-    CLASSIFIER_O_PBITS = 10,
-    CLASSIFIER_I_VID = 11,
-    CLASSIFIER_I_PBITS = 12,
-    CLASSIFIER_ETHER_TYPE = 13,
-    CLASSIFIER_IP_PROTO =14,
-    CLASSIFIER_SRC_PORT = 15,
-    CLASSIFIER_DST_PORT = 16,
-    CLASSIFIER_PKT_TAG_TYPE = 17,
-    EGRESS_QOS_TYPE = 18,
-    EGRESS_QOS_QUEUE_ID = 19,
-    EGRESS_QOS_TM_SCHED_ID = 20,
-    ACTION_CMDS_BITMASK = 21,
-    ACTION_O_VID = 22,
-    ACTION_O_PBITS = 23,
-    ACTION_I_VID = 24,
-    ACTION_I_PBITS = 25,
-    STATE = 26,
-    GROUP_ID = 27
-};
-
-enum AllocCfgAction {
-    ALLOC_OBJECT_CREATE,
-    ALLOC_OBJECT_DELETE
-};
-
-enum AllocObjectState {
-    ALLOC_OBJECT_STATE_NOT_CONFIGURED,
-    ALLOC_OBJECT_STATE_INACTIVE,
-    ALLOC_OBJECT_STATE_PROCESSING,
-    ALLOC_OBJECT_STATE_ACTIVE
-};
-
-enum AllocCfgStatus {
-    ALLOC_CFG_STATUS_SUCCESS,
-    ALLOC_CFG_STATUS_FAIL
-};
-
-typedef struct {
-    uint32_t pon_intf_id;
-    uint32_t alloc_id;
-    AllocObjectState state;
-    AllocCfgStatus status;
-} alloc_cfg_complete_result;
-
-// key for map used for tracking ITU PON Alloc Configuration results from BAL
-typedef std::tuple<uint32_t, uint32_t> alloc_cfg_compltd_key;
-
-// The elements in this acl_classifier_key structure constitute key to
-// acl_classifier_to_acl_id_map.
-// Fill invalid values in the acl_classifier_key structure to -1.
-typedef struct acl_classifier_key {
-    int32_t ether_type;
-    int16_t ip_proto;
-    int32_t src_port;
-    int32_t dst_port;
-    // Add more classifiers elements as needed here
-    // For now, ACLs will be classified only based on
-    // above elements.
-} acl_classifier_key;
-
+//***************************************//
+// Function declations used by the core. //
+//***************************************//
 Status Enable_(int argc, char *argv[]);
 Status ActivateOnu_(uint32_t intf_id, uint32_t onu_id,
     const char *vendor_id, const char *vendor_specific, uint32_t pir);
@@ -156,4 +238,16 @@
 void stats_collection();
 Status check_connection();
 Status check_bal_ready();
+
+// Stubbed defntions of bcmolt_cfg_get required for unit-test
+#ifdef TEST_MODE
+extern bcmos_errno bcmolt_cfg_get__bal_state_stub(bcmolt_oltid olt_id, void* ptr);
+extern bcmos_errno bcmolt_cfg_get__onu_state_stub(bcmolt_oltid olt_id, void* ptr);
+extern bcmos_errno bcmolt_cfg_get__tm_sched_stub(bcmolt_oltid olt_id, void* ptr);
+extern bcmos_errno bcmolt_cfg_get__pon_intf_stub(bcmolt_oltid olt_id, void* ptr);
+extern bcmos_errno bcmolt_cfg_get__nni_intf_stub(bcmolt_oltid olt_id, void* ptr);
+extern bcmos_errno bcmolt_cfg_get__olt_topology_stub(bcmolt_oltid olt_id, void* ptr);
+extern bcmos_errno bcmolt_cfg_get__flow_stub(bcmolt_oltid olt_id, void* ptr);
+#endif //TEST_MODE
+
 #endif
diff --git a/agent/configure b/agent/configure
index 7c41265..f861fd7 100755
--- a/agent/configure
+++ b/agent/configure
@@ -574,8 +574,6 @@
 LIBOBJS=
 cross_compiling=no
 subdirs=
-MFLAGS=
-MAKEFLAGS=
 
 # Identity of this package.
 PACKAGE_NAME='openolt'
diff --git a/agent/src/core.cc b/agent/src/core_api_handler.cc
similarity index 65%
rename from agent/src/core.cc
rename to agent/src/core_api_handler.cc
index 0337bed..24e956d 100644
--- a/agent/src/core.cc
+++ b/agent/src/core_api_handler.cc
@@ -31,11 +31,12 @@
 
 #include "device.h"
 #include "core.h"
+#include "core_data.h"
 #include "indications.h"
 #include "stats_collection.h"
 #include "error_format.h"
 #include "state.h"
-#include "utils.h"
+#include "core_utils.h"
 
 extern "C"
 {
@@ -56,171 +57,13 @@
 // #include <bcm_dev_log_task.h>
 }
 
-dev_log_id openolt_log_id = bcm_dev_log_id_register("OPENOLT", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
-dev_log_id omci_log_id = bcm_dev_log_id_register("OMCI", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
-
-#define BAL_RSC_MANAGER_BASE_TM_SCHED_ID 16384
-#define MAX_TM_QMP_ID 16
-#define TMQ_MAP_PROFILE_SIZE 8
-#define MAX_TM_SCHED_ID 1023
-#define MAX_SUBS_TM_SCHED_ID (MAX_SUPPORTED_PON == 16 ? MAX_TM_SCHED_ID-4-16 : MAX_TM_SCHED_ID-10-64)
-#define EAP_ETHER_TYPE 34958
-#define XGS_BANDWIDTH_GRANULARITY 16000
-#define GPON_BANDWIDTH_GRANULARITY 32000
-#define NUM_OF_PRIORITIES 8
-#define NUMBER_OF_DEFAULT_INTERFACE_QUEUES 4 // <= NUM_OF_PRIORITIES
-#define FILL_ARRAY(ARRAY,START,END,VALUE) for(int i=START;i<END;ARRAY[i++]=VALUE);
-#define COUNT_OF(array) (sizeof(array) / sizeof(array[0]))
-
-#define GET_FLOW_INTERFACE_TYPE(type) \
-       (type == BCMOLT_FLOW_INTERFACE_TYPE_PON) ? "PON" : \
-       (type == BCMOLT_FLOW_INTERFACE_TYPE_NNI) ? "NNI" : \
-       (type == BCMOLT_FLOW_INTERFACE_TYPE_HOST) ? "HOST" : "unknown"
-#define GET_PKT_TAG_TYPE(type) \
-       (type == BCMOLT_PKT_TAG_TYPE_UNTAGGED) ? "UNTAG" : \
-       (type == BCMOLT_PKT_TAG_TYPE_SINGLE_TAG) ? "SINGLE_TAG" : \
-       (type == BCMOLT_PKT_TAG_TYPE_DOUBLE_TAG) ? "DOUBLE_TAG" : "unknown"
-#define GET_ACL_ACTION_TYPE(type) \
-       (type == BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_TRAP_TO_HOST) ? "trap_to_host" : \
-       (type == BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_DROP) ? "drop" : \
-       (type == BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_REDIRECT) ? "redirction" : "unknown"
-#define GET_ACL_MEMBERS_UPDATE_COMMAND(command) \
-       (command == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD) ? "add" : \
-       (command == BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE) ? "remove" : \
-       (command == BCMOLT_MEMBERS_UPDATE_COMMAND_SET) ? "set" : "unknown"
-#define GET_INTERFACE_TYPE(type) \
-       (type == BCMOLT_INTERFACE_TYPE_PON) ? "PON" : \
-       (type == BCMOLT_INTERFACE_TYPE_NNI) ? "NNI" : \
-       (type == BCMOLT_INTERFACE_TYPE_HOST) ? "HOST" : "unknown"
-
-static unsigned int num_of_nni_ports = 0;
-static unsigned int num_of_pon_ports = 0;
 static std::string intf_technologies[MAX_SUPPORTED_PON];
 static const std::string UNKNOWN_TECH("unknown");
 static const std::string MIXED_TECH("mixed");
 static std::string board_technology(UNKNOWN_TECH);
 static std::string chip_family(UNKNOWN_TECH);
-static unsigned int OPENOLT_FIELD_LEN = 200;
 static std::string firmware_version = "Openolt.2019.07.01";
 
-const uint32_t tm_upstream_sched_id_start = (MAX_SUPPORTED_PON == 16 ? \
-    MAX_TM_SCHED_ID-3 : MAX_TM_SCHED_ID-9);
-const uint32_t tm_downstream_sched_id_start = (MAX_SUPPORTED_PON == 16 ? \
-    tm_upstream_sched_id_start-16 : tm_upstream_sched_id_start-64);
-
-/* Max Queue ID supported is 7 so based on priority_q configured for GEMPORTS
-in TECH PROFILE respective Queue ID from this list will be used for both
-US and DS Queues*/
-const uint32_t queue_id_list[8] = {0, 1, 2, 3, 4, 5, 6, 7};
-
-const std::string upstream = "upstream";
-const std::string downstream = "downstream";
-const std::string multicast = "multicast";
-bcmolt_oltid dev_id = 0;
-
-/* Constants used for retrying some BAL APIs */
-const uint32_t BAL_API_RETRY_TIME_IN_USECS = 1000000;
-const uint32_t MAX_BAL_API_RETRY_COUNT = 5;
-
-/* Current session */
-static bcmcli_session *current_session;
-static bcmcli_entry *api_parent_dir;
-bcmos_bool status_bcm_cli_quit = BCMOS_FALSE;
-bcmos_task bal_cli_thread;
-const char *bal_cli_thread_name = "bal_cli_thread";
-uint16_t flow_id_counters = 0;
-State state;
-
-static std::map<uint32_t, uint32_t> flowid_to_port; // For mapping upstream flows to logical ports
-static std::map<uint32_t, uint32_t> flowid_to_gemport; // For mapping downstream flows into gemports
-static std::map<uint32_t, std::set<uint32_t> > port_to_flows; // For mapping logical ports to downstream flows
-
-/* This represents the Key to 'sched_map' map.
- Represents (pon_intf_id, onu_id, uni_id, direction) */
-typedef std::tuple<uint32_t, uint32_t, uint32_t, std::string> sched_map_key_tuple;
-/* 'sched_map' maps sched_map_key_tuple to DBA (Upstream) or
- Subscriber (Downstream) Scheduler ID */
-static std::map<sched_map_key_tuple, int> sched_map;
-
-/* Flow control is for flow_id and flow_type */
-typedef std::pair<uint16_t, uint16_t> flow_pair;
-static std::map<flow_pair, int32_t> flow_map;
-
-/* This represents the Key to 'qos_type_map' map.
- Represents (pon_intf_id, onu_id, uni_id) */
-typedef std::tuple<uint32_t, uint32_t, uint32_t> qos_type_map_key_tuple;
-/* 'qos_type_map' maps qos_type_map_key_tuple to qos_type*/
-static std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type> qos_type_map;
-
-/* This represents the Key to 'sched_qmp_id_map' map.
-Represents (sched_id, pon_intf_id, onu_id, uni_id) */
-typedef std::tuple<uint32_t, uint32_t, uint32_t, uint32_t> sched_qmp_id_map_key_tuple;
-/* 'sched_qmp_id_map' maps sched_qmp_id_map_key_tuple to TM Queue Mapping Profile ID */
-static std::map<sched_qmp_id_map_key_tuple, int> sched_qmp_id_map;
-/* 'qmp_id_to_qmp_map' maps TM Queue Mapping Profile ID to TM Queue Mapping Profile */
-static std::map<int, std::vector < uint32_t > > qmp_id_to_qmp_map;
-
-// Flag used to watch whether mocked alloc_cfg_compltd_key is added to alloc_cfg_compltd_map
-#ifdef TEST_MODE
-bool ALLOC_CFG_FLAG = false;
-#endif
-
-#define ALLOC_CFG_COMPLETE_WAIT_TIMEOUT 1000 // in milli-seconds
-// Map used to track response from BAL for ITU PON Alloc Configuration.
-// The key is alloc_cfg_compltd_key and value is a concurrent thread-safe queue which is
-// used for pushing (from BAL) and popping (at application) the results.
-std::map<alloc_cfg_compltd_key,  Queue<alloc_cfg_complete_result> *> alloc_cfg_compltd_map;
-// Lock to protect critical section data structure used for handling AllocObject configuration response.
-bcmos_fastlock alloc_cfg_wait_lock;
-
-
-/*** ACL Handling related data start ***/
-
-static std::map<acl_classifier_key, uint16_t> acl_classifier_to_acl_id_map;
-
-bool operator<(const acl_classifier_key& a1, const acl_classifier_key& a2)
-{
-    return ((a1.ether_type + 2*a1.ip_proto + 3*a1.src_port + 4*a1.dst_port) <
-            (a2.ether_type + 2*a2.ip_proto + 3*a2.src_port + 4*a2.dst_port));
-}
-
-typedef std::tuple<uint16_t, std::string> flow_id_flow_direction;
-typedef std::tuple<int16_t, uint16_t, int32_t> acl_id_gem_id_intf_id;
-static std::map<flow_id_flow_direction, acl_id_gem_id_intf_id> flow_to_acl_map;
-
-// Keeps a reference count of how many flows are referencing a given ACL ID.
-// Key represents the ACL-ID and value is number of flows referencing the given ACL-ID.
-// When there is at least one flow referencing the ACL-ID, the ACL should be installed.
-// When there are no flows referencing the ACL-ID, the ACL should be removed.
-static std::map<uint16_t, uint16_t> acl_ref_cnt;
-
-typedef std::tuple<uint16_t, uint16_t> gem_id_intf_id; // key to gem_ref_cnt
-// Keeps a reference count of how many ACL related flows are referencing a given (gem-id, pon_intf_id).
-// When there is at least on flow, we should install the gem. When there are no flows
-// the gem should be removed.
-static std::map<gem_id_intf_id, uint16_t> gem_ref_cnt;
-
-// Needed to keep track of how many flows for a given acl_id, intf_id and intf_type are
-// installed. When there is at least on flow for this key, we should have interface registered
-// for the given ACL-ID. When there are no flows, the intf should unregister itself from
-// the ACL-ID.
-typedef std::tuple<uint16_t, uint8_t, std::string> acl_id_intf_id_intf_type;
-static std::map<acl_id_intf_id_intf_type, uint16_t> intf_acl_registration_ref_cnt;
-
-#define MAX_ACL_ID 33
-std::bitset<MAX_ACL_ID> acl_id_bitset;
-
-/*** ACL Handling related data end ***/
-
-std::bitset<MAX_TM_SCHED_ID> tm_sched_bitset;
-std::bitset<MAX_TM_QMP_ID> tm_qmp_bitset;
-
-static bcmos_fastlock data_lock;
-
-
-#define MIN_ALLOC_ID_GPON 256
-#define MIN_ALLOC_ID_XGSPON 1024
-
 static bcmos_errno CreateSched(std::string direction, uint32_t access_intf_id, uint32_t onu_id, uint32_t uni_id, \
                           uint32_t port_no, uint32_t alloc_id, tech_profile::AdditionalBW additional_bw, uint32_t weight, \
                           uint32_t priority, tech_profile::SchedulingPolicy sched_policy,
@@ -233,441 +76,6 @@
 static bcmos_errno CreateDefaultSched(uint32_t intf_id, const std::string direction);
 static bcmos_errno CreateDefaultQueue(uint32_t intf_id, const std::string direction);
 
-uint16_t get_dev_id(void) {
-    return dev_id;
-}
-
-// Stubbed defntions of bcmolt_cfg_get required for unit-test
-#ifdef TEST_MODE
-extern bcmos_errno bcmolt_cfg_get__bal_state_stub(bcmolt_oltid olt_id, void* ptr);
-extern bcmos_errno bcmolt_cfg_get__onu_state_stub(bcmolt_oltid olt_id, void* ptr);
-extern bcmos_errno bcmolt_cfg_get__tm_sched_stub(bcmolt_oltid olt_id, void* ptr);
-extern bcmos_errno bcmolt_cfg_get__pon_intf_stub(bcmolt_oltid olt_id, void* ptr);
-extern bcmos_errno bcmolt_cfg_get__nni_intf_stub(bcmolt_oltid olt_id, void* ptr);
-extern bcmos_errno bcmolt_cfg_get__olt_topology_stub(bcmolt_oltid olt_id, void* ptr);
-extern bcmos_errno bcmolt_cfg_get__flow_stub(bcmolt_oltid olt_id, void* ptr);
-#endif
-/**
-* Returns the default NNI (Upstream direction) or PON (Downstream direction) scheduler
-* Every NNI port and PON port have default scheduler.
-* The NNI0 default scheduler ID is 18432, and NNI1 is 18433 and so on.
-* Similarly, PON0 default scheduler ID is 16384. PON1 is 16385 and so on.
-*
-* @param intf_id NNI or PON interface ID
-* @param direction "upstream" or "downstream"
-*
-* @return default scheduler ID for the given interface.
-*/
-static inline int get_default_tm_sched_id(int intf_id, std::string direction) {
-    if (direction.compare(upstream) == 0) {
-        return tm_upstream_sched_id_start + intf_id;
-    } else if (direction.compare(downstream) == 0) {
-        return tm_downstream_sched_id_start + intf_id;
-    }
-    else {
-        OPENOLT_LOG(ERROR, openolt_log_id, "invalid direction - %s\n", direction.c_str());
-        return 0;
-    }
-}
-
-/**
-* Gets a unique tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction
-* The tm_sched_id is locally cached in a map, so that it can rendered when necessary.
-* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem
-*
-* @param intf_id NNI or PON intf ID
-* @param onu_id ONU ID
-* @param uni_id UNI ID
-* @param gemport_id GEM Port ID
-* @param direction Upstream or downstream
-*
-* @return tm_sched_id
-*/
-uint32_t get_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction) {
-    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction);
-    int sched_id = -1;
-
-    std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
-    if (it != sched_map.end()) {
-        sched_id = it->second;
-    }
-    if (sched_id != -1) {
-        return sched_id;
-    }
-
-    bcmos_fastlock_lock(&data_lock);
-    // Complexity of O(n). Is there better way that can avoid linear search?
-    for (sched_id = 0; sched_id < MAX_TM_SCHED_ID; sched_id++) {
-        if (tm_sched_bitset[sched_id] == 0) {
-            tm_sched_bitset[sched_id] = 1;
-            break;
-        }
-    }
-    bcmos_fastlock_unlock(&data_lock, 0);
-
-    if (sched_id < MAX_TM_SCHED_ID) {
-        bcmos_fastlock_lock(&data_lock);
-        sched_map[key] = sched_id;
-        bcmos_fastlock_unlock(&data_lock, 0);
-        return sched_id;
-    } else {
-        return -1;
-    }
-}
-
-/**
-* Free tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction
-*
-* @param intf_id NNI or PON intf ID
-* @param onu_id ONU ID
-* @param uni_id UNI ID
-* @param gemport_id GEM Port ID
-* @param direction Upstream or downstream
-*/
-void free_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction) {
-    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction);
-    std::map<sched_map_key_tuple, int>::const_iterator it;
-    bcmos_fastlock_lock(&data_lock);
-    it = sched_map.find(key);
-    if (it != sched_map.end()) {
-        tm_sched_bitset[it->second] = 0;
-        sched_map.erase(it);
-    }
-    bcmos_fastlock_unlock(&data_lock, 0);
-}
-
-bool is_tm_sched_id_present(int pon_intf_id, int onu_id, int uni_id, std::string direction) {
-    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction);
-    std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
-    if (it != sched_map.end()) {
-        return true;
-    }
-    return false;
-}
-
-/**
-* Check whether given two tm qmp profiles are equal or not
-*
-* @param tmq_map_profileA <vector> TM QUEUE MAPPING PROFILE
-* @param tmq_map_profileB <vector> TM QUEUE MAPPING PROFILE
-*
-* @return boolean, true if given tmq_map_profiles are equal else false
-*/
-
-bool check_tm_qmp_equality(std::vector<uint32_t> tmq_map_profileA, std::vector<uint32_t> tmq_map_profileB) {
-    for (uint32_t i = 0; i < TMQ_MAP_PROFILE_SIZE; i++) {
-        if (tmq_map_profileA[i] != tmq_map_profileB[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-/**
-* Modifies given queues_pbit_map to parsable format
-* e.g: Modifes "0b00000101" to "10100000"
-*
-* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
-* @param size Queue count
-*
-* @return string queues_pbit_map
-*/
-std::string* get_valid_queues_pbit_map(std::string *queues_pbit_map, uint32_t size) {
-    for(uint32_t i=0; i < size; i++) {
-        /* Deletes 2 characters from index number 0 */
-        queues_pbit_map[i].erase(0, 2);
-        std::reverse(queues_pbit_map[i].begin(), queues_pbit_map[i].end());
-    }
-    return queues_pbit_map;
-}
-
-/**
-* Creates TM QUEUE MAPPING PROFILE for given queues_pbit_map and queues_priority_q
-*
-* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
-* @param queues_priority_q PRIORITY_Q configured for each GEM in TECH PROFILE
-* @param size Queue count
-*
-* @return <vector> TM QUEUE MAPPING PROFILE
-*/
-std::vector<uint32_t> get_tmq_map_profile(std::string *queues_pbit_map, uint32_t *queues_priority_q, uint32_t size) {
-    std::vector<uint32_t> tmq_map_profile(8,0);
-
-    for(uint32_t i=0; i < size; i++) {
-        for (uint32_t j = 0; j < queues_pbit_map[i].size(); j++) {
-            if (queues_pbit_map[i][j]=='1') {
-                tmq_map_profile.at(j) = queue_id_list[queues_priority_q[i]];
-            }
-        }
-    }
-    return tmq_map_profile;
-}
-
-/**
-* Gets corresponding tm_qmp_id for a given tmq_map_profile
-*
-* @param <vector> TM QUEUE MAPPING PROFILE
-*
-* @return tm_qmp_id
-*/
-int get_tm_qmp_id(std::vector<uint32_t> tmq_map_profile) {
-    int tm_qmp_id = -1;
-
-    std::map<int, std::vector < uint32_t > >::const_iterator it = qmp_id_to_qmp_map.begin();
-    while(it != qmp_id_to_qmp_map.end()) {
-        if(check_tm_qmp_equality(tmq_map_profile, it->second)) {
-            tm_qmp_id = it->first;
-            break;
-        }
-        it++;
-    }
-    return tm_qmp_id;
-}
-
-/**
-* Updates sched_qmp_id_map with given sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id
-*
-* @param upstream/downstream sched_id
-* @param PON intf ID
-* @param onu_id ONU ID
-* @param uni_id UNI ID
-* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
-*/
-void update_sched_qmp_id_map(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
-                             uint32_t uni_id, int tm_qmp_id) {
-   bcmos_fastlock_lock(&data_lock);
-   sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
-   sched_qmp_id_map.insert(make_pair(key, tm_qmp_id));
-   bcmos_fastlock_unlock(&data_lock, 0);
-}
-
-/**
-* Gets corresponding tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
-*
-* @param upstream/downstream sched_id
-* @param PON intf ID
-* @param onu_id ONU ID
-* @param uni_id UNI ID
-*
-* @return tm_qmp_id
-*/
-int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
-    sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
-    int tm_qmp_id = -1;
-
-    std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
-    if (it != sched_qmp_id_map.end()) {
-        tm_qmp_id = it->second;
-    }
-    return tm_qmp_id;
-}
-
-/**
-* Gets a unique tm_qmp_id for a given tmq_map_profile
-* The tm_qmp_id is locally cached in a map, so that it can be rendered when necessary.
-* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem
-*
-* @param upstream/downstream sched_id
-* @param PON intf ID
-* @param onu_id ONU ID
-* @param uni_id UNI ID
-* @param <vector> TM QUEUE MAPPING PROFILE
-*
-* @return tm_qmp_id
-*/
-int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, \
-                  std::vector<uint32_t> tmq_map_profile) {
-    int tm_qmp_id;
-
-    bcmos_fastlock_lock(&data_lock);
-    /* Complexity of O(n). Is there better way that can avoid linear search? */
-    for (tm_qmp_id = 0; tm_qmp_id < MAX_TM_QMP_ID; tm_qmp_id++) {
-        if (tm_qmp_bitset[tm_qmp_id] == 0) {
-            tm_qmp_bitset[tm_qmp_id] = 1;
-            break;
-        }
-    }
-    bcmos_fastlock_unlock(&data_lock, 0);
-
-    if (tm_qmp_id < MAX_TM_QMP_ID) {
-        bcmos_fastlock_lock(&data_lock);
-        qmp_id_to_qmp_map.insert(make_pair(tm_qmp_id, tmq_map_profile));
-        bcmos_fastlock_unlock(&data_lock, 0);
-        update_sched_qmp_id_map(sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id);
-        return tm_qmp_id;
-    } else {
-        return -1;
-    }
-}
-
-/**
-* Free tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
-*
-* @param upstream/downstream sched_id
-* @param PON intf ID
-* @param onu_id ONU ID
-* @param uni_id UNI ID
-* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
-*
-* @return boolean, true if no more reference for TM QMP else false
-*/
-bool free_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
-                    uint32_t uni_id, int tm_qmp_id) {
-    bool result;
-    sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
-    std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
-    bcmos_fastlock_lock(&data_lock);
-    if (it != sched_qmp_id_map.end()) {
-        sched_qmp_id_map.erase(it);
-    }
-    bcmos_fastlock_unlock(&data_lock, 0);
-
-    uint32_t tm_qmp_ref_count = 0;
-    std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it2 = sched_qmp_id_map.begin();
-    while(it2 != sched_qmp_id_map.end()) {
-        if(it2->second == tm_qmp_id) {
-            tm_qmp_ref_count++;
-        }
-        it2++;
-    }
-
-    if (tm_qmp_ref_count == 0) {
-        std::map<int, std::vector < uint32_t > >::const_iterator it3 = qmp_id_to_qmp_map.find(tm_qmp_id);
-        if (it3 != qmp_id_to_qmp_map.end()) {
-            bcmos_fastlock_lock(&data_lock);
-            tm_qmp_bitset[tm_qmp_id] = 0;
-            qmp_id_to_qmp_map.erase(it3);
-            bcmos_fastlock_unlock(&data_lock, 0);
-            OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So clearing it\n", \
-                        tm_qmp_id, tm_qmp_ref_count);
-            result = true;
-        }
-    } else {
-        OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So not clearing it\n", \
-                    tm_qmp_id, tm_qmp_ref_count);
-        result = false;
-    }
-    return result;
-}
-
-// Gets free ACL ID if available, else -1
-int get_acl_id() {
-    int acl_id;
-    bcmos_fastlock_lock(&data_lock);
-    /* Complexity of O(n). Is there better way that can avoid linear search? */
-    for (acl_id = 0; acl_id < MAX_ACL_ID; acl_id++) {
-        if (acl_id_bitset[acl_id] == 0) {
-            acl_id_bitset[acl_id] = 1;
-            break;
-        }
-    }
-    bcmos_fastlock_unlock(&data_lock, 0);
-    if (acl_id < MAX_ACL_ID) {
-        return acl_id ;
-    } else {
-        return -1;
-    }
-}
-
-// Frees up the ACL ID.
-void free_acl_id (int acl_id) {
-    if (acl_id < MAX_ACL_ID) {
-        bcmos_fastlock_lock(&data_lock);
-        acl_id_bitset[acl_id] = 0;
-        bcmos_fastlock_unlock(&data_lock, 0);
-    }
-}
-
-/**
-* Returns qos type as string
-*
-* @param qos_type bcmolt_egress_qos_type enum
-*/
-std::string get_qos_type_as_string(bcmolt_egress_qos_type qos_type) {
-    switch (qos_type)
-    {
-        case BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE: return "FIXED_QUEUE";
-        case BCMOLT_EGRESS_QOS_TYPE_TC_TO_QUEUE: return "TC_TO_QUEUE";
-        case BCMOLT_EGRESS_QOS_TYPE_PBIT_TO_TC: return "PBIT_TO_TC";
-        case BCMOLT_EGRESS_QOS_TYPE_NONE: return "NONE";
-        case BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE: return "PRIORITY_TO_QUEUE";
-        default: OPENOLT_LOG(ERROR, openolt_log_id, "qos-type-not-supported %d\n", qos_type);
-                 return "qos-type-not-supported";
-    }
-}
-
-/**
-* Gets/Updates qos type for given pon_intf_id, onu_id, uni_id
-*
-* @param PON intf ID
-* @param onu_id ONU ID
-* @param uni_id UNI ID
-* @param queue_size TrafficQueues Size
-*
-* @return qos_type
-*/
-bcmolt_egress_qos_type get_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, uint32_t queue_size = 0) {
-    qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
-    bcmolt_egress_qos_type egress_qos_type = BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
-    std::string qos_string;
-
-    std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
-    if (it != qos_type_map.end()) {
-        egress_qos_type = it->second;
-        qos_string = get_qos_type_as_string(egress_qos_type);
-        OPENOLT_LOG(INFO, openolt_log_id, "Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d is %s\n", \
-                    pon_intf_id, onu_id, uni_id, qos_string.c_str());
-    }
-    else {
-        /* QOS Type has been pre-defined as Fixed Queue but it will be updated based on number of GEMPORTS
-           associated for a given subscriber. If GEM count = 1 for a given subscriber, qos_type will be Fixed Queue
-           else Priority to Queue */
-        egress_qos_type = (queue_size > 1) ? \
-            BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE : BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
-        bcmos_fastlock_lock(&data_lock);
-        qos_type_map.insert(make_pair(key, egress_qos_type));
-        bcmos_fastlock_unlock(&data_lock, 0);
-        qos_string = get_qos_type_as_string(egress_qos_type);
-        OPENOLT_LOG(INFO, openolt_log_id, "Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d is %s\n", \
-                    pon_intf_id, onu_id, uni_id, qos_string.c_str());
-    }
-    return egress_qos_type;
-}
-
-/**
-* Clears qos type for given pon_intf_id, onu_id, uni_id
-*
-* @param PON intf ID
-* @param onu_id ONU ID
-* @param uni_id UNI ID
-*/
-void clear_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
-    qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
-    std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
-    bcmos_fastlock_lock(&data_lock);
-    if (it != qos_type_map.end()) {
-        qos_type_map.erase(it);
-        OPENOLT_LOG(INFO, openolt_log_id, "Cleared Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d\n", \
-                    pon_intf_id, onu_id, uni_id);
-    }
-    bcmos_fastlock_unlock(&data_lock, 0);
-}
-
-/**
-* Returns Scheduler/Queue direction as string
-*
-* @param direction as specified in tech_profile.proto
-*/
-std::string GetDirection(int direction) {
-    switch (direction)
-    {
-        case tech_profile::Direction::UPSTREAM: return upstream;
-        case tech_profile::Direction::DOWNSTREAM: return downstream;
-        default: OPENOLT_LOG(ERROR, openolt_log_id, "direction-not-supported %d\n", direction);
-                 return "direction-not-supported";
-    }
-}
-
 inline const char *get_flow_acton_command(uint32_t command) {
     char actions[200] = { };
     char *s_actions_ptr = actions;
@@ -682,95 +90,6 @@
     return s_actions_ptr;
 }
 
-// This method handles waiting for AllocObject configuration.
-// Returns error if the AllocObject is not in the appropriate state based on action requested.
-bcmos_errno wait_for_alloc_action(uint32_t intf_id, uint32_t alloc_id, AllocCfgAction action) {
-    Queue<alloc_cfg_complete_result> cfg_result;
-    alloc_cfg_compltd_key k(intf_id, alloc_id);
-    alloc_cfg_compltd_map[k] =  &cfg_result;
-    bcmos_errno err = BCM_ERR_OK;
-    #ifdef TEST_MODE
-    ALLOC_CFG_FLAG = true;
-    #endif
-
-    // Try to pop the result from BAL with a timeout of ALLOC_CFG_COMPLETE_WAIT_TIMEOUT ms
-    std::pair<alloc_cfg_complete_result, bool> result = cfg_result.pop(ALLOC_CFG_COMPLETE_WAIT_TIMEOUT);
-    if (result.second == false) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for alloc cfg complete indication intf_id %d, alloc_id %d\n",
-                    intf_id, alloc_id);
-        // Invalidate the queue pointer.
-        bcmos_fastlock_lock(&alloc_cfg_wait_lock);
-        alloc_cfg_compltd_map[k] = NULL;
-        bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
-        err = BCM_ERR_INTERNAL;
-        #ifdef TEST_MODE
-        ALLOC_CFG_FLAG = false;
-        #endif
-    }
-    else if (result.first.status == ALLOC_CFG_STATUS_FAIL) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "error processing alloc cfg request intf_id %d, alloc_id %d\n",
-                    intf_id, alloc_id);
-        err = BCM_ERR_INTERNAL;
-    }
-
-    if (err == BCM_ERR_OK) {
-        if (action == ALLOC_OBJECT_CREATE) {
-            if (result.first.state != ALLOC_OBJECT_STATE_ACTIVE) {
-                OPENOLT_LOG(ERROR, openolt_log_id, "alloc object not in active state intf_id %d, alloc_id %d alloc_obj_state %d\n",
-                            intf_id, alloc_id, result.first.state);
-               err = BCM_ERR_INTERNAL;
-            } else {
-                OPENOLT_LOG(INFO, openolt_log_id, "Create upstream bandwidth allocation success, intf_id %d, alloc_id %d\n",
-                            intf_id, alloc_id);
-            }
-        } else { // ALLOC_OBJECT_DELETE
-              if (result.first.state != ALLOC_OBJECT_STATE_NOT_CONFIGURED) {
-                  OPENOLT_LOG(ERROR, openolt_log_id, "alloc object is not reset intf_id %d, alloc_id %d alloc_obj_state %d\n",
-                              intf_id, alloc_id, result.first.state);
-                  err = BCM_ERR_INTERNAL;
-              } else {
-                  OPENOLT_LOG(INFO, openolt_log_id, "Remove alloc object success, intf_id %d, alloc_id %d\n",
-                              intf_id, alloc_id);
-              }
-        }
-    }
-
-    // Remove entry from map
-    bcmos_fastlock_lock(&alloc_cfg_wait_lock);
-    alloc_cfg_compltd_map.erase(k);
-    bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
-    #ifdef TEST_MODE
-    ALLOC_CFG_FLAG = false;
-    #endif
-    return err;
-}
-
-char* openolt_read_sysinfo(const char* field_name, char* field_val)
-{
-   FILE *fp;
-   /* Prepare the command*/
-   char command[150];
-
-   snprintf(command, sizeof command, "bash -l -c \"onlpdump -s\" | perl -ne 'print $1 if /%s: (\\S+)/'", field_name);
-   /* Open the command for reading. */
-   fp = popen(command, "r");
-   if (fp == NULL) {
-       /*The client has to check for a Null field value in this case*/
-       OPENOLT_LOG(INFO, openolt_log_id,  "Failed to query the %s\n", field_name);
-       return field_val;
-   }
-
-   /*Read the field value*/
-   if (fp) {
-       uint8_t ret;
-       ret = fread(field_val, OPENOLT_FIELD_LEN, 1, fp);
-       if (ret >= OPENOLT_FIELD_LEN)
-           OPENOLT_LOG(INFO, openolt_log_id,  "Read data length %u\n", ret);
-       pclose(fp);
-   }
-   return field_val;
-}
-
 Status GetDeviceInfo_(openolt::DeviceInfo* device_info) {
     device_info->set_vendor(VENDOR_ID);
     device_info->set_model(MODEL_ID);
@@ -894,104 +213,6 @@
     return Status::OK;
 }
 
-Status pushOltOperInd(uint32_t intf_id, const char *type, const char *state)
-{
-    openolt::Indication ind;
-    openolt::IntfOperIndication* intf_oper_ind = new openolt::IntfOperIndication;
-
-    intf_oper_ind->set_type(type);
-    intf_oper_ind->set_intf_id(intf_id);
-    intf_oper_ind->set_oper_state(state);
-    ind.set_allocated_intf_oper_ind(intf_oper_ind);
-    oltIndQ.push(ind);
-    return Status::OK;
-}
-
-#define CLI_HOST_PROMPT_FORMAT "BCM.%u> "
-
-/* Build CLI prompt */
-static void openolt_cli_get_prompt_cb(bcmcli_session *session, char *buf, uint32_t max_len)
-{
-    snprintf(buf, max_len, CLI_HOST_PROMPT_FORMAT, dev_id);
-}
-
-static int _bal_apiend_cli_thread_handler(long data)
-{
-    char init_string[]="\n";
-    bcmcli_session *sess = current_session;
-    bcmos_task_parm bal_cli_task_p_dummy;
-
-    /* Switch to interactive mode if not stopped in the init script */
-    if (!bcmcli_is_stopped(sess)) {
-        /* Force a CLI command prompt
-         * The string passed into the parse function
-         * must be modifiable, so a string constant like
-         * bcmcli_parse(current_session, "\n") will not
-         * work.
-         */
-        bcmcli_parse(sess, init_string);
-
-        /* Process user input until EOF or quit command */
-        bcmcli_driver(sess);
-    }
-    OPENOLT_LOG(INFO, openolt_log_id, "BAL API End CLI terminated\n");
-
-    /* Cleanup */
-    bcmcli_session_close(current_session);
-    bcmcli_token_destroy(NULL);
-    return 0;
-}
-
-/* Init API CLI commands for the current device */
-bcmos_errno bcm_openolt_api_cli_init(bcmcli_entry *parent_dir, bcmcli_session *session)
-{
-    bcmos_errno rc;
-
-    api_parent_dir = parent_dir;
-
-    rc = bcm_api_cli_set_commands(session);
-
-#ifdef BCM_SUBSYSTEM_HOST
-    /* Subscribe for device change indication */
-    rc = rc ? rc : bcmolt_olt_sel_ind_register(_api_cli_olt_change_ind);
-#endif
-
-    return rc;
-}
-
-static bcmos_errno bcm_cli_quit(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
-{
-    bcmcli_stop(session);
-    bcmcli_session_print(session, "CLI terminated by 'Quit' command\n");
-    status_bcm_cli_quit = BCMOS_TRUE;
-
-    return BCM_ERR_OK;
-}
-
-int get_status_bcm_cli_quit(void) {
-     return status_bcm_cli_quit;
-}
-
-bcmos_errno bcmolt_apiend_cli_init() {
-    bcmos_errno ret;
-    bcmos_task_parm bal_cli_task_p = {};
-    bcmos_task_parm bal_cli_task_p_dummy;
-
-    /** before creating the task, check if it is already created by the other half of BAL i.e. Core side */
-    if (BCM_ERR_OK != bcmos_task_query(&bal_cli_thread, &bal_cli_task_p_dummy)) {
-        /* Create BAL CLI thread */
-        bal_cli_task_p.name = bal_cli_thread_name;
-        bal_cli_task_p.handler = _bal_apiend_cli_thread_handler;
-        bal_cli_task_p.priority = TASK_PRIORITY_CLI;
-
-        ret = bcmos_task_create(&bal_cli_thread, &bal_cli_task_p);
-        if (BCM_ERR_OK != ret) {
-            bcmos_printf("Couldn't create BAL API end CLI thread\n");
-            return ret;
-        }
-    }
-}
-
 Status Enable_(int argc, char *argv[]) {
     bcmos_errno err;
     bcmolt_host_init_parms init_parms = {};
@@ -1162,29 +383,6 @@
     return grpc::Status(grpc::StatusCode::UNKNOWN, "failed to re-enable olt ,few PON ports are still in disabled state");
 }
 
-bcmos_errno get_pon_interface_status(bcmolt_interface pon_ni, bcmolt_interface_state *state) {
-    bcmos_errno err;
-    bcmolt_pon_interface_key pon_key;
-    bcmolt_pon_interface_cfg pon_cfg;
-    pon_key.pon_ni = pon_ni;
-
-    BCMOLT_CFG_INIT(&pon_cfg, pon_interface, pon_key);
-    BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, state);
-    BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, itu);
-    #ifdef TEST_MODE
-    // It is impossible to mock the setting of pon_cfg.data.state because
-    // the actual bcmolt_cfg_get passes the address of pon_cfg.hdr and we cannot
-    // set the pon_cfg.data.state. So a new stub function is created and address
-    // of pon_cfg is passed. This is one-of case where we need to add test specific
-    // code in production code.
-    err = bcmolt_cfg_get__pon_intf_stub(dev_id, &pon_cfg);
-    #else
-    err = bcmolt_cfg_get(dev_id, &pon_cfg.hdr);
-    #endif
-    *state = pon_cfg.data.state;
-    return err;
-}
-
 inline uint64_t get_flow_status(uint16_t flow_id, uint16_t flow_type, uint16_t data_id) {
     bcmos_errno err;
     bcmolt_flow_key flow_key;
@@ -1600,36 +798,6 @@
     return Status::OK;
 }
 
-/* Same as bcmolt_cfg_get but with added logic of retrying the API
-   in case of some specific failures like timeout or object not yet ready
-*/
-bcmos_errno bcmolt_cfg_get_mult_retry(bcmolt_oltid olt, bcmolt_cfg *cfg) {
-    bcmos_errno err;
-    uint32_t current_try = 0;
-
-    while (current_try < MAX_BAL_API_RETRY_COUNT) {
-        err = bcmolt_cfg_get(olt, cfg);
-        current_try++;
-
-        if (err == BCM_ERR_STATE || err == BCM_ERR_TIMEOUT) {
-            OPENOLT_LOG(WARNING, openolt_log_id, "bcmolt_cfg_get: err = %s\n", bcmos_strerror(err));
-            bcmos_usleep(BAL_API_RETRY_TIME_IN_USECS);
-            continue;
-        }
-        else {
-           break;
-        }
-    }
-
-    if (err != BCM_ERR_OK) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "bcmolt_cfg_get tried (%d) times with retry time(%d usecs) err = %s\n",
-                           current_try,
-                           BAL_API_RETRY_TIME_IN_USECS,
-                           bcmos_strerror(err));
-    }
-    return err;
-}
-
 Status ProbeDeviceCapabilities_() {
     bcmos_errno err;
     bcmolt_device_cfg dev_cfg = { };
@@ -1727,87 +895,6 @@
 
     return Status::OK;
 }
-#if 0
-Status ProbePonIfTechnology_() {
-    // Probe maximum extent possible as configured into BAL driver to determine
-    // which are active in the current BAL topology. And for those
-    // that are active, determine each port's access technology, i.e. "gpon" or "xgspon".
-    for (uint32_t intf_id = 0; intf_id < num_of_pon_ports; ++intf_id) {
-        bcmolt_pon_interface_cfg interface_obj;
-        bcmolt_pon_interface_key interface_key;
-
-        interface_key.pon_ni = intf_id;
-        BCMOLT_CFG_INIT(&interface_obj, pon_interface, interface_key);
-        if (board_technology == "XGS-PON"
-            BCMOLT_MSG_FIELD_GET(&interface_obj, xgs_ngpon2_trx);
-        else if (board_technology == "GPON")
-            BCMOLT_MSG_FIELD_GET(&interface_obj, gpon_trx);
-
-        bcmos_errno err = bcmolt_cfg_get(dev_id, &interface_obj.hdr);
-        if (err != BCM_ERR_OK) {
-            intf_technologies[intf_id] = UNKNOWN_TECH;
-            if(err != BCM_ERR_RANGE) OPENOLT_LOG(ERROR, openolt_log_id, "Failed to get PON config: %d err %d\n", intf_id, err);
-        }
-        else {
-            if (board_technology == "XGS-PON") {
-                switch(interface_obj.data.xgpon_trx.transceiver_type) {
-                    case BCMOLT_XGPON_TRX_TYPE_LTH_7222_PC:
-                    case BCMOLT_XGPON_TRX_TYPE_WTD_RTXM266_702:
-                    case BCMOLT_XGPON_TRX_TYPE_LTH_7222_BC_PLUS:
-                    case BCMOLT_XGPON_TRX_TYPE_LTH_7226_PC:
-                    case BCMOLT_XGPON_TRX_TYPE_LTH_5302_PC:
-                    case BCMOLT_XGPON_TRX_TYPE_LTH_7226_A_PC_PLUS:
-                    case BCMOLT_XGPON_TRX_TYPE_D272RR_SSCB_DM:
-                        intf_technologies[intf_id] = "XGS-PON";
-                        break;
-                }
-            } else if (board_technology == "GPON") {
-                switch(interface_obj.data.gpon_trx.transceiver_type) {
-                    case BCMOLT_TRX_TYPE_SPS_43_48_H_HP_CDE_SD_2013:
-                    case BCMOLT_TRX_TYPE_LTE_3680_M:
-                    case BCMOLT_TRX_TYPE_SOURCE_PHOTONICS:
-                    case BCMOLT_TRX_TYPE_LTE_3680_P_TYPE_C_PLUS:
-                    case BCMOLT_TRX_TYPE_LTE_3680_P_BC:
-                        intf_technologies[intf_id] = "GPON";
-                        break;
-                }
-            }
-
-            if (board_technology != UNKNOWN_TECH) {
-                board_technology = intf_technologies[intf_id];
-            } else if (board_technology != MIXED_TECH && board_technology != intf_technologies[intf_id]) {
-                intf_technologies[intf_id] = MIXED_TECH;
-            }
-
-        }
-    }
-    return Status::OK;
-}
-#endif
-unsigned NumNniIf_() {return num_of_nni_ports;}
-unsigned NumPonIf_() {return num_of_pon_ports;}
-
-bcmos_errno get_nni_interface_status(bcmolt_interface id, bcmolt_interface_state *state) {
-    bcmos_errno err;
-    bcmolt_nni_interface_key nni_key;
-    bcmolt_nni_interface_cfg nni_cfg;
-    nni_key.id = id;
-
-    BCMOLT_CFG_INIT(&nni_cfg, nni_interface, nni_key);
-    BCMOLT_FIELD_SET_PRESENT(&nni_cfg.data, nni_interface_cfg_data, state);
-    #ifdef TEST_MODE
-    // It is impossible to mock the setting of nni_cfg.data.state because
-    // the actual bcmolt_cfg_get passes the address of nni_cfg.hdr and we cannot
-    // set the nni_cfg.data.state. So a new stub function is created and address
-    // of nni_cfg is passed. This is one-of case where we need to add test specific
-    // code in production code.
-    err = bcmolt_cfg_get__nni_intf_stub(dev_id, &nni_cfg);
-    #else
-    err = bcmolt_cfg_get(dev_id, &nni_cfg.hdr);
-    #endif
-    *state = nni_cfg.data.state;
-    return err;
-}
 
 Status SetStateUplinkIf_(uint32_t intf_id, bool set_state) {
     bcmos_errno err = BCM_ERR_OK;
@@ -2195,492 +1282,6 @@
 
     return Status::OK;
 }
-
-uint32_t GetPortNum_(uint32_t flow_id) {
-    bcmos_fastlock_lock(&data_lock);
-    uint32_t port_no = 0;
-    std::map<uint32_t, uint32_t >::const_iterator it = flowid_to_port.find(flow_id);
-    if (it != flowid_to_port.end()) {
-        port_no = it->second;
-    }
-    bcmos_fastlock_unlock(&data_lock, 0);
-    return port_no;
-}
-
-#define ACL_LOG(level,msg,err) \
-    do { \
-    OPENOLT_LOG(level, openolt_log_id, "--------> %s (acl_id %d) err: %d <--------\n", msg, key.id, err); \
-    OPENOLT_LOG(level, openolt_log_id, "action_type %s\n", \
-        GET_ACL_ACTION_TYPE(action_type)); \
-    OPENOLT_LOG(level, openolt_log_id, "classifier(ether type %d), ip_proto %d, src_port %d, dst_port %d\n", \
-        acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port); \
-    } while(0)
-
-#define FLOW_LOG(level,msg,err) \
-    do { \
-    OPENOLT_LOG(level, openolt_log_id, "--------> %s (flow_id %d) err: %d <--------\n", msg, key.flow_id, err); \
-    OPENOLT_LOG(level, openolt_log_id, "intf_id %d, onu_id %d, uni_id %d, port_no %u, cookie %"PRIu64"\n", \
-        access_intf_id, onu_id, uni_id, port_no, cookie); \
-    OPENOLT_LOG(level, openolt_log_id, "flow_type %s, queue_id %d, sched_id %d\n", flow_type.c_str(), \
-        cfg.data.egress_qos.u.fixed_queue.queue_id, cfg.data.egress_qos.tm_sched.id); \
-    OPENOLT_LOG(level, openolt_log_id, "Ingress(intfd_type %s, intf_id %d), Egress(intf_type %s, intf_id %d)\n", \
-        GET_FLOW_INTERFACE_TYPE(cfg.data.ingress_intf.intf_type), cfg.data.ingress_intf.intf_id,  \
-        GET_FLOW_INTERFACE_TYPE(cfg.data.egress_intf.intf_type), cfg.data.egress_intf.intf_id); \
-    OPENOLT_LOG(level, openolt_log_id, "classifier(o_vid %d, o_pbits %d, i_vid %d, i_pbits %d, ether type 0x%x)\n", \
-        c_val.o_vid, c_val.o_pbits, c_val.i_vid, c_val.i_pbits,  classifier.eth_type()); \
-    OPENOLT_LOG(level, openolt_log_id, "classifier(ip_proto 0x%x, gemport_id %d, src_port %d, dst_port %d, pkt_tag_type %s)\n", \
-        c_val.ip_proto, gemport_id, c_val.src_port,  c_val.dst_port, GET_PKT_TAG_TYPE(c_val.pkt_tag_type)); \
-    OPENOLT_LOG(level, openolt_log_id, "action(cmds_bitmask %s, o_vid %d, o_pbits %d, i_vid %d, i_pbits %d)\n\n", \
-        get_flow_acton_command(a_val.cmds_bitmask), a_val.o_vid, a_val.o_pbits, a_val.i_vid, a_val.i_pbits); \
-    } while(0)
-
-#define FLOW_PARAM_LOG() \
-    do { \
-    OPENOLT_LOG(INFO, openolt_log_id, "--------> flow comparison (now before) <--------\n"); \
-    OPENOLT_LOG(INFO, openolt_log_id, "flow_id (%d %d)\n", \
-        key.flow_id, it->first.first); \
-    OPENOLT_LOG(INFO, openolt_log_id, "onu_id (%d %lu)\n", \
-        cfg.data.onu_id , get_flow_status(it->first.first, it->first.second, ONU_ID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "type (%d %lu)\n", \
-        key.flow_type, get_flow_status(it->first.first, it->first.second, FLOW_TYPE)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "svc_port_id (%d %lu)\n", \
-        cfg.data.svc_port_id, get_flow_status(it->first.first, it->first.second, SVC_PORT_ID));  \
-    OPENOLT_LOG(INFO, openolt_log_id, "priority (%d %lu)\n", \
-        cfg.data.priority, get_flow_status(it->first.first, it->first.second, PRIORITY)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "cookie (%lu %lu)\n", \
-        cfg.data.cookie, get_flow_status(it->first.first, it->first.second, COOKIE)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "ingress intf_type (%s %s)\n", \
-        GET_FLOW_INTERFACE_TYPE(cfg.data.ingress_intf.intf_type), \
-        GET_FLOW_INTERFACE_TYPE(get_flow_status(it->first.first, it->first.second, INGRESS_INTF_TYPE))); \
-    OPENOLT_LOG(INFO, openolt_log_id, "ingress intf id (%d %lu)\n", \
-        cfg.data.ingress_intf.intf_id , get_flow_status(it->first.first, it->first.second, INGRESS_INTF_ID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "egress intf_type (%d %lu)\n", \
-        cfg.data.egress_intf.intf_type , get_flow_status(it->first.first, it->first.second, EGRESS_INTF_TYPE)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "egress intf_id (%d %lu)\n", \
-        cfg.data.egress_intf.intf_id , get_flow_status(it->first.first, it->first.second, EGRESS_INTF_ID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier o_vid (%d %lu)\n", \
-        c_val.o_vid , get_flow_status(it->first.first, it->first.second, CLASSIFIER_O_VID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier o_pbits (%d %lu)\n", \
-        c_val.o_pbits , get_flow_status(it->first.first, it->first.second, CLASSIFIER_O_PBITS)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier i_vid (%d %lu)\n", \
-        c_val.i_vid , get_flow_status(it->first.first, it->first.second, CLASSIFIER_I_VID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier i_pbits (%d %lu)\n", \
-        c_val.i_pbits , get_flow_status(it->first.first, it->first.second, CLASSIFIER_I_PBITS)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier ether_type (0x%x 0x%lx)\n", \
-        c_val.ether_type , get_flow_status(it->first.first, it->first.second, CLASSIFIER_ETHER_TYPE));  \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier ip_proto (%d %lu)\n", \
-        c_val.ip_proto , get_flow_status(it->first.first, it->first.second, CLASSIFIER_IP_PROTO)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier src_port (%d %lu)\n", \
-        c_val.src_port , get_flow_status(it->first.first, it->first.second, CLASSIFIER_SRC_PORT)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier dst_port (%d %lu)\n", \
-        c_val.dst_port , get_flow_status(it->first.first, it->first.second, CLASSIFIER_DST_PORT)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier pkt_tag_type (%s %s)\n", \
-        GET_PKT_TAG_TYPE(c_val.pkt_tag_type), \
-        GET_PKT_TAG_TYPE(get_flow_status(it->first.first, it->first.second, CLASSIFIER_PKT_TAG_TYPE))); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier egress_qos type (%d %lu)\n", \
-        cfg.data.egress_qos.type , get_flow_status(it->first.first, it->first.second, EGRESS_QOS_TYPE)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier egress_qos queue_id (%d %lu)\n", \
-        cfg.data.egress_qos.u.fixed_queue.queue_id, \
-        get_flow_status(it->first.first, it->first.second, EGRESS_QOS_QUEUE_ID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier egress_qos sched_id (%d %lu)\n", \
-        cfg.data.egress_qos.tm_sched.id, \
-        get_flow_status(it->first.first, it->first.second, EGRESS_QOS_TM_SCHED_ID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "classifier cmds_bitmask (%s %s)\n", \
-        get_flow_acton_command(a_val.cmds_bitmask), \
-        get_flow_acton_command(get_flow_status(it->first.first, it->first.second, ACTION_CMDS_BITMASK))); \
-    OPENOLT_LOG(INFO, openolt_log_id, "action o_vid (%d %lu)\n", \
-        a_val.o_vid , get_flow_status(it->first.first, it->first.second, ACTION_O_VID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "action i_vid (%d %lu)\n", \
-        a_val.i_vid , get_flow_status(it->first.first, it->first.second, ACTION_I_VID)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "action o_pbits (%d %lu)\n", \
-        a_val.o_pbits , get_flow_status(it->first.first, it->first.second, ACTION_O_PBITS)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "action i_pbits (%d %lu)\n\n", \
-        a_val.i_pbits, get_flow_status(it->first.first, it->first.second, ACTION_I_PBITS)); \
-    OPENOLT_LOG(INFO, openolt_log_id, "group_id (%d %lu)\n\n", \
-        a_val.group_id, get_flow_status(it->first.first, it->first.second, GROUP_ID)); \
-    } while(0)
-
-#define FLOW_CHECKER
-//#define SHOW_FLOW_PARAM
-
-Status install_gem_port(int32_t intf_id, int32_t onu_id, int32_t gemport_id) {
-    bcmos_errno err;
-    bcmolt_itupon_gem_cfg cfg; /* declare main API struct */
-    bcmolt_itupon_gem_key key = {}; /* declare key */
-    bcmolt_gem_port_configuration configuration = {};
-
-    key.pon_ni = intf_id;
-    key.gem_port_id = gemport_id;
-
-    BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
-
-    bcmolt_gem_port_direction configuration_direction;
-    configuration_direction = BCMOLT_GEM_PORT_DIRECTION_BIDIRECTIONAL;
-    BCMOLT_FIELD_SET(&configuration, gem_port_configuration, direction, configuration_direction);
-
-    bcmolt_gem_port_type configuration_type;
-    configuration_type = BCMOLT_GEM_PORT_TYPE_UNICAST;
-    BCMOLT_FIELD_SET(&configuration, gem_port_configuration, type, configuration_type);
-
-    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, configuration, configuration);
-
-    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, onu_id, onu_id);
-
-    bcmolt_control_state encryption_mode;
-    encryption_mode = BCMOLT_CONTROL_STATE_DISABLE;
-    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
-
-    bcmolt_us_gem_port_destination upstream_destination_queue;
-    upstream_destination_queue = BCMOLT_US_GEM_PORT_DESTINATION_DATA;
-    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, upstream_destination_queue, upstream_destination_queue);
-
-    bcmolt_control_state control;
-    control = BCMOLT_CONTROL_STATE_ENABLE;
-    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, control, control);
-
-    err = bcmolt_cfg_set(dev_id, &cfg.hdr);
-    if(err != BCM_ERR_OK) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "failed to install gem_port = %d\n", gemport_id);
-        return bcm_to_grpc_err(err, "Access_Control set ITU PON Gem port failed");
-    }
-
-    OPENOLT_LOG(INFO, openolt_log_id, "gem port installed successfully = %d\n", gemport_id);
-
-    return Status::OK;
-}
-
-Status remove_gem_port(int32_t intf_id, int32_t gemport_id) {
-    bcmolt_itupon_gem_cfg gem_cfg;
-    bcmolt_itupon_gem_key key = {
-        .pon_ni = (bcmolt_interface)intf_id,
-        .gem_port_id = (bcmolt_gem_port_id)gemport_id
-    };
-    bcmos_errno err;
-
-    BCMOLT_CFG_INIT(&gem_cfg, itupon_gem, key);
-    err = bcmolt_cfg_clear(dev_id, &gem_cfg.hdr);
-    if (err != BCM_ERR_OK)
-    {
-        OPENOLT_LOG(ERROR, openolt_log_id, "failed to remove gem_port = %d err=%s\n", gemport_id, gem_cfg.hdr.hdr.err_text);
-        return bcm_to_grpc_err(err, "Access_Control clear ITU PON Gem port failed");
-    }
-
-    OPENOLT_LOG(INFO, openolt_log_id, "gem port removed successfully = %d\n", gemport_id);
-
-    return Status::OK;
-}
-
-Status update_acl_interface(int32_t intf_id, bcmolt_interface_type intf_type, uint32_t access_control_id,
-                bcmolt_members_update_command acl_cmd) {
-    bcmos_errno err;
-    bcmolt_access_control_interfaces_update oper; /* declare main API struct */
-    bcmolt_access_control_key acl_key = {}; /* declare key */
-    bcmolt_intf_ref interface_ref_list_elem = {};
-    bcmolt_interface_type interface_ref_list_elem_intf_type;
-    bcmolt_interface_id interface_ref_list_elem_intf_id;
-    bcmolt_intf_ref_list_u8 interface_ref_list = {};
-
-    if (acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_ADD && acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "acl cmd = %d not supported currently\n", acl_cmd);
-        return bcm_to_grpc_err(BCM_ERR_PARM, "unsupported acl cmd");
-    }
-    interface_ref_list.arr = (bcmolt_intf_ref*)bcmos_calloc(sizeof(bcmolt_intf_ref)*1);
-
-    if (interface_ref_list.arr == NULL)
-         return bcm_to_grpc_err(BCM_ERR_PARM, "allocate interface_ref_list failed");
-    OPENOLT_LOG(INFO, openolt_log_id, "update acl interface received for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
-            intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
-            acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
-
-    acl_key.id = access_control_id;
-
-    /* Initialize the API struct. */
-    BCMOLT_OPER_INIT(&oper, access_control, interfaces_update, acl_key);
-
-    bcmolt_members_update_command command;
-    command = acl_cmd;
-    BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, command, command);
-
-    interface_ref_list_elem_intf_type = intf_type;
-    BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_type, interface_ref_list_elem_intf_type);
-
-    interface_ref_list_elem_intf_id = intf_id;
-    BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_id, interface_ref_list_elem_intf_id);
-
-    interface_ref_list.len = 1;
-    BCMOLT_ARRAY_ELEM_SET(&interface_ref_list, 0, interface_ref_list_elem);
-
-    BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, interface_ref_list, interface_ref_list);
-
-    err =  bcmolt_oper_submit(dev_id, &oper.hdr);
-    if (err != BCM_ERR_OK) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "update acl interface fail for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
-            intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
-            acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
-        return bcm_to_grpc_err(err, "Access_Control submit interface failed");
-    }
-
-    bcmos_free(interface_ref_list.arr);
-    OPENOLT_LOG(INFO, openolt_log_id, "update acl interface success for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
-            intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
-            acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
-
-    return Status::OK;
-}
-
-Status install_acl(const acl_classifier_key acl_key) {
-
-    bcmos_errno err;
-    bcmolt_access_control_cfg cfg;
-    bcmolt_access_control_key key = { };
-    bcmolt_classifier c_val = { };
-    // hardcode the action for now.
-    bcmolt_access_control_fwd_action_type action_type = BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_TRAP_TO_HOST;
-
-    int acl_id = get_acl_id();
-    if (acl_id < 0) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "exhausted acl_id for eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d\n",
-                acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port);
-        bcmos_fastlock_unlock(&data_lock, 0);
-        return bcm_to_grpc_err(BCM_ERR_INTERNAL, "exhausted acl id");
-    }
-
-    key.id = acl_id;
-    /* config access control instance */
-    BCMOLT_CFG_INIT(&cfg, access_control, key);
-
-    if (acl_key.ether_type > 0) {
-        OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ether_type 0x%04x\n", acl_key.ether_type);
-        BCMOLT_FIELD_SET(&c_val, classifier, ether_type, acl_key.ether_type);
-    }
-
-    if (acl_key.ip_proto > 0) {
-        OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ip_proto %d\n", acl_key.ip_proto);
-        BCMOLT_FIELD_SET(&c_val, classifier, ip_proto, acl_key.ip_proto);
-    }
-
-    if (acl_key.dst_port > 0) {
-        OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify dst_port %d\n", acl_key.dst_port);
-        BCMOLT_FIELD_SET(&c_val, classifier, dst_port, acl_key.dst_port);
-    }
-
-    if (acl_key.src_port > 0) {
-        OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify src_port %d\n", acl_key.src_port);
-        BCMOLT_FIELD_SET(&c_val, classifier, src_port, acl_key.src_port);
-    }
-
-    BCMOLT_MSG_FIELD_SET(&cfg, classifier, c_val);
-    BCMOLT_MSG_FIELD_SET(&cfg, priority, 10000);
-    BCMOLT_MSG_FIELD_SET(&cfg, statistics_control, BCMOLT_CONTROL_STATE_ENABLE);
-
-    BCMOLT_MSG_FIELD_SET(&cfg, forwarding_action.action, action_type);
-
-    err = bcmolt_cfg_set(dev_id, &cfg.hdr);
-    if (err != BCM_ERR_OK) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control set configuration failed, Error %d\n", err);
-        // Free the acl_id
-        free_acl_id(acl_id);
-        return bcm_to_grpc_err(err, "Access_Control set configuration failed");
-    }
-
-    ACL_LOG(INFO, "ACL add ok", err);
-
-    // Update the map that we have installed an acl for the given classfier.
-    acl_classifier_to_acl_id_map[acl_key] = acl_id;
-    return Status::OK;
-}
-
-Status remove_acl(int acl_id) {
-    bcmos_errno err;
-    bcmolt_access_control_cfg cfg; /* declare main API struct */
-    bcmolt_access_control_key key = {}; /* declare key */
-
-    key.id = acl_id;
-
-    /* Initialize the API struct. */
-    BCMOLT_CFG_INIT(&cfg, access_control, key);
-    BCMOLT_FIELD_SET_PRESENT(&cfg.data, access_control_cfg_data, state);
-    err = bcmolt_cfg_get(dev_id, &cfg.hdr);
-    if (err != BCM_ERR_OK) {
-        OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control get state failed\n");
-        return bcm_to_grpc_err(err, "Access_Control get state failed");
-    }
-
-    if (cfg.data.state == BCMOLT_CONFIG_STATE_CONFIGURED) {
-        key.id = acl_id;
-        /* Initialize the API struct. */
-        BCMOLT_CFG_INIT(&cfg, access_control, key);
-
-        err = bcmolt_cfg_clear(dev_id, &cfg.hdr);
-        if (err != BCM_ERR_OK) {
-            // Should we free acl_id here ? We should ideally never land here..
-            OPENOLT_LOG(ERROR, openolt_log_id, "Error %d while removing Access_Control rule ID %d\n",
-                err, acl_id);
-            return Status(grpc::StatusCode::INTERNAL, "Failed to remove Access_Control");
-        }
-    }
-
-    // Free up acl_id
-    free_acl_id(acl_id);
-
-    OPENOLT_LOG(INFO, openolt_log_id, "acl removed successfully %d\n", acl_id);
-
-    return Status::OK;
-}
-
-// Formulates ACL Classifier Key based on the following fields
-// a. ether_type b. ip_proto c. src_port d. dst_port
-// If any of the field is not available it is populated as -1.
-void formulate_acl_classifier_key(acl_classifier_key *key, const ::openolt::Classifier& classifier) {
-
-        // TODO: Is 0 a valid value for any of the following classifiers?
-        // because in the that case, the 'if' check would fail and -1 would be filled as value.
-        //
-        if (classifier.eth_type()) {
-            OPENOLT_LOG(DEBUG, openolt_log_id, "classify ether_type 0x%04x\n", classifier.eth_type());
-            key->ether_type = classifier.eth_type();
-        } else key->ether_type = -1;
-
-        if (classifier.ip_proto()) {
-            OPENOLT_LOG(DEBUG, openolt_log_id, "classify ip_proto %d\n", classifier.ip_proto());
-            key->ip_proto = classifier.ip_proto();
-        } else key->ip_proto = -1;
-
-
-        if (classifier.src_port()) {
-            OPENOLT_LOG(DEBUG, openolt_log_id, "classify src_port %d\n", classifier.src_port());
-            key->src_port = classifier.src_port();
-        } else key->src_port = -1;
-
-
-        if (classifier.dst_port()) {
-            OPENOLT_LOG(DEBUG, openolt_log_id, "classify dst_port %d\n", classifier.dst_port());
-            key->dst_port = classifier.dst_port();
-        } else key->dst_port = -1;
-}
-
-Status handle_acl_rule_install(int32_t onu_id, uint32_t flow_id,
-                               const std::string flow_type, int32_t access_intf_id,
-                               int32_t network_intf_id, int32_t gemport_id,
-                               const ::openolt::Classifier& classifier) {
-    int acl_id;
-    int32_t intf_id = flow_type.compare(upstream) == 0? access_intf_id: network_intf_id;
-    const std::string intf_type = flow_type.compare(upstream) == 0? "pon": "nni";
-    bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
-
-    Status resp;
-
-    // few map keys we are going to use later.
-    flow_id_flow_direction fl_id_fl_dir(flow_id, flow_type);
-    gem_id_intf_id gem_intf(gemport_id, access_intf_id);
-    acl_classifier_key acl_key;
-    formulate_acl_classifier_key(&acl_key, classifier);
-    const acl_classifier_key acl_key_const = {.ether_type=acl_key.ether_type, .ip_proto=acl_key.ip_proto,
-        .src_port=acl_key.src_port, .dst_port=acl_key.dst_port};
-
-    bcmos_fastlock_lock(&data_lock);
-
-    // Check if the acl is already installed
-    if (acl_classifier_to_acl_id_map.count(acl_key_const) > 0) {
-        // retreive the acl_id
-        acl_id = acl_classifier_to_acl_id_map[acl_key_const];
-        acl_id_gem_id_intf_id ac_id_gm_id_if_id(acl_id, gemport_id, intf_id);
-        if (flow_to_acl_map.count(fl_id_fl_dir)) {
-            // coult happen if same trap flow is received again
-            OPENOLT_LOG(INFO, openolt_log_id, "flow and related acl already handled, nothing more to do\n");
-            bcmos_fastlock_unlock(&data_lock, 0);
-            return Status::OK;
-        }
-
-        OPENOLT_LOG(INFO, openolt_log_id, "Acl for flow_id=%u with eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d already installed with acl id = %u\n",
-                flow_id, acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port, acl_id);
-
-        // The acl_ref_cnt is needed to know how many flows refer an ACL.
-        // When the flow is removed, we decrement the reference count.
-        // When the reference count becomes 0, we remove the ACL.
-        if (acl_ref_cnt.count(acl_id) > 0) {
-            acl_ref_cnt[acl_id] ++;
-        } else {
-            // We should ideally not land here. The acl_ref_cnt should have been
-            // initialized the first time acl was installed.
-            acl_ref_cnt[acl_id] = 1;
-        }
-
-    } else {
-        resp = install_acl(acl_key_const);
-        if (!resp.ok()) {
-            OPENOLT_LOG(ERROR, openolt_log_id, "Acl for flow_id=%u with eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d failed\n",
-                    flow_id, acl_key_const.ether_type, acl_key_const.ip_proto, acl_key_const.src_port, acl_key_const.dst_port);
-            bcmos_fastlock_unlock(&data_lock, 0);
-            return resp;
-        }
-
-        acl_id = acl_classifier_to_acl_id_map[acl_key_const];
-
-        // Initialize the acl reference count
-        acl_ref_cnt[acl_id] = 1;
-
-        OPENOLT_LOG(INFO, openolt_log_id, "acl add success for flow_id=%u with acl_id=%d\n", flow_id, acl_id);
-    }
-
-    // Register the interface for the given acl
-    acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
-    // This is needed to keep a track of which interface (pon/nni) has registered for an ACL.
-    // If it is registered, how many flows refer to it.
-    if (intf_acl_registration_ref_cnt.count(ac_id_inf_id_inf_type) > 0) {
-        intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]++;
-    } else {
-        // The given interface is not registered for the ACL. We need to do it now.
-        resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_ADD);
-        if (!resp.ok()){
-            OPENOLT_LOG(ERROR, openolt_log_id, "failed to update acl interfaces intf_id=%d, intf_type=%s, acl_id=%d", intf_id, intf_type.c_str(), acl_id);
-            // TODO: Ideally we should return error from hear and clean up other other stateful
-            // counters we creaed earlier. Will leave it out for now.
-        } 
-        intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] = 1;
-    }
-
-
-    // Install the gem port if needed.
-    if (gemport_id > 0 && access_intf_id >= 0) {
-        if (gem_ref_cnt.count(gem_intf) > 0) {
-            // The gem port is already installed
-            // Increment the ref counter indicating number of flows referencing this gem port
-            gem_ref_cnt[gem_intf]++;
-            OPENOLT_LOG(DEBUG, openolt_log_id, "increment gem_ref_cnt in acl handler, ref_cnt=%d\n", gem_ref_cnt[gem_intf]);
-
-        } else {
-            // We should ideally never land here. The gem port should have been created the
-            // first time ACL was installed.
-            // Install the gem port
-            Status resp = install_gem_port(access_intf_id, onu_id, gemport_id);
-            if (!resp.ok()) {
-                // TODO: We might need to reverse all previous data, but leave it out for now.
-                OPENOLT_LOG(ERROR, openolt_log_id, "failed to install the gemport=%d for acl_id=%d, intf_id=%d\n", gemport_id, acl_id, access_intf_id);
-                bcmos_fastlock_unlock(&data_lock, 0);
-                return resp;
-            }
-            // Initialize the refence count for the gemport.
-            gem_ref_cnt[gem_intf] = 1;
-            OPENOLT_LOG(DEBUG, openolt_log_id, "intialized gem ref count in acl handler\n");
-        }
-    } else {
-        OPENOLT_LOG(DEBUG, openolt_log_id, "not incrementing gem_ref_cnt in acl handler flow_id=%d, gemport_id=%d, intf_id=%d\n", flow_id, gemport_id, access_intf_id);
-    }
-
-    // Update the flow_to_acl_map
-    // This info is needed during flow remove. We need to which ACL ID and GEM PORT ID
-    // the flow was referring to.
-    // After retrieving the ACL ID and GEM PORT ID, we decrement the corresponding
-    // reference counters for those ACL ID and GEMPORT ID.
-    acl_id_gem_id_intf_id ac_id_gm_id_if_id(acl_id, gemport_id, intf_id);
-    flow_to_acl_map[fl_id_fl_dir] = ac_id_gm_id_if_id;
-
-    bcmos_fastlock_unlock(&data_lock, 0);
-
-    return Status::OK;
-}
-
 Status FlowAdd_(int32_t access_intf_id, int32_t onu_id, int32_t uni_id, uint32_t port_no,
                 uint32_t flow_id, const std::string flow_type,
                 int32_t alloc_id, int32_t network_intf_id,
@@ -2783,19 +1384,6 @@
     }
 
     {
-        /* removed by BAL v3.0
-        if (classifier.o_tpid()) {
-            OPENOLT_LOG(DEBUG, openolt_log_id, "classify o_tpid 0x%04x\n", classifier.o_tpid());
-            BCMBAL_ATTRIBUTE_PROP_SET(&val, classifier, o_tpid, classifier.o_tpid());
-        }
-        */
-        /* removed by BAL v3.0
-        if (classifier.i_tpid()) {
-            OPENOLT_LOG(DEBUG, openolt_log_id, "classify i_tpid 0x%04x\n", classifier.i_tpid());
-            BCMBAL_ATTRIBUTE_PROP_SET(&val, classifier, i_tpid, classifier.i_tpid());
-        }
-        */
-
         if (classifier.eth_type()) {
             ether_type = classifier.eth_type();
             OPENOLT_LOG(DEBUG, openolt_log_id, "classify ether_type 0x%04x\n", classifier.eth_type());
@@ -2894,12 +1482,7 @@
         OPENOLT_LOG(DEBUG, openolt_log_id, "action pop o_tag\n");
         BCMOLT_FIELD_SET(&a_val, action, cmds_bitmask, BCMOLT_ACTION_CMD_ID_REMOVE_OUTER_TAG);
     }
-    /* removed by BAL v3.0
-    if (cmd.trap_to_host()) {
-        OPENOLT_LOG(INFO, openolt_log_id, "action trap-to-host\n");
-        BCMBAL_ATTRIBUTE_PROP_SET(&val, action, cmds_bitmask, BCMBAL_ACTION_CMD_ID_TRAP_TO_HOST);
-    }
-    */
+
     if (action.o_vid()) {
         OPENOLT_LOG(DEBUG, openolt_log_id, "action o_vid=%d\n", action.o_vid());
         o_vid = action.o_vid();
@@ -2910,12 +1493,7 @@
         OPENOLT_LOG(DEBUG, openolt_log_id, "action o_pbits=0x%x\n", action.o_pbits());
         BCMOLT_FIELD_SET(&a_val, action, o_pbits, action.o_pbits());
     }
-    /* removed by BAL v3.0
-    if (action.o_tpid()) {
-        OPENOLT_LOG(INFO, openolt_log_id, "action o_tpid=0x%04x\n", action.o_tpid());
-        BCMBAL_ATTRIBUTE_PROP_SET(&val, action, o_tpid, action.o_tpid());
-    }
-    */
+
     if (action.i_vid()) {
         OPENOLT_LOG(DEBUG, openolt_log_id, "action i_vid=%d\n", action.i_vid());
         BCMOLT_FIELD_SET(&a_val, action, i_vid, action.i_vid());
@@ -2925,12 +1503,7 @@
         OPENOLT_LOG(DEBUG, openolt_log_id, "action i_pbits=0x%x\n", action.i_pbits());
         BCMOLT_FIELD_SET(&a_val, action, i_pbits, action.i_pbits());
     }
-    /* removed by BAL v3.0
-    if (action.i_tpid()) {
-        OPENOLT_LOG(DEBUG, openolt_log_id, "action i_tpid=0x%04x\n", action.i_tpid());
-        BCMBAL_ATTRIBUTE_PROP_SET(&val, action, i_tpid, action.i_tpid());
-    }
-    */
+
     BCMOLT_MSG_FIELD_SET(&cfg, action, a_val);
 
     if ((access_intf_id >= 0) && (onu_id >= 0)) {
@@ -3088,57 +1661,6 @@
     return Status::OK;
 }
 
-void clear_gem_port(int gemport_id, int access_intf_id) {
-    gem_id_intf_id gem_intf(gemport_id, access_intf_id);
-    if (gemport_id > 0 && access_intf_id >= 0 && gem_ref_cnt.count(gem_intf) > 0) {
-        OPENOLT_LOG(DEBUG, openolt_log_id, "decrementing gem_ref_cnt gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
-        gem_ref_cnt[gem_intf]--;
-        if (gem_ref_cnt[gem_intf] == 0) {
-            // For datapath flow this may not be necessary (to be verified)
-            remove_gem_port(access_intf_id, gemport_id);
-            gem_ref_cnt.erase(gem_intf);
-            OPENOLT_LOG(DEBUG, openolt_log_id, "removing gem_ref_cnt entry gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
-        } else {
-            OPENOLT_LOG(DEBUG, openolt_log_id, "gem_ref_cnt  not zero yet gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
-        }
-    } else {
-        OPENOLT_LOG(DEBUG, openolt_log_id, "not decrementing gem_ref_cnt gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
-    }
-}
-
-Status handle_acl_rule_cleanup(int16_t acl_id, int32_t gemport_id, int32_t intf_id, const std::string flow_type) {
-    const std::string intf_type= flow_type.compare(upstream) == 0 ? "pon": "nni";
-    acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
-    intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]--;
-    if (intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] == 0) {
-        bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
-        Status resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE);
-        if (!resp.ok()){
-            OPENOLT_LOG(ERROR, openolt_log_id, "failed to update acl interfaces intf_id=%d, intf_type=%s, acl_id=%d", intf_id, intf_type.c_str(), acl_id);
-        }
-        intf_acl_registration_ref_cnt.erase(ac_id_inf_id_inf_type);
-    }
-
-    acl_ref_cnt[acl_id]--;
-    if (acl_ref_cnt[acl_id] == 0) {
-        remove_acl(acl_id);
-        acl_ref_cnt.erase(acl_id);
-        // Iterate acl_classifier_to_acl_id_map and delete classifier the key corresponding to acl_id
-        std::map<acl_classifier_key, uint16_t>::iterator it;
-        for (it=acl_classifier_to_acl_id_map.begin(); it!=acl_classifier_to_acl_id_map.end(); ++it)  {
-            if (it->second == acl_id) {
-                OPENOLT_LOG(INFO, openolt_log_id, "cleared classifier key corresponding to acl_id = %d\n", acl_id);
-                acl_classifier_to_acl_id_map.erase(it->first);
-                break;
-            }
-        }
-    }
-
-    clear_gem_port(gemport_id, intf_id);
-
-    return Status::OK;
-}
-
 Status FlowRemove_(uint32_t flow_id, const std::string flow_type) {
 
     bcmolt_flow_cfg cfg;
@@ -3878,52 +2400,6 @@
     return Status::OK;
 }
 
-Status check_connection() {
-    int maxTrials = 60;
-    while (!bcmolt_api_conn_mgr_is_connected(dev_id)) {
-        sleep(1);
-        if (--maxTrials == 0)
-            return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check connection failed");
-        else
-            OPENOLT_LOG(INFO, openolt_log_id, "waiting for daemon connection ...\n");
-    }
-    OPENOLT_LOG(INFO, openolt_log_id, "daemon is connected\n");
-    return Status::OK;
-}
-
-Status check_bal_ready() {
-    bcmos_errno err;
-    int maxTrials = 30;
-    bcmolt_olt_cfg olt_cfg = { };
-    bcmolt_olt_key olt_key = { };
-
-    BCMOLT_CFG_INIT(&olt_cfg, olt, olt_key);
-    BCMOLT_MSG_FIELD_GET(&olt_cfg, bal_state);
-
-    while (olt_cfg.data.bal_state != BCMOLT_BAL_STATE_BAL_AND_SWITCH_READY) {
-        if (--maxTrials == 0)
-            return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check bal ready failed");
-        sleep(5);
-        #ifdef TEST_MODE
-        // It is impossible to mock the setting of olt_cfg.data.bal_state because
-        // the actual bcmolt_cfg_get passes the address of olt_cfg.hdr and we cannot
-        // set the olt_cfg.data.bal_state. So a new stub function is created and address
-        // of olt_cfg is passed. This is one-of case where we need to add test specific
-        // code in production code.
-        if (bcmolt_cfg_get__bal_state_stub(dev_id, &olt_cfg)) {
-        #else
-        if (bcmolt_cfg_get(dev_id, &olt_cfg.hdr)) {
-        #endif
-            continue;
-        }
-        else
-            OPENOLT_LOG(INFO, openolt_log_id, "waiting for BAL ready ...\n");
-    }
-
-    OPENOLT_LOG(INFO, openolt_log_id, "BAL is ready\n");
-    return Status::OK;
-}
-
 Status PerformGroupOperation_(const openolt::Group *group_cfg) {
 
     bcmos_errno err;
diff --git a/agent/src/core_data.cc b/agent/src/core_data.cc
new file mode 100644
index 0000000..dc98400
--- /dev/null
+++ b/agent/src/core_data.cc
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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.
+ */
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include "Queue.h"
+#include <sstream>
+#include <chrono>
+#include <thread>
+#include <bitset>
+#include <inttypes.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "device.h"
+#include "core.h"
+#include "core_data.h"
+#include "indications.h"
+#include "stats_collection.h"
+#include "error_format.h"
+#include "state.h"
+#include "core_utils.h"
+
+extern "C"
+{
+#include <bcmolt_api.h>
+#include <bcmolt_host_api.h>
+#include <bcmolt_api_model_supporting_enums.h>
+
+#include <bcmolt_api_conn_mgr.h>
+//CLI header files
+#include <bcmcli_session.h>
+#include <bcmcli.h>
+#include <bcm_api_cli.h>
+
+#include <bcmos_common.h>
+#include <bcm_config.h>
+// FIXME : dependency problem
+// #include <bcm_common_gpon.h>
+// #include <bcm_dev_log_task.h>
+}
+
+dev_log_id openolt_log_id = bcm_dev_log_id_register("OPENOLT", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
+dev_log_id omci_log_id = bcm_dev_log_id_register("OMCI", DEV_LOG_LEVEL_INFO, DEV_LOG_ID_TYPE_BOTH);
+
+
+unsigned int num_of_nni_ports = 0;
+unsigned int num_of_pon_ports = 0;
+
+const uint32_t tm_upstream_sched_id_start = (MAX_SUPPORTED_PON == 16 ? \
+    MAX_TM_SCHED_ID-3 : MAX_TM_SCHED_ID-9);
+const uint32_t tm_downstream_sched_id_start = (MAX_SUPPORTED_PON == 16 ? \
+    tm_upstream_sched_id_start-16 : tm_upstream_sched_id_start-64);
+
+/* Max Queue ID supported is 7 so based on priority_q configured for GEMPORTS
+in TECH PROFILE respective Queue ID from this list will be used for both
+US and DS Queues*/
+const uint32_t queue_id_list[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+
+const std::string upstream = "upstream";
+const std::string downstream = "downstream";
+const std::string multicast = "multicast";
+bcmolt_oltid dev_id = 0;
+
+/* Constants used for retrying some BAL APIs */
+const uint32_t BAL_API_RETRY_TIME_IN_USECS = 1000000;
+const uint32_t MAX_BAL_API_RETRY_COUNT = 5;
+
+const unsigned int OPENOLT_FIELD_LEN = 200;
+
+/* Current session */
+bcmcli_session *current_session;
+bcmcli_entry *api_parent_dir;
+bcmos_bool status_bcm_cli_quit = BCMOS_FALSE;
+bcmos_task bal_cli_thread;
+const char *bal_cli_thread_name = "bal_cli_thread";
+uint16_t flow_id_counters = 0;
+State state;
+
+std::map<uint32_t, uint32_t> flowid_to_port; // For mapping upstream flows to logical ports
+std::map<uint32_t, uint32_t> flowid_to_gemport; // For mapping downstream flows into gemports
+std::map<uint32_t, std::set<uint32_t> > port_to_flows; // For mapping logical ports to downstream flows
+
+/* This represents the Key to 'sched_map' map.
+ Represents (pon_intf_id, onu_id, uni_id, direction) */
+typedef std::tuple<uint32_t, uint32_t, uint32_t, std::string> sched_map_key_tuple;
+/* 'sched_map' maps sched_map_key_tuple to DBA (Upstream) or
+ Subscriber (Downstream) Scheduler ID */
+std::map<sched_map_key_tuple, int> sched_map;
+
+/* Flow control is for flow_id and flow_type */
+typedef std::pair<uint16_t, uint16_t> flow_pair;
+std::map<flow_pair, int32_t> flow_map;
+
+/* This represents the Key to 'qos_type_map' map.
+ Represents (pon_intf_id, onu_id, uni_id) */
+typedef std::tuple<uint32_t, uint32_t, uint32_t> qos_type_map_key_tuple;
+/* 'qos_type_map' maps qos_type_map_key_tuple to qos_type*/
+std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type> qos_type_map;
+
+/* This represents the Key to 'sched_qmp_id_map' map.
+Represents (sched_id, pon_intf_id, onu_id, uni_id) */
+typedef std::tuple<uint32_t, uint32_t, uint32_t, uint32_t> sched_qmp_id_map_key_tuple;
+/* 'sched_qmp_id_map' maps sched_qmp_id_map_key_tuple to TM Queue Mapping Profile ID */
+std::map<sched_qmp_id_map_key_tuple, int> sched_qmp_id_map;
+/* 'qmp_id_to_qmp_map' maps TM Queue Mapping Profile ID to TM Queue Mapping Profile */
+std::map<int, std::vector < uint32_t > > qmp_id_to_qmp_map;
+
+// Flag used to watch whether mocked alloc_cfg_compltd_key is added to alloc_cfg_compltd_map
+#ifdef TEST_MODE
+bool ALLOC_CFG_FLAG = false;
+#endif
+
+// Map used to track response from BAL for ITU PON Alloc Configuration.
+// The key is alloc_cfg_compltd_key and value is a concurrent thread-safe queue which is
+// used for pushing (from BAL) and popping (at application) the results.
+std::map<alloc_cfg_compltd_key,  Queue<alloc_cfg_complete_result> *> alloc_cfg_compltd_map;
+// Lock to protect critical section data structure used for handling AllocObject configuration response.
+bcmos_fastlock alloc_cfg_wait_lock;
+
+
+/*** ACL Handling related data start ***/
+
+std::map<acl_classifier_key, uint16_t> acl_classifier_to_acl_id_map;
+
+bool operator<(const acl_classifier_key& a1, const acl_classifier_key& a2)
+{
+    return ((a1.ether_type + 2*a1.ip_proto + 3*a1.src_port + 4*a1.dst_port) <
+            (a2.ether_type + 2*a2.ip_proto + 3*a2.src_port + 4*a2.dst_port));
+}
+
+typedef std::tuple<uint16_t, std::string> flow_id_flow_direction;
+typedef std::tuple<int16_t, uint16_t, int32_t> acl_id_gem_id_intf_id;
+std::map<flow_id_flow_direction, acl_id_gem_id_intf_id> flow_to_acl_map;
+
+// Keeps a reference count of how many flows are referencing a given ACL ID.
+// Key represents the ACL-ID and value is number of flows referencing the given ACL-ID.
+// When there is at least one flow referencing the ACL-ID, the ACL should be installed.
+// When there are no flows referencing the ACL-ID, the ACL should be removed.
+std::map<uint16_t, uint16_t> acl_ref_cnt;
+
+typedef std::tuple<uint16_t, uint16_t> gem_id_intf_id; // key to gem_ref_cnt
+// Keeps a reference count of how many ACL related flows are referencing a given (gem-id, pon_intf_id).
+// When there is at least on flow, we should install the gem. When there are no flows
+// the gem should be removed.
+std::map<gem_id_intf_id, uint16_t> gem_ref_cnt;
+
+// Needed to keep track of how many flows for a given acl_id, intf_id and intf_type are
+// installed. When there is at least on flow for this key, we should have interface registered
+// for the given ACL-ID. When there are no flows, the intf should unregister itself from
+// the ACL-ID.
+typedef std::tuple<uint16_t, uint8_t, std::string> acl_id_intf_id_intf_type;
+std::map<acl_id_intf_id_intf_type, uint16_t> intf_acl_registration_ref_cnt;
+
+std::bitset<MAX_ACL_ID> acl_id_bitset;
+
+/*** ACL Handling related data end ***/
+
+std::bitset<MAX_TM_SCHED_ID> tm_sched_bitset;
+std::bitset<MAX_TM_QMP_ID> tm_qmp_bitset;
+
+// Lock used to gaurd critical section during various API handling at the core_api_handler
+bcmos_fastlock data_lock;
diff --git a/agent/src/core_data.h b/agent/src/core_data.h
new file mode 100644
index 0000000..5c900f5
--- /dev/null
+++ b/agent/src/core_data.h
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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.
+ */
+#ifndef OPENOLT_CORE_DATA_H_
+#define OPENOLT_CORE_DATA_H_
+
+#include <bitset>
+
+#include "core.h"
+#include "Queue.h"
+
+extern "C"
+{
+#include <bcmolt_api.h>
+#include <bcmolt_api_model_supporting_enums.h>
+
+#include <bcmolt_api_conn_mgr.h>
+//CLI header files
+#include <bcmcli_session.h>
+#include <bcmcli.h>
+#include <bcm_api_cli.h>
+
+#include <bcmos_common.h>
+#include <bcm_config.h>
+// FIXME : dependency problem
+// #include <bcm_common_gpon.h>
+// #include <bcm_dev_log_task.h>
+}
+
+#define ALLOC_CFG_COMPLETE_WAIT_TIMEOUT 1000 // in milli-seconds
+
+#define MIN_ALLOC_ID_GPON 256
+#define MIN_ALLOC_ID_XGSPON 1024
+
+#define MAX_ACL_ID 33
+
+// **************************************//
+// Enums and structures used by the core //
+// **************************************//
+enum FLOW_CFG {
+    ONU_ID = 0,
+    FLOW_TYPE = 1,
+    SVC_PORT_ID = 2,
+    PRIORITY = 3,
+    COOKIE = 4,
+    INGRESS_INTF_TYPE= 5,
+    EGRESS_INTF_TYPE= 6,
+    INGRESS_INTF_ID = 7,
+    EGRESS_INTF_ID = 8,
+    CLASSIFIER_O_VID = 9,
+    CLASSIFIER_O_PBITS = 10,
+    CLASSIFIER_I_VID = 11,
+    CLASSIFIER_I_PBITS = 12,
+    CLASSIFIER_ETHER_TYPE = 13,
+    CLASSIFIER_IP_PROTO =14,
+    CLASSIFIER_SRC_PORT = 15,
+    CLASSIFIER_DST_PORT = 16,
+    CLASSIFIER_PKT_TAG_TYPE = 17,
+    EGRESS_QOS_TYPE = 18,
+    EGRESS_QOS_QUEUE_ID = 19,
+    EGRESS_QOS_TM_SCHED_ID = 20,
+    ACTION_CMDS_BITMASK = 21,
+    ACTION_O_VID = 22,
+    ACTION_O_PBITS = 23,
+    ACTION_I_VID = 24,
+    ACTION_I_PBITS = 25,
+    STATE = 26,
+    GROUP_ID = 27
+};
+
+enum AllocCfgAction {
+    ALLOC_OBJECT_CREATE,
+    ALLOC_OBJECT_DELETE
+};
+
+enum AllocObjectState {
+    ALLOC_OBJECT_STATE_NOT_CONFIGURED,
+    ALLOC_OBJECT_STATE_INACTIVE,
+    ALLOC_OBJECT_STATE_PROCESSING,
+    ALLOC_OBJECT_STATE_ACTIVE
+};
+
+enum AllocCfgStatus {
+    ALLOC_CFG_STATUS_SUCCESS,
+    ALLOC_CFG_STATUS_FAIL
+};
+
+typedef struct {
+    uint32_t pon_intf_id;
+    uint32_t alloc_id;
+    AllocObjectState state;
+    AllocCfgStatus status;
+} alloc_cfg_complete_result;
+
+// key for map used for tracking ITU PON Alloc Configuration results from BAL
+typedef std::tuple<uint32_t, uint32_t> alloc_cfg_compltd_key;
+
+// The elements in this acl_classifier_key structure constitute key to
+// acl_classifier_to_acl_id_map.
+// Fill invalid values in the acl_classifier_key structure to -1.
+typedef struct acl_classifier_key {
+    int32_t ether_type;
+    int16_t ip_proto;
+    int32_t src_port;
+    int32_t dst_port;
+    // Add more classifiers elements as needed here
+    // For now, ACLs will be classified only based on
+    // above elements.
+} acl_classifier_key;
+
+// *******************************************************//
+// Extern Variable/Constant declarations used by the core //
+// *******************************************************//
+extern State state;
+
+extern dev_log_id openolt_log_id;
+extern dev_log_id omci_log_id;
+
+extern unsigned int num_of_nni_ports;
+extern unsigned int num_of_pon_ports;
+
+extern const uint32_t tm_upstream_sched_id_start;
+extern const uint32_t tm_downstream_sched_id_start;
+
+extern const uint32_t queue_id_list[8];
+
+extern const std::string upstream;
+extern const std::string downstream;
+extern const std::string multicast;
+extern bcmolt_oltid dev_id;
+
+extern const uint32_t BAL_API_RETRY_TIME_IN_USECS;
+extern const uint32_t MAX_BAL_API_RETRY_COUNT;
+
+extern const unsigned int OPENOLT_FIELD_LEN;
+
+/* Current session */
+extern bcmcli_session *current_session;
+extern bcmcli_entry *api_parent_dir;
+extern bcmos_bool status_bcm_cli_quit;
+extern bcmos_task bal_cli_thread;
+extern const char *bal_cli_thread_name;
+extern uint16_t flow_id_counters;
+
+extern std::map<uint32_t, uint32_t> flowid_to_port; // For mapping upstream flows to logical ports
+extern std::map<uint32_t, uint32_t> flowid_to_gemport; // For mapping downstream flows into gemports
+extern std::map<uint32_t, std::set<uint32_t> > port_to_flows; // For mapping logical ports to downstream flows
+
+/* This represents the Key to 'sched_map' map.
+ Represents (pon_intf_id, onu_id, uni_id, direction) */
+typedef std::tuple<uint32_t, uint32_t, uint32_t, std::string> sched_map_key_tuple;
+/* 'sched_map' maps sched_map_key_tuple to DBA (Upstream) or
+ Subscriber (Downstream) Scheduler ID */
+extern std::map<sched_map_key_tuple, int> sched_map;
+
+/* Flow control is for flow_id and flow_type */
+typedef std::pair<uint16_t, uint16_t> flow_pair;
+extern std::map<flow_pair, int32_t> flow_map;
+
+/* This represents the Key to 'qos_type_map' map.
+ Represents (pon_intf_id, onu_id, uni_id) */
+typedef std::tuple<uint32_t, uint32_t, uint32_t> qos_type_map_key_tuple;
+/* 'qos_type_map' maps qos_type_map_key_tuple to qos_type*/
+extern std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type> qos_type_map;
+
+/* This represents the Key to 'sched_qmp_id_map' map.
+Represents (sched_id, pon_intf_id, onu_id, uni_id) */
+typedef std::tuple<uint32_t, uint32_t, uint32_t, uint32_t> sched_qmp_id_map_key_tuple;
+/* 'sched_qmp_id_map' maps sched_qmp_id_map_key_tuple to TM Queue Mapping Profile ID */
+extern std::map<sched_qmp_id_map_key_tuple, int> sched_qmp_id_map;
+/* 'qmp_id_to_qmp_map' maps TM Queue Mapping Profile ID to TM Queue Mapping Profile */
+extern std::map<int, std::vector < uint32_t > > qmp_id_to_qmp_map;
+
+// Flag used to watch whether mocked alloc_cfg_compltd_key is added to alloc_cfg_compltd_map
+#ifdef TEST_MODE
+extern bool ALLOC_CFG_FLAG;
+#endif
+
+// Map used to track response from BAL for ITU PON Alloc Configuration.
+// The key is alloc_cfg_compltd_key and value is a concurrent thread-safe queue which is
+// used for pushing (from BAL) and popping (at application) the results.
+extern std::map<alloc_cfg_compltd_key,  Queue<alloc_cfg_complete_result> *> alloc_cfg_compltd_map;
+// Lock to protect critical section data structure used for handling AllocObject configuration response.
+extern bcmos_fastlock alloc_cfg_wait_lock;
+
+
+/*** ACL Handling related data start ***/
+
+extern std::map<acl_classifier_key, uint16_t> acl_classifier_to_acl_id_map;
+extern bool operator<(const acl_classifier_key& a1, const acl_classifier_key& a2);
+
+typedef std::tuple<uint16_t, std::string> flow_id_flow_direction;
+typedef std::tuple<int16_t, uint16_t, int32_t> acl_id_gem_id_intf_id;
+extern std::map<flow_id_flow_direction, acl_id_gem_id_intf_id> flow_to_acl_map;
+
+// Keeps a reference count of how many flows are referencing a given ACL ID.
+// Key represents the ACL-ID and value is number of flows referencing the given ACL-ID.
+// When there is at least one flow referencing the ACL-ID, the ACL should be installed.
+// When there are no flows referencing the ACL-ID, the ACL should be removed.
+extern std::map<uint16_t, uint16_t> acl_ref_cnt;
+
+typedef std::tuple<uint16_t, uint16_t> gem_id_intf_id; // key to gem_ref_cnt
+// Keeps a reference count of how many ACL related flows are referencing a given (gem-id, pon_intf_id).
+// When there is at least on flow, we should install the gem. When there are no flows
+// the gem should be removed.
+extern std::map<gem_id_intf_id, uint16_t> gem_ref_cnt;
+
+// Needed to keep track of how many flows for a given acl_id, intf_id and intf_type are
+// installed. When there is at least on flow for this key, we should have interface registered
+// for the given ACL-ID. When there are no flows, the intf should unregister itself from
+// the ACL-ID.
+typedef std::tuple<uint16_t, uint8_t, std::string> acl_id_intf_id_intf_type;
+extern std::map<acl_id_intf_id_intf_type, uint16_t> intf_acl_registration_ref_cnt;
+
+extern std::bitset<MAX_ACL_ID> acl_id_bitset;
+
+/*** ACL Handling related data end ***/
+
+extern std::bitset<MAX_TM_SCHED_ID> tm_sched_bitset;
+extern std::bitset<MAX_TM_QMP_ID> tm_qmp_bitset;
+
+extern Queue<openolt::Indication> oltIndQ;
+
+extern bcmos_fastlock data_lock;
+
+
+#endif // OPENOLT_CORE_DATA_H_
diff --git a/agent/src/core_utils.cc b/agent/src/core_utils.cc
new file mode 100644
index 0000000..f63ca52
--- /dev/null
+++ b/agent/src/core_utils.cc
@@ -0,0 +1,1221 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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.
+ */
+
+#include "core_utils.h"
+
+std::string serial_number_to_str(bcmolt_serial_number* serial_number) {
+#define SERIAL_NUMBER_SIZE 12
+    char buff[SERIAL_NUMBER_SIZE+1];
+
+    sprintf(buff, "%c%c%c%c%1X%1X%1X%1X%1X%1X%1X%1X",
+            serial_number->vendor_id.arr[0],
+            serial_number->vendor_id.arr[1],
+            serial_number->vendor_id.arr[2],
+            serial_number->vendor_id.arr[3],
+            serial_number->vendor_specific.arr[0]>>4 & 0x0f,
+            serial_number->vendor_specific.arr[0] & 0x0f,
+            serial_number->vendor_specific.arr[1]>>4 & 0x0f,
+            serial_number->vendor_specific.arr[1] & 0x0f,
+            serial_number->vendor_specific.arr[2]>>4 & 0x0f,
+            serial_number->vendor_specific.arr[2] & 0x0f,
+            serial_number->vendor_specific.arr[3]>>4 & 0x0f,
+            serial_number->vendor_specific.arr[3] & 0x0f);
+
+    return buff;
+}
+
+std::string vendor_specific_to_str(char const * const vendor_specific) {
+    char buff[SERIAL_NUMBER_SIZE+1];
+
+    sprintf(buff, "%1X%1X%1X%1X%1X%1X%1X%1X",
+            vendor_specific[0]>>4 & 0x0f,
+            vendor_specific[0] & 0x0f,
+            vendor_specific[1]>>4 & 0x0f,
+            vendor_specific[1] & 0x0f,
+            vendor_specific[2]>>4 & 0x0f,
+            vendor_specific[2] & 0x0f,
+            vendor_specific[3]>>4 & 0x0f,
+            vendor_specific[3] & 0x0f);
+
+    return buff;
+}
+/**
+* Returns the default NNI (Upstream direction) or PON (Downstream direction) scheduler
+* Every NNI port and PON port have default scheduler.
+* The NNI0 default scheduler ID is 18432, and NNI1 is 18433 and so on.
+* Similarly, PON0 default scheduler ID is 16384. PON1 is 16385 and so on.
+*
+* @param intf_id NNI or PON interface ID
+* @param direction "upstream" or "downstream"
+*
+* @return default scheduler ID for the given interface.
+*/
+
+uint16_t get_dev_id(void) {
+    return dev_id;
+}
+
+int get_default_tm_sched_id(int intf_id, std::string direction) {
+    if (direction.compare(upstream) == 0) {
+        return tm_upstream_sched_id_start + intf_id;
+    } else if (direction.compare(downstream) == 0) {
+        return tm_downstream_sched_id_start + intf_id;
+    }
+    else {
+        OPENOLT_LOG(ERROR, openolt_log_id, "invalid direction - %s\n", direction.c_str());
+        return 0;
+    }
+}
+
+/**
+* Gets a unique tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction
+* The tm_sched_id is locally cached in a map, so that it can rendered when necessary.
+* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem
+*
+* @param intf_id NNI or PON intf ID
+* @param onu_id ONU ID
+* @param uni_id UNI ID
+* @param gemport_id GEM Port ID
+* @param direction Upstream or downstream
+*
+* @return tm_sched_id
+*/
+uint32_t get_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction) {
+    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction);
+    int sched_id = -1;
+
+    std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
+    if (it != sched_map.end()) {
+        sched_id = it->second;
+    }
+    if (sched_id != -1) {
+        return sched_id;
+    }
+
+    bcmos_fastlock_lock(&data_lock);
+    // Complexity of O(n). Is there better way that can avoid linear search?
+    for (sched_id = 0; sched_id < MAX_TM_SCHED_ID; sched_id++) {
+        if (tm_sched_bitset[sched_id] == 0) {
+            tm_sched_bitset[sched_id] = 1;
+            break;
+        }
+    }
+    bcmos_fastlock_unlock(&data_lock, 0);
+
+    if (sched_id < MAX_TM_SCHED_ID) {
+        bcmos_fastlock_lock(&data_lock);
+        sched_map[key] = sched_id;
+        bcmos_fastlock_unlock(&data_lock, 0);
+        return sched_id;
+    } else {
+        return -1;
+    }
+}
+
+/**
+* Free tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction
+*
+* @param intf_id NNI or PON intf ID
+* @param onu_id ONU ID
+* @param uni_id UNI ID
+* @param gemport_id GEM Port ID
+* @param direction Upstream or downstream
+*/
+void free_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction) {
+    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction);
+    std::map<sched_map_key_tuple, int>::const_iterator it;
+    bcmos_fastlock_lock(&data_lock);
+    it = sched_map.find(key);
+    if (it != sched_map.end()) {
+        tm_sched_bitset[it->second] = 0;
+        sched_map.erase(it);
+    }
+    bcmos_fastlock_unlock(&data_lock, 0);
+}
+
+bool is_tm_sched_id_present(int pon_intf_id, int onu_id, int uni_id, std::string direction) {
+    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction);
+    std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
+    if (it != sched_map.end()) {
+        return true;
+    }
+    return false;
+}
+
+/**
+* Check whether given two tm qmp profiles are equal or not
+*
+* @param tmq_map_profileA <vector> TM QUEUE MAPPING PROFILE
+* @param tmq_map_profileB <vector> TM QUEUE MAPPING PROFILE
+*
+* @return boolean, true if given tmq_map_profiles are equal else false
+*/
+
+bool check_tm_qmp_equality(std::vector<uint32_t> tmq_map_profileA, std::vector<uint32_t> tmq_map_profileB) {
+    for (uint32_t i = 0; i < TMQ_MAP_PROFILE_SIZE; i++) {
+        if (tmq_map_profileA[i] != tmq_map_profileB[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+/**
+* Modifies given queues_pbit_map to parsable format
+* e.g: Modifes "0b00000101" to "10100000"
+*
+* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
+* @param size Queue count
+*
+* @return string queues_pbit_map
+*/
+std::string* get_valid_queues_pbit_map(std::string *queues_pbit_map, uint32_t size) {
+    for(uint32_t i=0; i < size; i++) {
+        /* Deletes 2 characters from index number 0 */
+        queues_pbit_map[i].erase(0, 2);
+        std::reverse(queues_pbit_map[i].begin(), queues_pbit_map[i].end());
+    }
+    return queues_pbit_map;
+}
+
+/**
+* Creates TM QUEUE MAPPING PROFILE for given queues_pbit_map and queues_priority_q
+*
+* @param queues_pbit_map PBIT MAP configured for each GEM in TECH PROFILE
+* @param queues_priority_q PRIORITY_Q configured for each GEM in TECH PROFILE
+* @param size Queue count
+*
+* @return <vector> TM QUEUE MAPPING PROFILE
+*/
+std::vector<uint32_t> get_tmq_map_profile(std::string *queues_pbit_map, uint32_t *queues_priority_q, uint32_t size) {
+    std::vector<uint32_t> tmq_map_profile(8,0);
+
+    for(uint32_t i=0; i < size; i++) {
+        for (uint32_t j = 0; j < queues_pbit_map[i].size(); j++) {
+            if (queues_pbit_map[i][j]=='1') {
+                tmq_map_profile.at(j) = queue_id_list[queues_priority_q[i]];
+            }
+        }
+    }
+    return tmq_map_profile;
+}
+
+/**
+* Gets corresponding tm_qmp_id for a given tmq_map_profile
+*
+* @param <vector> TM QUEUE MAPPING PROFILE
+*
+* @return tm_qmp_id
+*/
+int get_tm_qmp_id(std::vector<uint32_t> tmq_map_profile) {
+    int tm_qmp_id = -1;
+
+    std::map<int, std::vector < uint32_t > >::const_iterator it = qmp_id_to_qmp_map.begin();
+    while(it != qmp_id_to_qmp_map.end()) {
+        if(check_tm_qmp_equality(tmq_map_profile, it->second)) {
+            tm_qmp_id = it->first;
+            break;
+        }
+        it++;
+    }
+    return tm_qmp_id;
+}
+
+/**
+* Updates sched_qmp_id_map with given sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id
+*
+* @param upstream/downstream sched_id
+* @param PON intf ID
+* @param onu_id ONU ID
+* @param uni_id UNI ID
+* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
+*/
+void update_sched_qmp_id_map(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
+                             uint32_t uni_id, int tm_qmp_id) {
+   bcmos_fastlock_lock(&data_lock);
+   sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
+   sched_qmp_id_map.insert(make_pair(key, tm_qmp_id));
+   bcmos_fastlock_unlock(&data_lock, 0);
+}
+
+/**
+* Gets corresponding tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
+*
+* @param upstream/downstream sched_id
+* @param PON intf ID
+* @param onu_id ONU ID
+* @param uni_id UNI ID
+*
+* @return tm_qmp_id
+*/
+int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
+    sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
+    int tm_qmp_id = -1;
+
+    std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
+    if (it != sched_qmp_id_map.end()) {
+        tm_qmp_id = it->second;
+    }
+    return tm_qmp_id;
+}
+
+/**
+* Gets a unique tm_qmp_id for a given tmq_map_profile
+* The tm_qmp_id is locally cached in a map, so that it can be rendered when necessary.
+* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem
+*
+* @param upstream/downstream sched_id
+* @param PON intf ID
+* @param onu_id ONU ID
+* @param uni_id UNI ID
+* @param <vector> TM QUEUE MAPPING PROFILE
+*
+* @return tm_qmp_id
+*/
+int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, \
+                  std::vector<uint32_t> tmq_map_profile) {
+    int tm_qmp_id;
+
+    bcmos_fastlock_lock(&data_lock);
+    /* Complexity of O(n). Is there better way that can avoid linear search? */
+    for (tm_qmp_id = 0; tm_qmp_id < MAX_TM_QMP_ID; tm_qmp_id++) {
+        if (tm_qmp_bitset[tm_qmp_id] == 0) {
+            tm_qmp_bitset[tm_qmp_id] = 1;
+            break;
+        }
+    }
+    bcmos_fastlock_unlock(&data_lock, 0);
+
+    if (tm_qmp_id < MAX_TM_QMP_ID) {
+        bcmos_fastlock_lock(&data_lock);
+        qmp_id_to_qmp_map.insert(make_pair(tm_qmp_id, tmq_map_profile));
+        bcmos_fastlock_unlock(&data_lock, 0);
+        update_sched_qmp_id_map(sched_id, pon_intf_id, onu_id, uni_id, tm_qmp_id);
+        return tm_qmp_id;
+    } else {
+        return -1;
+    }
+}
+
+/**
+* Free tm_qmp_id for a given sched_id, pon_intf_id, onu_id, uni_id
+*
+* @param upstream/downstream sched_id
+* @param PON intf ID
+* @param onu_id ONU ID
+* @param uni_id UNI ID
+* @param tm_qmp_id TM QUEUE MAPPING PROFILE ID
+*
+* @return boolean, true if no more reference for TM QMP else false
+*/
+bool free_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, \
+                    uint32_t uni_id, int tm_qmp_id) {
+    bool result;
+    sched_qmp_id_map_key_tuple key(sched_id, pon_intf_id, onu_id, uni_id);
+    std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it = sched_qmp_id_map.find(key);
+    bcmos_fastlock_lock(&data_lock);
+    if (it != sched_qmp_id_map.end()) {
+        sched_qmp_id_map.erase(it);
+    }
+    bcmos_fastlock_unlock(&data_lock, 0);
+
+    uint32_t tm_qmp_ref_count = 0;
+    std::map<sched_qmp_id_map_key_tuple, int>::const_iterator it2 = sched_qmp_id_map.begin();
+    while(it2 != sched_qmp_id_map.end()) {
+        if(it2->second == tm_qmp_id) {
+            tm_qmp_ref_count++;
+        }
+        it2++;
+    }
+
+    if (tm_qmp_ref_count == 0) {
+        std::map<int, std::vector < uint32_t > >::const_iterator it3 = qmp_id_to_qmp_map.find(tm_qmp_id);
+        if (it3 != qmp_id_to_qmp_map.end()) {
+            bcmos_fastlock_lock(&data_lock);
+            tm_qmp_bitset[tm_qmp_id] = 0;
+            qmp_id_to_qmp_map.erase(it3);
+            bcmos_fastlock_unlock(&data_lock, 0);
+            OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So clearing it\n", \
+                        tm_qmp_id, tm_qmp_ref_count);
+            result = true;
+        }
+    } else {
+        OPENOLT_LOG(INFO, openolt_log_id, "Reference count for tm qmp profile id %d is : %d. So not clearing it\n", \
+                    tm_qmp_id, tm_qmp_ref_count);
+        result = false;
+    }
+    return result;
+}
+
+// Gets free ACL ID if available, else -1
+int get_acl_id() {
+    int acl_id;
+    bcmos_fastlock_lock(&data_lock);
+    /* Complexity of O(n). Is there better way that can avoid linear search? */
+    for (acl_id = 0; acl_id < MAX_ACL_ID; acl_id++) {
+        if (acl_id_bitset[acl_id] == 0) {
+            acl_id_bitset[acl_id] = 1;
+            break;
+        }
+    }
+    bcmos_fastlock_unlock(&data_lock, 0);
+    if (acl_id < MAX_ACL_ID) {
+        return acl_id ;
+    } else {
+        return -1;
+    }
+}
+
+// Frees up the ACL ID.
+void free_acl_id (int acl_id) {
+    if (acl_id < MAX_ACL_ID) {
+        bcmos_fastlock_lock(&data_lock);
+        acl_id_bitset[acl_id] = 0;
+        bcmos_fastlock_unlock(&data_lock, 0);
+    }
+}
+
+/**
+* Returns qos type as string
+*
+* @param qos_type bcmolt_egress_qos_type enum
+*/
+std::string get_qos_type_as_string(bcmolt_egress_qos_type qos_type) {
+    switch (qos_type)
+    {
+        case BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE: return "FIXED_QUEUE";
+        case BCMOLT_EGRESS_QOS_TYPE_TC_TO_QUEUE: return "TC_TO_QUEUE";
+        case BCMOLT_EGRESS_QOS_TYPE_PBIT_TO_TC: return "PBIT_TO_TC";
+        case BCMOLT_EGRESS_QOS_TYPE_NONE: return "NONE";
+        case BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE: return "PRIORITY_TO_QUEUE";
+        default: OPENOLT_LOG(ERROR, openolt_log_id, "qos-type-not-supported %d\n", qos_type);
+                 return "qos-type-not-supported";
+    }
+}
+
+/**
+* Gets/Updates qos type for given pon_intf_id, onu_id, uni_id
+*
+* @param PON intf ID
+* @param onu_id ONU ID
+* @param uni_id UNI ID
+* @param queue_size TrafficQueues Size
+*
+* @return qos_type
+*/
+bcmolt_egress_qos_type get_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, uint32_t queue_size) {
+    qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
+    bcmolt_egress_qos_type egress_qos_type = BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
+    std::string qos_string;
+
+    std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
+    if (it != qos_type_map.end()) {
+        egress_qos_type = it->second;
+        qos_string = get_qos_type_as_string(egress_qos_type);
+        OPENOLT_LOG(INFO, openolt_log_id, "Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d is %s\n", \
+                    pon_intf_id, onu_id, uni_id, qos_string.c_str());
+    }
+    else {
+        /* QOS Type has been pre-defined as Fixed Queue but it will be updated based on number of GEMPORTS
+           associated for a given subscriber. If GEM count = 1 for a given subscriber, qos_type will be Fixed Queue
+           else Priority to Queue */
+        egress_qos_type = (queue_size > 1) ? \
+            BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE : BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE;
+        bcmos_fastlock_lock(&data_lock);
+        qos_type_map.insert(make_pair(key, egress_qos_type));
+        bcmos_fastlock_unlock(&data_lock, 0);
+        qos_string = get_qos_type_as_string(egress_qos_type);
+        OPENOLT_LOG(INFO, openolt_log_id, "Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d is %s\n", \
+                    pon_intf_id, onu_id, uni_id, qos_string.c_str());
+    }
+    return egress_qos_type;
+}
+
+/**
+* Clears qos type for given pon_intf_id, onu_id, uni_id
+*
+* @param PON intf ID
+* @param onu_id ONU ID
+* @param uni_id UNI ID
+*/
+void clear_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id) {
+    qos_type_map_key_tuple key(pon_intf_id, onu_id, uni_id);
+    std::map<qos_type_map_key_tuple, bcmolt_egress_qos_type>::const_iterator it = qos_type_map.find(key);
+    bcmos_fastlock_lock(&data_lock);
+    if (it != qos_type_map.end()) {
+        qos_type_map.erase(it);
+        OPENOLT_LOG(INFO, openolt_log_id, "Cleared Qos-type for subscriber connected to pon_intf_id %d, onu_id %d and uni_id %d\n", \
+                    pon_intf_id, onu_id, uni_id);
+    }
+    bcmos_fastlock_unlock(&data_lock, 0);
+}
+
+/**
+* Returns Scheduler/Queue direction as string
+*
+* @param direction as specified in tech_profile.proto
+*/
+std::string GetDirection(int direction) {
+    switch (direction)
+    {
+        case tech_profile::Direction::UPSTREAM: return upstream;
+        case tech_profile::Direction::DOWNSTREAM: return downstream;
+        default: OPENOLT_LOG(ERROR, openolt_log_id, "direction-not-supported %d\n", direction);
+                 return "direction-not-supported";
+    }
+}
+
+// This method handles waiting for AllocObject configuration.
+// Returns error if the AllocObject is not in the appropriate state based on action requested.
+bcmos_errno wait_for_alloc_action(uint32_t intf_id, uint32_t alloc_id, AllocCfgAction action) {
+    Queue<alloc_cfg_complete_result> cfg_result;
+    alloc_cfg_compltd_key k(intf_id, alloc_id);
+    alloc_cfg_compltd_map[k] =  &cfg_result;
+    bcmos_errno err = BCM_ERR_OK;
+    #ifdef TEST_MODE
+    ALLOC_CFG_FLAG = true;
+    #endif
+
+    // Try to pop the result from BAL with a timeout of ALLOC_CFG_COMPLETE_WAIT_TIMEOUT ms
+    std::pair<alloc_cfg_complete_result, bool> result = cfg_result.pop(ALLOC_CFG_COMPLETE_WAIT_TIMEOUT);
+    if (result.second == false) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "timeout waiting for alloc cfg complete indication intf_id %d, alloc_id %d\n",
+                    intf_id, alloc_id);
+        // Invalidate the queue pointer.
+        bcmos_fastlock_lock(&alloc_cfg_wait_lock);
+        alloc_cfg_compltd_map[k] = NULL;
+        bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
+        err = BCM_ERR_INTERNAL;
+        #ifdef TEST_MODE
+        ALLOC_CFG_FLAG = false;
+        #endif
+    }
+    else if (result.first.status == ALLOC_CFG_STATUS_FAIL) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "error processing alloc cfg request intf_id %d, alloc_id %d\n",
+                    intf_id, alloc_id);
+        err = BCM_ERR_INTERNAL;
+    }
+
+    if (err == BCM_ERR_OK) {
+        if (action == ALLOC_OBJECT_CREATE) {
+            if (result.first.state != ALLOC_OBJECT_STATE_ACTIVE) {
+                OPENOLT_LOG(ERROR, openolt_log_id, "alloc object not in active state intf_id %d, alloc_id %d alloc_obj_state %d\n",
+                            intf_id, alloc_id, result.first.state);
+               err = BCM_ERR_INTERNAL;
+            } else {
+                OPENOLT_LOG(INFO, openolt_log_id, "Create upstream bandwidth allocation success, intf_id %d, alloc_id %d\n",
+                            intf_id, alloc_id);
+            }
+        } else { // ALLOC_OBJECT_DELETE
+              if (result.first.state != ALLOC_OBJECT_STATE_NOT_CONFIGURED) {
+                  OPENOLT_LOG(ERROR, openolt_log_id, "alloc object is not reset intf_id %d, alloc_id %d alloc_obj_state %d\n",
+                              intf_id, alloc_id, result.first.state);
+                  err = BCM_ERR_INTERNAL;
+              } else {
+                  OPENOLT_LOG(INFO, openolt_log_id, "Remove alloc object success, intf_id %d, alloc_id %d\n",
+                              intf_id, alloc_id);
+              }
+        }
+    }
+
+    // Remove entry from map
+    bcmos_fastlock_lock(&alloc_cfg_wait_lock);
+    alloc_cfg_compltd_map.erase(k);
+    bcmos_fastlock_unlock(&alloc_cfg_wait_lock, 0);
+    #ifdef TEST_MODE
+    ALLOC_CFG_FLAG = false;
+    #endif
+    return err;
+}
+
+char* openolt_read_sysinfo(const char* field_name, char* field_val)
+{
+   FILE *fp;
+   /* Prepare the command*/
+   char command[150];
+
+   snprintf(command, sizeof command, "bash -l -c \"onlpdump -s\" | perl -ne 'print $1 if /%s: (\\S+)/'", field_name);
+   /* Open the command for reading. */
+   fp = popen(command, "r");
+   if (fp == NULL) {
+       /*The client has to check for a Null field value in this case*/
+       OPENOLT_LOG(INFO, openolt_log_id,  "Failed to query the %s\n", field_name);
+       return field_val;
+   }
+
+   /*Read the field value*/
+   if (fp) {
+       uint8_t ret;
+       ret = fread(field_val, OPENOLT_FIELD_LEN, 1, fp);
+       if (ret >= OPENOLT_FIELD_LEN)
+           OPENOLT_LOG(INFO, openolt_log_id,  "Read data length %u\n", ret);
+       pclose(fp);
+   }
+   return field_val;
+}
+
+Status pushOltOperInd(uint32_t intf_id, const char *type, const char *state)
+{
+    openolt::Indication ind;
+    openolt::IntfOperIndication* intf_oper_ind = new openolt::IntfOperIndication;
+
+    intf_oper_ind->set_type(type);
+    intf_oper_ind->set_intf_id(intf_id);
+    intf_oper_ind->set_oper_state(state);
+    ind.set_allocated_intf_oper_ind(intf_oper_ind);
+    oltIndQ.push(ind);
+    return Status::OK;
+}
+
+#define CLI_HOST_PROMPT_FORMAT "BCM.%u> "
+
+/* Build CLI prompt */
+void openolt_cli_get_prompt_cb(bcmcli_session *session, char *buf, uint32_t max_len)
+{
+    snprintf(buf, max_len, CLI_HOST_PROMPT_FORMAT, dev_id);
+}
+
+int _bal_apiend_cli_thread_handler(long data)
+{
+    char init_string[]="\n";
+    bcmcli_session *sess = current_session;
+    bcmos_task_parm bal_cli_task_p_dummy;
+
+    /* Switch to interactive mode if not stopped in the init script */
+    if (!bcmcli_is_stopped(sess)) {
+        /* Force a CLI command prompt
+         * The string passed into the parse function
+         * must be modifiable, so a string constant like
+         * bcmcli_parse(current_session, "\n") will not
+         * work.
+         */
+        bcmcli_parse(sess, init_string);
+
+        /* Process user input until EOF or quit command */
+        bcmcli_driver(sess);
+    }
+    OPENOLT_LOG(INFO, openolt_log_id, "BAL API End CLI terminated\n");
+
+    /* Cleanup */
+    bcmcli_session_close(current_session);
+    bcmcli_token_destroy(NULL);
+    return 0;
+}
+
+/* Init API CLI commands for the current device */
+bcmos_errno bcm_openolt_api_cli_init(bcmcli_entry *parent_dir, bcmcli_session *session)
+{
+    bcmos_errno rc;
+
+    api_parent_dir = parent_dir;
+
+    rc = bcm_api_cli_set_commands(session);
+
+#ifdef BCM_SUBSYSTEM_HOST
+    /* Subscribe for device change indication */
+    rc = rc ? rc : bcmolt_olt_sel_ind_register(_api_cli_olt_change_ind);
+#endif
+
+    return rc;
+}
+
+bcmos_errno bcm_cli_quit(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms)
+{
+    bcmcli_stop(session);
+    bcmcli_session_print(session, "CLI terminated by 'Quit' command\n");
+    status_bcm_cli_quit = BCMOS_TRUE;
+
+    return BCM_ERR_OK;
+}
+
+int get_status_bcm_cli_quit(void) {
+     return status_bcm_cli_quit;
+}
+
+bcmos_errno bcmolt_apiend_cli_init() {
+    bcmos_errno ret;
+    bcmos_task_parm bal_cli_task_p = {};
+    bcmos_task_parm bal_cli_task_p_dummy;
+
+    /** before creating the task, check if it is already created by the other half of BAL i.e. Core side */
+    if (BCM_ERR_OK != bcmos_task_query(&bal_cli_thread, &bal_cli_task_p_dummy)) {
+        /* Create BAL CLI thread */
+        bal_cli_task_p.name = bal_cli_thread_name;
+        bal_cli_task_p.handler = _bal_apiend_cli_thread_handler;
+        bal_cli_task_p.priority = TASK_PRIORITY_CLI;
+
+        ret = bcmos_task_create(&bal_cli_thread, &bal_cli_task_p);
+        if (BCM_ERR_OK != ret) {
+            bcmos_printf("Couldn't create BAL API end CLI thread\n");
+            return ret;
+        }
+    }
+}
+
+bcmos_errno get_pon_interface_status(bcmolt_interface pon_ni, bcmolt_interface_state *state) {
+    bcmos_errno err;
+    bcmolt_pon_interface_key pon_key;
+    bcmolt_pon_interface_cfg pon_cfg;
+    pon_key.pon_ni = pon_ni;
+
+    BCMOLT_CFG_INIT(&pon_cfg, pon_interface, pon_key);
+    BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, state);
+    BCMOLT_FIELD_SET_PRESENT(&pon_cfg.data, pon_interface_cfg_data, itu);
+    #ifdef TEST_MODE
+    // It is impossible to mock the setting of pon_cfg.data.state because
+    // the actual bcmolt_cfg_get passes the address of pon_cfg.hdr and we cannot
+    // set the pon_cfg.data.state. So a new stub function is created and address
+    // of pon_cfg is passed. This is one-of case where we need to add test specific
+    // code in production code.
+    err = bcmolt_cfg_get__pon_intf_stub(dev_id, &pon_cfg);
+    #else
+    err = bcmolt_cfg_get(dev_id, &pon_cfg.hdr);
+    #endif
+    *state = pon_cfg.data.state;
+    return err;
+}
+
+/* Same as bcmolt_cfg_get but with added logic of retrying the API
+   in case of some specific failures like timeout or object not yet ready
+*/
+bcmos_errno bcmolt_cfg_get_mult_retry(bcmolt_oltid olt, bcmolt_cfg *cfg) {
+    bcmos_errno err;
+    uint32_t current_try = 0;
+
+    while (current_try < MAX_BAL_API_RETRY_COUNT) {
+        err = bcmolt_cfg_get(olt, cfg);
+        current_try++;
+
+        if (err == BCM_ERR_STATE || err == BCM_ERR_TIMEOUT) {
+            OPENOLT_LOG(WARNING, openolt_log_id, "bcmolt_cfg_get: err = %s\n", bcmos_strerror(err));
+            bcmos_usleep(BAL_API_RETRY_TIME_IN_USECS);
+            continue;
+        }
+        else {
+           break;
+        }
+    }
+
+    if (err != BCM_ERR_OK) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "bcmolt_cfg_get tried (%d) times with retry time(%d usecs) err = %s\n",
+                           current_try,
+                           BAL_API_RETRY_TIME_IN_USECS,
+                           bcmos_strerror(err));
+    }
+    return err;
+}
+
+
+unsigned NumNniIf_() {return num_of_nni_ports;}
+unsigned NumPonIf_() {return num_of_pon_ports;}
+
+bcmos_errno get_nni_interface_status(bcmolt_interface id, bcmolt_interface_state *state) {
+    bcmos_errno err;
+    bcmolt_nni_interface_key nni_key;
+    bcmolt_nni_interface_cfg nni_cfg;
+    nni_key.id = id;
+
+    BCMOLT_CFG_INIT(&nni_cfg, nni_interface, nni_key);
+    BCMOLT_FIELD_SET_PRESENT(&nni_cfg.data, nni_interface_cfg_data, state);
+    #ifdef TEST_MODE
+    // It is impossible to mock the setting of nni_cfg.data.state because
+    // the actual bcmolt_cfg_get passes the address of nni_cfg.hdr and we cannot
+    // set the nni_cfg.data.state. So a new stub function is created and address
+    // of nni_cfg is passed. This is one-of case where we need to add test specific
+    // code in production code.
+    err = bcmolt_cfg_get__nni_intf_stub(dev_id, &nni_cfg);
+    #else
+    err = bcmolt_cfg_get(dev_id, &nni_cfg.hdr);
+    #endif
+    *state = nni_cfg.data.state;
+    return err;
+}
+
+Status install_gem_port(int32_t intf_id, int32_t onu_id, int32_t gemport_id) {
+    bcmos_errno err;
+    bcmolt_itupon_gem_cfg cfg; /* declare main API struct */
+    bcmolt_itupon_gem_key key = {}; /* declare key */
+    bcmolt_gem_port_configuration configuration = {};
+
+    key.pon_ni = intf_id;
+    key.gem_port_id = gemport_id;
+
+    BCMOLT_CFG_INIT(&cfg, itupon_gem, key);
+
+    bcmolt_gem_port_direction configuration_direction;
+    configuration_direction = BCMOLT_GEM_PORT_DIRECTION_BIDIRECTIONAL;
+    BCMOLT_FIELD_SET(&configuration, gem_port_configuration, direction, configuration_direction);
+
+    bcmolt_gem_port_type configuration_type;
+    configuration_type = BCMOLT_GEM_PORT_TYPE_UNICAST;
+    BCMOLT_FIELD_SET(&configuration, gem_port_configuration, type, configuration_type);
+
+    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, configuration, configuration);
+
+    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, onu_id, onu_id);
+
+    bcmolt_control_state encryption_mode;
+    encryption_mode = BCMOLT_CONTROL_STATE_DISABLE;
+    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, encryption_mode, encryption_mode);
+
+    bcmolt_us_gem_port_destination upstream_destination_queue;
+    upstream_destination_queue = BCMOLT_US_GEM_PORT_DESTINATION_DATA;
+    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, upstream_destination_queue, upstream_destination_queue);
+
+    bcmolt_control_state control;
+    control = BCMOLT_CONTROL_STATE_ENABLE;
+    BCMOLT_FIELD_SET(&cfg.data, itupon_gem_cfg_data, control, control);
+
+    err = bcmolt_cfg_set(dev_id, &cfg.hdr);
+    if(err != BCM_ERR_OK) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "failed to install gem_port = %d\n", gemport_id);
+        return bcm_to_grpc_err(err, "Access_Control set ITU PON Gem port failed");
+    }
+
+    OPENOLT_LOG(INFO, openolt_log_id, "gem port installed successfully = %d\n", gemport_id);
+
+    return Status::OK;
+}
+
+Status remove_gem_port(int32_t intf_id, int32_t gemport_id) {
+    bcmolt_itupon_gem_cfg gem_cfg;
+    bcmolt_itupon_gem_key key = {
+        .pon_ni = (bcmolt_interface)intf_id,
+        .gem_port_id = (bcmolt_gem_port_id)gemport_id
+    };
+    bcmos_errno err;
+
+    BCMOLT_CFG_INIT(&gem_cfg, itupon_gem, key);
+    err = bcmolt_cfg_clear(dev_id, &gem_cfg.hdr);
+    if (err != BCM_ERR_OK)
+    {
+        OPENOLT_LOG(ERROR, openolt_log_id, "failed to remove gem_port = %d err=%s\n", gemport_id, gem_cfg.hdr.hdr.err_text);
+        return bcm_to_grpc_err(err, "Access_Control clear ITU PON Gem port failed");
+    }
+
+    OPENOLT_LOG(INFO, openolt_log_id, "gem port removed successfully = %d\n", gemport_id);
+
+    return Status::OK;
+}
+
+Status update_acl_interface(int32_t intf_id, bcmolt_interface_type intf_type, uint32_t access_control_id,
+                bcmolt_members_update_command acl_cmd) {
+    bcmos_errno err;
+    bcmolt_access_control_interfaces_update oper; /* declare main API struct */
+    bcmolt_access_control_key acl_key = {}; /* declare key */
+    bcmolt_intf_ref interface_ref_list_elem = {};
+    bcmolt_interface_type interface_ref_list_elem_intf_type;
+    bcmolt_interface_id interface_ref_list_elem_intf_id;
+    bcmolt_intf_ref_list_u8 interface_ref_list = {};
+
+    if (acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_ADD && acl_cmd != BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "acl cmd = %d not supported currently\n", acl_cmd);
+        return bcm_to_grpc_err(BCM_ERR_PARM, "unsupported acl cmd");
+    }
+    interface_ref_list.arr = (bcmolt_intf_ref*)bcmos_calloc(sizeof(bcmolt_intf_ref)*1);
+
+    if (interface_ref_list.arr == NULL)
+         return bcm_to_grpc_err(BCM_ERR_PARM, "allocate interface_ref_list failed");
+    OPENOLT_LOG(INFO, openolt_log_id, "update acl interface received for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
+            intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
+            acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
+
+    acl_key.id = access_control_id;
+
+    /* Initialize the API struct. */
+    BCMOLT_OPER_INIT(&oper, access_control, interfaces_update, acl_key);
+
+    bcmolt_members_update_command command;
+    command = acl_cmd;
+    BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, command, command);
+
+    interface_ref_list_elem_intf_type = intf_type;
+    BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_type, interface_ref_list_elem_intf_type);
+
+    interface_ref_list_elem_intf_id = intf_id;
+    BCMOLT_FIELD_SET(&interface_ref_list_elem, intf_ref, intf_id, interface_ref_list_elem_intf_id);
+
+    interface_ref_list.len = 1;
+    BCMOLT_ARRAY_ELEM_SET(&interface_ref_list, 0, interface_ref_list_elem);
+
+    BCMOLT_FIELD_SET(&oper.data, access_control_interfaces_update_data, interface_ref_list, interface_ref_list);
+
+    err =  bcmolt_oper_submit(dev_id, &oper.hdr);
+    if (err != BCM_ERR_OK) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "update acl interface fail for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
+            intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
+            acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
+        return bcm_to_grpc_err(err, "Access_Control submit interface failed");
+    }
+
+    bcmos_free(interface_ref_list.arr);
+    OPENOLT_LOG(INFO, openolt_log_id, "update acl interface success for intf_id = %d, intf_type = %s, acl_id = %d, acl_cmd = %s\n",
+            intf_id, intf_type == BCMOLT_INTERFACE_TYPE_PON? "pon": "nni", access_control_id,
+            acl_cmd == BCMOLT_MEMBERS_UPDATE_COMMAND_ADD? "add": "remove");
+
+    return Status::OK;
+}
+
+Status install_acl(const acl_classifier_key acl_key) {
+
+    bcmos_errno err;
+    bcmolt_access_control_cfg cfg;
+    bcmolt_access_control_key key = { };
+    bcmolt_classifier c_val = { };
+    // hardcode the action for now.
+    bcmolt_access_control_fwd_action_type action_type = BCMOLT_ACCESS_CONTROL_FWD_ACTION_TYPE_TRAP_TO_HOST;
+
+    int acl_id = get_acl_id();
+    if (acl_id < 0) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "exhausted acl_id for eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d\n",
+                acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port);
+        bcmos_fastlock_unlock(&data_lock, 0);
+        return bcm_to_grpc_err(BCM_ERR_INTERNAL, "exhausted acl id");
+    }
+
+    key.id = acl_id;
+    /* config access control instance */
+    BCMOLT_CFG_INIT(&cfg, access_control, key);
+
+    if (acl_key.ether_type > 0) {
+        OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ether_type 0x%04x\n", acl_key.ether_type);
+        BCMOLT_FIELD_SET(&c_val, classifier, ether_type, acl_key.ether_type);
+    }
+
+    if (acl_key.ip_proto > 0) {
+        OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify ip_proto %d\n", acl_key.ip_proto);
+        BCMOLT_FIELD_SET(&c_val, classifier, ip_proto, acl_key.ip_proto);
+    }
+
+    if (acl_key.dst_port > 0) {
+        OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify dst_port %d\n", acl_key.dst_port);
+        BCMOLT_FIELD_SET(&c_val, classifier, dst_port, acl_key.dst_port);
+    }
+
+    if (acl_key.src_port > 0) {
+        OPENOLT_LOG(DEBUG, openolt_log_id, "Access_Control classify src_port %d\n", acl_key.src_port);
+        BCMOLT_FIELD_SET(&c_val, classifier, src_port, acl_key.src_port);
+    }
+
+    BCMOLT_MSG_FIELD_SET(&cfg, classifier, c_val);
+    BCMOLT_MSG_FIELD_SET(&cfg, priority, 10000);
+    BCMOLT_MSG_FIELD_SET(&cfg, statistics_control, BCMOLT_CONTROL_STATE_ENABLE);
+
+    BCMOLT_MSG_FIELD_SET(&cfg, forwarding_action.action, action_type);
+
+    err = bcmolt_cfg_set(dev_id, &cfg.hdr);
+    if (err != BCM_ERR_OK) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control set configuration failed, Error %d\n", err);
+        // Free the acl_id
+        free_acl_id(acl_id);
+        return bcm_to_grpc_err(err, "Access_Control set configuration failed");
+    }
+
+    ACL_LOG(INFO, "ACL add ok", err);
+
+    // Update the map that we have installed an acl for the given classfier.
+    acl_classifier_to_acl_id_map[acl_key] = acl_id;
+    return Status::OK;
+}
+
+Status remove_acl(int acl_id) {
+    bcmos_errno err;
+    bcmolt_access_control_cfg cfg; /* declare main API struct */
+    bcmolt_access_control_key key = {}; /* declare key */
+
+    key.id = acl_id;
+
+    /* Initialize the API struct. */
+    BCMOLT_CFG_INIT(&cfg, access_control, key);
+    BCMOLT_FIELD_SET_PRESENT(&cfg.data, access_control_cfg_data, state);
+    err = bcmolt_cfg_get(dev_id, &cfg.hdr);
+    if (err != BCM_ERR_OK) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Access_Control get state failed\n");
+        return bcm_to_grpc_err(err, "Access_Control get state failed");
+    }
+
+    if (cfg.data.state == BCMOLT_CONFIG_STATE_CONFIGURED) {
+        key.id = acl_id;
+        /* Initialize the API struct. */
+        BCMOLT_CFG_INIT(&cfg, access_control, key);
+
+        err = bcmolt_cfg_clear(dev_id, &cfg.hdr);
+        if (err != BCM_ERR_OK) {
+            // Should we free acl_id here ? We should ideally never land here..
+            OPENOLT_LOG(ERROR, openolt_log_id, "Error %d while removing Access_Control rule ID %d\n",
+                err, acl_id);
+            return Status(grpc::StatusCode::INTERNAL, "Failed to remove Access_Control");
+        }
+    }
+
+    // Free up acl_id
+    free_acl_id(acl_id);
+
+    OPENOLT_LOG(INFO, openolt_log_id, "acl removed successfully %d\n", acl_id);
+
+    return Status::OK;
+}
+
+// Formulates ACL Classifier Key based on the following fields
+// a. ether_type b. ip_proto c. src_port d. dst_port
+// If any of the field is not available it is populated as -1.
+void formulate_acl_classifier_key(acl_classifier_key *key, const ::openolt::Classifier& classifier) {
+
+        // TODO: Is 0 a valid value for any of the following classifiers?
+        // because in the that case, the 'if' check would fail and -1 would be filled as value.
+        //
+        if (classifier.eth_type()) {
+            OPENOLT_LOG(DEBUG, openolt_log_id, "classify ether_type 0x%04x\n", classifier.eth_type());
+            key->ether_type = classifier.eth_type();
+        } else key->ether_type = -1;
+
+        if (classifier.ip_proto()) {
+            OPENOLT_LOG(DEBUG, openolt_log_id, "classify ip_proto %d\n", classifier.ip_proto());
+            key->ip_proto = classifier.ip_proto();
+        } else key->ip_proto = -1;
+
+
+        if (classifier.src_port()) {
+            OPENOLT_LOG(DEBUG, openolt_log_id, "classify src_port %d\n", classifier.src_port());
+            key->src_port = classifier.src_port();
+        } else key->src_port = -1;
+
+
+        if (classifier.dst_port()) {
+            OPENOLT_LOG(DEBUG, openolt_log_id, "classify dst_port %d\n", classifier.dst_port());
+            key->dst_port = classifier.dst_port();
+        } else key->dst_port = -1;
+}
+
+Status handle_acl_rule_install(int32_t onu_id, uint32_t flow_id,
+                               const std::string flow_type, int32_t access_intf_id,
+                               int32_t network_intf_id, int32_t gemport_id,
+                               const ::openolt::Classifier& classifier) {
+    int acl_id;
+    int32_t intf_id = flow_type.compare(upstream) == 0? access_intf_id: network_intf_id;
+    const std::string intf_type = flow_type.compare(upstream) == 0? "pon": "nni";
+    bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
+
+    Status resp;
+
+    // few map keys we are going to use later.
+    flow_id_flow_direction fl_id_fl_dir(flow_id, flow_type);
+    gem_id_intf_id gem_intf(gemport_id, access_intf_id);
+    acl_classifier_key acl_key;
+    formulate_acl_classifier_key(&acl_key, classifier);
+    const acl_classifier_key acl_key_const = {.ether_type=acl_key.ether_type, .ip_proto=acl_key.ip_proto,
+        .src_port=acl_key.src_port, .dst_port=acl_key.dst_port};
+
+    bcmos_fastlock_lock(&data_lock);
+
+    // Check if the acl is already installed
+    if (acl_classifier_to_acl_id_map.count(acl_key_const) > 0) {
+        // retreive the acl_id
+        acl_id = acl_classifier_to_acl_id_map[acl_key_const];
+        acl_id_gem_id_intf_id ac_id_gm_id_if_id(acl_id, gemport_id, intf_id);
+        if (flow_to_acl_map.count(fl_id_fl_dir)) {
+            // coult happen if same trap flow is received again
+            OPENOLT_LOG(INFO, openolt_log_id, "flow and related acl already handled, nothing more to do\n");
+            bcmos_fastlock_unlock(&data_lock, 0);
+            return Status::OK;
+        }
+
+        OPENOLT_LOG(INFO, openolt_log_id, "Acl for flow_id=%u with eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d already installed with acl id = %u\n",
+                flow_id, acl_key.ether_type, acl_key.ip_proto, acl_key.src_port, acl_key.dst_port, acl_id);
+
+        // The acl_ref_cnt is needed to know how many flows refer an ACL.
+        // When the flow is removed, we decrement the reference count.
+        // When the reference count becomes 0, we remove the ACL.
+        if (acl_ref_cnt.count(acl_id) > 0) {
+            acl_ref_cnt[acl_id] ++;
+        } else {
+            // We should ideally not land here. The acl_ref_cnt should have been
+            // initialized the first time acl was installed.
+            acl_ref_cnt[acl_id] = 1;
+        }
+
+    } else {
+        resp = install_acl(acl_key_const);
+        if (!resp.ok()) {
+            OPENOLT_LOG(ERROR, openolt_log_id, "Acl for flow_id=%u with eth_type = %d, ip_proto = %d, src_port = %d, dst_port = %d failed\n",
+                    flow_id, acl_key_const.ether_type, acl_key_const.ip_proto, acl_key_const.src_port, acl_key_const.dst_port);
+            bcmos_fastlock_unlock(&data_lock, 0);
+            return resp;
+        }
+
+        acl_id = acl_classifier_to_acl_id_map[acl_key_const];
+
+        // Initialize the acl reference count
+        acl_ref_cnt[acl_id] = 1;
+
+        OPENOLT_LOG(INFO, openolt_log_id, "acl add success for flow_id=%u with acl_id=%d\n", flow_id, acl_id);
+    }
+
+    // Register the interface for the given acl
+    acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
+    // This is needed to keep a track of which interface (pon/nni) has registered for an ACL.
+    // If it is registered, how many flows refer to it.
+    if (intf_acl_registration_ref_cnt.count(ac_id_inf_id_inf_type) > 0) {
+        intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]++;
+    } else {
+        // The given interface is not registered for the ACL. We need to do it now.
+        resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_ADD);
+        if (!resp.ok()){
+            OPENOLT_LOG(ERROR, openolt_log_id, "failed to update acl interfaces intf_id=%d, intf_type=%s, acl_id=%d", intf_id, intf_type.c_str(), acl_id);
+            // TODO: Ideally we should return error from hear and clean up other other stateful
+            // counters we creaed earlier. Will leave it out for now.
+        } 
+        intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] = 1;
+    }
+
+
+    // Install the gem port if needed.
+    if (gemport_id > 0 && access_intf_id >= 0) {
+        if (gem_ref_cnt.count(gem_intf) > 0) {
+            // The gem port is already installed
+            // Increment the ref counter indicating number of flows referencing this gem port
+            gem_ref_cnt[gem_intf]++;
+            OPENOLT_LOG(DEBUG, openolt_log_id, "increment gem_ref_cnt in acl handler, ref_cnt=%d\n", gem_ref_cnt[gem_intf]);
+
+        } else {
+            // We should ideally never land here. The gem port should have been created the
+            // first time ACL was installed.
+            // Install the gem port
+            Status resp = install_gem_port(access_intf_id, onu_id, gemport_id);
+            if (!resp.ok()) {
+                // TODO: We might need to reverse all previous data, but leave it out for now.
+                OPENOLT_LOG(ERROR, openolt_log_id, "failed to install the gemport=%d for acl_id=%d, intf_id=%d\n", gemport_id, acl_id, access_intf_id);
+                bcmos_fastlock_unlock(&data_lock, 0);
+                return resp;
+            }
+            // Initialize the refence count for the gemport.
+            gem_ref_cnt[gem_intf] = 1;
+            OPENOLT_LOG(DEBUG, openolt_log_id, "intialized gem ref count in acl handler\n");
+        }
+    } else {
+        OPENOLT_LOG(DEBUG, openolt_log_id, "not incrementing gem_ref_cnt in acl handler flow_id=%d, gemport_id=%d, intf_id=%d\n", flow_id, gemport_id, access_intf_id);
+    }
+
+    // Update the flow_to_acl_map
+    // This info is needed during flow remove. We need to which ACL ID and GEM PORT ID
+    // the flow was referring to.
+    // After retrieving the ACL ID and GEM PORT ID, we decrement the corresponding
+    // reference counters for those ACL ID and GEMPORT ID.
+    acl_id_gem_id_intf_id ac_id_gm_id_if_id(acl_id, gemport_id, intf_id);
+    flow_to_acl_map[fl_id_fl_dir] = ac_id_gm_id_if_id;
+
+    bcmos_fastlock_unlock(&data_lock, 0);
+
+    return Status::OK;
+}
+
+void clear_gem_port(int gemport_id, int access_intf_id) {
+    gem_id_intf_id gem_intf(gemport_id, access_intf_id);
+    if (gemport_id > 0 && access_intf_id >= 0 && gem_ref_cnt.count(gem_intf) > 0) {
+        OPENOLT_LOG(DEBUG, openolt_log_id, "decrementing gem_ref_cnt gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
+        gem_ref_cnt[gem_intf]--;
+        if (gem_ref_cnt[gem_intf] == 0) {
+            // For datapath flow this may not be necessary (to be verified)
+            remove_gem_port(access_intf_id, gemport_id);
+            gem_ref_cnt.erase(gem_intf);
+            OPENOLT_LOG(DEBUG, openolt_log_id, "removing gem_ref_cnt entry gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
+        } else {
+            OPENOLT_LOG(DEBUG, openolt_log_id, "gem_ref_cnt  not zero yet gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
+        }
+    } else {
+        OPENOLT_LOG(DEBUG, openolt_log_id, "not decrementing gem_ref_cnt gemport_id=%d access_intf_id=%d\n", gemport_id, access_intf_id);
+    }
+}
+
+Status handle_acl_rule_cleanup(int16_t acl_id, int32_t gemport_id, int32_t intf_id, const std::string flow_type) {
+    const std::string intf_type= flow_type.compare(upstream) == 0 ? "pon": "nni";
+    acl_id_intf_id_intf_type ac_id_inf_id_inf_type(acl_id, intf_id, intf_type);
+    intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type]--;
+    if (intf_acl_registration_ref_cnt[ac_id_inf_id_inf_type] == 0) {
+        bcmolt_interface_type olt_if_type = intf_type == "pon"? BCMOLT_INTERFACE_TYPE_PON: BCMOLT_INTERFACE_TYPE_NNI;
+        Status resp = update_acl_interface(intf_id, olt_if_type, acl_id, BCMOLT_MEMBERS_UPDATE_COMMAND_REMOVE);
+        if (!resp.ok()){
+            OPENOLT_LOG(ERROR, openolt_log_id, "failed to update acl interfaces intf_id=%d, intf_type=%s, acl_id=%d", intf_id, intf_type.c_str(), acl_id);
+        }
+        intf_acl_registration_ref_cnt.erase(ac_id_inf_id_inf_type);
+    }
+
+    acl_ref_cnt[acl_id]--;
+    if (acl_ref_cnt[acl_id] == 0) {
+        remove_acl(acl_id);
+        acl_ref_cnt.erase(acl_id);
+        // Iterate acl_classifier_to_acl_id_map and delete classifier the key corresponding to acl_id
+        std::map<acl_classifier_key, uint16_t>::iterator it;
+        for (it=acl_classifier_to_acl_id_map.begin(); it!=acl_classifier_to_acl_id_map.end(); ++it)  {
+            if (it->second == acl_id) {
+                OPENOLT_LOG(INFO, openolt_log_id, "cleared classifier key corresponding to acl_id = %d\n", acl_id);
+                acl_classifier_to_acl_id_map.erase(it->first);
+                break;
+            }
+        }
+    }
+
+    clear_gem_port(gemport_id, intf_id);
+
+    return Status::OK;
+}
+
+Status check_bal_ready() {
+    bcmos_errno err;
+    int maxTrials = 30;
+    bcmolt_olt_cfg olt_cfg = { };
+    bcmolt_olt_key olt_key = { };
+
+    BCMOLT_CFG_INIT(&olt_cfg, olt, olt_key);
+    BCMOLT_MSG_FIELD_GET(&olt_cfg, bal_state);
+
+    while (olt_cfg.data.bal_state != BCMOLT_BAL_STATE_BAL_AND_SWITCH_READY) {
+        if (--maxTrials == 0)
+            return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check bal ready failed");
+        sleep(5);
+        #ifdef TEST_MODE
+        // It is impossible to mock the setting of olt_cfg.data.bal_state because
+        // the actual bcmolt_cfg_get passes the address of olt_cfg.hdr and we cannot
+        // set the olt_cfg.data.bal_state. So a new stub function is created and address
+        // of olt_cfg is passed. This is one-of case where we need to add test specific
+        // code in production code.
+        if (bcmolt_cfg_get__bal_state_stub(dev_id, &olt_cfg)) {
+        #else
+        if (bcmolt_cfg_get(dev_id, &olt_cfg.hdr)) {
+        #endif
+            continue;
+        }
+        else
+            OPENOLT_LOG(INFO, openolt_log_id, "waiting for BAL ready ...\n");
+    }
+
+    OPENOLT_LOG(INFO, openolt_log_id, "BAL is ready\n");
+    return Status::OK;
+}
+
+Status check_connection() {
+    int maxTrials = 60;
+    while (!bcmolt_api_conn_mgr_is_connected(dev_id)) {
+        sleep(1);
+        if (--maxTrials == 0)
+            return grpc::Status(grpc::StatusCode::UNAVAILABLE, "check connection failed");
+        else
+            OPENOLT_LOG(INFO, openolt_log_id, "waiting for daemon connection ...\n");
+    }
+    OPENOLT_LOG(INFO, openolt_log_id, "daemon is connected\n");
+    return Status::OK;
+}
+
diff --git a/agent/src/core_utils.h b/agent/src/core_utils.h
new file mode 100644
index 0000000..5a7c6bd
--- /dev/null
+++ b/agent/src/core_utils.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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.
+ */
+#ifndef OPENOLT_CORE_UTILS_H_
+#define OPENOLT_CORE_UTILS_H_
+#include <string>
+#include <unistd.h>
+
+#include "core.h"
+#include "core_data.h"
+#include "error_format.h"
+
+extern "C"
+{
+#include <bcmolt_api.h>
+#include <bcmolt_host_api.h>
+#include <bcmolt_api_model_supporting_enums.h>
+#include <bcmolt_api_model_supporting_structs.h>
+
+#include <bcmolt_api_conn_mgr.h>
+//CLI header files
+#include <bcmcli_session.h>
+#include <bcmcli.h>
+#include <bcm_api_cli.h>
+
+#include <bcmos_common.h>
+#include <bcm_config.h>
+// FIXME : dependency problem
+// #include <bcm_common_gpon.h>
+// #include <bcm_dev_log_task.h>
+}
+
+
+std::string serial_number_to_str(bcmolt_serial_number* serial_number);
+std::string vendor_specific_to_str(const char* const serial_number);
+uint16_t get_dev_id(void);
+int get_default_tm_sched_id(int intf_id, std::string direction);
+uint32_t get_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction);
+void free_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction);
+bool is_tm_sched_id_present(int pon_intf_id, int onu_id, int uni_id, std::string direction);
+bool check_tm_qmp_equality(std::vector<uint32_t> tmq_map_profileA, std::vector<uint32_t> tmq_map_profileB);
+std::string* get_valid_queues_pbit_map(std::string *queues_pbit_map, uint32_t size);
+std::vector<uint32_t> get_tmq_map_profile(std::string *queues_pbit_map, uint32_t *queues_priority_q, uint32_t size);
+int get_tm_qmp_id(std::vector<uint32_t> tmq_map_profile);
+void update_sched_qmp_id_map(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id,
+                             uint32_t uni_id, int tm_qmp_id);
+int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id);
+int get_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id,
+                  std::vector<uint32_t> tmq_map_profile);
+bool free_tm_qmp_id(uint32_t sched_id,uint32_t pon_intf_id, uint32_t onu_id,
+                    uint32_t uni_id, int tm_qmp_id);
+int get_acl_id();
+void free_acl_id (int acl_id);
+std::string get_qos_type_as_string(bcmolt_egress_qos_type qos_type);
+bcmolt_egress_qos_type get_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id, uint32_t queue_size=0);
+void clear_qos_type(uint32_t pon_intf_id, uint32_t onu_id, uint32_t uni_id);
+std::string GetDirection(int direction);
+bcmos_errno wait_for_alloc_action(uint32_t intf_id, uint32_t alloc_id, AllocCfgAction action);
+char* openolt_read_sysinfo(const char* field_name, char* field_val);
+Status pushOltOperInd(uint32_t intf_id, const char *type, const char *state);
+void openolt_cli_get_prompt_cb(bcmcli_session *session, char *buf, uint32_t max_len);
+int _bal_apiend_cli_thread_handler(long data);
+bcmos_errno bcm_openolt_api_cli_init(bcmcli_entry *parent_dir, bcmcli_session *session);
+bcmos_errno bcm_cli_quit(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t n_parms);
+int get_status_bcm_cli_quit(void);
+bcmos_errno bcmolt_apiend_cli_init();
+bcmos_errno get_pon_interface_status(bcmolt_interface pon_ni, bcmolt_interface_state *state);
+bcmos_errno bcmolt_cfg_get_mult_retry(bcmolt_oltid olt, bcmolt_cfg *cfg);
+unsigned NumNniIf_();
+unsigned NumPonIf_();
+bcmos_errno get_nni_interface_status(bcmolt_interface id, bcmolt_interface_state *state);
+Status install_gem_port(int32_t intf_id, int32_t onu_id, int32_t gemport_id);
+Status remove_gem_port(int32_t intf_id, int32_t gemport_id);
+Status update_acl_interface(int32_t intf_id, bcmolt_interface_type intf_type, uint32_t access_control_id,
+                bcmolt_members_update_command acl_cmd);
+Status install_acl(const acl_classifier_key acl_key);
+Status remove_acl(int acl_id);
+void formulate_acl_classifier_key(acl_classifier_key *key, const ::openolt::Classifier& classifier);
+Status handle_acl_rule_install(int32_t onu_id, uint32_t flow_id,
+                               const std::string flow_type, int32_t access_intf_id,
+                               int32_t network_intf_id, int32_t gemport_id,
+                               const ::openolt::Classifier& classifier);
+void clear_gem_port(int gemport_id, int access_intf_id);
+Status handle_acl_rule_cleanup(int16_t acl_id, int32_t gemport_id, int32_t intf_id, const std::string flow_type);
+Status check_bal_ready();
+Status check_connection();
+#endif // OPENOLT_CORE_UTILS_H_
+
+
diff --git a/agent/src/indications.cc b/agent/src/indications.cc
index c9f112e..b4eeb58 100644
--- a/agent/src/indications.cc
+++ b/agent/src/indications.cc
@@ -16,7 +16,8 @@
 
 #include "indications.h"
 #include "core.h"
-#include "utils.h"
+#include "core_data.h"
+#include "core_utils.h"
 #include "stats_collection.h"
 #include "translation.h"
 #include "state.h"
diff --git a/agent/src/stats_collection.cc b/agent/src/stats_collection.cc
index f0feca4..9caa98e 100644
--- a/agent/src/stats_collection.cc
+++ b/agent/src/stats_collection.cc
@@ -20,6 +20,7 @@
 
 #include "indications.h"
 #include "core.h"
+#include "core_data.h"
 #include "translation.h"
 
 extern "C"
diff --git a/agent/src/utils.cc b/agent/src/utils.cc
deleted file mode 100644
index 21ca84b..0000000
--- a/agent/src/utils.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2018-present Open Networking Foundation
-
- * 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.
- */
-#include <string.h>
-#include "utils.h"
-
-std::string serial_number_to_str(bcmolt_serial_number* serial_number) {
-#define SERIAL_NUMBER_SIZE 12
-    char buff[SERIAL_NUMBER_SIZE+1];
-
-    sprintf(buff, "%c%c%c%c%1X%1X%1X%1X%1X%1X%1X%1X",
-            serial_number->vendor_id.arr[0],
-            serial_number->vendor_id.arr[1],
-            serial_number->vendor_id.arr[2],
-            serial_number->vendor_id.arr[3],
-            serial_number->vendor_specific.arr[0]>>4 & 0x0f,
-            serial_number->vendor_specific.arr[0] & 0x0f,
-            serial_number->vendor_specific.arr[1]>>4 & 0x0f,
-            serial_number->vendor_specific.arr[1] & 0x0f,
-            serial_number->vendor_specific.arr[2]>>4 & 0x0f,
-            serial_number->vendor_specific.arr[2] & 0x0f,
-            serial_number->vendor_specific.arr[3]>>4 & 0x0f,
-            serial_number->vendor_specific.arr[3] & 0x0f);
-
-    return buff;
-}
-
-std::string vendor_specific_to_str(char const * const vendor_specific) {
-    char buff[SERIAL_NUMBER_SIZE+1];
-
-    sprintf(buff, "%1X%1X%1X%1X%1X%1X%1X%1X",
-            vendor_specific[0]>>4 & 0x0f,
-            vendor_specific[0] & 0x0f,
-            vendor_specific[1]>>4 & 0x0f,
-            vendor_specific[1] & 0x0f,
-            vendor_specific[2]>>4 & 0x0f,
-            vendor_specific[2] & 0x0f,
-            vendor_specific[3]>>4 & 0x0f,
-            vendor_specific[3] & 0x0f);
-
-    return buff;
-}
-
diff --git a/agent/src/utils.h b/agent/src/utils.h
deleted file mode 100644
index c35d6f0..0000000
--- a/agent/src/utils.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2018-present Open Networking Foundation
-
- * 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.
- */
-#ifndef OPENOLT_UTILS_H_
-#define OPENOLT_UTILS_H_
-
-#include <string>
-
-extern "C"
-{
-#include <bcmos_system.h>
-#include <bcmolt_api.h>
-#include <bcmolt_api_model_supporting_structs.h>
-}
-
-std::string serial_number_to_str(bcmolt_serial_number* serial_number);
-std::string vendor_specific_to_str(const char* const serial_number);
-
-#endif
diff --git a/agent/test/Makefile.in b/agent/test/Makefile.in
index f3f0e5e..2d700cd 100644
--- a/agent/test/Makefile.in
+++ b/agent/test/Makefile.in
@@ -27,10 +27,27 @@
 # openolt.proto and tech_profile.proto
 OPENOLT_PROTO_VER ?= v1.0.3
 
+GTEST_VER ?= release-1.8.0
+gtest-target = $(HOME)/openolt-agent-test-lib/gtest/$(GTEST_VER)/lib/libgtest.a
+
+CMOCK_VER ?= 0207b30
+cmock-target = $(HOME)/openolt-agent-test-lib/cmock/$(CMOCK_VER)/include/cmock.h
+
+GMOCK_GLOBAL_VER ?= 1.0.2
+gmock-global-target = $(HOME)/openolt-agent-test-lib/gmock-global/$(GMOCK_GLOBAL_VER)/gmock-global/gmock-global.h
+
+
 # GRPC installation
 GRPC_ADDR = https://github.com/grpc/grpc
 GRPC_DST = /tmp/grpc
 GRPC_VER = v1.10.x
+grpc-cpp-plugin-bin = $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/bin/grpc_cpp_plugin
+
+# Protobuf installation
+PROTOBUF_VER = 3.5.0
+PROTOBUF_ADDR = https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOBUF_VER)/protobuf-cpp-$(PROTOBUF_VER).tar.gz
+PROTOBUF_DST = /tmp/protobuf-$(PROTOBUF_VER)
+protoc-bin = $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/bin/protoc
 
 USER := $(shell echo $(USER))
 #
@@ -43,63 +60,79 @@
 
 CXX = g++-4.9
 CXXFLAGS += -g -O2
-CXXFLAGS += $(shell pkg-config --cflags-only-I grpc++)
-CPPFLAGS += `pkg-config --cflags protobuf grpc`
+CXXFLAGS += $(shell PKG_CONFIG_PATH=$(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/lib/pkgconfig pkg-config --cflags-only-I grpc++)
+CPPFLAGS += `PKG_CONFIG_PATH=$(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/lib/pkgconfig pkg-config --cflags protobuf grpc`
 CXXFLAGS += -std=c++11 -fpermissive -Wno-literal-suffix
 CXXFLAGS += -DTEST_MODE -DENABLE_LOG
 LDFLAGS +=
-LDFLAGS += `pkg-config --libs protobuf grpc++ grpc` -ldl -lgpr
+LDFLAGS += `PKG_CONFIG_PATH=$(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/lib/pkgconfig pkg-config --libs protobuf grpc++ grpc` -ldl -lgpr
 CXXFLAGSDEVICE = -I../device -I../device/$(OPENOLTDEVICE) -I../device/generic
 
 export CXX CXXFLAGS OPENOLT_PROTO_VER
 
-BAL_API_DIR=bal-api-3.2.3.2
+BAL_API_VER=bal-api-3.2.3.2
+BAL_API_DIR=$(BAL_API_VER)
 BALLIBNAME=bcm_host_api_stubs
 BALLIBDIR=$(BAL_API_DIR)/stubs
 BAL_INC = -I$(BAL_API_DIR)/include \
           -I$(BAL_API_DIR)/include/object_model
-CXXFLAGS += $(BAL_INC)
+TEST_LIB_INC = -I$(HOME)/openolt-agent-test-lib/gtest/$(GTEST_VER)/include \
+			   -I$(HOME)/openolt-agent-test-lib/cmock/$(CMOCK_VER)/include \
+			   -I$(HOME)/openolt-agent-test-lib/gmock-global/$(GMOCK_GLOBAL_VER)
+CXXFLAGS += $(BAL_INC) $(TEST_LIB_INC)
 
 
-
-prereq:
+prereqs-system:
 	sudo apt-get -q -y install git pkg-config build-essential autoconf libtool libgflags-dev libgtest-dev clang libc++-dev unzip docker.io
 	sudo apt-get install -y build-essential autoconf libssl-dev gawk debhelper dh-systemd init-system-helpers curl cmake ccache g++-4.9
 
-	# Install GRPC, libprotobuf and protoc
+prereqs-local: $(protoc-bin) $(grpc-cpp-plugin-bin) prereqs-test-lib
+
+$(protoc-bin):
+	# Install protobuf
+	rm -rf $(PROTOBUF_DST)
+	cd /tmp && wget $(PROTOBUF_ADDR)
+	cd /tmp && tar -zxvf protobuf-cpp-$(PROTOBUF_VER).tar.gz
+	cd $(PROTOBUF_DST) && ./autogen.sh
+	mkdir -p $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)
+	cd $(PROTOBUF_DST) && ./configure --prefix=$(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)
+	make -C $(PROTOBUF_DST)
+	make -C $(PROTOBUF_DST) install
+
+$(grpc-cpp-plugin-bin):
+	# Install GRPC, protoc
 	rm -rf $(GRPC_DST)
-	git clone -b $(GRPC_VER) $(GRPC_ADDR) $(GRPC_DST)
+	cd /tmp && git clone -b $(GRPC_VER) $(GRPC_ADDR) $(GRPC_DST)
 	cd $(GRPC_DST) && git submodule update --init
-	cd $(GRPC_DST)/third_party/protobuf && ./autogen.sh && ./configure
-	make -C $(GRPC_DST)/third_party/protobuf
-	sudo make -C $(GRPC_DST)/third_party/protobuf install
-	sudo ldconfig
+	mkdir -p $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)
 	make -C $(GRPC_DST)
-	sudo make -C $(GRPC_DST) install
-	sudo ldconfig
+	make -C $(GRPC_DST) install prefix=$(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)
 
-prereq-mock-lib: gtest cmock gmock-global
+prereqs-test-lib: $(gtest-target) $(cmock-target) $(gmock-global-target)
 
-gtest:
-	# Install gtest and gmock
+$(gtest-target):
+	# Install gtest
 	rm -rf /tmp/googletest && cd /tmp && git clone https://github.com/google/googletest.git
-	cd /tmp/googletest && git checkout release-1.8.0
-	cd /tmp/googletest && cmake CMakeLists.txt
+	cd /tmp/googletest && git checkout $(GTEST_VER)
+	mkdir -p $(HOME)/openolt-agent-test-lib/gtest/$(GTEST_VER)
+	cd /tmp/googletest && cmake CMakeLists.txt -DCMAKE_INSTALL_PREFIX=$(HOME)/openolt-agent-test-lib/gtest/$(GTEST_VER)
 	make -C /tmp/googletest
-	sudo make -C /tmp/googletest install
+	make -C /tmp/googletest install
 
-cmock:
+$(cmock-target):
 	# Install c-mock
 	rm -rf /tmp/C-Mock && cd /tmp && git clone https://github.com/hjagodzinski/C-Mock.git
-	cd /tmp/C-Mock && git checkout 0207b3026f04bbdf0bd9d9f8dfd00945a4318251
-	make -C /tmp/C-Mock
-	sudo make -C /tmp/C-Mock install
+	cd /tmp/C-Mock && git checkout $(CMOCK_VER)
+	mkdir -p $(HOME)/openolt-agent-test-lib/cmock/$(CMOCK_VER)
+	make -C /tmp/C-Mock install PREFIX=$(HOME)/openolt-agent-test-lib/cmock/$(CMOCK_VER)
 
-gmock-global:
+$(gmock-global-target):
 	# Install gmock-global
 	rm -rf /tmp/gmock-global && cd /tmp && git clone https://github.com/apriorit/gmock-global.git
-	cd /tmp/gmock-global && git checkout 1.0.2
-	sudo cp -rf /tmp/gmock-global/include/gmock-global /usr/local/include/
+	cd /tmp/gmock-global && git checkout $(GMOCK_GLOBAL_VER)
+	mkdir -p $(HOME)/openolt-agent-test-lib/gmock-global/$(GMOCK_GLOBAL_VER)
+	cp -rf /tmp/gmock-global/include/gmock-global $(HOME)/openolt-agent-test-lib/gmock-global/$(GMOCK_GLOBAL_VER)
+
 ########################################################################
 ##
 ##
@@ -109,7 +142,7 @@
 
 .DEFAULT_GOAL := all
 
-.PHONY = bcm_host_api_stubs libopenoltapi.a libopenolt.a build clean
+.PHONY = bcm_host_api_stubs libopenoltapi.a libopenolt.a build clean prereqs-system prereqs-local
 
 all: bcm_host_api_stubs libopenoltapi.a libopenolt.a build
 
@@ -120,26 +153,26 @@
 #TEST_SRCS = $($(filter-out src/bal_stub.cc, $(wildcard src/*.cc)))
 TEST_SRCS = src/main_test.cc src/bal_mocker.cc src/test_core.cc 
 TEST_OBJS = $(TEST_SRCS:.cc=.o)
+
 build: $(TEST_OBJS)
-	$(CXX) $(shell cmock-config --libs) -L$(TEST_OPENOLT_LIB_DIR) -L/usr/lib/ -I/usr/include -I./inc -o $(TEST_BIN) $(TEST_OBJS) -lgmock -lgtest -lopenolt -lopenoltapi  $(LDFLAGS)
+	$(CXX) $(shell cmock-config --libs $(HOME)/openolt-agent-test-lib/gtest/$(GTEST_VER)/lib) -L$(TEST_OPENOLT_LIB_DIR) -L/usr/lib/ -I/usr/include -I./inc -I../src -o $(TEST_BIN) $(TEST_OBJS) -lgmock -lgtest -lopenolt -lopenoltapi $(LDFLAGS)
 src/%.o: src/%.cc
-	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I./inc -I../common -I/usr/include -c $< -o $@
+	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) $(TEST_LIB_INC) -I./inc -I../common -I../src -I/usr/include -c $< -o $@
 
 
 # bcm_host_api_stubs
-BAL_API_DIR=bal-api-3.2.3.2
 bcm_host_api_stubs:
 	# TODO: There is temporary hack below to introduce the definition of bcmos_mutex.
-	# This should ideally come as part of bal-api-3.2.3.2
+	# This should ideally come as part of bal-api-x.x.x.x
 	if [ -d $(BAL_API_DIR) ]; then \
 		echo "$(BAL_API_DIR) exists"; \
 	else \
-		git clone https://github.com/balapi/bal-api-3.2.3.2.git ;\
-		sed -i "\$$i #define BCMOLT_TM_QUEUE_KEY_TM_Q_SET_ID_DEFAULT 0" ./bal-api-3.2.3.2/include/bcmos_system.h; \
-		sed -i "\$$i struct bcmos_mutex \{ pthread_mutex_t m; };" ./bal-api-3.2.3.2/include/bcmos_system.h; \
-		sed -i "\$$i extern void* bcmos_calloc(uint32_t size);"  ./bal-api-3.2.3.2/include/bcmos_common.h; \
-		sed -i "\$$i #define BCMOLT_INTERFACE_TYPE_EPON_1_G 3"  ./bal-api-3.2.3.2/include/bcmos_common.h; \
-		sed -i "\$$i #define BCMOLT_INTERFACE_TYPE_EPON_10_G 4"  ./bal-api-3.2.3.2/include/bcmos_common.h; \
+		git clone https://github.com/balapi/$(BAL_API_VER).git ;\
+		sed -i "\$$i #define BCMOLT_TM_QUEUE_KEY_TM_Q_SET_ID_DEFAULT 0" ./$(BAL_API_DIR)/include/bcmos_system.h; \
+		sed -i "\$$i struct bcmos_mutex \{ pthread_mutex_t m; };" ./$(BAL_API_DIR)/include/bcmos_system.h; \
+		sed -i "\$$i extern void* bcmos_calloc(uint32_t size);"  ./$(BAL_API_DIR)/include/bcmos_common.h; \
+		sed -i "\$$i #define BCMOLT_INTERFACE_TYPE_EPON_1_G 3"  ./$(BAL_API_DIR)/include/bcmos_common.h; \
+		sed -i "\$$i #define BCMOLT_INTERFACE_TYPE_EPON_10_G 4"  ./$(BAL_API_DIR)/include/bcmos_common.h; \
 	fi
 
 # openoltapi
@@ -161,16 +194,16 @@
 	ar cr lib/$@ $^
 	ranlib lib/$@
 ../common/%.o: ../common/%.cc
-	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I../common -I./inc -I./device/$(OPENOLTDEVICE) -c $< -o $@
+	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I../common -I./inc -I../src -c $< -o $@
 ../src/%.o: ../src/%.cc
-	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I../common -I./inc -I./device/$(OPENOLTDEVICE) -c $< -o $@
+	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I../common -I./inc -I../src -c $< -o $@
 src/%.o: src/%.cc
-	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I../common -I./inc -I./device/$(OPENOLTDEVICE) -c $< -o $@
+	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I../common -I./inc -I../src -c $< -o $@
 ../device/$(OPENOLTDEVICE)/%.o: ../device/$(OPENOLTDEVICE)/%.cc
-	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I../common -I./inc -I./device/$(OPENOLTDEVICE) -c $< -o $@
+	$(CXX) $(CXXFLAGS) $(CXXFLAGSDEVICE) -I../common -I./inc -I../src -c $< -o $@
 
 test: all
-	./test_openolt --gtest_output="xml:./test_openolt_report.xml"
+	./test_openolt --gtest_output="xml:./test_openolt_report_xunit.xml"
 
 clean:
-	rm -f src/*.o lib/*.a ../src/*.o ../common/*.o ./test_openolt  ./test_openolt_report.xml
+	rm -f src/*.o lib/*.a ../src/*.o ../common/*.o ./test_openolt  ./test_openolt_report_xunit.xml
diff --git a/agent/test/README.md b/agent/test/README.md
index 6a3b40a..8b34329 100644
--- a/agent/test/README.md
+++ b/agent/test/README.md
@@ -29,9 +29,7 @@
 make OPENOLT_PROTO_VER=master test
 ```
 
-By default, the OPENOLT_PROTO_VER defaults to git tag *v1.0.3* of https://github.com/opencord/voltha-protos repo.
-
-Once you have successfully built and run the unit-test, the test report will be available in `test_openolt_report.xml` file in `agent/test`.
+Once you have successfully built and run the unit-test, the test report will be available in `test_openolt_report_xunit.xml` file in `agent/test`.
 To clean all build artifacts and test reports, do `make clean` in `agent/test`.
 
 ## Adding new Unit Test Cases
diff --git a/agent/test/configure b/agent/test/configure
index 7c41265..f861fd7 100755
--- a/agent/test/configure
+++ b/agent/test/configure
@@ -574,8 +574,6 @@
 LIBOBJS=
 cross_compiling=no
 subdirs=
-MFLAGS=
-MAKEFLAGS=
 
 # Identity of this package.
 PACKAGE_NAME='openolt'
diff --git a/agent/test/inc/bal_mocker.h b/agent/test/inc/bal_mocker.h
index f60c581..50b981d 100644
--- a/agent/test/inc/bal_mocker.h
+++ b/agent/test/inc/bal_mocker.h
@@ -15,7 +15,7 @@
  */
 #ifndef __BAL_MOCKER_H__
 #define __BAL_MOCKER_H__
-#include <cmock/cmock.h>
+#include <cmock.h>
 #include <gmock-global/gmock-global.h>
 #include <cstdlib>
 #include <grpc++/grpc++.h>
diff --git a/agent/test/src/test_core.cc b/agent/test/src/test_core.cc
index 1d3c2ef..137faac 100644
--- a/agent/test/src/test_core.cc
+++ b/agent/test/src/test_core.cc
@@ -17,6 +17,7 @@
 #include "Queue.h"
 #include "bal_mocker.h"
 #include "core.h"
+#include "core_data.h"
 #include <future>
 using namespace testing;
 using namespace std;
@@ -227,7 +228,7 @@
 // For testing Enable/Disable functionality
 ////////////////////////////////////////////////////////////////////////
 
-int num_of_pon_ports = 16;
+int num_of_pon_port = 16;
 
 // Create a mock function for bcmolt_cfg_get__olt_topology_stub C++ function
 MOCK_GLOBAL_FUNC2(bcmolt_cfg_get__olt_topology_stub, bcmos_errno(bcmolt_oltid, void*));
@@ -243,7 +244,7 @@
 
     BCMOLT_CFG_INIT(&olt_cfg, olt, olt_key);
 
-    olt_cfg.data.topology.topology_maps.len = num_of_pon_ports;
+    olt_cfg.data.topology.topology_maps.len = num_of_pon_port;
     EXPECT_GLOBAL_CALL(bcmolt_cfg_get__olt_topology_stub, bcmolt_cfg_get__olt_topology_stub(_, _))
                      .WillOnce(DoAll(SetArg1ToBcmOltCfg(olt_cfg), Return(bal_cfg_get_stub_res)));
 
@@ -309,7 +310,7 @@
     pon_cfg.data.state = BCMOLT_INTERFACE_STATE_INACTIVE;
 
     EXPECT_GLOBAL_CALL(bcmolt_cfg_get__pon_intf_stub, bcmolt_cfg_get__pon_intf_stub(_, _))
-                     .Times(num_of_pon_ports)
+                     .Times(num_of_pon_port)
                      .WillRepeatedly(DoAll(SetArg1ToBcmOltPonCfg(pon_cfg), Return(olt_cfg_get_pon_stub_res)));
 
     bcmolt_tm_sched_cfg tm_sched_cfg;
@@ -318,7 +319,7 @@
     tm_sched_cfg.data.state = BCMOLT_CONFIG_STATE_NOT_CONFIGURED;
 
     EXPECT_GLOBAL_CALL(bcmolt_cfg_get__tm_sched_stub, bcmolt_cfg_get__tm_sched_stub(_, _))
-                     .Times(num_of_pon_ports)
+                     .Times(num_of_pon_port)
                      .WillRepeatedly(DoAll(SetArg1ToBcmOltTmSchedCfg(tm_sched_cfg), Return(olt_cfg_get_tmstub_res)));
 
     olt_reenable_res = Reenable_();
@@ -343,10 +344,10 @@
     pon_cfg.data.state = BCMOLT_INTERFACE_STATE_INACTIVE;
 
     EXPECT_GLOBAL_CALL(bcmolt_cfg_get__pon_intf_stub, bcmolt_cfg_get__pon_intf_stub(_, _))
-                     .Times(num_of_pon_ports)
+                     .Times(num_of_pon_port)
                      .WillRepeatedly(DoAll(SetArg1ToBcmOltPonCfg(pon_cfg), Return(olt_cfg_get_pon_stub_res)));
     EXPECT_CALL(balMock,bcmolt_oper_submit(_, _))
-                         .Times(num_of_pon_ports)
+                         .Times(num_of_pon_port)
                          .WillRepeatedly(Return(olt_oper_res));
 
     olt_reenable_res = Reenable_();
@@ -372,7 +373,7 @@
 
             BCMOLT_CFG_INIT(&olt_cfg, olt, olt_key);
 
-            olt_cfg.data.topology.topology_maps.len = num_of_pon_ports;
+            olt_cfg.data.topology.topology_maps.len = num_of_pon_port;
         }
 
         virtual void TearDown() {
diff --git a/protos/Makefile b/protos/Makefile
index 80b9875..b117a09 100644
--- a/protos/Makefile
+++ b/protos/Makefile
@@ -20,15 +20,16 @@
 # repo that we need to refer to, to pick the right version of
 # openolt.proto and tech_profile.proto
 OPENOLT_PROTO_VER ?= v3.1.0
+GRPC_VER ?= v1.10.x
 
 CXX ?= g++
 #powerpc64-fsl-linux-g++
-CPPFLAGS += `pkg-config --cflags protobuf grpc` -I googleapis/gens -I./
+CPPFLAGS += `PKG_CONFIG_PATH=$(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/lib/pkgconfig pkg-config --cflags protobuf grpc` -I googleapis/gens -I./
 CXXFLAGS += -std=c++11
 #LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc` -ldl
-PROTOC = protoc
+PROTOC = $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/bin/protoc
 GRPC_CPP_PLUGIN = grpc_cpp_plugin
-GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
+GRPC_CPP_PLUGIN_PATH ?= $(HOME)/openolt-agent-test-lib/grpc/$(GRPC_VER)/bin/$(GRPC_CPP_PLUGIN)
 
 OBJS = voltha_protos/tech_profile.pb.o voltha_protos/tech_profile.grpc.pb.o voltha_protos/openolt.pb.o voltha_protos/openolt.grpc.pb.o ./googleapis/gens/google/api/annotations.grpc.pb.o ./googleapis/gens/google/api/annotations.pb.o ./googleapis/gens/google/api/http.pb.o