blob: c211f1e99fa7b2b972e0816d18661f0f8344869e [file] [log] [blame]
Kent Hagerman3136fbd2020-05-14 10:30:45 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package device
18
19import (
20 "context"
21 "fmt"
22 "strconv"
23
24 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
25 "github.com/opencord/voltha-lib-go/v3/pkg/log"
26 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
27 "google.golang.org/grpc/codes"
28 "google.golang.org/grpc/status"
29)
30
31// updateMeterTable updates the meter table of that logical device
32func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
33 logger.Debug("updateMeterTable")
34 if meterMod == nil {
35 return nil
36 }
37 switch meterMod.GetCommand() {
38 case ofp.OfpMeterModCommand_OFPMC_ADD:
39 return agent.meterAdd(ctx, meterMod)
40 case ofp.OfpMeterModCommand_OFPMC_DELETE:
41 return agent.meterDelete(ctx, meterMod)
42 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
43 return agent.meterModify(ctx, meterMod)
44 }
45 return status.Errorf(codes.Internal,
46 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
47}
48
49func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
50 logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
51 if meterMod == nil {
52 return nil
53 }
54
55 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
56 agent.meterLock.Lock()
57 //check if the meter already exists or not
58 _, ok := agent.meters[meterMod.MeterId]
59 if ok {
60 logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
61 agent.meterLock.Unlock()
62 return nil
63 }
64
65 mChunk := MeterChunk{
66 meter: meterEntry,
67 }
68 //Add to map and acquire the per meter lock
69 agent.meters[meterMod.MeterId] = &mChunk
70 mChunk.lock.Lock()
71 defer mChunk.lock.Unlock()
72 agent.meterLock.Unlock()
73 meterID := strconv.Itoa(int(meterMod.MeterId))
74 if err := agent.clusterDataProxy.AddWithID(ctx, "meters/"+agent.logicalDeviceID, meterID, meterEntry); err != nil {
75 logger.Errorw("failed-adding-meter", log.Fields{"deviceID": agent.logicalDeviceID, "meterID": meterID, "err": err})
76 //Revert the map
77 agent.meterLock.Lock()
78 delete(agent.meters, meterMod.MeterId)
79 agent.meterLock.Unlock()
80 return err
81 }
82
83 logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry})
84 return nil
85}
86
87func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
88 logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
89 if meterMod == nil {
90 return nil
91 }
92 agent.meterLock.RLock()
93 meterChunk, ok := agent.meters[meterMod.MeterId]
94 agent.meterLock.RUnlock()
95 if ok {
96 //Dont let anyone to do any changes to this meter until this is done.
97 //And wait if someone else is already making modifications. Do this with per meter lock.
98 meterChunk.lock.Lock()
99 defer meterChunk.lock.Unlock()
100 if err := agent.deleteFlowsOfMeter(ctx, meterMod.MeterId); err != nil {
101 return err
102 }
103 //remove from the store and cache
104 if err := agent.removeLogicalDeviceMeter(ctx, meterMod.MeterId); err != nil {
105 return err
106 }
107 logger.Debugw("meterDelete-success", log.Fields{"meterID": meterMod.MeterId})
108 } else {
109 logger.Warnw("meter-not-found", log.Fields{"meterID": meterMod.MeterId})
110 }
111 return nil
112}
113
114func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
115 logger.Debug("meterModify")
116 if meterMod == nil {
117 return nil
118 }
119 newMeter := fu.MeterEntryFromMeterMod(meterMod)
120 agent.meterLock.RLock()
121 meterChunk, ok := agent.meters[newMeter.Config.MeterId]
122 agent.meterLock.RUnlock()
123 if !ok {
124 return fmt.Errorf("no-meter-to-modify:%d", newMeter.Config.MeterId)
125 }
126 //Release the map lock and syncronize per meter
127 meterChunk.lock.Lock()
128 defer meterChunk.lock.Unlock()
129 oldMeter := meterChunk.meter
130 newMeter.Stats.FlowCount = oldMeter.Stats.FlowCount
131
132 if err := agent.updateLogicalDeviceMeter(ctx, newMeter, meterChunk); err != nil {
133 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "meterID": newMeter.Config.MeterId})
134 return err
135 }
136 logger.Debugw("replaced-with-new-meter", log.Fields{"oldMeter": oldMeter, "newMeter": newMeter})
137 return nil
138}