[VOL-3870] Support all the 5 tcont type

Change-Id: I55f88753d60f2b8f868331ea0b4c29bb11d57cd2
diff --git a/VERSION b/VERSION
index 4772543..619b537 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.3.2
+3.3.3
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 15c7e9c..eb35925 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -22,6 +22,7 @@
 	"encoding/hex"
 	"errors"
 	"fmt"
+	"github.com/opencord/voltha-lib-go/v4/pkg/meters"
 	"strconv"
 	"strings"
 	"sync"
@@ -511,25 +512,15 @@
 			"flow-metadata": sq.flowMetadata,
 			"meter-id":      sq.meterID,
 			"device-id":     f.deviceHandler.device.Id}, nil)
-	} else if len(meterInfo.MeterConfig.Bands) < MaxMeterBand {
-		logger.Errorw(ctx, "invalid-number-of-bands-in-meter",
-			log.Fields{"Bands": meterInfo.MeterConfig.Bands,
-				"meter-id":  sq.meterID,
-				"device-id": f.deviceHandler.device.Id})
-		return olterrors.NewErrInvalidValue(log.Fields{
-			"reason":          "Invalid-number-of-bands-in-meter",
-			"meterband-count": len(meterInfo.MeterConfig.Bands),
-			"metabands":       meterInfo.MeterConfig.Bands,
-			"meter-id":        sq.meterID,
-			"device-id":       f.deviceHandler.device.Id}, nil)
 	}
-	cir := meterInfo.MeterConfig.Bands[0].Rate
-	cbs := meterInfo.MeterConfig.Bands[0].BurstSize
-	eir := meterInfo.MeterConfig.Bands[1].Rate
-	ebs := meterInfo.MeterConfig.Bands[1].BurstSize
-	pir := cir + eir
-	pbs := cbs + ebs
-	TrafficShaping := &tp_pb.TrafficShapingInfo{Cir: cir, Cbs: cbs, Pir: pir, Pbs: pbs}
+
+	var TrafficShaping *tp_pb.TrafficShapingInfo
+	if TrafficShaping, err = meters.GetTrafficShapingInfo(ctx, &meterInfo.MeterConfig); err != nil {
+		return olterrors.NewErrInvalidValue(log.Fields{
+			"reason":    "invalid-meter-config",
+			"meter-id":  sq.meterID,
+			"device-id": f.deviceHandler.device.Id}, nil)
+	}
 
 	TrafficSched := []*tp_pb.TrafficScheduler{f.techprofile[sq.intfID].GetTrafficScheduler(sq.tpInst.(*tp.TechProfile), SchedCfg, TrafficShaping)}
 	TrafficSched[0].TechProfileId = sq.tpID
diff --git a/internal/pkg/core/openolt_flowmgr_test.go b/internal/pkg/core/openolt_flowmgr_test.go
index fad128a..3a561be 100644
--- a/internal/pkg/core/openolt_flowmgr_test.go
+++ b/internal/pkg/core/openolt_flowmgr_test.go
@@ -112,33 +112,36 @@
 		InstanceCtrl: tp.InstanceControl{Onu: "1", Uni: "1", MaxGemPayloadSize: "1"},
 	}
 	tprofile.UsScheduler.Direction = "UPSTREAM"
-	tprofile.UsScheduler.AdditionalBw = "AdditionalBW_None"
 	tprofile.UsScheduler.QSchedPolicy = "WRR"
 
 	tprofile2 := tprofile
 	tprofile2.DsScheduler.Direction = "DOWNSTREAM"
-	tprofile2.DsScheduler.AdditionalBw = "AdditionalBW_None"
 	tprofile2.DsScheduler.QSchedPolicy = "WRR"
-	bands := make([]*ofp.OfpMeterBandHeader, 2)
-	bands[0] = &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 1000, BurstSize: 5000, Data: &ofp.OfpMeterBandHeader_Drop{}}
-	bands[1] = &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 2000, BurstSize: 5000, Data: &ofp.OfpMeterBandHeader_Drop{}}
-	ofpMeterConfig := &ofp.OfpMeterConfig{Flags: 1, MeterId: 1, Bands: bands}
-	flowmetadata := &voltha.FlowMetadata{
-		Meters: []*ofp.OfpMeterConfig{ofpMeterConfig},
-	}
+
 	tests := []struct {
 		name       string
 		schedQueue schedQueue
 		wantErr    bool
 	}{
 		// TODO: Add test cases.
-		{"CreateSchedulerQueues-1", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 1, flowmetadata}, false},
-		{"CreateSchedulerQueues-2", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 1, flowmetadata}, false},
-		{"CreateSchedulerQueues-3", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 2, flowmetadata}, true},
-		{"CreateSchedulerQueues-4", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 2, flowmetadata}, true},
-		{"CreateSchedulerQueues-5", schedQueue{tp_pb.Direction_UPSTREAM, 1, 2, 2, 64, 2, tprofile, 2, flowmetadata}, true},
-		{"CreateSchedulerQueues-6", schedQueue{tp_pb.Direction_DOWNSTREAM, 1, 2, 2, 65, 2, tprofile2, 2, flowmetadata}, true},
-		{"CreateSchedulerQueues-13", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 1, flowmetadata}, false},
+		{"CreateSchedulerQueues-1", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 1, createFlowMetadata(tprofile, 1, Upstream)}, false},
+		{"CreateSchedulerQueues-2", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 1, createFlowMetadata(tprofile2, 1, Downstream)}, false},
+		{"CreateSchedulerQueues-13", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 1, createFlowMetadata(tprofile, 2, Upstream)}, false},
+		{"CreateSchedulerQueues-14", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 1, createFlowMetadata(tprofile2, 2, Downstream)}, false},
+		{"CreateSchedulerQueues-15", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 1, createFlowMetadata(tprofile, 3, Upstream)}, false},
+		{"CreateSchedulerQueues-16", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 1, createFlowMetadata(tprofile2, 3, Downstream)}, false},
+		{"CreateSchedulerQueues-17", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 1, createFlowMetadata(tprofile, 4, Upstream)}, false},
+		{"CreateSchedulerQueues-18", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 1, createFlowMetadata(tprofile2, 4, Downstream)}, false},
+		{"CreateSchedulerQueues-19", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 1, createFlowMetadata(tprofile, 5, Upstream)}, false},
+		{"CreateSchedulerQueues-20", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 1, createFlowMetadata(tprofile2, 5, Downstream)}, false},
+
+		{"CreateSchedulerQueues-1", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 1, createFlowMetadata(tprofile, 0, Upstream)}, true},
+		{"CreateSchedulerQueues-2", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 1, createFlowMetadata(tprofile2, 0, Downstream)}, true},
+		{"CreateSchedulerQueues-3", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 2, createFlowMetadata(tprofile, 2, Upstream)}, true},
+		{"CreateSchedulerQueues-4", schedQueue{tp_pb.Direction_DOWNSTREAM, 0, 1, 1, 65, 1, tprofile2, 2, createFlowMetadata(tprofile2, 2, Downstream)}, true},
+		{"CreateSchedulerQueues-5", schedQueue{tp_pb.Direction_UPSTREAM, 1, 2, 2, 64, 2, tprofile, 2, createFlowMetadata(tprofile, 3, Upstream)}, true},
+		{"CreateSchedulerQueues-6", schedQueue{tp_pb.Direction_DOWNSTREAM, 1, 2, 2, 65, 2, tprofile2, 2, createFlowMetadata(tprofile2, 3, Downstream)}, true},
+
 		//Negative testcases
 		{"CreateSchedulerQueues-7", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 1, &voltha.FlowMetadata{}}, true},
 		{"CreateSchedulerQueues-8", schedQueue{tp_pb.Direction_UPSTREAM, 0, 1, 1, 64, 1, tprofile, 0, &voltha.FlowMetadata{}}, true},
@@ -158,6 +161,50 @@
 	}
 }
 
+func createFlowMetadata(techProfile *tp.TechProfile, tcontType int, direction string) *voltha.FlowMetadata {
+	var additionalBw string
+	bands := make([]*ofp.OfpMeterBandHeader, 0)
+	switch tcontType {
+	case 1:
+		//tcont-type-1
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 10000, BurstSize: 0, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 10000, BurstSize: 0, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		additionalBw = "AdditionalBW_None"
+	case 2:
+		//tcont-type-2
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 60000, BurstSize: 10000, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 50000, BurstSize: 10000, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		additionalBw = "AdditionalBW_None"
+	case 3:
+		//tcont-type-3
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 100000, BurstSize: 10000, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 50000, BurstSize: 20000, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		additionalBw = "AdditionalBW_NA"
+	case 4:
+		//tcont-type-4
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 200000, BurstSize: 10000, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		additionalBw = "AdditionalBW_BestEffort"
+	case 5:
+		//tcont-type-5
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 50000, BurstSize: 10000, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 100000, BurstSize: 10000, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		bands = append(bands, &ofp.OfpMeterBandHeader{Type: ofp.OfpMeterBandType_OFPMBT_DROP, Rate: 10000, BurstSize: 0, Data: &ofp.OfpMeterBandHeader_Drop{}})
+		additionalBw = "AdditionalBW_BestEffort"
+	default:
+		// do nothing, we will return meter config with no meter bands
+	}
+
+	if direction == Downstream {
+		techProfile.DsScheduler.AdditionalBw = additionalBw
+	} else {
+		techProfile.UsScheduler.AdditionalBw = additionalBw
+	}
+
+	ofpMeterConfig := &ofp.OfpMeterConfig{Flags: 1, MeterId: 1, Bands: bands}
+	return &voltha.FlowMetadata{
+		Meters: []*ofp.OfpMeterConfig{ofpMeterConfig}}
+}
+
 func TestOpenOltFlowMgr_RemoveSchedulerQueues(t *testing.T) {
 	tprofile := &tp.TechProfile{Name: "tp1", SubscriberIdentifier: "subscriber1",
 		ProfileType: "pt1", NumGemPorts: 1, Version: 1,
@@ -1269,7 +1316,7 @@
 				{
 					Type:      voltha.OfpMeterBandType_OFPMBT_DROP,
 					Rate:      16000,
-					BurstSize: 30,
+					BurstSize: 0,
 				},
 				{
 					Type:      voltha.OfpMeterBandType_OFPMBT_DROP,
diff --git a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/meters/common.go b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/meters/common.go
new file mode 100644
index 0000000..0a171f6
--- /dev/null
+++ b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/meters/common.go
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019-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.
+ */
+package meters
+
+import (
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+)
+
+var logger log.CLogger
+
+func init() {
+	// Setup this package so that it's log level can be modified at run time
+	var err error
+	logger, err = log.RegisterPackage(log.JSON, log.ErrorLevel, log.Fields{})
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/vendor/github.com/opencord/voltha-lib-go/v4/pkg/meters/meter_utils.go b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/meters/meter_utils.go
new file mode 100644
index 0000000..38f35b9
--- /dev/null
+++ b/vendor/github.com/opencord/voltha-lib-go/v4/pkg/meters/meter_utils.go
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019-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.
+ */
+package meters
+
+import (
+	"context"
+	"fmt"
+	"github.com/opencord/voltha-lib-go/v4/pkg/log"
+	ofp "github.com/opencord/voltha-protos/v4/go/openflow_13"
+	tp_pb "github.com/opencord/voltha-protos/v4/go/tech_profile"
+)
+
+// GetTrafficShapingInfo returns CIR,PIR and GIR values
+func GetTrafficShapingInfo(ctx context.Context, meterConfig *ofp.OfpMeterConfig) (*tp_pb.TrafficShapingInfo, error) {
+	switch meterBandSize := len(meterConfig.Bands); {
+	case meterBandSize == 1:
+		band := meterConfig.Bands[0]
+		if band.BurstSize == 0 { // GIR, tcont type 1
+			return &tp_pb.TrafficShapingInfo{Gir: band.Rate}, nil
+		}
+		return &tp_pb.TrafficShapingInfo{Pir: band.Rate, Pbs: band.BurstSize}, nil // PIR, tcont type 4
+	case meterBandSize == 2:
+		firstBand, secondBand := meterConfig.Bands[0], meterConfig.Bands[1]
+		if firstBand.BurstSize == 0 && secondBand.BurstSize == 0 &&
+			firstBand.Rate == secondBand.Rate { // PIR == GIR, tcont type 1
+			return &tp_pb.TrafficShapingInfo{Pir: firstBand.Rate, Gir: secondBand.Rate}, nil
+		}
+		if firstBand.BurstSize > 0 && secondBand.BurstSize > 0 { // PIR, CIR, tcont type 2 or 3
+			if firstBand.Rate > secondBand.Rate { // always PIR >= CIR
+				return &tp_pb.TrafficShapingInfo{Pir: firstBand.Rate, Pbs: firstBand.BurstSize, Cir: secondBand.Rate, Cbs: secondBand.BurstSize}, nil
+			}
+			return &tp_pb.TrafficShapingInfo{Pir: secondBand.Rate, Pbs: secondBand.BurstSize, Cir: firstBand.Rate, Cbs: firstBand.BurstSize}, nil
+		}
+	case meterBandSize == 3: // PIR,CIR,GIR, tcont type 5
+		var count, girIndex int
+		for i, band := range meterConfig.Bands {
+			if band.BurstSize == 0 { // find GIR
+				count = count + 1
+				girIndex = i
+			}
+		}
+		if count == 1 {
+			bands := make([]*ofp.OfpMeterBandHeader, len(meterConfig.Bands))
+			copy(bands, meterConfig.Bands)
+			pirCirBands := append(bands[:girIndex], bands[girIndex+1:]...)
+			firstBand, secondBand := pirCirBands[0], pirCirBands[1]
+			if firstBand.Rate > secondBand.Rate {
+				return &tp_pb.TrafficShapingInfo{Pir: firstBand.Rate, Pbs: firstBand.BurstSize, Cir: secondBand.Rate, Cbs: secondBand.BurstSize, Gir: meterConfig.Bands[girIndex].Rate}, nil
+			}
+			return &tp_pb.TrafficShapingInfo{Pir: secondBand.Rate, Pbs: secondBand.BurstSize, Cir: firstBand.Rate, Cbs: firstBand.BurstSize, Gir: meterConfig.Bands[girIndex].Rate}, nil
+		}
+	default:
+		logger.Errorw(ctx, "invalid-meter-config", log.Fields{"meter-config": meterConfig})
+		return nil, fmt.Errorf("invalid-meter-config: %v", meterConfig)
+	}
+	return nil, fmt.Errorf("invalid-meter-config: %v", meterConfig)
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 27b3671..0e28f74 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -69,6 +69,7 @@
 github.com/opencord/voltha-lib-go/v4/pkg/flows
 github.com/opencord/voltha-lib-go/v4/pkg/kafka
 github.com/opencord/voltha-lib-go/v4/pkg/log
+github.com/opencord/voltha-lib-go/v4/pkg/meters
 github.com/opencord/voltha-lib-go/v4/pkg/pmmetrics
 github.com/opencord/voltha-lib-go/v4/pkg/ponresourcemanager
 github.com/opencord/voltha-lib-go/v4/pkg/probe