[VOL-2055] Use Tech Profile ID to differentiate downstream traffic scheduler

- CreateQueue / RemoveQueue / CreateSched / RemoveSched / FlowAdd updated to include
  tech_profile_id to select downstream scheduler.
- A DS scheduler is now identified by the tuple (pon, onu, uni, dir, tech_profile_id)
- voltha_protos v3.3.5 is now referred.
- Unit tests updated.
- VERSION updated.

Change-Id: I399bbb03aa33b61a02da10af0a40d354d44bd5cf
diff --git a/Makefile b/Makefile
index 9598444..fb7f456 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@
 
 ## Variables
 OPENOLTDEVICE     ?= asfvolt16
-OPENOLT_PROTO_VER ?= v3.3.4
+OPENOLT_PROTO_VER ?= v3.3.5
 GTEST_VER         ?= release-1.8.0
 CMOCK_VER         ?= 0207b30
 GMOCK_GLOBAL_VER  ?= 1.0.2
diff --git a/README.md b/README.md
index 465d6aa..f9f88a6 100644
--- a/README.md
+++ b/README.md
@@ -272,7 +272,7 @@
 make OPENOLTDEVICE=asfvolt16 OPENOLT_PROTO_VER=master
 ```
 
-By default, the `OPENOLT_PROTO_VER` defaults to git tag *v3.3.4* of the
+By default, the `OPENOLT_PROTO_VER` defaults to git tag *v3.3.5* of the
 [voltha-protos](https://gerrit.opencord.org/gitweb?p=voltha-protos.git;a=summary)
 repo.
 
diff --git a/VERSION b/VERSION
index 79a6144..59aa62c 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.4.4
+2.4.5
diff --git a/agent/Makefile.in b/agent/Makefile.in
index 3cbe94d..62f3ba3 100644
--- a/agent/Makefile.in
+++ b/agent/Makefile.in
@@ -42,7 +42,7 @@
 # This specifies the GIT tag in https://github.com/opencord/voltha-protos
 # repo that we need to refer to, to pick the right version of
 # openolt.proto and tech_profile.proto
-OPENOLT_PROTO_VER ?= v3.3.4
+OPENOLT_PROTO_VER ?= v3.3.5
 
 # Variables used for Inband build
 INBAND = "n"
diff --git a/agent/common/core.h b/agent/common/core.h
index 31e10ed..33a9066 100644
--- a/agent/common/core.h
+++ b/agent/common/core.h
@@ -219,7 +219,7 @@
                 int32_t alloc_id, int32_t network_intf_id,
                 int32_t gemport_id, const ::openolt::Classifier& classifier,
                 const ::openolt::Action& action, int32_t priority_value,
-                uint64_t cookie, int32_t group_id);
+                uint64_t cookie, int32_t group_id, uint32_t tech_profile_id);
 Status FlowRemove_(uint32_t flow_id, const std::string flow_type);
 Status Disable_();
 Status Reenable_();
diff --git a/agent/common/server.cc b/agent/common/server.cc
index 13017a7..53b6317 100644
--- a/agent/common/server.cc
+++ b/agent/common/server.cc
@@ -141,7 +141,8 @@
             request->action(),
             request->priority(),
             request->cookie(),
-            request->group_id());
+            request->group_id(),
+            request->tech_profile_id());
     }
 
     Status FlowRemove(
diff --git a/agent/src/core_api_handler.cc b/agent/src/core_api_handler.cc
index c6ced48..6319faa 100644
--- a/agent/src/core_api_handler.cc
+++ b/agent/src/core_api_handler.cc
@@ -67,12 +67,12 @@
 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,
-                          tech_profile::TrafficShapingInfo traffic_shaping_info);
-static bcmos_errno RemoveSched(int intf_id, int onu_id, int uni_id, int alloc_id, std::string direction);
+                          tech_profile::TrafficShapingInfo traffic_shaping_info, uint32_t tech_profile_id);
+static bcmos_errno RemoveSched(int intf_id, int onu_id, int uni_id, int alloc_id, std::string direction, int tech_profile_id);
 static bcmos_errno CreateQueue(std::string direction, uint32_t access_intf_id, uint32_t onu_id, uint32_t uni_id, \
-                               bcmolt_egress_qos_type qos_type, uint32_t priority, uint32_t gemport_id);
+                               bcmolt_egress_qos_type qos_type, uint32_t priority, uint32_t gemport_id, uint32_t tech_profile_id);
 static bcmos_errno RemoveQueue(std::string direction, uint32_t access_intf_id, uint32_t onu_id, uint32_t uni_id, \
-                               bcmolt_egress_qos_type qos_type, uint32_t priority, uint32_t gemport_id);
+                               bcmolt_egress_qos_type qos_type, uint32_t priority, uint32_t gemport_id, uint32_t tech_profile_id);
 static bcmos_errno CreateDefaultSched(uint32_t intf_id, const std::string direction);
 static bcmos_errno CreateDefaultQueue(uint32_t intf_id, const std::string direction);
 
@@ -1341,7 +1341,7 @@
                 int32_t alloc_id, int32_t network_intf_id,
                 int32_t gemport_id, const ::openolt::Classifier& classifier,
                 const ::openolt::Action& action, int32_t priority_value, uint64_t cookie,
-                int32_t group_id) {
+                int32_t group_id, uint32_t tech_profile_id) {
     bcmolt_flow_cfg cfg;
     bcmolt_flow_key key = { }; /**< Object key. */
     int32_t o_vid = -1;
@@ -1563,7 +1563,7 @@
     if ((access_intf_id >= 0) && (onu_id >= 0)) {
         qos_type = get_qos_type(access_intf_id, onu_id, uni_id);
         if (key.flow_type == BCMOLT_FLOW_TYPE_DOWNSTREAM) {
-            tm_val.sched_id = get_tm_sched_id(access_intf_id, onu_id, uni_id, downstream);
+            tm_val.sched_id = get_tm_sched_id(access_intf_id, onu_id, uni_id, downstream, tech_profile_id);
 
             if (qos_type == BCMOLT_EGRESS_QOS_TYPE_FIXED_QUEUE) {
                 // Queue 0 on DS subscriber scheduler
@@ -1866,14 +1866,15 @@
 
 bcmos_errno CreateSched(std::string direction, uint32_t 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, tech_profile::TrafficShapingInfo tf_sh_info) {
+                 tech_profile::SchedulingPolicy sched_policy, tech_profile::TrafficShapingInfo tf_sh_info,
+                 uint32_t tech_profile_id) {
 
     bcmos_errno err;
 
     if (direction == downstream) {
         bcmolt_tm_sched_cfg tm_sched_cfg;
         bcmolt_tm_sched_key tm_sched_key = {.id = 1};
-        tm_sched_key.id = get_tm_sched_id(intf_id, onu_id, uni_id, direction);
+        tm_sched_key.id = get_tm_sched_id(intf_id, onu_id, uni_id, direction, tech_profile_id);
 
         // bcmbal_tm_sched_owner
         // In downstream it is sub_term scheduler
@@ -2063,6 +2064,7 @@
     uint32_t weight;
     tech_profile::SchedulingPolicy sched_policy;
     tech_profile::TrafficShapingInfo traffic_shaping_info;
+    uint32_t tech_profile_id;
     bcmos_errno err;
 
     for (int i = 0; i < traffic_scheds->traffic_scheds_size(); i++) {
@@ -2079,8 +2081,9 @@
         weight = sched_config.weight();
         sched_policy = sched_config.sched_policy();
         traffic_shaping_info = traffic_sched.traffic_shaping_info();
+        tech_profile_id = traffic_sched.tech_profile_id();
         err =  CreateSched(direction, intf_id, onu_id, uni_id, port_no, alloc_id, additional_bw, weight, priority,
-                           sched_policy, traffic_shaping_info);
+                           sched_policy, traffic_shaping_info, tech_profile_id);
         if (err) {
             OPENOLT_LOG(ERROR, openolt_log_id, "Failed to create scheduler, err = %s\n", bcmos_strerror(err));
             return bcm_to_grpc_err(err, "Failed to create scheduler");
@@ -2089,7 +2092,7 @@
     return Status::OK;
 }
 
-bcmos_errno RemoveSched(int intf_id, int onu_id, int uni_id, int alloc_id, std::string direction) {
+bcmos_errno RemoveSched(int intf_id, int onu_id, int uni_id, int alloc_id, std::string direction, int tech_profile_id) {
 
     bcmos_errno err;
     bcmolt_interface_state state;
@@ -2140,8 +2143,8 @@
         bcmolt_tm_sched_cfg cfg;
         bcmolt_tm_sched_key key = { };
 
-        if (is_tm_sched_id_present(intf_id, onu_id, uni_id, direction)) {
-            key.id = get_tm_sched_id(intf_id, onu_id, uni_id, direction);
+        if (is_tm_sched_id_present(intf_id, onu_id, uni_id, direction, tech_profile_id)) {
+            key.id = get_tm_sched_id(intf_id, onu_id, uni_id, direction, tech_profile_id);
             sched_id = key.id;
         } else {
             OPENOLT_LOG(INFO, openolt_log_id, "schduler not present in %s, err %d\n", direction.c_str(), err);
@@ -2152,14 +2155,14 @@
         err = bcmolt_cfg_clear(dev_id, &(cfg.hdr));
         if (err) {
             OPENOLT_LOG(ERROR, openolt_log_id, "Failed to remove scheduler, direction = %s, sched_id %d, \
-intf_id %d, onu_id %d, err = %s\n", direction.c_str(), key.id, intf_id, onu_id, bcmos_strerror(err));
+intf_id %d, onu_id %d, tech_profile_id %d, err = %s\n", direction.c_str(), key.id, intf_id, onu_id, tech_profile_id, bcmos_strerror(err));
             return err;
         }
     }
 
-    OPENOLT_LOG(INFO, openolt_log_id, "Removed sched, direction = %s, id %d, intf_id %d, onu_id %d\n",
-                direction.c_str(), sched_id, intf_id, onu_id);
-    free_tm_sched_id(intf_id, onu_id, uni_id, direction);
+    OPENOLT_LOG(INFO, openolt_log_id, "Removed sched, direction = %s, id %d, intf_id %d, onu_id %d, tech_profile_id %d\n",
+                direction.c_str(), sched_id, intf_id, onu_id, tech_profile_id);
+    free_tm_sched_id(intf_id, onu_id, uni_id, direction, tech_profile_id);
     return BCM_ERR_OK;
 }
 
@@ -2168,6 +2171,7 @@
     uint32_t onu_id = traffic_scheds->onu_id();
     uint32_t uni_id = traffic_scheds->uni_id();
     std::string direction;
+    uint32_t tech_profile_id;
     bcmos_errno err;
 
     for (int i = 0; i < traffic_scheds->traffic_scheds_size(); i++) {
@@ -2178,7 +2182,8 @@
             return bcm_to_grpc_err(BCM_ERR_PARM, "direction-not-supported");
 
         int alloc_id = traffic_sched.alloc_id();
-        err = RemoveSched(intf_id, onu_id, uni_id, alloc_id, direction);
+        int tech_profile_id = traffic_sched.tech_profile_id();
+        err = RemoveSched(intf_id, onu_id, uni_id, alloc_id, direction, tech_profile_id);
         if (err) {
             OPENOLT_LOG(ERROR, openolt_log_id, "Error-removing-traffic-scheduler, err = %s\n",bcmos_strerror(err));
             return bcm_to_grpc_err(err, "error-removing-traffic-scheduler");
@@ -2273,15 +2278,15 @@
 }
 
 bcmos_errno CreateQueue(std::string direction, uint32_t access_intf_id, uint32_t onu_id, uint32_t uni_id,
-                        bcmolt_egress_qos_type qos_type, uint32_t priority, uint32_t gemport_id) {
+                        bcmolt_egress_qos_type qos_type, uint32_t priority, uint32_t gemport_id, uint32_t tech_profile_id) {
     bcmos_errno err;
     bcmolt_tm_queue_cfg cfg;
     bcmolt_tm_queue_key key = { };
     OPENOLT_LOG(INFO, openolt_log_id, "creating %s queue. access_intf_id = %d, onu_id = %d, uni_id = %d \
-gemport_id = %d\n", direction.c_str(), access_intf_id, onu_id, uni_id, gemport_id);
+gemport_id = %d, tech_profile_id = %d\n", direction.c_str(), access_intf_id, onu_id, uni_id, gemport_id, tech_profile_id);
 
     key.sched_id = (direction.compare(upstream) == 0) ? get_default_tm_sched_id(nni_intf_id, direction) : \
-        get_tm_sched_id(access_intf_id, onu_id, uni_id, direction);
+        get_tm_sched_id(access_intf_id, onu_id, uni_id, direction, tech_profile_id);
 
     if (priority > 7) {
         return BCM_ERR_RANGE;
@@ -2317,13 +2322,13 @@
     err = bcmolt_cfg_set(dev_id, &cfg.hdr);
     if (err) {
         OPENOLT_LOG(ERROR, openolt_log_id, "Failed to create subscriber tm queue, direction = %s, queue_id %d, \
-sched_id %d, tm_q_set_id %d, intf_id %d, onu_id %d, uni_id %d, err = %s\n", \
-            direction.c_str(), key.id, key.sched_id, key.tm_q_set_id, access_intf_id, onu_id, uni_id, bcmos_strerror(err));
+sched_id %d, tm_q_set_id %d, intf_id %d, onu_id %d, uni_id %d, tech_profile_id %d, err = %s\n", \
+            direction.c_str(), key.id, key.sched_id, key.tm_q_set_id, access_intf_id, onu_id, uni_id, tech_profile_id, bcmos_strerror(err));
         return err;
     }
 
     OPENOLT_LOG(INFO, openolt_log_id, "Created tm_queue, direction %s, id %d, sched_id %d, tm_q_set_id %d, \
-intf_id %d, onu_id %d, uni_id %d\n", direction.c_str(), key.id, key.sched_id, key.tm_q_set_id, access_intf_id, onu_id, uni_id);
+intf_id %d, onu_id %d, uni_id %d, tech_profiled_id %d\n", direction.c_str(), key.id, key.sched_id, key.tm_q_set_id, access_intf_id, onu_id, uni_id, tech_profile_id);
     return BCM_ERR_OK;
 }
 
@@ -2331,6 +2336,7 @@
     uint32_t intf_id = traffic_queues->intf_id();
     uint32_t onu_id = traffic_queues->onu_id();
     uint32_t uni_id = traffic_queues->uni_id();
+    uint32_t tech_profile_id = traffic_queues->tech_profile_id();
     uint32_t sched_id;
     std::string direction;
     bcmos_errno err;
@@ -2354,7 +2360,7 @@
         tmq_map_profile = get_tmq_map_profile(get_valid_queues_pbit_map(queues_pbit_map, COUNT_OF(queues_pbit_map)), \
                                               queues_priority_q, COUNT_OF(queues_priority_q));
         sched_id = (direction.compare(upstream) == 0) ? get_default_tm_sched_id(nni_intf_id, direction) : \
-            get_tm_sched_id(intf_id, onu_id, uni_id, direction);
+            get_tm_sched_id(intf_id, onu_id, uni_id, direction, tech_profile_id);
 
         int tm_qmp_id = get_tm_qmp_id(tmq_map_profile);
         if (tm_qmp_id == -1) {
@@ -2376,7 +2382,7 @@
         if (direction.compare("direction-not-supported") == 0)
             return bcm_to_grpc_err(BCM_ERR_PARM, "direction-not-supported");
 
-        err = CreateQueue(direction, intf_id, onu_id, uni_id, qos_type, traffic_queue.priority(), traffic_queue.gemport_id());
+        err = CreateQueue(direction, intf_id, onu_id, uni_id, qos_type, traffic_queue.priority(), traffic_queue.gemport_id(), tech_profile_id);
 
         // If the queue exists already, lets not return failure and break the loop.
         if (err && err != BCM_ERR_ALREADY) {
@@ -2388,14 +2394,14 @@
 }
 
 bcmos_errno RemoveQueue(std::string direction, uint32_t access_intf_id, uint32_t onu_id, uint32_t uni_id,
-                        bcmolt_egress_qos_type qos_type, uint32_t priority, uint32_t gemport_id) {
+                        bcmolt_egress_qos_type qos_type, uint32_t priority, uint32_t gemport_id, uint32_t tech_profile_id) {
     bcmolt_tm_queue_cfg cfg;
     bcmolt_tm_queue_key key = { };
     bcmos_errno err;
 
     if (direction == downstream) {
-        if (is_tm_sched_id_present(access_intf_id, onu_id, uni_id, direction)) {
-            key.sched_id = get_tm_sched_id(access_intf_id, onu_id, uni_id, direction);
+        if (is_tm_sched_id_present(access_intf_id, onu_id, uni_id, direction, tech_profile_id)) {
+            key.sched_id = get_tm_sched_id(access_intf_id, onu_id, uni_id, direction, tech_profile_id);
             key.id = queue_id_list[priority];
         } else {
             OPENOLT_LOG(INFO, openolt_log_id, "queue not present in DS. Not clearing, access_intf_id %d, onu_id %d, uni_id %d, gemport_id %d, direction %s\n", access_intf_id, onu_id, uni_id, gemport_id, direction.c_str());
@@ -2439,6 +2445,7 @@
     uint32_t onu_id = traffic_queues->onu_id();
     uint32_t uni_id = traffic_queues->uni_id();
     uint32_t port_no = traffic_queues->port_no();
+    uint32_t tech_profile_id = traffic_queues->tech_profile_id();
     uint32_t sched_id;
     std::string direction;
     bcmos_errno err;
@@ -2451,16 +2458,16 @@
         if (direction.compare("direction-not-supported") == 0)
             return bcm_to_grpc_err(BCM_ERR_PARM, "direction-not-supported");
 
-        err = RemoveQueue(direction, intf_id, onu_id, uni_id, qos_type, traffic_queue.priority(), traffic_queue.gemport_id());
+        err = RemoveQueue(direction, intf_id, onu_id, uni_id, qos_type, traffic_queue.priority(), traffic_queue.gemport_id(), tech_profile_id);
         if (err) {
             OPENOLT_LOG(ERROR, openolt_log_id, "Failed to remove queue, err = %s\n",bcmos_strerror(err));
             return bcm_to_grpc_err(err, "Failed to remove queue");
         }
     }
 
-    if (qos_type == BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE && (direction.compare(upstream) == 0 || direction.compare(downstream) == 0 && is_tm_sched_id_present(intf_id, onu_id, uni_id, direction))) {
+    if (qos_type == BCMOLT_EGRESS_QOS_TYPE_PRIORITY_TO_QUEUE && (direction.compare(upstream) == 0 || direction.compare(downstream) == 0 && is_tm_sched_id_present(intf_id, onu_id, uni_id, direction, tech_profile_id))) {
         sched_id = (direction.compare(upstream) == 0) ? get_default_tm_sched_id(nni_intf_id, direction) : \
-            get_tm_sched_id(intf_id, onu_id, uni_id, direction);
+            get_tm_sched_id(intf_id, onu_id, uni_id, direction, tech_profile_id);
 
         int tm_qmp_id = get_tm_qmp_id(sched_id, intf_id, onu_id, uni_id);
         if (free_tm_qmp_id(sched_id, intf_id, onu_id, uni_id, tm_qmp_id)) {
diff --git a/agent/src/core_data.cc b/agent/src/core_data.cc
index 8cb51a8..ec292e3 100644
--- a/agent/src/core_data.cc
+++ b/agent/src/core_data.cc
@@ -98,8 +98,8 @@
 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;
+ Represents (pon_intf_id, onu_id, uni_id, direction, tech_profile_id) */
+typedef std::tuple<uint32_t, uint32_t, uint32_t, std::string, uint32_t> 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;
diff --git a/agent/src/core_data.h b/agent/src/core_data.h
index 4de8114..f58ddd7 100644
--- a/agent/src/core_data.h
+++ b/agent/src/core_data.h
@@ -171,8 +171,8 @@
 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;
+ Represents (pon_intf_id, onu_id, uni_id, direction, tech_profile_id) */
+typedef std::tuple<uint32_t, uint32_t, uint32_t, std::string, uint32_t> 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;
diff --git a/agent/src/core_utils.cc b/agent/src/core_utils.cc
index 6570c2f..1412000 100644
--- a/agent/src/core_utils.cc
+++ b/agent/src/core_utils.cc
@@ -83,18 +83,20 @@
 /**
 * 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
+* VOLTHA replays whole configuration on OLT reboot, so caching locally is not a problem.
+* Note that tech_profile_id is used to differentiate service schedulers in downstream 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
+* @param tech_profile_id Technology Profile ID
 *
 * @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);
+uint32_t get_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
+    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
     int sched_id = -1;
 
     std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
@@ -126,16 +128,17 @@
 }
 
 /**
-* Free tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction
+* Free tm_sched_id for a given intf_id, onu_id, uni_id, gemport_id, direction, tech_profile_id
 *
 * @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
+* @param tech_profile_id Technology Profile ID
 */
-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);
+void free_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
+    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
     std::map<sched_map_key_tuple, int>::const_iterator it;
     bcmos_fastlock_lock(&data_lock);
     it = sched_map.find(key);
@@ -146,8 +149,8 @@
     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);
+bool is_tm_sched_id_present(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id) {
+    sched_map_key_tuple key(pon_intf_id, onu_id, uni_id, direction, tech_profile_id);
     std::map<sched_map_key_tuple, int>::const_iterator it = sched_map.find(key);
     if (it != sched_map.end()) {
         return true;
diff --git a/agent/src/core_utils.h b/agent/src/core_utils.h
index b686867..5f64e47 100644
--- a/agent/src/core_utils.h
+++ b/agent/src/core_utils.h
@@ -49,9 +49,9 @@
 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);
+uint32_t get_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id);
+void free_tm_sched_id(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id);
+bool is_tm_sched_id_present(int pon_intf_id, int onu_id, int uni_id, std::string direction, int tech_profile_id);
 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);
diff --git a/agent/test/Makefile b/agent/test/Makefile
index a27f399..a32c160 100644
--- a/agent/test/Makefile
+++ b/agent/test/Makefile
@@ -21,7 +21,7 @@
 TOP_DIR=`pwd`
 OPENOLTDEVICE ?= asfvolt16
 
-OPENOLT_PROTO_VER ?= v3.3.4
+OPENOLT_PROTO_VER ?= v3.3.5
 
 GTEST_VER ?= release-1.8.0
 gtest-target = /usr/local/lib/libgtest.a
diff --git a/agent/test/src/test_core.cc b/agent/test/src/test_core.cc
index 7f9926f..d5b4dc8 100644
--- a/agent/test/src/test_core.cc
+++ b/agent/test/src/test_core.cc
@@ -1237,6 +1237,7 @@
         int32_t priority_value = 0;
         uint64_t cookie = 0;
         int32_t group_id = -1;
+        uint32_t tech_profile_id = 64;
 
         NiceMock<BalMocker> balMock;
         openolt::Flow* flow;
@@ -1363,7 +1364,7 @@
     ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type,
-        alloc_id, network_intf_id, gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        alloc_id, network_intf_id, gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
 }
 
@@ -1375,7 +1376,7 @@
                      .WillRepeatedly(DoAll(SetArg1ToBcmOltFlowCfg(flow_cfg), Return(flow_cfg_get_stub_res)));
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
-        gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
 }
 #endif
@@ -1392,7 +1393,7 @@
     ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
-        gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
 }
 
@@ -1401,7 +1402,7 @@
     flow_type = "bidirectional";
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
-        gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
 }
 
@@ -1410,7 +1411,7 @@
     network_intf_id = -1;
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
-        gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
 }
 
@@ -1431,7 +1432,7 @@
     ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id,
-        network_intf_id, gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        network_intf_id, gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
 }
 
@@ -1455,7 +1456,7 @@
     ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
-        gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
 }
 
@@ -1480,7 +1481,7 @@
     ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(olt_cfg_set_res));
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
-        gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
 }
 
@@ -1501,7 +1502,7 @@
     CreateTrafficQueues_(traffic_queues);
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
-        gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
 }
 
@@ -1532,7 +1533,7 @@
     CreateTrafficQueues_(traffic_queues);
 
     Status status = FlowAdd_(access_intf_id, onu_id, uni_id, port_no, flow_id, flow_type, alloc_id, network_intf_id,
-        gemport_id, *classifier, *action, priority_value, cookie, group_id);
+        gemport_id, *classifier, *action, priority_value, cookie, group_id, tech_profile_id);
     ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
 }
 
diff --git a/protos/Makefile b/protos/Makefile
index d4e22fb..92b99d8 100644
--- a/protos/Makefile
+++ b/protos/Makefile
@@ -19,7 +19,7 @@
 # This specifies the GIT tag in https://github.com/opencord/voltha-protos
 # repo that we need to refer to, to pick the right version of
 # openolt.proto and tech_profile.proto
-OPENOLT_PROTO_VER ?= v3.3.4
+OPENOLT_PROTO_VER ?= v3.3.5
 GRPC_VER ?= v1.10.x
 
 CXX ?= g++