blob: c211f1e99fa7b2b972e0816d18661f0f8344869e [file] [log] [blame]
/*
* Copyright 2018-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 device
import (
"context"
"fmt"
"strconv"
fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
"github.com/opencord/voltha-lib-go/v3/pkg/log"
ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// updateMeterTable updates the meter table of that logical device
func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
logger.Debug("updateMeterTable")
if meterMod == nil {
return nil
}
switch meterMod.GetCommand() {
case ofp.OfpMeterModCommand_OFPMC_ADD:
return agent.meterAdd(ctx, meterMod)
case ofp.OfpMeterModCommand_OFPMC_DELETE:
return agent.meterDelete(ctx, meterMod)
case ofp.OfpMeterModCommand_OFPMC_MODIFY:
return agent.meterModify(ctx, meterMod)
}
return status.Errorf(codes.Internal,
"unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
}
func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
if meterMod == nil {
return nil
}
meterEntry := fu.MeterEntryFromMeterMod(meterMod)
agent.meterLock.Lock()
//check if the meter already exists or not
_, ok := agent.meters[meterMod.MeterId]
if ok {
logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
agent.meterLock.Unlock()
return nil
}
mChunk := MeterChunk{
meter: meterEntry,
}
//Add to map and acquire the per meter lock
agent.meters[meterMod.MeterId] = &mChunk
mChunk.lock.Lock()
defer mChunk.lock.Unlock()
agent.meterLock.Unlock()
meterID := strconv.Itoa(int(meterMod.MeterId))
if err := agent.clusterDataProxy.AddWithID(ctx, "meters/"+agent.logicalDeviceID, meterID, meterEntry); err != nil {
logger.Errorw("failed-adding-meter", log.Fields{"deviceID": agent.logicalDeviceID, "meterID": meterID, "err": err})
//Revert the map
agent.meterLock.Lock()
delete(agent.meters, meterMod.MeterId)
agent.meterLock.Unlock()
return err
}
logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry})
return nil
}
func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
if meterMod == nil {
return nil
}
agent.meterLock.RLock()
meterChunk, ok := agent.meters[meterMod.MeterId]
agent.meterLock.RUnlock()
if ok {
//Dont let anyone to do any changes to this meter until this is done.
//And wait if someone else is already making modifications. Do this with per meter lock.
meterChunk.lock.Lock()
defer meterChunk.lock.Unlock()
if err := agent.deleteFlowsOfMeter(ctx, meterMod.MeterId); err != nil {
return err
}
//remove from the store and cache
if err := agent.removeLogicalDeviceMeter(ctx, meterMod.MeterId); err != nil {
return err
}
logger.Debugw("meterDelete-success", log.Fields{"meterID": meterMod.MeterId})
} else {
logger.Warnw("meter-not-found", log.Fields{"meterID": meterMod.MeterId})
}
return nil
}
func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
logger.Debug("meterModify")
if meterMod == nil {
return nil
}
newMeter := fu.MeterEntryFromMeterMod(meterMod)
agent.meterLock.RLock()
meterChunk, ok := agent.meters[newMeter.Config.MeterId]
agent.meterLock.RUnlock()
if !ok {
return fmt.Errorf("no-meter-to-modify:%d", newMeter.Config.MeterId)
}
//Release the map lock and syncronize per meter
meterChunk.lock.Lock()
defer meterChunk.lock.Unlock()
oldMeter := meterChunk.meter
newMeter.Stats.FlowCount = oldMeter.Stats.FlowCount
if err := agent.updateLogicalDeviceMeter(ctx, newMeter, meterChunk); err != nil {
logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "meterID": newMeter.Config.MeterId})
return err
}
logger.Debugw("replaced-with-new-meter", log.Fields{"oldMeter": oldMeter, "newMeter": newMeter})
return nil
}