First Commit of Voltha-Go-Controller from Radisys
Change-Id: I8e2e908e7ab09a4fe3d86849da18b6d69dcf4ab0
diff --git a/internal/pkg/application/meters.go b/internal/pkg/application/meters.go
new file mode 100644
index 0000000..4b5fd71
--- /dev/null
+++ b/internal/pkg/application/meters.go
@@ -0,0 +1,331 @@
+/*
+* Copyright 2022-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 application
+
+import (
+ "encoding/json"
+ "errors"
+ "sync"
+
+ cntlr "voltha-go-controller/internal/pkg/controller"
+ "voltha-go-controller/database"
+ "voltha-go-controller/internal/pkg/of"
+ "github.com/opencord/voltha-lib-go/v7/pkg/log"
+)
+
+// VoltShaperConfig is shaper profile configuration structure
+type VoltShaperConfig struct {
+ Name string
+ BurstSize uint32
+}
+
+// VoltBwConfig is bandwidth profile configuration structure
+type VoltBwConfig struct {
+ Name string
+ Fir uint32
+ Air uint32
+ Eir uint32
+}
+
+// VoltBandwidthProf is bandwidth profile stored at VGC
+type VoltBandwidthProf struct {
+ VoltBwConfig
+}
+
+// VoltShaperProf is shaper profile stored at VGC
+type VoltShaperProf struct {
+ VoltShaperConfig
+}
+
+// VoltMeterProf is meter profile stored at VGC
+type VoltMeterProf struct {
+ VoltMeter
+}
+
+// MeterMgr structure
+type MeterMgr struct {
+ Meters sync.Map
+ MetersByID sync.Map
+ LastMeterID uint32
+}
+
+// Init to initialize MeterMgr
+func (m *MeterMgr) Init() {
+ m.LastMeterID = 0
+}
+
+// VoltMeter : A VOLT meter is a combination of BW and shaper profiles
+// The ID is generated by the VOLT application
+type VoltMeter struct {
+ Name string
+ ID uint32
+ Fir uint32
+ Air uint32
+ Eir uint32
+ BurstSize uint32
+ AssociatedServices uint32
+ Version string
+ Cir uint32
+ Cbs uint32
+ Pir uint32
+ Pbs uint32
+ Gir uint32
+ Ebs uint32
+}
+
+// WriteToDb to write a meter profile to DB
+func (vm *VoltMeter) WriteToDb() error {
+ vm.Version = database.PresentVersionMap[database.MeterPath]
+ b, err := json.Marshal(vm)
+ if err != nil {
+ return err
+ }
+ if err1 := db.PutMeter(vm.Name, string(b)); err1 != nil {
+ return err1
+ }
+ return nil
+}
+
+// DelFromDb to delete a meter profile from DB
+func (vm *VoltMeter) DelFromDb() {
+ _ = db.DelMeter(vm.Name)
+}
+
+// GetMeterByName to get meter by name
+func (m *MeterMgr) GetMeterByName(name string) (*VoltMeter, bool) {
+ meter, ok := m.Meters.Load(name)
+ logger.Infow(ctx, "Meter Obtained Name", log.Fields{"Meter": meter})
+ if ok {
+ return meter.(*VoltMeter), ok
+ }
+ return nil, ok
+}
+
+// GetMeterByID to get meter by ID
+func (m *MeterMgr) GetMeterByID(id uint32) (*VoltMeter, bool) {
+ meter, ok := m.MetersByID.Load(id)
+ logger.Infow(ctx, "Meter Obtained ID", log.Fields{"Meter": meter})
+ if ok {
+ return meter.(*VoltMeter), ok
+ }
+ return nil, ok
+}
+
+// AddMeter to add meter
+func (m *MeterMgr) AddMeter(meter *VoltMeter) {
+ m.Meters.Store(meter.Name, meter)
+ m.MetersByID.Store(meter.ID, meter)
+ logger.Infow(ctx, "Meter Added/Updated", log.Fields{"Meter": meter, "Name": meter.Name, "Id": meter.ID})
+}
+
+// DelMeter to delete meter
+func (m *MeterMgr) DelMeter(meter *VoltMeter) {
+ m.Meters.Delete(meter.Name)
+ m.MetersByID.Delete(meter.ID)
+ logger.Infow(ctx, "Meter Deleted", log.Fields{"Meter": meter, "Name": meter.Name, "Id": meter.ID})
+}
+
+// AddToDevice to add meter to the device
+func (vm *VoltMeter) AddToDevice(port string, device string, aggVM *VoltMeter) {
+ logger.Debugw(ctx, "Adding Meter To Device", log.Fields{"Id": vm.ID, "Device": device, "Port": port})
+ meter := of.NewMeter(vm.ID)
+ // meter.AddBand(vm.Air, vm.BurstSize)
+ // meter.AddBand(vm.Eir, vm.BurstSize)
+ // if aggVM != nil {
+ // meter.AddBand(aggVM.Air, aggVM.BurstSize)
+ // meter.AddBand(aggVM.Eir, aggVM.BurstSize)
+ // }
+
+ //Community VGC Impl
+
+ //Set Cir
+ if vm.Cir != 0 {
+ meter.AddBand(vm.Cir, vm.Cbs)
+ }
+
+ //Set Air to 0 if both air & gir are set
+ if vm.Air != 0 && vm.Gir != 0 {
+ vm.Air = 0
+ }
+
+ //Set Pir & Pbs
+ var pir uint32
+ var pbs uint32
+ if vm.Pir != 0 {
+ pir = vm.Pir
+ } else {
+ pir = vm.Eir + vm.Cir + vm.Gir + vm.Air
+ }
+
+ if vm.Pbs != 0 {
+ pbs = vm.Pbs
+ } else {
+ pbs = vm.Ebs + vm.Cbs
+ }
+ meter.AddBand(pir, pbs)
+
+ //Set Gir
+ if vm.Gir != 0 {
+ meter.AddBand(vm.Gir, 0)
+ }
+
+ logger.Infow(ctx, "Meter Config", log.Fields{"Cir": vm.Cir, "Air": vm.Air, "Pir": vm.Pir, "Gir": vm.Gir, "Eir": vm.Eir})
+ logger.Infow(ctx, "Meter Burst Config", log.Fields{"Cbs": vm.Cbs, "Pbs": vm.Pbs})
+ logger.Infow(ctx, "Meter Burst Oper", log.Fields{"Pir": pir, "Pbs": pbs})
+ //Set Air
+ // Air is used in place of Gir only if Gir is
+ // not present and Air is not 0
+ if vm.Air != 0 {
+ meter.AddBand(vm.Air, 0)
+ }
+
+ logger.Debug(ctx, "Total Bands are", log.Fields{"meter": *meter})
+ if err := cntlr.GetController().ModMeter(port, device, of.MeterCommandAdd, meter); err != nil {
+ logger.Warnw(ctx, "Add meter to device Failed", log.Fields{"Id": vm.ID, "meter": *meter, "Error": err})
+ }
+}
+
+// AddMeterToDevice to add meter to the device
+func (m *MeterMgr) AddMeterToDevice(port string, device string, meterID uint32, aggMeterID uint32) {
+ var aggVM *VoltMeter
+ vm, err := m.GetMeterByProfID(meterID)
+ if err == nil {
+ if 0 != aggMeterID { //Assuming valid meter id will never be 0
+ if aggVM, err = m.GetMeterByProfID(aggMeterID); err != nil {
+ logger.Warnw(ctx, "Aggregated Meter not found", log.Fields{"Id": aggMeterID})
+ }
+ }
+ vm.AddToDevice(port, device, aggVM)
+ } else {
+ logger.Warnw(ctx, "Meter not found", log.Fields{"Id": meterID})
+ }
+}
+
+// RestoreMetersFromDb to read from the DB and restore all the services
+func (m *MeterMgr) RestoreMetersFromDb() {
+ // VNETS must be learnt first
+ logger.Infow(ctx, "LastMeterID on restart", log.Fields{"LastMeterID": m.LastMeterID})
+ ms, _ := db.GetMeters()
+ for _, mt := range ms {
+ b, ok := mt.Value.([]byte)
+ if !ok {
+ logger.Warn(ctx, "The value type is not []byte")
+ continue
+ }
+ var meter VoltMeter
+ err := json.Unmarshal(b, &meter)
+ if err != nil {
+ logger.Warn(ctx, "Unmarshal of meter profile failed")
+ continue
+ }
+ logger.Infow(ctx, "Retrieved Meter", log.Fields{"Meter": meter.Name})
+ m.AddMeter(&meter)
+ if meter.ID > m.LastMeterID {
+ m.LastMeterID = meter.ID
+ }
+ }
+ logger.Infow(ctx, "LastMeterID on reading DB", log.Fields{"LastMeterID": m.LastMeterID})
+}
+
+// AddMeterProf to add the meter profile name as key
+func (va *VoltApplication) AddMeterProf(cfg VoltMeter) {
+
+ mm := &va.MeterMgr
+ if _, ok := mm.GetMeterByName(cfg.Name); ok {
+ logger.Warnw(ctx, "Meter profile exists", log.Fields{"Name": cfg.Name})
+ return
+ }
+
+ mm.LastMeterID++
+ //FIX-ME: Hardcoded the meter-id temp till meter delete is introduced
+ //Restriction: Only one meter profile should be used across all services
+ // id := uint32(1) //mm.LastMeterId
+ id := mm.LastMeterID
+ cfg.ID = id
+ mm.AddMeter(&cfg)
+ if err := cfg.WriteToDb(); err != nil {
+ logger.Warnw(ctx, "MeterProf Write to DB Failed", log.Fields{"MeterConfig": cfg, "Error": err})
+ }
+}
+
+// UpdateMeterProf to update the meter profile
+func (va *VoltApplication) UpdateMeterProf(cfg VoltMeter) {
+ mm := &va.MeterMgr
+ if _, ok := mm.GetMeterByName(cfg.Name); !ok {
+ logger.Warnw(ctx, "Meter profile does not exist", log.Fields{"Name": cfg.Name})
+ return
+ }
+ mm.AddMeter(&cfg)
+ if err := cfg.WriteToDb(); err != nil {
+ logger.Warnw(ctx, "MeterProf Write to DB Failed", log.Fields{"MeterConfig": cfg, "Error": err})
+ }
+}
+
+// GetMeterByProfID to get a meter based on the identities of bandwidth profile and shaper
+// profile names.
+func (m *MeterMgr) GetMeterByProfID(id uint32) (*VoltMeter, error) {
+ if mtr, ok := m.GetMeterByID(id); ok {
+ return mtr, nil
+ }
+ return nil, errors.New("Meter Missing")
+}
+
+// GetMeter to get a meter based on the identities of bandwidth profile and shaper
+// profile names.
+func (m *MeterMgr) GetMeter(meterID string) (*VoltMeter, error) {
+ if mt, ok := m.GetMeterByName(meterID); ok {
+ return mt, nil
+ }
+ return nil, errors.New("Meter Missing")
+}
+
+// DeleteFromDevice to delete meter from the device
+func (vm *VoltMeter) DeleteFromDevice(port string, device string) {
+
+ meter := of.NewMeter(vm.ID)
+
+ logger.Debugw(ctx, "Delete meter from device", log.Fields{"Id": vm.ID, "meter": *meter})
+ if err := cntlr.GetController().ModMeter(port, device, of.MeterCommandDel, meter); err != nil {
+ logger.Warnw(ctx, "Delete meter from device Failed", log.Fields{"Id": vm.ID, "meter": *meter, "Error": err})
+ }
+}
+
+// DelMeterProf to delete meter profile
+func (va *VoltApplication) DelMeterProf(name string) error {
+ mm := &va.MeterMgr
+ if _, ok := mm.GetMeterByName(name); !ok {
+ logger.Warnw(ctx, "Meter profile does not exist", log.Fields{"Name": name})
+ return errors.New("Meter profile doesn't exist")
+ }
+ cfg, _ := mm.GetMeterByName(name)
+ if cfg.AssociatedServices != 0 {
+ logger.Warnw(ctx, "Mismatch in submgr and vgc oeter profile service reference",
+ log.Fields{"MeterProfile": name, "serviceCount": cfg.AssociatedServices})
+ return errors.New("Service reference is not 0")
+ }
+ //TODO : delete from all devices
+ delmeterFromDevice := func(key interface{}, value interface{}) bool {
+ device := key.(string)
+ port, _ := GetApplication().GetNniPort(device)
+ cfg.DeleteFromDevice(port, device)
+ return true
+ }
+ va.DevicesDisc.Range(delmeterFromDevice)
+ cfg.DelFromDb()
+ //Delete meter from device will be invoked by caller separately
+ mm.DelMeter(cfg)
+ return nil
+}