blob: f032a65647b16fd38b03bc3d97afe035b645f15a [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -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 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
khenaidoo19d7b632018-10-30 10:49:50 -040022 "errors"
23 "fmt"
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070024 "strconv"
David Bainbridged1afd662020-03-26 18:27:41 -070025 "sync"
26 "time"
27
khenaidoob9203542018-09-17 22:56:37 -040028 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050029 "github.com/opencord/voltha-go/db/model"
npujar1d86a522019-11-14 17:11:16 +053030 fd "github.com/opencord/voltha-go/rw_core/flowdecomposition"
khenaidoo442e7c72020-03-10 16:13:48 -040031 "github.com/opencord/voltha-go/rw_core/route"
Scott Bakerb671a862019-10-24 10:53:40 -070032 coreutils "github.com/opencord/voltha-go/rw_core/utils"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080033 fu "github.com/opencord/voltha-lib-go/v3/pkg/flows"
34 "github.com/opencord/voltha-lib-go/v3/pkg/log"
35 ic "github.com/opencord/voltha-protos/v3/go/inter_container"
36 ofp "github.com/opencord/voltha-protos/v3/go/openflow_13"
37 "github.com/opencord/voltha-protos/v3/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040038 "google.golang.org/grpc/codes"
39 "google.golang.org/grpc/status"
khenaidoo442e7c72020-03-10 16:13:48 -040040)
41
Kent Hagerman2b216042020-04-03 18:28:56 -040042// LogicalAgent represent attributes of logical device agent
43type LogicalAgent struct {
npujar1d86a522019-11-14 17:11:16 +053044 logicalDeviceID string
David Bainbridged1afd662020-03-26 18:27:41 -070045 serialNumber string
npujar1d86a522019-11-14 17:11:16 +053046 rootDeviceID string
Kent Hagerman2b216042020-04-03 18:28:56 -040047 deviceMgr *Manager
48 ldeviceMgr *LogicalManager
khenaidoo3306c992019-05-24 16:57:35 -040049 clusterDataProxy *model.Proxy
Kent Hagerman4f355f52020-03-30 16:01:33 -040050 stopped bool
khenaidoo820197c2020-02-13 16:35:33 -050051 deviceRoutes *route.DeviceRoutes
khenaidoo820197c2020-02-13 16:35:33 -050052 lockDeviceRoutes sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040053 logicalPortsNo map[uint32]bool //value is true for NNI port
54 lockLogicalPortsNo sync.RWMutex
55 flowDecomposer *fd.FlowDecomposer
khenaidoo442e7c72020-03-10 16:13:48 -040056 defaultTimeout time.Duration
khenaidoo6e55d9e2019-12-12 18:26:26 -050057 logicalDevice *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -040058 requestQueue *coreutils.RequestQueue
59 startOnce sync.Once
60 stopOnce sync.Once
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070061
62 meters map[uint32]*MeterChunk
63 meterLock sync.RWMutex
64 flows map[uint64]*FlowChunk
65 flowLock sync.RWMutex
66 groups map[uint32]*GroupChunk
67 groupLock sync.RWMutex
68}
69
70//MeterChunk keeps a meter entry and its lock. The lock in the struct is used to syncronize the
71//modifications for the related meter.
72type MeterChunk struct {
73 meter *ofp.OfpMeterEntry
74 lock sync.Mutex
75}
76
77//FlowChunk keeps a flow and the lock for this flow. The lock in the struct is used to syncronize the
78//modifications for the related flow.
79type FlowChunk struct {
80 flow *ofp.OfpFlowStats
81 lock sync.Mutex
82}
83
84//GroupChunk keeps a group entry and its lock. The lock in the struct is used to syncronize the
85//modifications for the related group.
86type GroupChunk struct {
87 group *ofp.OfpGroupEntry
88 lock sync.Mutex
khenaidoob9203542018-09-17 22:56:37 -040089}
90
Kent Hagerman2b216042020-04-03 18:28:56 -040091func newLogicalDeviceAgent(id string, sn string, deviceID string, ldeviceMgr *LogicalManager,
92 deviceMgr *Manager, cdProxy *model.Proxy, timeout time.Duration) *LogicalAgent {
93 var agent LogicalAgent
npujar1d86a522019-11-14 17:11:16 +053094 agent.logicalDeviceID = id
David Bainbridged1afd662020-03-26 18:27:41 -070095 agent.serialNumber = sn
npujar1d86a522019-11-14 17:11:16 +053096 agent.rootDeviceID = deviceID
khenaidoob9203542018-09-17 22:56:37 -040097 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040098 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040099 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -0400100 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo2c6a0992019-04-29 13:46:56 -0400101 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -0400102 agent.defaultTimeout = timeout
Kent Hagerman730cbdf2020-03-31 12:22:08 -0400103 agent.requestQueue = coreutils.NewRequestQueue()
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700104 agent.meters = make(map[uint32]*MeterChunk)
105 agent.flows = make(map[uint64]*FlowChunk)
106 agent.groups = make(map[uint32]*GroupChunk)
khenaidoob9203542018-09-17 22:56:37 -0400107 return &agent
108}
109
khenaidoo4d4802d2018-10-04 21:59:49 -0400110// start creates the logical device and add it to the data model
Kent Hagerman2b216042020-04-03 18:28:56 -0400111func (agent *LogicalAgent) start(ctx context.Context, loadFromDB bool) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400112 needToStart := false
113 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
114 return nil
115 }
116
Girish Kumarf56a4682020-03-20 20:07:46 +0000117 logger.Infow("starting-logical_device-agent", log.Fields{"logical-device-id": agent.logicalDeviceID, "load-from-db": loadFromDB})
khenaidoo442e7c72020-03-10 16:13:48 -0400118
119 var startSucceeded bool
120 defer func() {
121 if !startSucceeded {
122 if err := agent.stop(ctx); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000123 logger.Errorw("failed-to-cleanup-after-unsuccessful-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400124 }
125 }
126 }()
127
khenaidoo297cd252019-02-07 22:10:23 -0500128 var ld *voltha.LogicalDevice
khenaidoo442e7c72020-03-10 16:13:48 -0400129 if !loadFromDB {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400130 //Build the logical device based on information retrieved from the device adapter
131 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -0500132 var err error
npujar1d86a522019-11-14 17:11:16 +0530133 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
khenaidoo7e3d8f12019-08-02 16:06:30 -0400134 return err
135 }
npujar1d86a522019-11-14 17:11:16 +0530136 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500137
138 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
139 var datapathID uint64
Kent Hagerman2b216042020-04-03 18:28:56 -0400140 if datapathID, err = coreutils.CreateDataPathID(agent.serialNumber); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500141 return err
142 }
143 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400144 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
Girish Kumarf56a4682020-03-20 20:07:46 +0000145 logger.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo7e3d8f12019-08-02 16:06:30 -0400146 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500147 ld.Flows = &ofp.Flows{Items: nil}
148 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoo49085352020-01-13 19:15:43 -0500149 ld.Ports = []*voltha.LogicalPort{}
khenaidoo297cd252019-02-07 22:10:23 -0500150
khenaidoo297cd252019-02-07 22:10:23 -0500151 // Save the logical device
Kent Hagerman4f355f52020-03-30 16:01:33 -0400152 if err := agent.clusterDataProxy.AddWithID(ctx, "logical_devices", ld.Id, ld); err != nil {
153 logger.Errorw("failed-to-add-logical-device", log.Fields{"logical-device-id": agent.logicalDeviceID})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530154 return err
155 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400156 logger.Debugw("logicaldevice-created", log.Fields{"logical-device-id": agent.logicalDeviceID, "root-id": ld.RootDeviceId})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500157
158 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
khenaidoofc1314d2019-03-14 09:34:21 -0400159
khenaidoo442e7c72020-03-10 16:13:48 -0400160 // Setup the logicalports - internal processing, no need to propagate the client context
npujar1d86a522019-11-14 17:11:16 +0530161 go func() {
khenaidoo442e7c72020-03-10 16:13:48 -0400162 err := agent.setupLogicalPorts(context.Background())
npujar1d86a522019-11-14 17:11:16 +0530163 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000164 logger.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530165 }
166 }()
khenaidoo297cd252019-02-07 22:10:23 -0500167 } else {
168 // load from dB - the logical may not exist at this time. On error, just return and the calling function
169 // will destroy this agent.
Kent Hagerman4f355f52020-03-30 16:01:33 -0400170 ld := &voltha.LogicalDevice{}
171 have, err := agent.clusterDataProxy.Get(ctx, "logical_devices/"+agent.logicalDeviceID, ld)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530172 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400173 return err
Kent Hagerman4f355f52020-03-30 16:01:33 -0400174 } else if !have {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500175 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500176 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400177
khenaidoo8c3303d2019-02-13 14:59:39 -0500178 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530179 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400180
khenaidoo6e55d9e2019-12-12 18:26:26 -0500181 // Update the last data
182 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
183
khenaidoo3d3b8c22019-05-22 18:10:39 -0400184 // Setup the local list of logical ports
185 agent.addLogicalPortsToMap(ld.Ports)
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700186 // load the flows, meters and groups from KV to cache
187 agent.loadFlows(ctx)
188 agent.loadMeters(ctx)
189 agent.loadGroups(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400190 }
khenaidoofc1314d2019-03-14 09:34:21 -0400191
khenaidoo820197c2020-02-13 16:35:33 -0500192 // Setup the device routes. Building routes may fail if the pre-conditions are not satisfied (e.g. no PON ports present)
khenaidoo442e7c72020-03-10 16:13:48 -0400193 if loadFromDB {
khenaidoo820197c2020-02-13 16:35:33 -0500194 go func() {
195 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000196 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -0500197 }
198 }()
khenaidoo4c9e5592019-09-09 16:20:41 -0400199 }
khenaidoo442e7c72020-03-10 16:13:48 -0400200 startSucceeded = true
201
khenaidoob9203542018-09-17 22:56:37 -0400202 return nil
203}
204
khenaidoo442e7c72020-03-10 16:13:48 -0400205// stop stops the logical device agent. This removes the logical device from the data model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400206func (agent *LogicalAgent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400207 var returnErr error
208 agent.stopOnce.Do(func() {
Girish Kumarf56a4682020-03-20 20:07:46 +0000209 logger.Info("stopping-logical_device-agent")
khenaidoo8c3303d2019-02-13 14:59:39 -0500210
khenaidoo442e7c72020-03-10 16:13:48 -0400211 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
212 // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once.
213 returnErr = err
214 return
215 }
216 defer agent.requestQueue.RequestComplete()
217
218 //Remove the logical device from the model
Kent Hagerman4f355f52020-03-30 16:01:33 -0400219 if err := agent.clusterDataProxy.Remove(ctx, "logical_devices/"+agent.logicalDeviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400220 returnErr = err
khenaidoo442e7c72020-03-10 16:13:48 -0400221 } else {
Girish Kumarf56a4682020-03-20 20:07:46 +0000222 logger.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400223 }
224
Kent Hagerman4f355f52020-03-30 16:01:33 -0400225 agent.stopped = true
khenaidoo442e7c72020-03-10 16:13:48 -0400226
Girish Kumarf56a4682020-03-20 20:07:46 +0000227 logger.Info("logical_device-agent-stopped")
khenaidoo442e7c72020-03-10 16:13:48 -0400228 })
229 return returnErr
khenaidoo4d4802d2018-10-04 21:59:49 -0400230}
231
khenaidoo6e55d9e2019-12-12 18:26:26 -0500232// GetLogicalDevice returns the latest logical device data
Kent Hagerman2b216042020-04-03 18:28:56 -0400233func (agent *LogicalAgent) GetLogicalDevice(ctx context.Context) (*voltha.LogicalDevice, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400234 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
235 return nil, err
236 }
237 defer agent.requestQueue.RequestComplete()
238 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice), nil
khenaidoo92e62c52018-10-03 14:02:54 -0400239}
240
npujar1d86a522019-11-14 17:11:16 +0530241// ListLogicalDeviceFlows returns logical device flows
Kent Hagerman2b216042020-04-03 18:28:56 -0400242func (agent *LogicalAgent) ListLogicalDeviceFlows(ctx context.Context) (*ofp.Flows, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000243 logger.Debug("ListLogicalDeviceFlows")
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700244 var flowStats []*ofp.OfpFlowStats
245 agent.flowLock.RLock()
246 defer agent.flowLock.RUnlock()
247 for _, flowChunk := range agent.flows {
248 flowStats = append(flowStats, (proto.Clone(flowChunk.flow)).(*ofp.OfpFlowStats))
khenaidoodd237172019-05-27 16:37:17 -0400249 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700250 return &ofp.Flows{Items: flowStats}, nil
khenaidoodd237172019-05-27 16:37:17 -0400251}
252
npujar1d86a522019-11-14 17:11:16 +0530253// ListLogicalDeviceMeters returns logical device meters
Kent Hagerman2b216042020-04-03 18:28:56 -0400254func (agent *LogicalAgent) ListLogicalDeviceMeters(ctx context.Context) (*ofp.Meters, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000255 logger.Debug("ListLogicalDeviceMeters")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500256
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700257 var meterEntries []*ofp.OfpMeterEntry
258 agent.meterLock.RLock()
259 defer agent.meterLock.RUnlock()
260 for _, meterChunk := range agent.meters {
261 meterEntries = append(meterEntries, (proto.Clone(meterChunk.meter)).(*ofp.OfpMeterEntry))
Manikkaraj kb1a10922019-07-29 12:10:34 -0400262 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700263 return &ofp.Meters{Items: meterEntries}, nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400264}
265
npujar1d86a522019-11-14 17:11:16 +0530266// ListLogicalDeviceFlowGroups returns logical device flow groups
Kent Hagerman2b216042020-04-03 18:28:56 -0400267func (agent *LogicalAgent) ListLogicalDeviceFlowGroups(ctx context.Context) (*ofp.FlowGroups, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000268 logger.Debug("ListLogicalDeviceFlowGroups")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500269
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700270 var groupEntries []*ofp.OfpGroupEntry
271 agent.groupLock.RLock()
272 defer agent.groupLock.RUnlock()
273 for _, value := range agent.groups {
274 groupEntries = append(groupEntries, (proto.Clone(value.group)).(*ofp.OfpGroupEntry))
khenaidoodd237172019-05-27 16:37:17 -0400275 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700276 return &ofp.FlowGroups{Items: groupEntries}, nil
khenaidoodd237172019-05-27 16:37:17 -0400277}
278
npujar1d86a522019-11-14 17:11:16 +0530279// ListLogicalDevicePorts returns logical device ports
Kent Hagerman2b216042020-04-03 18:28:56 -0400280func (agent *LogicalAgent) ListLogicalDevicePorts(ctx context.Context) (*voltha.LogicalPorts, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +0000281 logger.Debug("ListLogicalDevicePorts")
khenaidoo442e7c72020-03-10 16:13:48 -0400282 logicalDevice, err := agent.GetLogicalDevice(ctx)
283 if err != nil {
284 return nil, err
285 }
286 if logicalDevice == nil {
287 return &voltha.LogicalPorts{}, nil
288 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500289 lPorts := make([]*voltha.LogicalPort, 0)
290 lPorts = append(lPorts, logicalDevice.Ports...)
khenaidoo442e7c72020-03-10 16:13:48 -0400291 return &voltha.LogicalPorts{Items: lPorts}, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400292}
293
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700294//updateLogicalDeviceFlow updates flow in the store and cache
295//It is assumed that the chunk lock has been acquired before this function is called
296func (agent *LogicalAgent) updateLogicalDeviceFlow(ctx context.Context, flow *ofp.OfpFlowStats, flowChunk *FlowChunk) error {
297 path := fmt.Sprintf("logical_flows/%s/%d", agent.logicalDeviceID, flow.Id)
298 if err := agent.clusterDataProxy.Update(ctx, path, flow); err != nil {
299 return status.Errorf(codes.Internal, "failed-update-flow:%s:%d %s", agent.logicalDeviceID, flow.Id, err)
khenaidoo43c82122018-11-22 18:38:28 -0500300 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700301 flowChunk.flow = flow
khenaidoo43c82122018-11-22 18:38:28 -0500302 return nil
303}
304
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700305//removeLogicalDeviceFlow deletes the flow from store and cache.
306//It is assumed that the chunk lock has been acquired before this function is called
307func (agent *LogicalAgent) removeLogicalDeviceFlow(ctx context.Context, flowID uint64) error {
308 path := fmt.Sprintf("logical_flows/%s/%d", agent.logicalDeviceID, flowID)
309 if err := agent.clusterDataProxy.Remove(ctx, path); err != nil {
310 return fmt.Errorf("couldnt-delete-flow-from-the-store-%s", path)
311 }
312 agent.flowLock.Lock()
313 defer agent.flowLock.Unlock()
314 delete(agent.flows, flowID)
315 return nil
316}
khenaidoo4c9e5592019-09-09 16:20:41 -0400317
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700318//updateLogicalDeviceMeter updates meter info in store and cache
319//It is assumed that the chunk lock has been acquired before this function is called
320func (agent *LogicalAgent) updateLogicalDeviceMeter(ctx context.Context, meter *ofp.OfpMeterEntry, meterChunk *MeterChunk) error {
321 path := fmt.Sprintf("meters/%s/%d", agent.logicalDeviceID, meter.Config.MeterId)
322 if err := agent.clusterDataProxy.Update(ctx, path, meter); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000323 logger.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400324 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400325 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700326 meterChunk.meter = meter
Manikkaraj kb1a10922019-07-29 12:10:34 -0400327 return nil
328}
329
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700330//removeLogicalDeviceMeter deletes the meter from store and cache
331//It is assumed that the chunk lock has been acquired before this function is called
332func (agent *LogicalAgent) removeLogicalDeviceMeter(ctx context.Context, meterID uint32) error {
333 path := fmt.Sprintf("meters/%s/%d", agent.logicalDeviceID, meterID)
334 if err := agent.clusterDataProxy.Remove(ctx, path); err != nil {
335 return fmt.Errorf("couldnt-delete-meter-from-store-%s", path)
336 }
337 agent.meterLock.Lock()
338 defer agent.meterLock.Unlock()
339 delete(agent.meters, meterID)
340 return nil
341}
khenaidoo4c9e5592019-09-09 16:20:41 -0400342
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700343//updateLogicalDeviceFlowGroup updates the flow groups in store and cache
344//It is assumed that the chunk lock has been acquired before this function is called
345func (agent *LogicalAgent) updateLogicalDeviceFlowGroup(ctx context.Context, groupEntry *ofp.OfpGroupEntry, groupChunk *GroupChunk) error {
346 path := fmt.Sprintf("groups/%s/%d", agent.logicalDeviceID, groupEntry.Desc.GroupId)
347 if err := agent.clusterDataProxy.Update(ctx, path, groupEntry); err != nil {
348 logger.Errorw("error-updating-logical-device-with-group", log.Fields{"error": err})
khenaidoo4c9e5592019-09-09 16:20:41 -0400349 return err
khenaidoo43c82122018-11-22 18:38:28 -0500350 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700351 groupChunk.group = groupEntry
352 return nil
353}
354
355//removeLogicalDeviceFlowGroup removes the flow groups in store and cache
356//It is assumed that the chunk lock has been acquired before this function is called
357func (agent *LogicalAgent) removeLogicalDeviceFlowGroup(ctx context.Context, groupID uint32) error {
358 path := fmt.Sprintf("groups/%s/%d", agent.logicalDeviceID, groupID)
359 if err := agent.clusterDataProxy.Remove(ctx, path); err != nil {
360 return fmt.Errorf("couldnt-delete-group-from-store-%s", path)
361 }
362 agent.groupLock.Lock()
363 defer agent.groupLock.Unlock()
364 delete(agent.groups, groupID)
khenaidoo43c82122018-11-22 18:38:28 -0500365 return nil
366}
367
khenaidoo6e55d9e2019-12-12 18:26:26 -0500368// getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock.
Kent Hagerman2b216042020-04-03 18:28:56 -0400369func (agent *LogicalAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice {
Girish Kumarf56a4682020-03-20 20:07:46 +0000370 logger.Debug("getLogicalDeviceWithoutLock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500371 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400372}
373
Kent Hagerman2b216042020-04-03 18:28:56 -0400374func (agent *LogicalAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000375 logger.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
khenaidoo2c6a0992019-04-29 13:46:56 -0400376 var err error
377 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530378 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400379 return err
380 }
381 agent.addLogicalPortToMap(port.PortNo, true)
382 } else if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530383 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400384 return err
385 }
386 agent.addLogicalPortToMap(port.PortNo, false)
387 } else {
khenaidoo820197c2020-02-13 16:35:33 -0500388 // Update the device routes to ensure all routes on the logical device have been calculated
389 if err = agent.buildRoutes(ctx); err != nil {
390 // Not an error - temporary state
Girish Kumarf56a4682020-03-20 20:07:46 +0000391 logger.Warnw("failed-to-update-routes", log.Fields{"device-id": device.Id, "port": port, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400392 }
393 }
394 return nil
395}
396
khenaidoo3d3b8c22019-05-22 18:10:39 -0400397// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
398// added to it. While the logical device was being created we could have received requests to add
399// NNI and UNI ports which were discarded. Now is the time to add them if needed
Kent Hagerman2b216042020-04-03 18:28:56 -0400400func (agent *LogicalAgent) setupLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000401 logger.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400402 // First add any NNI ports which could have been missing
npujar467fe752020-01-16 20:17:45 +0530403 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000404 logger.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400405 return err
406 }
407
408 // Now, set up the UNI ports if needed.
Kent Hagerman2b216042020-04-03 18:28:56 -0400409 children, err := agent.deviceMgr.GetAllChildDevices(ctx, agent.rootDeviceID)
npujar1d86a522019-11-14 17:11:16 +0530410 if err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000411 logger.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400412 return err
npujar1d86a522019-11-14 17:11:16 +0530413 }
414 responses := make([]coreutils.Response, 0)
415 for _, child := range children.Items {
416 response := coreutils.NewResponse()
417 responses = append(responses, response)
418 go func(child *voltha.Device) {
khenaidoo442e7c72020-03-10 16:13:48 -0400419 if err = agent.setupUNILogicalPorts(context.Background(), child); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000420 logger.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
npujar1d86a522019-11-14 17:11:16 +0530421 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
422 }
423 response.Done()
424 }(child)
425 }
426 // Wait for completion
427 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
428 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400429 }
430 return nil
431}
432
khenaidoofc1314d2019-03-14 09:34:21 -0400433// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
Kent Hagerman2b216042020-04-03 18:28:56 -0400434func (agent *LogicalAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000435 logger.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoob9203542018-09-17 22:56:37 -0400436 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400437 var err error
438
439 var device *voltha.Device
Kent Hagerman45a13e42020-04-13 12:23:50 -0400440 if device, err = agent.deviceMgr.getDevice(ctx, deviceID); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000441 logger.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400442 return err
443 }
444
445 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400446 for _, port := range device.Ports {
447 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530448 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000449 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400450 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400451 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400452 }
453 }
khenaidoofc1314d2019-03-14 09:34:21 -0400454 return err
455}
456
khenaidoo171b98e2019-10-31 11:48:15 -0400457// updatePortState updates the port state of the device
Kent Hagerman2b216042020-04-03 18:28:56 -0400458func (agent *LogicalAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000459 logger.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
khenaidoo442e7c72020-03-10 16:13:48 -0400460 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
461 return err
462 }
463 defer agent.requestQueue.RequestComplete()
khenaidoo171b98e2019-10-31 11:48:15 -0400464 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500465 original := agent.getLogicalDeviceWithoutLock()
466 updatedPorts := clonePorts(original.Ports)
467 for _, port := range updatedPorts {
468 if port.DeviceId == deviceID && port.DevicePortNo == portNo {
npujar1d86a522019-11-14 17:11:16 +0530469 if operStatus == voltha.OperStatus_ACTIVE {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500470 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
471 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
npujar1d86a522019-11-14 17:11:16 +0530472 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500473 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
474 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
npujar1d86a522019-11-14 17:11:16 +0530475 }
476 // Update the logical device
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500477 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000478 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
npujar1d86a522019-11-14 17:11:16 +0530479 return err
480 }
481 return nil
482 }
483 }
484 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
khenaidoo171b98e2019-10-31 11:48:15 -0400485}
486
khenaidoo3ab34882019-05-02 21:33:30 -0400487// updatePortsState updates the ports state related to the device
Kent Hagerman2b216042020-04-03 18:28:56 -0400488func (agent *LogicalAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000489 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400490 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
491 return err
492 }
493 defer agent.requestQueue.RequestComplete()
khenaidoo3ab34882019-05-02 21:33:30 -0400494 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500495 original := agent.getLogicalDeviceWithoutLock()
496 updatedPorts := clonePorts(original.Ports)
497 for _, port := range updatedPorts {
498 if port.DeviceId == device.Id {
kesavandbc2d1622020-01-21 00:42:01 -0500499 if state == voltha.OperStatus_ACTIVE {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500500 port.OfpPort.Config = port.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
501 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
kesavandbc2d1622020-01-21 00:42:01 -0500502 } else {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500503 port.OfpPort.Config = port.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
504 port.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400505 }
506 }
npujar1d86a522019-11-14 17:11:16 +0530507 }
508 // Updating the logical device will trigger the poprt change events to be populated to the controller
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500509 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, original, updatedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000510 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
npujar1d86a522019-11-14 17:11:16 +0530511 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400512 }
513 return nil
514}
515
khenaidoofc1314d2019-03-14 09:34:21 -0400516// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
Kent Hagerman2b216042020-04-03 18:28:56 -0400517func (agent *LogicalAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000518 logger.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400519 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400520 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400521 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400522 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400523 for _, port := range childDevice.Ports {
524 if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530525 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000526 logger.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400527 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400528 if added {
529 agent.addLogicalPortToMap(port.PortNo, false)
530 }
khenaidoo19d7b632018-10-30 10:49:50 -0400531 }
532 }
khenaidoofc1314d2019-03-14 09:34:21 -0400533 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400534}
535
Girish Gowdra408cd962020-03-11 14:31:31 -0700536// deleteAllLogicalPorts deletes all logical ports associated with this logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400537func (agent *LogicalAgent) deleteAllLogicalPorts(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000538 logger.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400539 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
540 return err
541 }
542 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -0400543 // Get the latest logical device info
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500544 cloned := agent.getLogicalDeviceWithoutLock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500545
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500546 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, cloned, []*voltha.LogicalPort{}); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000547 logger.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
Girish Gowdra408cd962020-03-11 14:31:31 -0700548 return err
khenaidoo0a822f92019-05-08 15:15:57 -0400549 }
550 return nil
551}
552
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500553func clonePorts(ports []*voltha.LogicalPort) []*voltha.LogicalPort {
554 return proto.Clone(&voltha.LogicalPorts{Items: ports}).(*voltha.LogicalPorts).Items
555}
556
557//updateLogicalDevicePortsWithoutLock updates the
Kent Hagerman2b216042020-04-03 18:28:56 -0400558func (agent *LogicalAgent) updateLogicalDevicePortsWithoutLock(ctx context.Context, device *voltha.LogicalDevice, newPorts []*voltha.LogicalPort) error {
Kent Hagermand9cc2e92019-11-04 13:28:15 -0500559 oldPorts := device.Ports
560 device.Ports = newPorts
561 if err := agent.updateLogicalDeviceWithoutLock(ctx, device); err != nil {
562 return err
563 }
564 agent.portUpdated(oldPorts, newPorts)
565 return nil
566}
567
khenaidoo92e62c52018-10-03 14:02:54 -0400568//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
Kent Hagerman2b216042020-04-03 18:28:56 -0400569func (agent *LogicalAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
Kent Hagerman4f355f52020-03-30 16:01:33 -0400570 if agent.stopped {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700571 return fmt.Errorf("logical device agent stopped-%s", logicalDevice.Id)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400572 }
573
npujar467fe752020-01-16 20:17:45 +0530574 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Kent Hagerman4f355f52020-03-30 16:01:33 -0400575 if err := agent.clusterDataProxy.Update(updateCtx, "logical_devices/"+agent.logicalDeviceID, logicalDevice); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +0000576 logger.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
Thomas Lee Se5a44012019-11-07 20:32:24 +0530577 return err
578 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400579
khenaidoo442e7c72020-03-10 16:13:48 -0400580 agent.logicalDevice = logicalDevice
581
khenaidoo92e62c52018-10-03 14:02:54 -0400582 return nil
583}
584
khenaidoo820197c2020-02-13 16:35:33 -0500585//generateDeviceRoutesIfNeeded generates the device routes if the logical device has been updated since the last time
khenaidoo4c9e5592019-09-09 16:20:41 -0400586//that device graph was generated.
Kent Hagerman2b216042020-04-03 18:28:56 -0400587func (agent *LogicalAgent) generateDeviceRoutesIfNeeded(ctx context.Context) error {
khenaidoo820197c2020-02-13 16:35:33 -0500588 agent.lockDeviceRoutes.Lock()
589 defer agent.lockDeviceRoutes.Unlock()
590
khenaidoo442e7c72020-03-10 16:13:48 -0400591 ld, err := agent.GetLogicalDevice(ctx)
592 if err != nil {
593 return err
594 }
khenaidoo820197c2020-02-13 16:35:33 -0500595
596 if agent.deviceRoutes != nil && agent.deviceRoutes.IsUpToDate(ld) {
npujar1d86a522019-11-14 17:11:16 +0530597 return nil
598 }
Girish Kumarf56a4682020-03-20 20:07:46 +0000599 logger.Debug("Generation of device route required")
khenaidoo820197c2020-02-13 16:35:33 -0500600 if err := agent.buildRoutes(ctx); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -0400601 // No Route is not an error
602 if !errors.Is(err, route.ErrNoRoute) {
603 return err
604 }
khenaidoo820197c2020-02-13 16:35:33 -0500605 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400606 return nil
607}
608
khenaidoo19d7b632018-10-30 10:49:50 -0400609//updateFlowTable updates the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400610func (agent *LogicalAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
611 logger.Debug("UpdateFlowTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400612 if flow == nil {
613 return nil
614 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700615
khenaidoo820197c2020-02-13 16:35:33 -0500616 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400617 return err
618 }
khenaidoo19d7b632018-10-30 10:49:50 -0400619 switch flow.GetCommand() {
620 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530621 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400622 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530623 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400624 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530625 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400626 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
627 return agent.flowModify(flow)
628 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
629 return agent.flowModifyStrict(flow)
630 }
631 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530632 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400633}
634
635//updateGroupTable updates the group table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400636func (agent *LogicalAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000637 logger.Debug("updateGroupTable")
khenaidoo19d7b632018-10-30 10:49:50 -0400638 if groupMod == nil {
639 return nil
640 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700641
khenaidoo820197c2020-02-13 16:35:33 -0500642 if err := agent.generateDeviceRoutesIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400643 return err
644 }
khenaidoo820197c2020-02-13 16:35:33 -0500645
khenaidoo19d7b632018-10-30 10:49:50 -0400646 switch groupMod.GetCommand() {
647 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530648 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400649 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530650 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400651 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530652 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400653 }
654 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530655 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400656}
657
Manikkaraj kb1a10922019-07-29 12:10:34 -0400658// updateMeterTable updates the meter table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400659func (agent *LogicalAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000660 logger.Debug("updateMeterTable")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400661 if meterMod == nil {
662 return nil
663 }
664 switch meterMod.GetCommand() {
665 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530666 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400667 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530668 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400669 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530670 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400671 }
672 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530673 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400674
675}
676
Kent Hagerman2b216042020-04-03 18:28:56 -0400677func (agent *LogicalAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000678 logger.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400679 if meterMod == nil {
680 return nil
681 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400682
683 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700684 agent.meterLock.Lock()
685 //check if the meter already exists or not
686 _, ok := agent.meters[meterMod.MeterId]
687 if ok {
688 logger.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
689 agent.meterLock.Unlock()
690 return nil
691 }
692
693 mChunk := MeterChunk{
694 meter: meterEntry,
695 }
696 //Add to map and acquire the per meter lock
697 agent.meters[meterMod.MeterId] = &mChunk
698 mChunk.lock.Lock()
699 defer mChunk.lock.Unlock()
700 agent.meterLock.Unlock()
701 meterID := strconv.Itoa(int(meterMod.MeterId))
702 if err := agent.clusterDataProxy.AddWithID(ctx, "meters/"+agent.logicalDeviceID, meterID, meterEntry); err != nil {
703 logger.Errorw("failed-adding-meter", log.Fields{"deviceID": agent.logicalDeviceID, "meterID": meterID, "err": err})
704 //Revert the map
705 agent.meterLock.Lock()
706 delete(agent.meters, meterMod.MeterId)
707 agent.meterLock.Unlock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400708 return err
709 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700710
711 logger.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400712 return nil
713}
714
Kent Hagerman2b216042020-04-03 18:28:56 -0400715func (agent *LogicalAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000716 logger.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400717 if meterMod == nil {
718 return nil
719 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700720 agent.meterLock.RLock()
721 meterChunk, ok := agent.meters[meterMod.MeterId]
722 agent.meterLock.RUnlock()
723 if ok {
724 //Dont let anyone to do any changes to this meter until this is done.
725 //And wait if someone else is already making modifications. Do this with per meter lock.
726 meterChunk.lock.Lock()
727 defer meterChunk.lock.Unlock()
728 if err := agent.deleteFlowsOfMeter(ctx, meterMod.MeterId); err != nil {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400729 return err
730 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700731 //remove from the store and cache
732 if err := agent.removeLogicalDeviceMeter(ctx, meterMod.MeterId); err != nil {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400733 return err
734 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700735 logger.Debugw("meterDelete-success", log.Fields{"meterID": meterMod.MeterId})
736 } else {
737 logger.Warnw("meter-not-found", log.Fields{"meterID": meterMod.MeterId})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400738 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400739 return nil
740}
741
Kent Hagerman2b216042020-04-03 18:28:56 -0400742func (agent *LogicalAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000743 logger.Debug("meterModify")
Manikkaraj kb1a10922019-07-29 12:10:34 -0400744 if meterMod == nil {
745 return nil
746 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700747 newMeter := fu.MeterEntryFromMeterMod(meterMod)
748 agent.meterLock.RLock()
749 meterChunk, ok := agent.meters[newMeter.Config.MeterId]
750 agent.meterLock.RUnlock()
751 if !ok {
752 return fmt.Errorf("no-meter-to-modify:%d", newMeter.Config.MeterId)
753 }
754 //Release the map lock and syncronize per meter
755 meterChunk.lock.Lock()
756 defer meterChunk.lock.Unlock()
757 oldMeter := meterChunk.meter
758 newMeter.Stats.FlowCount = oldMeter.Stats.FlowCount
759
760 if err := agent.updateLogicalDeviceMeter(ctx, newMeter, meterChunk); err != nil {
761 logger.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "meterID": newMeter.Config.MeterId})
khenaidoo442e7c72020-03-10 16:13:48 -0400762 return err
763 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700764 logger.Debugw("replaced-with-new-meter", log.Fields{"oldMeter": oldMeter, "newMeter": newMeter})
765 return nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400766
767}
768
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700769func (agent *LogicalAgent) deleteFlowsOfMeter(ctx context.Context, meterID uint32) error {
770 logger.Infow("Delete-flows-matching-meter", log.Fields{"meter": meterID})
771 agent.flowLock.Lock()
772 defer agent.flowLock.Unlock()
773 for flowID, flowChunk := range agent.flows {
774 if mID := fu.GetMeterIdFromFlow(flowChunk.flow); mID != 0 && mID == meterID {
775 logger.Debugw("Flow-to-be- deleted", log.Fields{"flow": flowChunk.flow})
776 path := fmt.Sprintf("logical_flows/%s/%d", agent.logicalDeviceID, flowID)
777 if err := agent.clusterDataProxy.Remove(ctx, path); err != nil {
778 //TODO: Think on carrying on and deleting the remaining flows, instead of returning.
779 //Anyways this returns an error to controller which possibly results with a re-deletion.
780 //Then how can we handle the new deletion request(Same for group deletion)?
781 return fmt.Errorf("couldnt-deleted-flow-from-store-%s", path)
782 }
783 delete(agent.flows, flowID)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400784 }
785 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700786 return nil
Manikkaraj kb1a10922019-07-29 12:10:34 -0400787}
788
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700789func (agent *LogicalAgent) updateFlowCountOfMeterStats(ctx context.Context, modCommand *ofp.OfpFlowMod, flow *ofp.OfpFlowStats, revertUpdate bool) bool {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400790
791 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530792 meterID := fu.GetMeterIdFromFlow(flow)
Girish Kumarf56a4682020-03-20 20:07:46 +0000793 logger.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
npujar1d86a522019-11-14 17:11:16 +0530794 if meterID == 0 {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700795 logger.Debugw("No-meter-present-in-the-flow", log.Fields{"flow": *flow})
796 return true
Manikkaraj kb1a10922019-07-29 12:10:34 -0400797 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700798
799 if flowCommand != ofp.OfpFlowModCommand_OFPFC_ADD && flowCommand != ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
800 return true
Manikkaraj kb1a10922019-07-29 12:10:34 -0400801 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700802 agent.meterLock.RLock()
803 meterChunk, ok := agent.meters[meterID]
804 agent.meterLock.RUnlock()
805 if !ok {
806 logger.Debugw("Meter-is-not-present-in-logical-device", log.Fields{"meterID": meterID})
807 return true
808 }
809
810 //acquire the meter lock
811 meterChunk.lock.Lock()
812 defer meterChunk.lock.Unlock()
813
814 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
815 if revertUpdate {
816 meterChunk.meter.Stats.FlowCount--
817 } else {
818 meterChunk.meter.Stats.FlowCount++
819 }
820 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
821 if revertUpdate {
822 meterChunk.meter.Stats.FlowCount++
823 } else {
824 meterChunk.meter.Stats.FlowCount--
Manikkaraj kb1a10922019-07-29 12:10:34 -0400825 }
826 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700827
828 // Update store and cache
829 if err := agent.updateLogicalDeviceMeter(ctx, meterChunk.meter, meterChunk); err != nil {
830 logger.Debugw("unable-to-update-meter-in-db", log.Fields{"logicalDevice": agent.logicalDeviceID, "meterID": meterID})
831 return false
832 }
833
834 logger.Debugw("updated-meter-flow-stats", log.Fields{"meterId": meterID})
835 return true
Manikkaraj kb1a10922019-07-29 12:10:34 -0400836}
837
khenaidoo19d7b632018-10-30 10:49:50 -0400838//flowAdd adds a flow to the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -0400839func (agent *LogicalAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +0000840 logger.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400841 if mod == nil {
842 return nil
843 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700844 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
845 if err != nil {
846 logger.Errorw("flowAdd-failed", log.Fields{"flowMod": mod, "err": err})
khenaidoo442e7c72020-03-10 16:13:48 -0400847 return err
848 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700849 var updated bool
850 var changed bool
851 if changed, updated, err = agent.decomposeAndAdd(ctx, flow, mod); err != nil {
852 logger.Errorw("flow-decompose-and-add-failed ", log.Fields{"flowMod": mod, "err": err})
853 return err
khenaidoo19d7b632018-10-30 10:49:50 -0400854 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700855 if changed && !updated {
856 if dbupdated := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !dbupdated {
857 return fmt.Errorf("couldnt-updated-flow-stats-%s", strconv.FormatUint(flow.Id, 10))
858 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400859 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700860 return nil
861
862}
863
864func (agent *LogicalAgent) decomposeAndAdd(ctx context.Context, flow *ofp.OfpFlowStats, mod *ofp.OfpFlowMod) (bool, bool, error) {
khenaidoo19d7b632018-10-30 10:49:50 -0400865 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400866 updated := false
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700867 alreadyExist := true
868 var flowToReplace *ofp.OfpFlowStats
869
870 //if flow is not found in the map, create a new entry, otherwise get the existing one.
871 agent.flowLock.Lock()
872 flowChunk, ok := agent.flows[flow.Id]
873 if !ok {
874 flowChunk = &FlowChunk{
875 flow: flow,
876 }
877 agent.flows[flow.Id] = flowChunk
878 alreadyExist = false
879 flowChunk.lock.Lock() //acquire chunk lock before releasing map lock
880 defer flowChunk.lock.Unlock()
881 agent.flowLock.Unlock()
882 } else {
883 agent.flowLock.Unlock() //release map lock before acquiring chunk lock
884 flowChunk.lock.Lock()
885 defer flowChunk.lock.Unlock()
886 }
887
888 if !alreadyExist {
889 flowID := strconv.FormatUint(flow.Id, 10)
890 if err := agent.clusterDataProxy.AddWithID(ctx, "logical_flows/"+agent.logicalDeviceID, flowID, flow); err != nil {
891 logger.Errorw("failed-adding-flow-to-db", log.Fields{"deviceID": agent.logicalDeviceID, "flowID": flowID, "err": err})
892 //Revert the map
893 //TODO: Solve the condition:If we have two flow Adds of the same flow (at least same priority and match) in quick succession
894 //then if the first one fails while the second one was waiting on the flowchunk, we will end up with an instance of flowChunk that is no longer in the map.
895 agent.flowLock.Lock()
896 delete(agent.flows, flow.Id)
897 agent.flowLock.Unlock()
898 return changed, updated, err
899 }
900 }
901 flows := make([]*ofp.OfpFlowStats, 0)
902 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400903 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
904 if checkOverlap {
905 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
906 // TODO: should this error be notified other than being logged?
Girish Kumarf56a4682020-03-20 20:07:46 +0000907 logger.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400908 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400909 // Add flow
khenaidoo19d7b632018-10-30 10:49:50 -0400910 changed = true
911 }
912 } else {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700913 if alreadyExist {
914 flowToReplace = flowChunk.flow
khenaidoo19d7b632018-10-30 10:49:50 -0400915 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400916 flow.ByteCount = flowToReplace.ByteCount
917 flow.PacketCount = flowToReplace.PacketCount
khenaidoo19d7b632018-10-30 10:49:50 -0400918 }
khenaidoo8b4abbf2020-04-24 17:04:30 -0400919 if !proto.Equal(flowToReplace, flow) {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400920 changed = true
921 updated = true
922 }
923 } else {
khenaidoo2c6a0992019-04-29 13:46:56 -0400924 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400925 }
khenaidoo19d7b632018-10-30 10:49:50 -0400926 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700927 logger.Debugw("flowAdd-changed", log.Fields{"changed": changed, "updated": updated})
khenaidoo19d7b632018-10-30 10:49:50 -0400928 if changed {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700929 updatedFlows = append(updatedFlows, flow)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400930 var flowMetadata voltha.FlowMetadata
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700931 lMeters, _ := agent.ListLogicalDeviceMeters(ctx)
932 if err := agent.GetMeterConfig(updatedFlows, lMeters.Items, &flowMetadata); err != nil {
933 logger.Error("Meter-referred-in-flow-not-present")
934 return changed, updated, err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400935 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700936 flowGroups, _ := agent.ListLogicalDeviceFlowGroups(ctx)
937 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *flowGroups)
khenaidoo820197c2020-02-13 16:35:33 -0500938 if err != nil {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700939 return changed, updated, err
khenaidoo820197c2020-02-13 16:35:33 -0500940 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700941
Girish Kumarf56a4682020-03-20 20:07:46 +0000942 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700943 // Update store and cache
944 if updated {
945 if err := agent.updateLogicalDeviceFlow(ctx, flow, flowChunk); err != nil {
946 return changed, updated, err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400947 }
948 }
khenaidoo442e7c72020-03-10 16:13:48 -0400949 respChannels := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &flowMetadata)
khenaidoo442e7c72020-03-10 16:13:48 -0400950 // Create the go routines to wait
951 go func() {
952 // Wait for completion
953 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChannels...); res != nil {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400954 logger.Infow("failed-to-add-flows-will-attempt-deletion", log.Fields{"errors": res, "logical-device-id": agent.logicalDeviceID})
955 // Revert added flows
956 if err := agent.revertAddedFlows(context.Background(), mod, flow, flowToReplace, deviceRules, &flowMetadata); err != nil {
957 logger.Errorw("failure-to-delete-flows-after-failed-addition", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
958 }
khenaidoo442e7c72020-03-10 16:13:48 -0400959 }
960 }()
khenaidoo19d7b632018-10-30 10:49:50 -0400961 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700962 return changed, updated, nil
khenaidoo19d7b632018-10-30 10:49:50 -0400963}
964
khenaidoo8b4abbf2020-04-24 17:04:30 -0400965// revertAddedFlows reverts flows after the flowAdd request has failed. All flows corresponding to that flowAdd request
966// will be reverted, both from the logical devices and the devices.
967func (agent *LogicalAgent) revertAddedFlows(ctx context.Context, mod *ofp.OfpFlowMod, addedFlow *ofp.OfpFlowStats, replacedFlow *ofp.OfpFlowStats, deviceRules *fu.DeviceRules, metadata *voltha.FlowMetadata) error {
968 logger.Debugw("revertFlowAdd", log.Fields{"added-flow": addedFlow, "replaced-flow": replacedFlow, "device-rules": deviceRules, "metadata": metadata})
khenaidoo8b4abbf2020-04-24 17:04:30 -0400969
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700970 agent.flowLock.RLock()
971 flowChunk, ok := agent.flows[addedFlow.Id]
972 agent.flowLock.RUnlock()
973 if !ok {
khenaidoo8b4abbf2020-04-24 17:04:30 -0400974 // Not found - do nothing
975 log.Debugw("flow-not-found", log.Fields{"added-flow": addedFlow})
976 return nil
977 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700978 //Leave the map lock and syncronize per flow
979 flowChunk.lock.Lock()
980 defer flowChunk.lock.Unlock()
khenaidoo8b4abbf2020-04-24 17:04:30 -0400981
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700982 if replacedFlow != nil {
983 if err := agent.updateLogicalDeviceFlow(ctx, replacedFlow, flowChunk); err != nil {
984 return err
985 }
986 } else {
987 if err := agent.removeLogicalDeviceFlow(ctx, addedFlow.Id); err != nil {
988 return err
khenaidooa29a4712020-05-05 10:17:17 -0400989 }
khenaidoo8b4abbf2020-04-24 17:04:30 -0400990 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -0700991 // Revert meters
992 if changedMeterStats := agent.updateFlowCountOfMeterStats(ctx, mod, addedFlow, true); !changedMeterStats {
993 return fmt.Errorf("Unable-to-revert-meterstats-for-flow-%s", strconv.FormatUint(addedFlow.Id, 10))
khenaidoo8b4abbf2020-04-24 17:04:30 -0400994 }
995
996 // Update the devices
997 respChnls := agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, metadata)
998
999 // Wait for the responses
1000 go func() {
1001 // Since this action is taken following an add failure, we may also receive a failure for the revert
1002 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1003 logger.Warnw("failure-reverting-added-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1004 }
1005 }()
1006
1007 return nil
1008}
1009
npujar1d86a522019-11-14 17:11:16 +05301010// GetMeterConfig returns meter config
Kent Hagerman2b216042020-04-03 18:28:56 -04001011func (agent *LogicalAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001012 m := make(map[uint32]bool)
1013 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +05301014 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -04001015 foundMeter := false
1016 // Meter is present in the flow , Get from logical device
1017 for _, meter := range meters {
1018 if flowMeterID == meter.Config.MeterId {
1019 metadata.Meters = append(metadata.Meters, meter.Config)
Girish Kumarf56a4682020-03-20 20:07:46 +00001020 logger.Debugw("Found meter in logical device",
Manikkaraj kb1a10922019-07-29 12:10:34 -04001021 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
1022 m[flowMeterID] = true
1023 foundMeter = true
1024 break
1025 }
1026 }
1027 if !foundMeter {
Girish Kumarf56a4682020-03-20 20:07:46 +00001028 logger.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +05301029 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001030 return fmt.Errorf("Meter-referred-by-flow-is-not-found-in-logicaldevice.MeterId-%d", flowMeterID)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001031 }
1032 }
1033 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001034 logger.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001035 return nil
1036
1037}
1038
khenaidoo19d7b632018-10-30 10:49:50 -04001039//flowDelete deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001040func (agent *LogicalAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001041 logger.Debug("flowDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001042 if mod == nil {
1043 return nil
1044 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001045
1046 fs, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1047 if err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -04001048 return err
1049 }
khenaidoo19d7b632018-10-30 10:49:50 -04001050
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001051 //build a list of what to delete
khenaidoo0458db62019-06-20 08:50:36 -04001052 toDelete := make([]*ofp.OfpFlowStats, 0)
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001053 toDeleteChunks := make([]*FlowChunk, 0)
1054 //Lock the map to search the matched flows
1055 agent.flowLock.RLock()
1056 for _, f := range agent.flows {
1057 if fu.FlowMatch(f.flow, fs) {
1058 toDelete = append(toDelete, f.flow)
1059 toDeleteChunks = append(toDeleteChunks, f)
khenaidoo0458db62019-06-20 08:50:36 -04001060 continue
1061 }
1062 // Check wild card match
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001063 if fu.FlowMatchesMod(f.flow, mod) {
1064 toDelete = append(toDelete, f.flow)
1065 toDeleteChunks = append(toDeleteChunks, f)
khenaidoo19d7b632018-10-30 10:49:50 -04001066 }
1067 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001068 agent.flowLock.RUnlock()
1069 //Delete the matched flows
khenaidoo0458db62019-06-20 08:50:36 -04001070 if len(toDelete) > 0 {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001071 logger.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toDelete": len(toDelete)})
1072 var meters []*ofp.OfpMeterEntry
1073 var flowGroups []*ofp.OfpGroupEntry
1074 if ofpMeters, err := agent.ListLogicalDeviceMeters(ctx); err != nil {
1075 meters = ofpMeters.Items
1076 }
1077
1078 if groups, err := agent.ListLogicalDeviceFlowGroups(ctx); err != nil {
1079 flowGroups = groups.Items
1080 }
1081
1082 for _, fc := range toDeleteChunks {
1083 if err := agent.deleteFlowAndUpdateMeterStats(ctx, mod, fc); err != nil {
1084 return err
1085 }
1086 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001087 var flowMetadata voltha.FlowMetadata
1088 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
Girish Kumarf56a4682020-03-20 20:07:46 +00001089 logger.Error("Meter-referred-in-flows-not-present")
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001090 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -04001091 }
khenaidoo787224a2020-04-16 18:08:47 -04001092 var respChnls []coreutils.Response
1093 var partialRoute bool
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001094 var deviceRules *fu.DeviceRules
1095 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
khenaidoo820197c2020-02-13 16:35:33 -05001096 if err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001097 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1098 // child device is deleted and a request to delete flows from the parent device is received
1099 if !errors.Is(err, route.ErrNoRoute) {
1100 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": toDelete, "error": err})
1101 return err
1102 }
1103 partialRoute = true
khenaidoo820197c2020-02-13 16:35:33 -05001104 }
khenaidoo0458db62019-06-20 08:50:36 -04001105
khenaidoo442e7c72020-03-10 16:13:48 -04001106 // Update the devices
khenaidoo787224a2020-04-16 18:08:47 -04001107 if partialRoute {
1108 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: toDelete}, &flowMetadata)
1109 } else {
1110 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
1111 }
khenaidoo442e7c72020-03-10 16:13:48 -04001112
1113 // Wait for the responses
1114 go func() {
1115 // Wait for completion
1116 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001117 logger.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001118 // TODO: Revert the flow deletion
1119 }
1120 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001121 }
khenaidoo19d7b632018-10-30 10:49:50 -04001122 //TODO: send announcement on delete
1123 return nil
1124}
1125
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001126func (agent *LogicalAgent) deleteFlowAndUpdateMeterStats(ctx context.Context, mod *ofp.OfpFlowMod, chunk *FlowChunk) error {
1127 chunk.lock.Lock()
1128 defer chunk.lock.Unlock()
1129 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, chunk.flow, false); !changedMeter {
1130 return fmt.Errorf("Cannot-delete-flow-%s. Meter-update-failed", chunk.flow)
1131 }
1132 // Update store and cache
1133 if err := agent.removeLogicalDeviceFlow(ctx, chunk.flow.Id); err != nil {
1134 return fmt.Errorf("Cannot-delete-flows-%s. Delete-from-store-failed", chunk.flow)
1135 }
1136 return nil
1137}
1138
Kent Hagerman2b216042020-04-03 18:28:56 -04001139func (agent *LogicalAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001140 logger.Debugw("send-add-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -04001141
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001142 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301143 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001144 response := coreutils.NewResponse()
1145 responses = append(responses, response)
1146 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001147 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1148 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301149 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001150 logger.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001151 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001152 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001153 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301154 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001155 }
khenaidoo442e7c72020-03-10 16:13:48 -04001156 // Return responses (an array of channels) for the caller to wait for a response from the far end.
1157 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001158}
khenaidoo19d7b632018-10-30 10:49:50 -04001159
Kent Hagerman2b216042020-04-03 18:28:56 -04001160func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001161 logger.Debugw("send-delete-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001162
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001163 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301164 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001165 response := coreutils.NewResponse()
1166 responses = append(responses, response)
1167 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001168 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1169 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301170 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001171 logger.Errorw("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001172 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001173 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001174 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301175 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001176 }
khenaidoo442e7c72020-03-10 16:13:48 -04001177 return responses
khenaidoo0458db62019-06-20 08:50:36 -04001178}
1179
Kent Hagerman2b216042020-04-03 18:28:56 -04001180func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) []coreutils.Response {
Girish Kumarf56a4682020-03-20 20:07:46 +00001181 logger.Debugw("send-update-flows-to-device-manager", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001182
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001183 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301184 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001185 response := coreutils.NewResponse()
1186 responses = append(responses, response)
1187 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidoo442e7c72020-03-10 16:13:48 -04001188 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1189 defer cancel()
npujar467fe752020-01-16 20:17:45 +05301190 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo787224a2020-04-16 18:08:47 -04001191 logger.Errorw("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001192 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001193 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001194 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301195 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001196 }
khenaidoo442e7c72020-03-10 16:13:48 -04001197 return responses
khenaidoo19d7b632018-10-30 10:49:50 -04001198}
1199
khenaidoo787224a2020-04-16 18:08:47 -04001200// getUNILogicalPortNo returns the UNI logical port number specified in the flow
1201func (agent *LogicalAgent) getUNILogicalPortNo(flow *ofp.OfpFlowStats) (uint32, error) {
1202 var uniPort uint32
1203 inPortNo := fu.GetInPort(flow)
1204 outPortNo := fu.GetOutPort(flow)
1205 if agent.isNNIPort(inPortNo) {
1206 uniPort = outPortNo
1207 } else if agent.isNNIPort(outPortNo) {
1208 uniPort = inPortNo
1209 }
1210 if uniPort != 0 {
1211 return uniPort, nil
1212 }
1213 return 0, status.Errorf(codes.NotFound, "no-uni-port: %v", flow)
1214}
1215
1216func (agent *LogicalAgent) deleteFlowsFromParentDevice(ctx context.Context, flows ofp.Flows, metadata *voltha.FlowMetadata) []coreutils.Response {
1217 logger.Debugw("deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows})
1218 responses := make([]coreutils.Response, 0)
1219 for _, flow := range flows.Items {
1220 response := coreutils.NewResponse()
1221 responses = append(responses, response)
1222 uniPort, err := agent.getUNILogicalPortNo(flow)
1223 if err != nil {
1224 logger.Error("no-uni-port-in-flow", log.Fields{"deviceID": agent.rootDeviceID, "flow": flow, "error": err})
1225 response.Error(err)
1226 response.Done()
1227 continue
1228 }
1229 logger.Debugw("uni-port", log.Fields{"flows": flows, "uni-port": uniPort})
1230 go func(uniPort uint32, metadata *voltha.FlowMetadata) {
1231 ctx, cancel := context.WithTimeout(context.Background(), agent.defaultTimeout)
1232 defer cancel()
1233 if err := agent.deviceMgr.deleteParentFlows(ctx, agent.rootDeviceID, uniPort, metadata); err != nil {
1234 logger.Error("flow-delete-failed", log.Fields{"device-id": agent.rootDeviceID, "error": err})
1235 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err))
1236 }
1237 response.Done()
1238 }(uniPort, metadata)
1239 }
1240 return responses
1241}
1242
khenaidoo19d7b632018-10-30 10:49:50 -04001243//flowDeleteStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001244func (agent *LogicalAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001245 logger.Debugw("flowDeleteStrict", log.Fields{"mod": mod})
khenaidoo19d7b632018-10-30 10:49:50 -04001246 if mod == nil {
1247 return nil
1248 }
khenaidoo19d7b632018-10-30 10:49:50 -04001249
Scott Bakerfdea1e32020-02-21 15:35:41 -08001250 flow, err := fu.FlowStatsEntryFromFlowModMessage(mod)
1251 if err != nil {
1252 return err
1253 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001254 logger.Debugw("flow-id-in-flow-delete-strict", log.Fields{"flowID": flow.Id})
1255 agent.flowLock.RLock()
1256 flowChunk, ok := agent.flows[flow.Id]
1257 agent.flowLock.RUnlock()
1258 if !ok {
1259 logger.Debugw("Skipping-flow-delete-strict-request. No-flow-found", log.Fields{"flowMod": mod})
1260 return nil
1261 }
1262 //Release the map lock and syncronize per flow
1263 flowChunk.lock.Lock()
1264 defer flowChunk.lock.Unlock()
1265
1266 var meters []*ofp.OfpMeterEntry
1267 var flowGroups []*ofp.OfpGroupEntry
1268 if ofMeters, er := agent.ListLogicalDeviceMeters(ctx); er == nil {
1269 meters = ofMeters.Items
1270 }
1271 if ofGroups, er := agent.ListLogicalDeviceFlowGroups(ctx); er == nil {
1272 flowGroups = ofGroups.Items
1273 }
1274 if changedMeter := agent.updateFlowCountOfMeterStats(ctx, mod, flow, false); !changedMeter {
1275 return fmt.Errorf("Cannot delete flow - %s. Meter update failed", flow)
1276 }
1277
1278 var flowMetadata voltha.FlowMetadata
1279 flowsToDelete := []*ofp.OfpFlowStats{flowChunk.flow}
1280 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
1281 logger.Error("meter-referred-in-flows-not-present")
1282 return err
1283 }
1284 var respChnls []coreutils.Response
1285 var partialRoute bool
1286 deviceRules, err := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
1287 if err != nil {
1288 // A no route error means no route exists between the ports specified in the flow. This can happen when the
1289 // child device is deleted and a request to delete flows from the parent device is received
1290 if !errors.Is(err, route.ErrNoRoute) {
1291 logger.Errorw("unexpected-error-received", log.Fields{"flows-to-delete": flowsToDelete, "error": err})
1292 return err
1293 }
1294 partialRoute = true
1295 }
1296
1297 // Update the model
1298 if err := agent.removeLogicalDeviceFlow(ctx, flow.Id); err != nil {
1299 return err
1300 }
1301 // Update the devices
1302 if partialRoute {
1303 respChnls = agent.deleteFlowsFromParentDevice(ctx, ofp.Flows{Items: flowsToDelete}, &flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -04001304 } else {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001305 respChnls = agent.deleteFlowsAndGroupsFromDevices(ctx, deviceRules, &flowMetadata)
khenaidoo19d7b632018-10-30 10:49:50 -04001306 }
1307
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001308 // Wait for completion
1309 go func() {
1310 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1311 logger.Warnw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1312 //TODO: Revert flow changes
Manikkaraj kb1a10922019-07-29 12:10:34 -04001313 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001314 }()
khenaidoo0458db62019-06-20 08:50:36 -04001315
khenaidoo19d7b632018-10-30 10:49:50 -04001316 return nil
1317}
1318
1319//flowModify modifies a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001320func (agent *LogicalAgent) flowModify(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001321 return errors.New("flowModify not implemented")
1322}
1323
1324//flowModifyStrict deletes a flow from the flow table of that logical device
Kent Hagerman2b216042020-04-03 18:28:56 -04001325func (agent *LogicalAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001326 return errors.New("flowModifyStrict not implemented")
1327}
1328
Kent Hagerman2b216042020-04-03 18:28:56 -04001329func (agent *LogicalAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001330 if groupMod == nil {
1331 return nil
1332 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001333 logger.Debugw("groupAdd", log.Fields{"GroupId": groupMod.GroupId})
1334 agent.groupLock.Lock()
1335 _, ok := agent.groups[groupMod.GroupId]
1336 if ok {
1337 agent.groupLock.Unlock()
1338 return fmt.Errorf("Group %d already exists", groupMod.GroupId)
1339 }
1340
1341 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1342 groupChunk := GroupChunk{
1343 group: groupEntry,
1344 }
1345 //add to map
1346 agent.groups[groupMod.GroupId] = &groupChunk
1347 groupChunk.lock.Lock()
1348 defer groupChunk.lock.Unlock()
1349 agent.groupLock.Unlock()
1350 //add to the kv store
1351 path := fmt.Sprintf("groups/%s", agent.logicalDeviceID)
1352 groupID := strconv.Itoa(int(groupMod.GroupId))
1353 if err := agent.clusterDataProxy.AddWithID(ctx, path, groupID, groupEntry); err != nil {
1354 logger.Errorw("failed-adding-group", log.Fields{"deviceID": agent.logicalDeviceID, "groupID": groupID, "err": err})
1355 agent.groupLock.Lock()
1356 delete(agent.groups, groupMod.GroupId)
1357 agent.groupLock.Unlock()
khenaidoo442e7c72020-03-10 16:13:48 -04001358 return err
1359 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001360 deviceRules := fu.NewDeviceRules()
1361 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1362 fg := fu.NewFlowsAndGroups()
1363 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1364 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo19d7b632018-10-30 10:49:50 -04001365
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001366 logger.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
khenaidoo6e55d9e2019-12-12 18:26:26 -05001367
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001368 // Update the devices
1369 respChnls := agent.addFlowsAndGroupsToDevices(ctx, deviceRules, &voltha.FlowMetadata{})
khenaidoo0458db62019-06-20 08:50:36 -04001370
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001371 // Wait for completion
1372 go func() {
1373 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1374 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1375 //TODO: Revert flow changes
khenaidoo19d7b632018-10-30 10:49:50 -04001376 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001377 }()
1378 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001379}
1380
Kent Hagerman2b216042020-04-03 18:28:56 -04001381func (agent *LogicalAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001382 logger.Debug("groupDelete")
khenaidoo19d7b632018-10-30 10:49:50 -04001383 if groupMod == nil {
1384 return nil
1385 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001386 affectedFlows := make([]*ofp.OfpFlowStats, 0)
1387 affectedGroups := make([]*ofp.OfpGroupEntry, 0)
npujar1d86a522019-11-14 17:11:16 +05301388 var groupsChanged bool
npujar1d86a522019-11-14 17:11:16 +05301389 groupID := groupMod.GroupId
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001390 var err error
npujar1d86a522019-11-14 17:11:16 +05301391 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001392 if err := func() error {
1393 agent.groupLock.Lock()
1394 defer agent.groupLock.Unlock()
1395 for key, groupChunk := range agent.groups {
1396 //Remove from store and cache. Do this in a one time lock allocation.
1397 path := fmt.Sprintf("groups/%s/%d", agent.logicalDeviceID, key)
1398 if err := agent.clusterDataProxy.Remove(ctx, path); err != nil {
1399 return fmt.Errorf("couldnt-deleted-group-from-store-%s", path)
1400 }
1401 delete(agent.groups, groupID)
1402 var flows []*ofp.OfpFlowStats
1403 if flows, err = agent.deleteFlowsOfGroup(ctx, key); err != nil {
1404 logger.Errorw("cannot-update-flow-for-group-delete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "groupID": key})
1405 return err
1406 }
1407 affectedFlows = append(affectedFlows, flows...)
1408 affectedGroups = append(affectedGroups, groupChunk.group)
1409 }
1410 return nil
1411 }(); err != nil {
1412 return err
1413 }
khenaidoo19d7b632018-10-30 10:49:50 -04001414 groupsChanged = true
1415 } else {
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001416 agent.groupLock.RLock()
1417 groupChunk, ok := agent.groups[groupID]
1418 agent.groupLock.RUnlock()
1419 if !ok {
1420 logger.Warnw("group-not-found", log.Fields{"groupID": groupID})
1421 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001422 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001423 groupChunk.lock.Lock()
1424 defer groupChunk.lock.Unlock()
1425 var flows []*ofp.OfpFlowStats
1426 if flows, err = agent.deleteFlowsOfGroup(ctx, groupID); err != nil {
1427 logger.Errorw("cannot-update-flow-for-group-delete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "groupID": groupID})
1428 return err
1429 }
1430 //remove from store
1431 if err := agent.removeLogicalDeviceFlowGroup(ctx, groupID); err != nil {
1432 return err
1433 }
1434 affectedFlows = append(affectedFlows, flows...)
1435 affectedGroups = append(affectedGroups, groupChunk.group)
npujar1d86a522019-11-14 17:11:16 +05301436 groupsChanged = true
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001437
khenaidoo19d7b632018-10-30 10:49:50 -04001438 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001439
1440 if err != nil || groupsChanged {
1441 var deviceRules *fu.DeviceRules
1442 deviceRules, err = agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: affectedFlows}, ofp.FlowGroups{Items: affectedGroups})
khenaidoo820197c2020-02-13 16:35:33 -05001443 if err != nil {
1444 return err
1445 }
Girish Kumarf56a4682020-03-20 20:07:46 +00001446 logger.Debugw("rules", log.Fields{"rules": deviceRules.String()})
khenaidoo0458db62019-06-20 08:50:36 -04001447
khenaidoo442e7c72020-03-10 16:13:48 -04001448 // Update the devices
1449 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, nil)
1450
1451 // Wait for completion
1452 go func() {
1453 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001454 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
khenaidoo442e7c72020-03-10 16:13:48 -04001455 //TODO: Revert flow changes
1456 }
1457 }()
khenaidoo43c82122018-11-22 18:38:28 -05001458 }
khenaidoo19d7b632018-10-30 10:49:50 -04001459 return nil
1460}
1461
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001462func (agent *LogicalAgent) deleteFlowsOfGroup(ctx context.Context, groupID uint32) ([]*ofp.OfpFlowStats, error) {
1463 logger.Infow("Delete-flows-matching-group", log.Fields{"groupID": groupID})
1464 var flowsRemoved []*ofp.OfpFlowStats
1465 agent.flowLock.Lock()
1466 defer agent.flowLock.Unlock()
1467 for flowID, flowChunk := range agent.flows {
1468 if fu.FlowHasOutGroup(flowChunk.flow, groupID) {
1469 path := fmt.Sprintf("logical_flows/%s/%d", agent.logicalDeviceID, flowID)
1470 if err := agent.clusterDataProxy.Remove(ctx, path); err != nil {
1471 return nil, fmt.Errorf("couldnt-delete-flow-from-store-%s", path)
1472 }
1473 delete(agent.flows, flowID)
1474 flowsRemoved = append(flowsRemoved, flowChunk.flow)
1475 }
1476 }
1477 return flowsRemoved, nil
1478}
1479
Kent Hagerman2b216042020-04-03 18:28:56 -04001480func (agent *LogicalAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001481 logger.Debug("groupModify")
khenaidoo19d7b632018-10-30 10:49:50 -04001482 if groupMod == nil {
1483 return nil
1484 }
khenaidoo19d7b632018-10-30 10:49:50 -04001485
npujar1d86a522019-11-14 17:11:16 +05301486 groupID := groupMod.GroupId
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001487 agent.groupLock.RLock()
1488 groupChunk, ok := agent.groups[groupID]
1489 agent.groupLock.RUnlock()
1490 if !ok {
npujar1d86a522019-11-14 17:11:16 +05301491 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001492 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001493 //Don't let any other thread to make modifications to this group till all done here.
1494 groupChunk.lock.Lock()
1495 defer groupChunk.lock.Unlock()
npujar1d86a522019-11-14 17:11:16 +05301496 //replace existing group entry with new group definition
1497 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001498 deviceRules := fu.NewDeviceRules()
1499 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1500 fg := fu.NewFlowsAndGroups()
1501 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1502 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001503
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001504 logger.Debugw("rules", log.Fields{"rules-for-group-modify": deviceRules.String()})
1505 //update KV
1506 if err := agent.updateLogicalDeviceFlowGroup(ctx, groupEntry, groupChunk); err != nil {
1507 logger.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
1508 return err
khenaidoo19d7b632018-10-30 10:49:50 -04001509 }
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07001510
1511 // Update the devices
1512 respChnls := agent.updateFlowsAndGroupsOfDevice(ctx, deviceRules, &voltha.FlowMetadata{})
1513
1514 // Wait for completion
1515 go func() {
1516 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, respChnls...); res != nil {
1517 logger.Warnw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "errors": res})
1518 //TODO: Revert flow changes
1519 }
1520 }()
khenaidoo19d7b632018-10-30 10:49:50 -04001521 return nil
1522}
1523
1524// deleteLogicalPort removes the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001525func (agent *LogicalAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001526 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1527 return err
1528 }
1529 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001530
khenaidoo6e55d9e2019-12-12 18:26:26 -05001531 logicalDevice := agent.getLogicalDeviceWithoutLock()
1532
khenaidoo92e62c52018-10-03 14:02:54 -04001533 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001534 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001535 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001536 index = i
1537 break
1538 }
1539 }
1540 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001541 clonedPorts := clonePorts(logicalDevice.Ports)
1542 if index < len(clonedPorts)-1 {
1543 copy(clonedPorts[index:], clonedPorts[index+1:])
1544 }
1545 clonedPorts[len(clonedPorts)-1] = nil
1546 clonedPorts = clonedPorts[:len(clonedPorts)-1]
Girish Kumarf56a4682020-03-20 20:07:46 +00001547 logger.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001548 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001549 logger.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001550 return err
1551 }
khenaidoo820197c2020-02-13 16:35:33 -05001552
1553 // Remove the logical port from cache
1554 agent.deleteLogicalPortsFromMap([]uint32{lPort.DevicePortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001555 // Reset the logical device routes
1556 go func() {
1557 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001558 logger.Warnw("device-routes-not-ready", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001559 }
1560 }()
khenaidoo92e62c52018-10-03 14:02:54 -04001561 }
1562 return nil
khenaidoob9203542018-09-17 22:56:37 -04001563}
1564
khenaidoo0a822f92019-05-08 15:15:57 -04001565// deleteLogicalPorts removes the logical ports associated with that deviceId
Kent Hagerman2b216042020-04-03 18:28:56 -04001566func (agent *LogicalAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001567 logger.Debugw("deleting-logical-ports", log.Fields{"device-id": deviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001568 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1569 return err
1570 }
1571 defer agent.requestQueue.RequestComplete()
khenaidoo0a822f92019-05-08 15:15:57 -04001572
khenaidoo6e55d9e2019-12-12 18:26:26 -05001573 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo820197c2020-02-13 16:35:33 -05001574 lPortstoKeep := []*voltha.LogicalPort{}
1575 lPortsNoToDelete := []uint32{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001576 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301577 if logicalPort.DeviceId != deviceID {
khenaidoo820197c2020-02-13 16:35:33 -05001578 lPortstoKeep = append(lPortstoKeep, logicalPort)
1579 } else {
1580 lPortsNoToDelete = append(lPortsNoToDelete, logicalPort.DevicePortNo)
khenaidoo0a822f92019-05-08 15:15:57 -04001581 }
1582 }
Andrea Campanella09400bd2020-04-02 11:58:04 +02001583 logger.Debugw("deleted-logical-ports", log.Fields{"ports": lPortstoKeep})
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001584 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, lPortstoKeep); err != nil {
Andrea Campanella09400bd2020-04-02 11:58:04 +02001585 logger.Errorw("logical-device-update-failed", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001586 return err
1587 }
khenaidoo820197c2020-02-13 16:35:33 -05001588 // Remove the port from the cached logical ports set
1589 agent.deleteLogicalPortsFromMap(lPortsNoToDelete)
1590
1591 // Reset the logical device routes
1592 go func() {
1593 if err := agent.buildRoutes(context.Background()); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001594 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001595 }
1596 }()
khenaidoo0a822f92019-05-08 15:15:57 -04001597
1598 return nil
1599}
1600
khenaidoo19d7b632018-10-30 10:49:50 -04001601// enableLogicalPort enables the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001602func (agent *LogicalAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001603 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1604 return err
1605 }
1606 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001607
khenaidoo6e55d9e2019-12-12 18:26:26 -05001608 logicalDevice := agent.getLogicalDeviceWithoutLock()
1609
khenaidoo19d7b632018-10-30 10:49:50 -04001610 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001611 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301612 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001613 index = i
1614 break
1615 }
1616 }
1617 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001618 clonedPorts := clonePorts(logicalDevice.Ports)
1619 clonedPorts[index].OfpPort.Config = clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1620 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001621 }
npujar1d86a522019-11-14 17:11:16 +05301622 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001623}
1624
1625// disableLogicalPort disabled the logical port
Kent Hagerman2b216042020-04-03 18:28:56 -04001626func (agent *LogicalAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo442e7c72020-03-10 16:13:48 -04001627 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1628 return err
1629 }
1630 defer agent.requestQueue.RequestComplete()
khenaidoo19d7b632018-10-30 10:49:50 -04001631
1632 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001633 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001634 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001635 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301636 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001637 index = i
1638 break
1639 }
1640 }
1641 if index >= 0 {
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001642 clonedPorts := clonePorts(logicalDevice.Ports)
1643 clonedPorts[index].OfpPort.Config = (clonedPorts[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
1644 return agent.updateLogicalDevicePortsWithoutLock(ctx, logicalDevice, clonedPorts)
khenaidoo19d7b632018-10-30 10:49:50 -04001645 }
npujar1d86a522019-11-14 17:11:16 +05301646 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001647}
1648
Kent Hagerman2b216042020-04-03 18:28:56 -04001649func (agent *LogicalAgent) getPreCalculatedRoute(ingress, egress uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001650 logger.Debugw("ROUTE", log.Fields{"len": len(agent.deviceRoutes.Routes)})
khenaidoo820197c2020-02-13 16:35:33 -05001651 for routeLink, route := range agent.deviceRoutes.Routes {
Girish Kumarf56a4682020-03-20 20:07:46 +00001652 logger.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001653 if ingress == routeLink.Ingress && egress == routeLink.Egress {
khenaidoo820197c2020-02-13 16:35:33 -05001654 return route, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001655 }
1656 }
khenaidoo820197c2020-02-13 16:35:33 -05001657 return nil, status.Errorf(codes.FailedPrecondition, "no route from:%d to:%d", ingress, egress)
khenaidoo89b0e942018-10-21 21:11:33 -04001658}
1659
npujar1d86a522019-11-14 17:11:16 +05301660// GetRoute returns route
Kent Hagerman2b216042020-04-03 18:28:56 -04001661func (agent *LogicalAgent) GetRoute(ctx context.Context, ingressPortNo uint32, egressPortNo uint32) ([]route.Hop, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001662 logger.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo820197c2020-02-13 16:35:33 -05001663 routes := make([]route.Hop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001664
khenaidoo19d7b632018-10-30 10:49:50 -04001665 // Note: A port value of 0 is equivalent to a nil port
1666
khenaidoo89b0e942018-10-21 21:11:33 -04001667 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001668 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001669 logger.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo2c6a0992019-04-29 13:46:56 -04001670 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001671 //This is a trap on the NNI Port
khenaidoo820197c2020-02-13 16:35:33 -05001672 if len(agent.deviceRoutes.Routes) == 0 {
khenaidoo8f474192019-04-03 17:20:44 -04001673 // If there are no routes set (usually when the logical device has only NNI port(s), then just return an
Humera Kouser4ff89012019-08-25 19:01:51 -04001674 // route with same IngressHop and EgressHop
khenaidoo820197c2020-02-13 16:35:33 -05001675 hop := route.Hop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001676 routes = append(routes, hop)
1677 routes = append(routes, hop)
khenaidoo820197c2020-02-13 16:35:33 -05001678 return routes, nil
khenaidoo8f474192019-04-03 17:20:44 -04001679 }
khenaidoo89b0e942018-10-21 21:11:33 -04001680 //Return a 'half' route to make the flow decomposer logic happy
khenaidoo820197c2020-02-13 16:35:33 -05001681 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001682 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001683 routes = append(routes, route.Hop{}) // first hop is set to empty
1684 routes = append(routes, path[1])
1685 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001686 }
1687 }
khenaidoo787224a2020-04-16 18:08:47 -04001688 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001689 }
1690 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001691 var err error
1692 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001693 logger.Warnw("no-nni-port", log.Fields{"error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001694 return nil, err
khenaidoo2c6a0992019-04-29 13:46:56 -04001695 }
khenaidoo89b0e942018-10-21 21:11:33 -04001696 }
1697 //If ingress port is not specified (nil), it may be a wildcarded
1698 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1699 //in which case we need to create a half-route where only the egress
1700 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001701 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001702 // We can use the 2nd hop of any upstream route, so just find the first upstream:
khenaidoo820197c2020-02-13 16:35:33 -05001703 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001704 if agent.isNNIPort(routeLink.Egress) {
khenaidoo820197c2020-02-13 16:35:33 -05001705 routes = append(routes, route.Hop{}) // first hop is set to empty
1706 routes = append(routes, path[1])
1707 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001708 }
1709 }
khenaidoo787224a2020-04-16 18:08:47 -04001710 return nil, fmt.Errorf("no upstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001711 }
1712 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001713 if egressPortNo == 0 {
khenaidoo820197c2020-02-13 16:35:33 -05001714 for routeLink, path := range agent.deviceRoutes.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001715 if routeLink.Ingress == ingressPortNo {
khenaidoo820197c2020-02-13 16:35:33 -05001716 routes = append(routes, path[0])
1717 routes = append(routes, route.Hop{})
1718 return routes, nil
khenaidoo89b0e942018-10-21 21:11:33 -04001719 }
1720 }
khenaidoo787224a2020-04-16 18:08:47 -04001721 return nil, fmt.Errorf("no downstream route from:%d to:%d :%w", ingressPortNo, egressPortNo, route.ErrNoRoute)
khenaidoo89b0e942018-10-21 21:11:33 -04001722 }
khenaidoo89b0e942018-10-21 21:11:33 -04001723 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001724 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001725}
1726
khenaidoo3d3b8c22019-05-22 18:10:39 -04001727//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1728//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1729//device is already held. Therefore it is safe to retrieve the logical device without lock.
Kent Hagerman2b216042020-04-03 18:28:56 -04001730func (agent *LogicalAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
khenaidoo89b0e942018-10-21 21:11:33 -04001731 lPorts := make([]uint32, 0)
1732 var exclPort uint32
1733 if len(excludePort) == 1 {
1734 exclPort = excludePort[0]
1735 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001736 lDevice := agent.getLogicalDeviceWithoutLock()
1737 for _, port := range lDevice.Ports {
1738 if port.OfpPort.PortNo != exclPort {
1739 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001740 }
1741 }
1742 return lPorts
1743}
khenaidoo19d7b632018-10-30 10:49:50 -04001744
khenaidoo820197c2020-02-13 16:35:33 -05001745// GetDeviceRoutes returns device graph
Kent Hagerman2b216042020-04-03 18:28:56 -04001746func (agent *LogicalAgent) GetDeviceRoutes() *route.DeviceRoutes {
khenaidoo820197c2020-02-13 16:35:33 -05001747 return agent.deviceRoutes
khenaidoo19d7b632018-10-30 10:49:50 -04001748}
1749
khenaidoo820197c2020-02-13 16:35:33 -05001750//rebuildRoutes rebuilds the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001751func (agent *LogicalAgent) buildRoutes(ctx context.Context) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001752 logger.Debugf("building-routes", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001753 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1754 return err
1755 }
1756 defer agent.requestQueue.RequestComplete()
1757
khenaidoo820197c2020-02-13 16:35:33 -05001758 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001759 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001760 }
1761 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001762 lDevice := agent.getLogicalDeviceWithoutLock()
1763
khenaidoo820197c2020-02-13 16:35:33 -05001764 if err := agent.deviceRoutes.ComputeRoutes(ctx, lDevice.Ports); err != nil {
1765 return err
1766 }
1767 if err := agent.deviceRoutes.Print(); err != nil {
1768 return err
1769 }
1770
khenaidoo2c6a0992019-04-29 13:46:56 -04001771 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001772}
1773
khenaidoo820197c2020-02-13 16:35:33 -05001774//updateRoutes updates the device routes
Kent Hagerman2b216042020-04-03 18:28:56 -04001775func (agent *LogicalAgent) updateRoutes(ctx context.Context, lp *voltha.LogicalPort) error {
Girish Kumarf56a4682020-03-20 20:07:46 +00001776 logger.Debugw("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -04001777 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1778 return err
1779 }
1780 defer agent.requestQueue.RequestComplete()
1781
khenaidoo820197c2020-02-13 16:35:33 -05001782 if agent.deviceRoutes == nil {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001783 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.deviceMgr.getDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001784 }
khenaidoo820197c2020-02-13 16:35:33 -05001785 if err := agent.deviceRoutes.AddPort(ctx, lp, agent.logicalDevice.Ports); err != nil {
1786 return err
khenaidoo0a822f92019-05-08 15:15:57 -04001787 }
khenaidoo820197c2020-02-13 16:35:33 -05001788 if err := agent.deviceRoutes.Print(); err != nil {
1789 return err
1790 }
1791 return nil
khenaidoo0a822f92019-05-08 15:15:57 -04001792}
1793
khenaidoofc1314d2019-03-14 09:34:21 -04001794// diff go over two lists of logical ports and return what's new, what's changed and what's removed.
Kent Hagerman8ad29952020-04-21 11:48:02 -04001795func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts map[string]*voltha.LogicalPort) {
1796 newPorts = make(map[string]*voltha.LogicalPort, len(newList))
1797 changedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1798 deletedPorts = make(map[string]*voltha.LogicalPort, len(oldList))
1799
khenaidoofc1314d2019-03-14 09:34:21 -04001800 for _, n := range newList {
Kent Hagerman8ad29952020-04-21 11:48:02 -04001801 newPorts[n.Id] = n
1802 }
1803
1804 for _, o := range oldList {
1805 if n, have := newPorts[o.Id]; have {
1806 delete(newPorts, o.Id) // not new
1807 if !proto.Equal(n, o) {
1808 changedPorts[n.Id] = n // changed
khenaidoofc1314d2019-03-14 09:34:21 -04001809 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001810 } else {
1811 deletedPorts[o.Id] = o // deleted
khenaidoo2bc48282019-07-16 18:13:46 -04001812 }
khenaidoofc1314d2019-03-14 09:34:21 -04001813 }
Kent Hagerman8ad29952020-04-21 11:48:02 -04001814
1815 return newPorts, changedPorts, deletedPorts
khenaidoofc1314d2019-03-14 09:34:21 -04001816}
1817
Kent Hagerman8ad29952020-04-21 11:48:02 -04001818// portUpdated is invoked when a port is updated on the logical device
1819func (agent *LogicalAgent) portUpdated(prevPorts, currPorts []*voltha.LogicalPort) interface{} {
khenaidoofc1314d2019-03-14 09:34:21 -04001820 // Get the difference between the two list
Kent Hagerman8ad29952020-04-21 11:48:02 -04001821 newPorts, changedPorts, deletedPorts := diff(prevPorts, currPorts)
1822
khenaidoofc1314d2019-03-14 09:34:21 -04001823 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001824 for _, newP := range newPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001825 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001826 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001827 }
1828 for _, change := range changedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001829 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001830 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001831 }
1832 for _, del := range deletedPorts {
Kent Hagerman45a13e42020-04-13 12:23:50 -04001833 go agent.ldeviceMgr.SendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001834 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001835 }
1836
1837 return nil
1838}
1839
khenaidoo8f474192019-04-03 17:20:44 -04001840// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1841// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1842// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1843// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001844func (agent *LogicalAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001845 logger.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
Chaitrashree G S7849b322020-03-29 19:25:49 -04001846
khenaidoo442e7c72020-03-10 16:13:48 -04001847 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1848 return false, err
1849 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001850 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001851 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001852 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001853 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001854 }
khenaidoo442e7c72020-03-10 16:13:48 -04001855 agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001856
khenaidoofc1314d2019-03-14 09:34:21 -04001857 var portCap *ic.PortCapability
1858 var err error
1859 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301860 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001861 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001862 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001863 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001864
khenaidoo442e7c72020-03-10 16:13:48 -04001865 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1866 return false, err
1867 }
1868
1869 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001870 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1871 if agent.portExist(device, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001872 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001873 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001874 }
1875
khenaidoofc1314d2019-03-14 09:34:21 -04001876 portCap.Port.RootPort = true
1877 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1878 lp.DeviceId = device.Id
1879 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1880 lp.OfpPort.PortNo = port.PortNo
1881 lp.OfpPort.Name = lp.Id
1882 lp.DevicePortNo = port.PortNo
1883
khenaidoo6e55d9e2019-12-12 18:26:26 -05001884 ld := agent.getLogicalDeviceWithoutLock()
1885
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001886 clonedPorts := clonePorts(ld.Ports)
1887 if clonedPorts == nil {
1888 clonedPorts = make([]*voltha.LogicalPort, 0)
khenaidoofc1314d2019-03-14 09:34:21 -04001889 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001890 clonedPorts = append(clonedPorts, lp)
khenaidoofc1314d2019-03-14 09:34:21 -04001891
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001892 if err = agent.updateLogicalDevicePortsWithoutLock(ctx, ld, clonedPorts); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001893 logger.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001894 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001895 }
khenaidoo910204f2019-04-08 17:56:40 -04001896
khenaidoo820197c2020-02-13 16:35:33 -05001897 // Update the device routes with this new logical port
khenaidoo910204f2019-04-08 17:56:40 -04001898 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001899 go func() {
1900 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001901 logger.Warnw("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "logical-port": lp.OfpPort.PortNo, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001902 }
1903 }()
khenaidoo910204f2019-04-08 17:56:40 -04001904
khenaidoo8f474192019-04-03 17:20:44 -04001905 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001906}
1907
Kent Hagerman2b216042020-04-03 18:28:56 -04001908func (agent *LogicalAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001909 ldevice := agent.getLogicalDeviceWithoutLock()
1910 for _, lPort := range ldevice.Ports {
1911 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1912 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001913 }
1914 }
1915 return false
1916}
1917
khenaidoo8f474192019-04-03 17:20:44 -04001918// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1919// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1920// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1921// scenario. This also applies to the case where the port was already added.
Kent Hagerman2b216042020-04-03 18:28:56 -04001922func (agent *LogicalAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001923 logger.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001924 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
Girish Kumarf56a4682020-03-20 20:07:46 +00001925 logger.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
khenaidoo8f474192019-04-03 17:20:44 -04001926 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001927 }
khenaidoo442e7c72020-03-10 16:13:48 -04001928 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1929 return false, err
1930 }
1931
khenaidoo1ce37ad2019-03-24 22:07:24 -04001932 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001933 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo442e7c72020-03-10 16:13:48 -04001934 agent.requestQueue.RequestComplete()
khenaidoo8f474192019-04-03 17:20:44 -04001935 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001936 }
khenaidoo442e7c72020-03-10 16:13:48 -04001937 agent.requestQueue.RequestComplete()
khenaidoofc1314d2019-03-14 09:34:21 -04001938 var portCap *ic.PortCapability
1939 var err error
1940 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301941 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001942 logger.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001943 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001944 }
khenaidoo442e7c72020-03-10 16:13:48 -04001945 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
1946 return false, err
1947 }
1948 defer agent.requestQueue.RequestComplete()
khenaidoo1ce37ad2019-03-24 22:07:24 -04001949 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1950 if agent.portExist(childDevice, port) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001951 logger.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001952 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001953 }
khenaidoofc1314d2019-03-14 09:34:21 -04001954 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001955 ldevice := agent.getLogicalDeviceWithoutLock()
1956
Girish Kumarf56a4682020-03-20 20:07:46 +00001957 logger.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
npujar1d86a522019-11-14 17:11:16 +05301958 portCap.Port.RootPort = false
1959 portCap.Port.Id = port.Label
1960 portCap.Port.OfpPort.PortNo = port.PortNo
1961 portCap.Port.DeviceId = childDevice.Id
1962 portCap.Port.DevicePortNo = port.PortNo
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001963 clonedPorts := clonePorts(ldevice.Ports)
1964 if clonedPorts == nil {
1965 clonedPorts = make([]*voltha.LogicalPort, 0)
npujar1d86a522019-11-14 17:11:16 +05301966 }
Kent Hagermand9cc2e92019-11-04 13:28:15 -05001967 clonedPorts = append(clonedPorts, portCap.Port)
1968 if err := agent.updateLogicalDevicePortsWithoutLock(ctx, ldevice, clonedPorts); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301969 return false, err
1970 }
1971 // Update the device graph with this new logical port
1972 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
khenaidoo820197c2020-02-13 16:35:33 -05001973
1974 go func() {
1975 if err := agent.updateRoutes(context.Background(), clonedLP); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001976 logger.Warn("routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
khenaidoo820197c2020-02-13 16:35:33 -05001977 }
1978 }()
1979
npujar1d86a522019-11-14 17:11:16 +05301980 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001981}
1982
Kent Hagerman2b216042020-04-03 18:28:56 -04001983func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001984 logger.Debugw("packet-out", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001985 "packet": hex.EncodeToString(packet.Data),
1986 "inPort": packet.GetInPort(),
1987 })
khenaidoo68c930b2019-05-13 11:46:51 -04001988 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001989 //frame := packet.GetData()
1990 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301991 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
Girish Kumarf56a4682020-03-20 20:07:46 +00001992 logger.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001993 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001994}
1995
Kent Hagerman2b216042020-04-03 18:28:56 -04001996func (agent *LogicalAgent) packetIn(port uint32, transactionID string, packet []byte) {
Girish Kumarf56a4682020-03-20 20:07:46 +00001997 logger.Debugw("packet-in", log.Fields{
Matteo Scandolo360605d2019-11-05 18:29:17 -08001998 "port": port,
1999 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05302000 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08002001 })
khenaidoo68c930b2019-05-13 11:46:51 -04002002 packetIn := fu.MkPacketIn(port, packet)
Kent Hagerman45a13e42020-04-13 12:23:50 -04002003 agent.ldeviceMgr.SendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Girish Kumarf56a4682020-03-20 20:07:46 +00002004 logger.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05002005}
khenaidoo2c6a0992019-04-29 13:46:56 -04002006
Kent Hagerman2b216042020-04-03 18:28:56 -04002007func (agent *LogicalAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
khenaidoo2c6a0992019-04-29 13:46:56 -04002008 agent.lockLogicalPortsNo.Lock()
2009 defer agent.lockLogicalPortsNo.Unlock()
2010 if exist := agent.logicalPortsNo[portNo]; !exist {
2011 agent.logicalPortsNo[portNo] = nniPort
2012 }
2013}
2014
Kent Hagerman2b216042020-04-03 18:28:56 -04002015func (agent *LogicalAgent) deleteLogicalPortsFromMap(portsNo []uint32) {
khenaidoo820197c2020-02-13 16:35:33 -05002016 agent.lockLogicalPortsNo.Lock()
2017 defer agent.lockLogicalPortsNo.Unlock()
2018 for _, pNo := range portsNo {
2019 delete(agent.logicalPortsNo, pNo)
2020 }
2021}
2022
Kent Hagerman2b216042020-04-03 18:28:56 -04002023func (agent *LogicalAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
khenaidoo3d3b8c22019-05-22 18:10:39 -04002024 agent.lockLogicalPortsNo.Lock()
2025 defer agent.lockLogicalPortsNo.Unlock()
2026 for _, lp := range lps {
2027 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
2028 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
2029 }
2030 }
2031}
2032
Mahir Gunyeladdb66a2020-04-29 18:08:50 -07002033func (agent *LogicalAgent) loadFlows(ctx context.Context) {
2034 agent.flowLock.Lock()
2035 defer agent.flowLock.Unlock()
2036
2037 var flowList []*ofp.OfpFlowStats
2038 if err := agent.clusterDataProxy.List(ctx, "logical_flows/"+agent.logicalDeviceID, &flowList); err != nil {
2039 logger.Errorw("Failed-to-list-logicalflows-from-cluster-data-proxy", log.Fields{"error": err})
2040 return
2041 }
2042 for _, flow := range flowList {
2043 if flow != nil {
2044 flowsChunk := FlowChunk{
2045 flow: flow,
2046 }
2047 agent.flows[flow.Id] = &flowsChunk
2048 }
2049 }
2050}
2051
2052func (agent *LogicalAgent) loadMeters(ctx context.Context) {
2053 agent.meterLock.Lock()
2054 defer agent.meterLock.Unlock()
2055
2056 var meters []*ofp.OfpMeterEntry
2057 if err := agent.clusterDataProxy.List(ctx, "meters/"+agent.logicalDeviceID, &meters); err != nil {
2058 logger.Errorw("Failed-to-list-meters-from-proxy", log.Fields{"error": err})
2059 return
2060 }
2061 for _, meter := range meters {
2062 if meter.Config != nil {
2063 meterChunk := MeterChunk{
2064 meter: meter,
2065 }
2066 agent.meters[meter.Config.MeterId] = &meterChunk
2067 }
2068 }
2069}
2070
2071func (agent *LogicalAgent) loadGroups(ctx context.Context) {
2072 agent.groupLock.Lock()
2073 defer agent.groupLock.Unlock()
2074
2075 var groups []*ofp.OfpGroupEntry
2076 if err := agent.clusterDataProxy.List(ctx, "groups/"+agent.logicalDeviceID, &groups); err != nil {
2077 logger.Errorw("Failed-to-list-groups-from-proxy", log.Fields{"error": err})
2078 return
2079 }
2080 for _, group := range groups {
2081 if group.Desc != nil {
2082 groupChunk := GroupChunk{
2083 group: group,
2084 }
2085 agent.groups[group.Desc.GroupId] = &groupChunk
2086 }
2087 }
2088 logger.Infow("Groups-are-loaded-into-the-cache-from-store", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
2089}
2090
Kent Hagerman2b216042020-04-03 18:28:56 -04002091func (agent *LogicalAgent) isNNIPort(portNo uint32) bool {
khenaidoo2c6a0992019-04-29 13:46:56 -04002092 agent.lockLogicalPortsNo.RLock()
2093 defer agent.lockLogicalPortsNo.RUnlock()
2094 if exist := agent.logicalPortsNo[portNo]; exist {
2095 return agent.logicalPortsNo[portNo]
2096 }
2097 return false
2098}
2099
Kent Hagerman2b216042020-04-03 18:28:56 -04002100func (agent *LogicalAgent) getFirstNNIPort() (uint32, error) {
khenaidoo2c6a0992019-04-29 13:46:56 -04002101 agent.lockLogicalPortsNo.RLock()
2102 defer agent.lockLogicalPortsNo.RUnlock()
2103 for portNo, nni := range agent.logicalPortsNo {
2104 if nni {
2105 return portNo, nil
2106 }
2107 }
2108 return 0, status.Error(codes.NotFound, "No NNI port found")
2109}
Esin Karaman09959ae2019-11-29 13:59:58 +00002110
2111//GetNNIPorts returns NNI ports.
Kent Hagerman2b216042020-04-03 18:28:56 -04002112func (agent *LogicalAgent) GetNNIPorts() []uint32 {
Esin Karaman09959ae2019-11-29 13:59:58 +00002113 agent.lockLogicalPortsNo.RLock()
2114 defer agent.lockLogicalPortsNo.RUnlock()
2115 nniPorts := make([]uint32, 0)
2116 for portNo, nni := range agent.logicalPortsNo {
2117 if nni {
2118 nniPorts = append(nniPorts, portNo)
2119 }
2120 }
2121 return nniPorts
2122}