[VOL-3870] Support all the 5 tcont type

Change-Id: I2bd499e8c5270e1ba082373681168fc9dae3ff6e
diff --git a/pkg/meters/common.go b/pkg/meters/common.go
new file mode 100644
index 0000000..0a171f6
--- /dev/null
+++ b/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/pkg/meters/meter_utils.go b/pkg/meters/meter_utils.go
new file mode 100644
index 0000000..38f35b9
--- /dev/null
+++ b/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/pkg/meters/meter_utils_test.go b/pkg/meters/meter_utils_test.go
new file mode 100644
index 0000000..9e7bd16
--- /dev/null
+++ b/pkg/meters/meter_utils_test.go
@@ -0,0 +1,175 @@
+/*
+ * 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"
+	"github.com/opencord/voltha-protos/v4/go/openflow_13"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestMeters_TestTcontType1(t *testing.T) {
+	//tcont-type-1
+	meterConfig := &openflow_13.OfpMeterConfig{
+		MeterId: 1,
+		Bands: []*openflow_13.OfpMeterBandHeader{
+			{
+				Rate:      10000,
+				BurstSize: 0,
+			},
+		},
+	}
+	shapingInfo, _ := GetTrafficShapingInfo(context.Background(), meterConfig)
+	assert.Equal(t, uint32(10000), shapingInfo.Gir)
+
+	//tcont-type-1
+	meterConfig = &openflow_13.OfpMeterConfig{
+		MeterId: 1,
+		Bands: []*openflow_13.OfpMeterBandHeader{
+			{
+				Rate:      10000,
+				BurstSize: 0,
+			},
+			{
+				Rate:      10000,
+				BurstSize: 0,
+			},
+		},
+	}
+	shapingInfo, _ = GetTrafficShapingInfo(context.Background(), meterConfig)
+	assert.Equal(t, uint32(10000), shapingInfo.Pir)
+	assert.Equal(t, uint32(10000), shapingInfo.Gir)
+}
+
+func TestMeters_TestTcontType2and3(t *testing.T) {
+	meterConfig := &openflow_13.OfpMeterConfig{
+		MeterId: 1,
+		Bands: []*openflow_13.OfpMeterBandHeader{
+			{
+				Rate:      10000,
+				BurstSize: 2000,
+			},
+			{
+				Rate:      30000,
+				BurstSize: 3000,
+			},
+		},
+	}
+	shapingInfo, _ := GetTrafficShapingInfo(context.Background(), meterConfig)
+	assert.Equal(t, uint32(30000), shapingInfo.Pir)
+	assert.Equal(t, uint32(10000), shapingInfo.Cir)
+}
+
+func TestMeters_TestTcontType4(t *testing.T) {
+	meterConfig := &openflow_13.OfpMeterConfig{
+		MeterId: 1,
+		Bands: []*openflow_13.OfpMeterBandHeader{
+			{
+				Rate:      10000,
+				BurstSize: 1000,
+			},
+		},
+	}
+	shapingInfo, _ := GetTrafficShapingInfo(context.Background(), meterConfig)
+	assert.Equal(t, uint32(10000), shapingInfo.Pir)
+}
+
+func TestMeters_TestTcontType5(t *testing.T) {
+	meterConfig := &openflow_13.OfpMeterConfig{
+		MeterId: 1,
+		Bands: []*openflow_13.OfpMeterBandHeader{
+			{
+				Rate:      10000,
+				BurstSize: 0,
+			},
+			{
+				Rate:      20000,
+				BurstSize: 4000,
+			},
+			{
+				Rate:      30000,
+				BurstSize: 5000,
+			},
+		},
+	}
+	shapingInfo, _ := GetTrafficShapingInfo(context.Background(), meterConfig)
+	assert.Equal(t, uint32(30000), shapingInfo.Pir)
+	assert.Equal(t, uint32(10000), shapingInfo.Gir)
+	assert.Equal(t, uint32(20000), shapingInfo.Cir)
+	assert.Equal(t, uint32(5000), shapingInfo.Pbs)
+}
+
+func TestMeters_TestInvalidValues(t *testing.T) {
+	// cir not found
+	meterConfig := &openflow_13.OfpMeterConfig{
+		MeterId: 1,
+		Bands: []*openflow_13.OfpMeterBandHeader{
+			{
+				Rate:      10000,
+				BurstSize: 0,
+			},
+			{
+				Rate:      20000,
+				BurstSize: 4000,
+			},
+		},
+	}
+	shapingInfo, _ := GetTrafficShapingInfo(context.Background(), meterConfig)
+	assert.Nil(t, shapingInfo)
+
+	// gir not found
+	meterConfig = &openflow_13.OfpMeterConfig{
+		MeterId: 1,
+		Bands: []*openflow_13.OfpMeterBandHeader{
+			{
+				Rate:      10000,
+				BurstSize: 3000,
+			},
+			{
+				Rate:      20000,
+				BurstSize: 4000,
+			},
+			{
+				Rate:      30000,
+				BurstSize: 5000,
+			},
+		},
+	}
+	shapingInfo, _ = GetTrafficShapingInfo(context.Background(), meterConfig)
+	assert.Nil(t, shapingInfo)
+
+	//gir not found
+	meterConfig = &openflow_13.OfpMeterConfig{
+		MeterId: 1,
+		Bands: []*openflow_13.OfpMeterBandHeader{
+			{
+				Rate:      10000,
+				BurstSize: 0,
+			},
+			{
+				Rate:      20000,
+				BurstSize: 0,
+			},
+			{
+				Rate:      30000,
+				BurstSize: 5000,
+			},
+		},
+	}
+	shapingInfo, _ = GetTrafficShapingInfo(context.Background(), meterConfig)
+	assert.Nil(t, shapingInfo)
+}