VOL-1221: OpenOLT Adapter/Driver will use a Technology Profile Instance to create the OLT Upstream and Downstream Queuing and Scheduling Constructs for a Bidirectional Flow.

Change-Id: I8106182a280ee24147e2b19da583d95c254c69ad
diff --git a/.gitignore b/.gitignore
index 8d9fb8f..0712759 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,6 @@
 
 # Build output
 build
+
+# IntelliJ Files
+.idea
diff --git a/agent/common/core.h b/agent/common/core.h
index 812a9b5..840d0c8 100644
--- a/agent/common/core.h
+++ b/agent/common/core.h
@@ -30,13 +30,11 @@
 
 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,
-    uint32_t alloc_id);
+    const char *vendor_id, const char *vendor_specific, uint32_t pir);
 Status DeactivateOnu_(uint32_t intf_id, uint32_t onu_id,
     const char *vendor_id, const char *vendor_specific);
 Status DeleteOnu_(uint32_t intf_id, uint32_t onu_id,
-    const char *vendor_id, const char *vendor_specific,
-    uint32_t alloc_id);
+    const char *vendor_id, const char *vendor_specific);
 Status EnablePonIf_(uint32_t intf_id);
 Status DisablePonIf_(uint32_t intf_id);
 Status EnableUplinkIf_(uint32_t intf_id);
@@ -48,17 +46,17 @@
 Status ProbeDeviceCapabilities_();
 Status ProbePonIfTechnology_();
 Status UplinkPacketOut_(uint32_t intf_id, const std::string pkt);
-Status FlowAdd_(int32_t onu_id,
+Status FlowAdd_(int32_t access_intf_id, int32_t onu_id,
                 uint32_t flow_id, const std::string flow_type,
-                int32_t access_intf_id, int32_t network_intf_id,
-                uint32_t gemport_id, uint32_t sched_id,
-                int32_t priority_value,
-                const ::openolt::Classifier& classifier,
-                const ::openolt::Action& action);
+                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);
 Status FlowRemove_(uint32_t flow_id, const std::string flow_type);
 Status Disable_();
 Status Reenable_();
 Status GetDeviceInfo_(openolt::DeviceInfo* device_info);
+Status CreateTconts_(const openolt::Tconts *tconts);
+Status RemoveTconts_(const openolt::Tconts *tconts);
 
 void stats_collection();
 #endif
diff --git a/agent/common/server.cc b/agent/common/server.cc
index e40f0cf..b556e06 100644
--- a/agent/common/server.cc
+++ b/agent/common/server.cc
@@ -67,8 +67,7 @@
             request->intf_id(),
             request->onu_id(),
             ((request->serial_number()).vendor_id()).c_str(),
-            ((request->serial_number()).vendor_specific()).c_str(),
-            request->pir(), request->alloc_id());
+            ((request->serial_number()).vendor_specific()).c_str(), request->pir());
     }
 
     Status DeactivateOnu(
@@ -90,8 +89,7 @@
             request->intf_id(),
             request->onu_id(),
             ((request->serial_number()).vendor_id()).c_str(),
-            ((request->serial_number()).vendor_specific()).c_str(),
-            request->alloc_id());
+            ((request->serial_number()).vendor_specific()).c_str());
     }
 
     Status OmciMsgOut(
@@ -128,16 +126,16 @@
             const openolt::Flow* request,
             openolt::Empty* response) override {
         return FlowAdd_(
+            request->access_intf_id(),
             request->onu_id(),
             request->flow_id(),
             request->flow_type(),
-            request->access_intf_id(),
+            request->alloc_id(),
             request->network_intf_id(),
             request->gemport_id(),
-            request->alloc_id(),
-            request->priority(),
             request->classifier(),
-            request->action());
+            request->action(),
+            request->priority());
     }
 
     Status FlowRemove(
@@ -256,7 +254,23 @@
 
     }
 
+    Status CreateTconts(
+            ServerContext* context,
+            const openolt::Tconts* request,
+            openolt::Empty* response) override {
+        std::cout << "create tconts";
+        CreateTconts_(request);
+        return Status::OK;
+    };
 
+    Status RemoveTconts(
+            ServerContext* context,
+            const openolt::Tconts* request,
+            openolt::Empty* response) override {
+        std::cout << "remove tconts";
+        RemoveTconts_(request);
+        return Status::OK;
+    };
 
 };
 
diff --git a/agent/src/core.cc b/agent/src/core.cc
index 7dcd24b..c7730c0 100644
--- a/agent/src/core.cc
+++ b/agent/src/core.cc
@@ -65,13 +65,33 @@
 
 static std::string firmware_version = "Openolt.2018.10.04";
 
+const uint32_t tm_upstream_sched_id_start = 18432;
+const uint32_t tm_downstream_sched_id_start = 16384;
+const uint32_t tm_queue_id_start = 4; //0 to 3 are default queues. Lets not use them.
+const std::string upstream = "upstream";
+const std::string downstream = "downstream";
+
 State state;
 
-static Status SchedAdd_(int intf_id, int onu_id, int agg_port_id, int sched_id, int pir);
-static Status SchedRemove_(int intf_id, int onu_id, int agg_port_id, int sched_id);
+Status SchedAdd_(std::string direction, uint32_t access_intf_id, uint32_t onu_id,
+                 uint32_t alloc_id, openolt::AdditionalBW additional_bw, uint32_t weight, uint32_t priority,
+                 openolt::SchedulingPolicy sched_policy);
+static Status SchedRemove_(std::string direction, int intf_id, int onu_id, int alloc_id);
 
-static inline int mk_sched_id(int intf_id, int onu_id) {
-    return 1023 + intf_id * 32 + onu_id;
+static inline int mk_sched_id(int intf_id, int onu_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 {
+        BCM_LOG(ERROR, openolt_log_id, "invalid direction - %s\n", direction.c_str());
+        return 0;
+    }
+}
+
+static inline int mk_queue_id(int pon_intf_id, int onu_id) {
+    return tm_queue_id_start + pon_intf_id * 32 + onu_id;
 }
 
 static inline int mk_agg_port_id(int intf_id, int onu_id) {
@@ -471,16 +491,15 @@
 }
 
 Status ActivateOnu_(uint32_t intf_id, uint32_t onu_id,
-    const char *vendor_id, const char *vendor_specific, uint32_t pir,
-    uint32_t alloc_id) {
+    const char *vendor_id, const char *vendor_specific, uint32_t pir) {
 
     bcmbal_subscriber_terminal_cfg sub_term_obj = {};
     bcmbal_subscriber_terminal_key subs_terminal_key;
     bcmbal_serial_number serial_num = {};
     bcmbal_registration_id registration_id = {};
 
-    BCM_LOG(INFO, openolt_log_id,  "Enabling ONU %d on PON %d : vendor id %s, vendor specific %s, pir %d, alloc_id %d\n",
-        onu_id, intf_id, vendor_id, vendor_specific_to_str(vendor_specific).c_str(), pir, alloc_id);
+    BCM_LOG(INFO, openolt_log_id,  "Enabling ONU %d on PON %d : vendor id %s, vendor specific %s, pir %d\n",
+        onu_id, intf_id, vendor_id, vendor_specific_to_str(vendor_specific).c_str(), pir);
 
     subs_terminal_key.sub_term_id = onu_id;
     subs_terminal_key.intf_id = intf_id;
@@ -506,19 +525,7 @@
         BCM_LOG(ERROR, openolt_log_id, "Failed to enable ONU %d on PON %d\n", onu_id, intf_id);
         return bcm_to_grpc_err(err, "Failed to enable ONU");
     }
-
-    if (alloc_id != 0) {
-        // Use alloc_id as both agg_port_id and sched_id.
-        // Additional Notes:
-        // The agg_port_id is a BAL nomenclature for alloc_id (TCONT identifier).
-        // The TCONT is associated with its own DBA scheduler with a unique scheduler ID.
-        // Use the alloc_id itself as the DBA Scheduler identifier (sched_id).
-        return SchedAdd_(intf_id, onu_id, alloc_id, alloc_id, pir);
-    } else {
-        return SchedAdd_(intf_id, onu_id, mk_agg_port_id(intf_id, onu_id), mk_sched_id(intf_id, onu_id), pir);
-    }
-
-    //return Status::OK;
+    return Status::OK;
 }
 
 Status DeactivateOnu_(uint32_t intf_id, uint32_t onu_id,
@@ -545,8 +552,7 @@
 }
 
 Status DeleteOnu_(uint32_t intf_id, uint32_t onu_id,
-    const char *vendor_id, const char *vendor_specific,
-    uint32_t alloc_id) {
+    const char *vendor_id, const char *vendor_specific) {
 
     BCM_LOG(INFO, openolt_log_id,  "DeleteOnu ONU %d on PON %d : vendor id %s, vendor specific %s\n",
         onu_id, intf_id, vendor_id, vendor_specific_to_str(vendor_specific).c_str());
@@ -559,16 +565,7 @@
     // Without sleep the race condition is lost by ~ 20 ms
     std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
-    if (alloc_id != 0) {
-        // Use alloc_id as both agg_port_id and sched_id
-        // Additional Notes:
-        // The agg_port_id is a BAL nomenclature for alloc_id (TCONT identifier).
-        // The TCONT is associated with its own DBA scheduler with a unique scheduler ID.
-        // Use the alloc_id itself as the DBA Scheduler identifier (sched_id).
-        SchedRemove_(intf_id, onu_id, alloc_id, alloc_id);
-    } else {
-        SchedRemove_(intf_id, onu_id, mk_agg_port_id(intf_id, onu_id), mk_sched_id(intf_id, onu_id));
-    }
+    // TODO: Delete the schedulers and queues.
 
     bcmos_errno err = BCM_ERR_OK;
     bcmbal_subscriber_terminal_cfg cfg;
@@ -697,18 +694,16 @@
     return Status::OK;
 }
 
-Status FlowAdd_(int32_t onu_id,
+Status FlowAdd_(int32_t access_intf_id, int32_t onu_id,
                 uint32_t flow_id, const std::string flow_type,
-                int32_t access_intf_id, int32_t network_intf_id,
-                uint32_t gemport_id, uint32_t sched_id,
-                int32_t priority_value,
-                const ::openolt::Classifier& classifier,
-                const ::openolt::Action& action) {
+                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) {
     bcmos_errno err;
     bcmbal_flow_cfg cfg;
     bcmbal_flow_key key = { };
 
-    BCM_LOG(INFO, openolt_log_id, "flow add - intf_id %d, onu_id %d, flow_id %d, `flow_type` %s, gemport_id %d, network_intf_id %d\n",
+    BCM_LOG(INFO, openolt_log_id, "flow add - intf_id %d, onu_id %d, flow_id %d, flow_type %s, gemport_id %d, network_intf_id %d\n",
         access_intf_id, onu_id, flow_id, flow_type.c_str(), gemport_id, network_intf_id);
 
     key.flow_id = flow_id;
@@ -861,19 +856,24 @@
     }
 
     if ((access_intf_id >= 0) && (onu_id >= 0)) {
-        bcmbal_tm_sched_id val;
-        if (sched_id != 0) {
-            val = sched_id;
-        } else {
-            val = (bcmbal_tm_sched_id) mk_sched_id(access_intf_id, onu_id);
-        }
-        BCMBAL_CFG_PROP_SET(&cfg, flow, dba_tm_sched_id, val);
 
         if (key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM) {
             bcmbal_tm_queue_ref val = { };
-            val.sched_id = access_intf_id << 7 | onu_id;
-            val.queue_id = 0;
+            val.sched_id = mk_sched_id(access_intf_id, onu_id, "downstream");
+            val.queue_id = mk_queue_id(access_intf_id, onu_id);
             BCMBAL_CFG_PROP_SET(&cfg, flow, queue, val);
+        } else if (key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM) {
+            bcmbal_tm_sched_id val1;
+            if (alloc_id != 0) {
+                val1 = alloc_id;
+            } else {
+                BCM_LOG(ERROR, openolt_log_id, "alloc_id not present");
+            }
+            BCMBAL_CFG_PROP_SET(&cfg, flow, dba_tm_sched_id, val1);
+
+            bcmbal_tm_queue_ref val2 = { };
+            val2.sched_id = mk_sched_id(network_intf_id, onu_id, "upstream");
+            BCMBAL_CFG_PROP_SET(&cfg, flow, queue, val2);
         }
     }
 
@@ -918,175 +918,176 @@
     return Status::OK;
 }
 
-Status SchedAdd_(int intf_id, int onu_id, int agg_port_id, int sched_id, int pir) {
+Status SchedAdd_(std::string direction, uint32_t intf_id, uint32_t onu_id,
+                 uint32_t alloc_id, openolt::AdditionalBW additional_bw, uint32_t weight, uint32_t priority,
+                 openolt::SchedulingPolicy sched_policy) {
 
     bcmos_errno err;
 
-    /* Downstream */
-
-    /* Create subscriber's tm_sched */
-    {
-        bcmbal_tm_sched_cfg cfg;
-        bcmbal_tm_sched_key key = { };
-        key.dir = BCMBAL_TM_SCHED_DIR_DS;
-        key.id = intf_id << 7 | onu_id;
-        BCMBAL_CFG_INIT(&cfg, tm_sched, key);
-
-        bcmbal_tm_sched_owner owner = { };
-        owner.type = BCMBAL_TM_SCHED_OWNER_TYPE_SUB_TERM;
-        owner.u.sub_term.intf_id = intf_id;
-        owner.u.sub_term.sub_term_id = onu_id;
-        BCMBAL_CFG_PROP_SET(&cfg, tm_sched, owner, owner);
-
-        bcmbal_tm_sched_parent parent = { };
-
-        BCMBAL_ATTRIBUTE_PROP_SET(&parent, tm_sched_parent, sched_id, intf_id + BAL_RSC_MANAGER_BASE_TM_SCHED_ID);
-
-        BCMBAL_ATTRIBUTE_PROP_SET(&parent, tm_sched_parent, weight, 1);
-
-        BCMBAL_CFG_PROP_SET(&cfg, tm_sched, sched_parent, parent);
-
-        BCMBAL_CFG_PROP_SET(&cfg, tm_sched, sched_type, BCMBAL_TM_SCHED_TYPE_WFQ);
-
-        bcmbal_tm_shaping shaping = { };
-        BCMBAL_ATTRIBUTE_PROP_SET(&shaping, tm_shaping, pir, pir);
-
-        BCMBAL_CFG_PROP_SET(&cfg, tm_sched, rate, shaping);
-
-        err = bcmbal_cfg_set(DEFAULT_ATERM_ID, &cfg.hdr);
-        if (err) {
-            BCM_LOG(ERROR, openolt_log_id, "Failed to create subscriber downstream sched, id %d, intf_id %d, onu_id %d\n",
-                key.id, intf_id, onu_id);
-            return bcm_to_grpc_err(err, "Failed to create subscriber downstream sched");
-        }
-    }
-
-    /* Create tm_queue */
-    {
+    if (direction == "downstream") {
         bcmbal_tm_queue_cfg cfg;
         bcmbal_tm_queue_key key = { };
-        key.sched_id = intf_id << 7 | onu_id;
+        // Note: We use the default scheduler available in the DL.
+        key.sched_id = mk_sched_id(intf_id, onu_id, direction);
         key.sched_dir = BCMBAL_TM_SCHED_DIR_DS;
-        key.id = 0;
+        key.id = mk_queue_id(intf_id, onu_id);
 
         BCMBAL_CFG_INIT(&cfg, tm_queue, key);
-        BCMBAL_CFG_PROP_SET(&cfg, tm_queue, weight, 1);
+        //Queue must be set with either weight or priority, not both,
+        // as its scheduler' sched_type is sp_wfq
+        BCMBAL_CFG_PROP_SET(&cfg, tm_queue, priority, priority);
+        //BCMBAL_CFG_PROP_SET(&cfg, tm_queue, weight, weight);
+        //BCMBAL_CFG_PROP_SET(&cfg, tm_queue, creation_mode, BCMBAL_TM_CREATION_MODE_MANUAL);
         err = bcmbal_cfg_set(DEFAULT_ATERM_ID, &cfg.hdr);
 
+        // TODO: Shaping parameters will be available after meter bands are supported.
+        // TODO: The shaping parameters will be applied on the downstream queue on the PON default scheduler.
         if (err) {
             BCM_LOG(ERROR, openolt_log_id, "Failed to create subscriber downstream tm queue, id %d, sched_id %d, intf_id %d, onu_id %d\n",
-                key.id, key.sched_id, intf_id, onu_id);
+                    key.id, key.sched_id, intf_id, onu_id);
             return bcm_to_grpc_err(err, "Failed to create subscriber downstream tm queue");
         }
+    } else { //"upstream"
+        bcmbal_tm_sched_cfg cfg;
+        bcmbal_tm_sched_key key = { };
+        bcmbal_tm_sched_type sched_type;
 
+        key.id = alloc_id;
+        key.dir = BCMBAL_TM_SCHED_DIR_US;
+
+        BCMBAL_CFG_INIT(&cfg, tm_sched, key);
+
+        {
+            bcmbal_tm_sched_owner val = { };
+
+            val.type = BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT;
+            BCMBAL_ATTRIBUTE_PROP_SET(&val.u.agg_port, tm_sched_owner_agg_port, intf_id, (bcmbal_intf_id) intf_id);
+            BCMBAL_ATTRIBUTE_PROP_SET(&val.u.agg_port, tm_sched_owner_agg_port, sub_term_id, (bcmbal_sub_id) onu_id);
+            BCMBAL_ATTRIBUTE_PROP_SET(&val.u.agg_port, tm_sched_owner_agg_port, agg_port_id, (bcmbal_aggregation_port_id) alloc_id);
+
+            BCMBAL_CFG_PROP_SET(&cfg, tm_sched, owner, val);
+
+        }
+        // TODO: Shaping parameters will be available after meter bands are supported.
+        // TODO: The shaping parameters will be applied on the upstream DBA scheduler.
+
+        err = bcmbal_cfg_set(DEFAULT_ATERM_ID, &(cfg.hdr));
+        if (err) {
+            BCM_LOG(ERROR, openolt_log_id, "Failed to create upstream DBA sched, id %d, intf_id %d, onu_id %d\n",
+                    key.id, intf_id,  onu_id);
+            return bcm_to_grpc_err(err, "Failed to create upstream DBA sched");
+        }
+        BCM_LOG(INFO, openolt_log_id, "Create upstream DBA sched, id %d, intf_id %d, onu_id %d\n",
+                key.id,intf_id,onu_id);
     }
 
-    /* Upstream */
+    return Status::OK;
 
-    bcmbal_tm_sched_cfg cfg;
-    bcmbal_tm_sched_key key = { };
-    bcmbal_tm_sched_type sched_type;
+}
 
-    if (sched_id != 0) {
-        key.id = sched_id;
-    } else {
-    key.id = mk_sched_id(intf_id, onu_id);
+Status CreateTconts_(const openolt::Tconts *tconts) {
+    uint32_t intf_id = tconts->intf_id();
+    uint32_t onu_id = tconts->onu_id();
+    std::string direction;
+    unsigned int alloc_id;
+    openolt::Scheduler scheduler;
+    openolt::AdditionalBW additional_bw;
+    uint32_t priority;
+    uint32_t weight;
+    openolt::SchedulingPolicy sched_policy;
+
+    for (int i = 0; i < tconts->tconts_size(); i++) {
+        openolt::Tcont tcont = tconts->tconts(i);
+        if (tcont.direction() == openolt::Direction::UPSTREAM) {
+            direction = "upstream";
+        } else if (tcont.direction() == openolt::Direction::DOWNSTREAM) {
+            direction = "downstream";
+        }
+        else {
+            BCM_LOG(ERROR, openolt_log_id, "direction-not-supported %d", tcont.direction());
+            return Status::CANCELLED;
+        }
+        alloc_id = tcont.alloc_id();
+        scheduler = tcont.scheduler();
+        additional_bw = scheduler.additional_bw();
+        priority = scheduler.priority();
+        weight = scheduler.weight();
+        sched_policy = scheduler.sched_policy();
+        // TODO: TrafficShapingInfo is not supported for now as meter band support is not there
+        SchedAdd_(direction, intf_id, onu_id, alloc_id, additional_bw, weight, priority, sched_policy);
     }
-    key.dir = BCMBAL_TM_SCHED_DIR_US;
-
-    BCMBAL_CFG_INIT(&cfg, tm_sched, key);
-
-    {
-        bcmbal_tm_sched_owner val = { };
-
-        val.type = BCMBAL_TM_SCHED_OWNER_TYPE_AGG_PORT;
-        BCMBAL_ATTRIBUTE_PROP_SET(&val.u.agg_port, tm_sched_owner_agg_port, intf_id, (bcmbal_intf_id) intf_id);
-        BCMBAL_ATTRIBUTE_PROP_SET(&val.u.agg_port, tm_sched_owner_agg_port, sub_term_id, (bcmbal_sub_id) onu_id);
-        BCMBAL_ATTRIBUTE_PROP_SET(&val.u.agg_port, tm_sched_owner_agg_port, agg_port_id, (bcmbal_aggregation_port_id) agg_port_id);
-
-        BCMBAL_CFG_PROP_SET(&cfg, tm_sched, owner, val);
-    }
-
-    err = bcmbal_cfg_set(DEFAULT_ATERM_ID, &(cfg.hdr));
-    if (err) {
-        BCM_LOG(ERROR, openolt_log_id, "Failed to create upstream DBA sched, id %d, intf_id %d, onu_id %d\n",
-            key.id, intf_id,  onu_id);
-        return bcm_to_grpc_err(err, "Failed to create upstream DBA sched");
-    }
-    BCM_LOG(INFO, openolt_log_id, "Create upstream DBA sched, id %d, intf_id %d, onu_id %d\n",
-        key.id,intf_id,onu_id);
-
     return Status::OK;
 }
 
-Status SchedRemove_(int intf_id, int onu_id, int agg_port_id, int sched_id) {
+Status RemoveTconts_(const openolt::Tconts *tconts) {
+    uint32_t intf_id = tconts->intf_id();
+    uint32_t onu_id = tconts->onu_id();
+    std::string direction;
+    unsigned int alloc_id;
+
+    for (int i = 0; i < tconts->tconts_size(); i++) {
+        openolt::Tcont tcont = tconts->tconts(i);
+        if (tcont.direction() == openolt::Direction::UPSTREAM) {
+            direction = "upstream";
+        } else if (tcont.direction() == openolt::Direction::DOWNSTREAM) {
+            direction = "downstream";
+        }
+        else {
+            BCM_LOG(ERROR, openolt_log_id, "direction-not-supported %d", tcont.direction());
+            return Status::CANCELLED;
+        }
+        alloc_id = tcont.alloc_id();
+        SchedRemove_(direction, intf_id, onu_id, alloc_id);
+    }
+    return Status::OK;
+}
+
+Status SchedRemove_(std::string direction, int intf_id, int onu_id, int alloc_id) {
 
     bcmos_errno err;
 
-    /* Upstream */
 
-    bcmbal_tm_sched_cfg tm_cfg_us;
-    bcmbal_tm_sched_key tm_key_us = { };
+    if (direction == "upstream") {
+        // DBA sched
+        bcmbal_tm_sched_cfg tm_cfg_us;
+        bcmbal_tm_sched_key tm_key_us = { };
 
-    if (sched_id != 0) {
-        tm_key_us.id = sched_id;
-    } else {
-    tm_key_us.id = mk_sched_id(intf_id, onu_id);
-    }
-    tm_key_us.dir = BCMBAL_TM_SCHED_DIR_US;
+        tm_key_us.id = alloc_id;
+        tm_key_us.dir = BCMBAL_TM_SCHED_DIR_US;
 
-    BCMBAL_CFG_INIT(&tm_cfg_us, tm_sched, tm_key_us);
+        BCMBAL_CFG_INIT(&tm_cfg_us, tm_sched, tm_key_us);
 
-    err = bcmbal_cfg_clear(DEFAULT_ATERM_ID, &(tm_cfg_us.hdr));
-    if (err) {
-        BCM_LOG(ERROR, openolt_log_id, "Failed to remove upstream DBA sched, id %d, intf_id %d, onu_id %d\n",
+        err = bcmbal_cfg_clear(DEFAULT_ATERM_ID, &(tm_cfg_us.hdr));
+        if (err) {
+            BCM_LOG(ERROR, openolt_log_id, "Failed to remove upstream DBA sched, id %d, intf_id %d, onu_id %d\n",
+                tm_key_us.id, intf_id, onu_id);
+            return Status(grpc::StatusCode::INTERNAL, "Failed to remove upstream DBA sched");
+        }
+
+        BCM_LOG(INFO, openolt_log_id, "Remove upstream DBA sched, id %d, intf_id %d, onu_id %d\n",
             tm_key_us.id, intf_id, onu_id);
-        return Status(grpc::StatusCode::INTERNAL, "Failed to remove upstream DBA sched");
+
+    } else if (direction == "downstream") {
+	    // Queue
+
+	    bcmbal_tm_queue_cfg queue_cfg;
+	    bcmbal_tm_queue_key queue_key = { };
+	    queue_key.sched_id = mk_sched_id(intf_id, onu_id, "downstream");
+	    queue_key.sched_dir = BCMBAL_TM_SCHED_DIR_DS;
+	    queue_key.id = mk_queue_id(intf_id, onu_id);;
+
+	    BCMBAL_CFG_INIT(&queue_cfg, tm_queue, queue_key);
+
+	    err = bcmbal_cfg_clear(DEFAULT_ATERM_ID, &(queue_cfg.hdr));
+	    if (err) {
+		    BCM_LOG(ERROR, openolt_log_id, "Failed to remove downstream tm queue, id %d, sched_id %d, intf_id %d, onu_id %d\n",
+				    queue_key.id, queue_key.sched_id, intf_id, onu_id);
+		    return Status(grpc::StatusCode::INTERNAL, "Failed to remove downstream tm queue");
+	    }
+
+	    BCM_LOG(INFO, openolt_log_id, "Remove upstream DBA sched, id %d, sched_id %d, intf_id %d, onu_id %d\n",
+			    queue_key.id, queue_key.sched_id, intf_id, onu_id);
     }
 
-    BCM_LOG(INFO, openolt_log_id, "Remove upstream DBA sched, id %d, intf_id %d, onu_id %d\n",
-        tm_key_us.id, intf_id, onu_id);
-
-    /* Downstream */
-
-    // Queue
-
-    bcmbal_tm_queue_cfg queue_cfg;
-    bcmbal_tm_queue_key queue_key = { };
-    queue_key.sched_id = intf_id << 7 | onu_id;
-    queue_key.sched_dir = BCMBAL_TM_SCHED_DIR_DS;
-    queue_key.id = 0;
-
-    BCMBAL_CFG_INIT(&queue_cfg, tm_queue, queue_key);
-
-    err = bcmbal_cfg_clear(DEFAULT_ATERM_ID, &(queue_cfg.hdr));
-    if (err) {
-        BCM_LOG(ERROR, openolt_log_id, "Failed to remove downstream tm queue, id %d, sched_id %d, intf_id %d, onu_id %d\n",
-            queue_key.id, queue_key.sched_id, intf_id, onu_id);
-        return Status(grpc::StatusCode::INTERNAL, "Failed to remove downstream tm queue");
-    }
-
-    BCM_LOG(INFO, openolt_log_id, "Remove upstream DBA sched, id %d, sched_id %d, intf_id %d, onu_id %d\n",
-        queue_key.id, queue_key.sched_id, intf_id, onu_id);
-
-    // Sheduler
-
-    bcmbal_tm_sched_cfg tm_cfg_ds;
-    bcmbal_tm_sched_key tm_key_ds = { };
-    tm_key_ds.dir = BCMBAL_TM_SCHED_DIR_DS;
-    tm_key_ds.id = intf_id << 7 | onu_id;
-    BCMBAL_CFG_INIT(&tm_cfg_ds, tm_sched, tm_key_ds);
-
-    err = bcmbal_cfg_clear(DEFAULT_ATERM_ID, &(tm_cfg_ds.hdr));
-    if (err) {
-        BCM_LOG(ERROR, openolt_log_id, "Failed to remove sub downstream sched, id %d, intf_id %d, onu_id %d\n",
-            tm_key_us.id, intf_id, onu_id);
-        return Status(grpc::StatusCode::INTERNAL, "Failed to remove sub downstream sched");
-    }
-
-    BCM_LOG(INFO, openolt_log_id, "Remove sub downstream sched, id %d, intf_id %d, onu_id %d\n",
-        tm_key_us.id, intf_id, onu_id);
-
     return Status::OK;
-    //return 0;
 }
diff --git a/agent/src/indications.cc b/agent/src/indications.cc
index 5807c0b..f99f10e 100644
--- a/agent/src/indications.cc
+++ b/agent/src/indications.cc
@@ -143,6 +143,26 @@
     return BCM_ERR_OK;
 }
 
+bcmos_errno IfIndication(bcmbal_obj *obj) {
+    openolt::Indication ind;
+    openolt::IntfIndication* intf_ind = new openolt::IntfIndication;
+
+    BCM_LOG(INFO, openolt_log_id, "intf indication, intf_id: %d\n",
+        ((bcmbal_interface_oper_status_change *)obj)->key.intf_id );
+
+    intf_ind->set_intf_id(((bcmbal_interface_oper_status_change *)obj)->key.intf_id);
+    if (((bcmbal_interface_oper_status_change *)obj)->data.new_oper_status == BCMBAL_STATUS_UP) {
+        intf_ind->set_oper_state("up");
+    } else {
+        intf_ind->set_oper_state("down");
+    }
+    ind.set_allocated_intf_ind(intf_ind);
+
+    oltIndQ.push(ind);
+
+    return BCM_ERR_OK;
+}
+
 bcmos_errno IfOperIndication(bcmbal_obj *obj) {
     openolt::Indication ind;
     openolt::IntfOperIndication* intf_oper_ind = new openolt::IntfOperIndication;
@@ -157,7 +177,7 @@
         intf_oper_ind->set_oper_state("down");
     }
 
-    BCM_LOG(INFO, openolt_log_id, "intf oper state indication, intf_type %s, intf_id %d, oper_state %d, admin_state %d\n",
+    BCM_LOG(INFO, openolt_log_id, "intf oper state indication, intf_type %s, intf_id %d, oper_state %s, admin_state %d\n",
         intf_oper_ind->type().c_str(),
         bcm_if_oper_ind->key.intf_id,
         intf_oper_ind->oper_state().c_str(),
@@ -250,6 +270,38 @@
     return BCM_ERR_OK;
 }
 
+bcmos_errno OnuIndication(bcmbal_obj *obj) {
+    openolt::Indication ind;
+    openolt::OnuIndication* onu_ind = new openolt::OnuIndication;
+
+    bcmbal_subscriber_terminal_key *key =
+        &(((bcmbal_subscriber_terminal_oper_status_change*)obj)->key);
+
+    bcmbal_subscriber_terminal_oper_status_change_data *data =
+        &(((bcmbal_subscriber_terminal_oper_status_change*)obj)->data);
+
+    BCM_LOG(INFO, openolt_log_id, "onu indication, intf_id %d, onu_id %d, oper_state %d, admin_state %d\n",
+        key->intf_id, key->sub_term_id, data->new_oper_status, data->admin_state);
+
+    onu_ind->set_intf_id(key->intf_id);
+    onu_ind->set_onu_id(key->sub_term_id);
+    if (data->new_oper_status == BCMBAL_STATUS_UP) {
+        onu_ind->set_oper_state("up");
+    } else {
+        onu_ind->set_oper_state("down");
+    }
+    if (data->admin_state == BCMBAL_STATE_UP) {
+        onu_ind->set_admin_state("up");
+    } else {
+        onu_ind->set_admin_state("down");
+    }
+
+    ind.set_allocated_onu_ind(onu_ind);
+
+    oltIndQ.push(ind);
+    return BCM_ERR_OK;
+}
+
 bcmos_errno OnuOperIndication(bcmbal_obj *obj) {
     openolt::Indication ind;
     openolt::OnuIndication* onu_ind = new openolt::OnuIndication;
@@ -581,6 +633,15 @@
         return Status(grpc::StatusCode::INTERNAL, "LOS indication subscribe failed");
     }
 
+    /* Interface indication */
+    cb_cfg.obj_type = BCMBAL_OBJ_ID_INTERFACE;
+    ind_subgroup = bcmbal_interface_auto_id_oper_status_change;
+    cb_cfg.p_subgroup = &ind_subgroup;
+    cb_cfg.ind_cb_hdlr = (f_bcmbal_ind_handler)IfIndication;
+    if (BCM_ERR_OK != bcmbal_subscribe_ind(DEFAULT_ATERM_ID, &cb_cfg)) {
+        return Status(grpc::StatusCode::INTERNAL, "Interface indication subscribe failed");
+    }
+
     /* Interface operational state change indication */
     cb_cfg.obj_type = BCMBAL_OBJ_ID_INTERFACE;
     ind_subgroup = bcmbal_interface_auto_id_oper_status_change;
@@ -617,6 +678,14 @@
         return Status(grpc::StatusCode::INTERNAL, "onu discovery indication subscribe failed");
     }
 
+    /* onu indication */
+    cb_cfg.obj_type = BCMBAL_OBJ_ID_SUBSCRIBER_TERMINAL;
+    ind_subgroup = bcmbal_subscriber_terminal_auto_id_oper_status_change;
+    cb_cfg.p_subgroup = &ind_subgroup;
+    cb_cfg.ind_cb_hdlr = (f_bcmbal_ind_handler)OnuIndication;
+    if (BCM_ERR_OK != bcmbal_subscribe_ind(DEFAULT_ATERM_ID, &cb_cfg)) {
+        return Status(grpc::StatusCode::INTERNAL, "onu indication subscribe failed");
+    }
     /* onu operational state change indication */
     cb_cfg.obj_type = BCMBAL_OBJ_ID_SUBSCRIBER_TERMINAL;
     ind_subgroup = bcmbal_subscriber_terminal_auto_id_oper_status_change;
diff --git a/protos/openolt.proto b/protos/openolt.proto
index 60bab72..8c35bba 100644
--- a/protos/openolt.proto
+++ b/protos/openolt.proto
@@ -130,6 +130,20 @@
         };
     }
 
+    rpc CreateTconts(Tconts) returns (Empty) {
+        option (google.api.http) = {
+            post: "/v1/CreateTconts"
+            body: "*"
+        };
+    }
+
+    rpc RemoveTconts(Tconts) returns (Empty) {
+        option (google.api.http) = {
+            post: "/v1/RemoveTconts"
+            body: "*"
+        };
+    }
+
     rpc EnableIndication(Empty) returns (stream Indication) {}
 }
 
@@ -219,7 +233,6 @@
     fixed32 onu_id = 2;
     SerialNumber serial_number = 3;
     fixed32 pir = 4;   // peak information rate assigned to onu
-    fixed32 alloc_id = 5;
 }
 
 message OmciMsg {
@@ -278,7 +291,7 @@
 
             enum SharingType {
                 DEDICATED_PER_INTF = 0;
-                SHARED_BY_ALL_INTF_ALL_TECH = 1; // Shared across all interfaces in all technologiesi in all ranges
+                SHARED_BY_ALL_INTF_ALL_TECH = 1; // Shared across all interfaces in all technologies in all ranges
                 SHARED_BY_ALL_INTF_SAME_TECH = 2; // Shared across all interfaces of the same technology used in this range
             }
 
@@ -443,5 +456,91 @@
     fixed32 onu_id = 2;
 }
 
+enum Direction {
+    UPSTREAM = 0;
+    DOWNSTREAM = 1;
+    BIDIRECTIONAL = 2;
+}
+
+enum SchedulingPolicy {
+    WRR = 0;
+    StrictPriority = 1;
+    Hybrid = 2;
+}
+
+enum AdditionalBW {
+    AdditionalBW_None = 0;
+    AdditionalBW_NA = 1;
+    AdditionalBW_BestEffort = 2;
+    AdditionalBW_Auto = 3;
+}
+
+enum DiscardPolicy {
+    TailDrop = 0;
+    WTailDrop = 1;
+    Red = 2;
+    WRed = 3;
+}
+
+enum InferredAdditionBWIndication {
+    InferredAdditionBWIndication_None = 0;
+    InferredAdditionBWIndication_Assured = 1;
+    InferredAdditionBWIndication_BestEffort = 2;
+}
+
+message Scheduler {
+    Direction direction = 1;
+    AdditionalBW additional_bw = 2; // Valid on for “direction == Upstream”.
+    fixed32 priority = 3;
+    fixed32 weight = 4;
+    SchedulingPolicy sched_policy = 5;
+}
+
+message TrafficShapingInfo {
+    fixed32 cir = 1;
+    fixed32 cbs = 2;
+    fixed32 pir = 3;
+    fixed32 pbs = 4;
+    fixed32 gir = 5; // only if “direction == Upstream ”
+    InferredAdditionBWIndication add_bw_ind = 6; // only if “direction == Upstream”
+}
+
+message Tcont {
+    Direction direction = 1;
+    fixed32 alloc_id = 2; // valid only if “direction == Upstream ”
+    Scheduler scheduler = 3;
+    TrafficShapingInfo traffic_shaping_info = 4;
+}
+
+message Tconts {
+    fixed32 intf_id = 1;
+    fixed32 onu_id = 2;
+    repeated Tcont tconts = 3;
+}
+
+message TailDropDiscardConfig {
+    fixed32 queue_size = 1;
+}
+
+message RedDiscardConfig {
+    fixed32 min_threshold = 1;
+    fixed32 max_threshold = 2;
+    fixed32 max_probability = 3;
+}
+
+message WRedDiscardConfig {
+    RedDiscardConfig green = 1;
+    RedDiscardConfig yellow = 2;
+    RedDiscardConfig red = 3;
+}
+
+message DiscardConfig {
+    DiscardPolicy discard_policy = 1;
+    oneof discard_config {
+        TailDropDiscardConfig tail_drop_discard_config = 2;
+        RedDiscardConfig red_discard_config = 3;
+        WRedDiscardConfig wred_discard_config = 4;
+    }
+}
 
 message Empty {}