blob: 7274e9f0b0899d6567a97cb32515654cc3ed9b9c [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
khenaidoob9203542018-09-17 22:56:37 -040017package core
18
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
khenaidoo19d7b632018-10-30 10:49:50 -040022 "errors"
23 "fmt"
npujar1d86a522019-11-14 17:11:16 +053024 "reflect"
25 "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"
khenaidoo89b0e942018-10-21 21:11:33 -040031 "github.com/opencord/voltha-go/rw_core/graph"
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"
khenaidoob9203542018-09-17 22:56:37 -040040)
41
npujar1d86a522019-11-14 17:11:16 +053042// LogicalDeviceAgent represent attributes of logical device agent
khenaidoob9203542018-09-17 22:56:37 -040043type LogicalDeviceAgent struct {
npujar1d86a522019-11-14 17:11:16 +053044 logicalDeviceID string
45 rootDeviceID string
khenaidoo3306c992019-05-24 16:57:35 -040046 deviceMgr *DeviceManager
47 ldeviceMgr *LogicalDeviceManager
48 clusterDataProxy *model.Proxy
49 exitChannel chan int
50 deviceGraph *graph.DeviceGraph
51 flowProxy *model.Proxy
52 groupProxy *model.Proxy
Manikkaraj kb1a10922019-07-29 12:10:34 -040053 meterProxy *model.Proxy
khenaidoo3306c992019-05-24 16:57:35 -040054 ldProxy *model.Proxy
55 portProxies map[string]*model.Proxy
56 portProxiesLock sync.RWMutex
57 lockLogicalDevice sync.RWMutex
khenaidoo4c9e5592019-09-09 16:20:41 -040058 lockDeviceGraph sync.RWMutex
khenaidoo3306c992019-05-24 16:57:35 -040059 logicalPortsNo map[uint32]bool //value is true for NNI port
60 lockLogicalPortsNo sync.RWMutex
61 flowDecomposer *fd.FlowDecomposer
62 defaultTimeout int64
khenaidoo6e55d9e2019-12-12 18:26:26 -050063 logicalDevice *voltha.LogicalDevice
khenaidoob9203542018-09-17 22:56:37 -040064}
65
npujar1d86a522019-11-14 17:11:16 +053066func newLogicalDeviceAgent(id string, deviceID string, ldeviceMgr *LogicalDeviceManager,
Stephane Barbarie1ab43272018-12-08 21:42:13 -050067 deviceMgr *DeviceManager,
khenaidoo2c6a0992019-04-29 13:46:56 -040068 cdProxy *model.Proxy, timeout int64) *LogicalDeviceAgent {
khenaidoob9203542018-09-17 22:56:37 -040069 var agent LogicalDeviceAgent
70 agent.exitChannel = make(chan int, 1)
npujar1d86a522019-11-14 17:11:16 +053071 agent.logicalDeviceID = id
72 agent.rootDeviceID = deviceID
khenaidoob9203542018-09-17 22:56:37 -040073 agent.deviceMgr = deviceMgr
khenaidoo9a468962018-09-19 15:33:13 -040074 agent.clusterDataProxy = cdProxy
khenaidoob9203542018-09-17 22:56:37 -040075 agent.ldeviceMgr = ldeviceMgr
khenaidoo19d7b632018-10-30 10:49:50 -040076 agent.flowDecomposer = fd.NewFlowDecomposer(agent.deviceMgr)
khenaidoo92e62c52018-10-03 14:02:54 -040077 agent.lockLogicalDevice = sync.RWMutex{}
khenaidoofc1314d2019-03-14 09:34:21 -040078 agent.portProxies = make(map[string]*model.Proxy)
79 agent.portProxiesLock = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040080 agent.lockLogicalPortsNo = sync.RWMutex{}
khenaidoo4c9e5592019-09-09 16:20:41 -040081 agent.lockDeviceGraph = sync.RWMutex{}
khenaidoo2c6a0992019-04-29 13:46:56 -040082 agent.logicalPortsNo = make(map[uint32]bool)
khenaidoo2c6a0992019-04-29 13:46:56 -040083 agent.defaultTimeout = timeout
khenaidoob9203542018-09-17 22:56:37 -040084 return &agent
85}
86
khenaidoo4d4802d2018-10-04 21:59:49 -040087// start creates the logical device and add it to the data model
khenaidoo297cd252019-02-07 22:10:23 -050088func (agent *LogicalDeviceAgent) start(ctx context.Context, loadFromdB bool) error {
npujar1d86a522019-11-14 17:11:16 +053089 log.Infow("starting-logical_device-agent", log.Fields{"logicaldeviceId": agent.logicalDeviceID, "loadFromdB": loadFromdB})
khenaidoo297cd252019-02-07 22:10:23 -050090 var ld *voltha.LogicalDevice
Thomas Lee Se5a44012019-11-07 20:32:24 +053091 var err error
khenaidoo297cd252019-02-07 22:10:23 -050092 if !loadFromdB {
khenaidoo7e3d8f12019-08-02 16:06:30 -040093 //Build the logical device based on information retrieved from the device adapter
94 var switchCap *ic.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -050095 var err error
npujar1d86a522019-11-14 17:11:16 +053096 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
khenaidoo7e3d8f12019-08-02 16:06:30 -040097 log.Errorw("error-creating-logical-device", log.Fields{"error": err})
98 return err
99 }
npujar1d86a522019-11-14 17:11:16 +0530100 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500101
102 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
103 var datapathID uint64
npujar1d86a522019-11-14 17:11:16 +0530104 if datapathID, err = CreateDataPathID(agent.logicalDeviceID); err != nil {
khenaidoo297cd252019-02-07 22:10:23 -0500105 log.Errorw("error-creating-datapath-id", log.Fields{"error": err})
106 return err
107 }
108 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400109 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
110 log.Debugw("Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
111 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500112 ld.Flows = &ofp.Flows{Items: nil}
113 ld.FlowGroups = &ofp.FlowGroups{Items: nil}
khenaidoo49085352020-01-13 19:15:43 -0500114 ld.Ports = []*voltha.LogicalPort{}
khenaidoo297cd252019-02-07 22:10:23 -0500115
khenaidoo297cd252019-02-07 22:10:23 -0500116 agent.lockLogicalDevice.Lock()
khenaidoo297cd252019-02-07 22:10:23 -0500117 // Save the logical device
Thomas Lee Se5a44012019-11-07 20:32:24 +0530118 added, err := agent.clusterDataProxy.AddWithID(ctx, "/logical_devices", ld.Id, ld, "")
119 if err != nil {
120 log.Errorw("failed-to-save-logical-devices-to-cluster-proxy", log.Fields{"error": err})
121 agent.lockLogicalDevice.Unlock()
122 return err
123 }
124 if added == nil {
npujar1d86a522019-11-14 17:11:16 +0530125 log.Errorw("failed-to-add-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500126 } else {
npujar1d86a522019-11-14 17:11:16 +0530127 log.Debugw("logicaldevice-created", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo297cd252019-02-07 22:10:23 -0500128 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500129
130 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
khenaidoo297cd252019-02-07 22:10:23 -0500131 agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400132
khenaidoo3d3b8c22019-05-22 18:10:39 -0400133 // TODO: Set the logical ports in a separate call once the port update issue is fixed.
npujar1d86a522019-11-14 17:11:16 +0530134 go func() {
135 err := agent.setupLogicalPorts(ctx)
136 if err != nil {
137 log.Errorw("unable-to-setup-logical-ports", log.Fields{"error": err})
138 }
139 }()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400140
khenaidoo297cd252019-02-07 22:10:23 -0500141 } else {
142 // load from dB - the logical may not exist at this time. On error, just return and the calling function
143 // will destroy this agent.
khenaidoo6e55d9e2019-12-12 18:26:26 -0500144 agent.lockLogicalDevice.Lock()
npujar467fe752020-01-16 20:17:45 +0530145 logicalDevice, err := agent.clusterDataProxy.Get(ctx, "/logical_devices/"+agent.logicalDeviceID, 0, true, "")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530146 if err != nil {
147 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
148 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500149 ld, ok := logicalDevice.(*voltha.LogicalDevice)
150 if !ok {
151 agent.lockLogicalDevice.Unlock()
152 return status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
khenaidoo297cd252019-02-07 22:10:23 -0500153 }
khenaidoo8c3303d2019-02-13 14:59:39 -0500154 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530155 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400156
khenaidoo6e55d9e2019-12-12 18:26:26 -0500157 // Update the last data
158 agent.logicalDevice = proto.Clone(ld).(*voltha.LogicalDevice)
159
160 agent.lockLogicalDevice.Unlock()
161
khenaidoo3d3b8c22019-05-22 18:10:39 -0400162 // Setup the local list of logical ports
163 agent.addLogicalPortsToMap(ld.Ports)
khenaidoob9203542018-09-17 22:56:37 -0400164 }
khenaidoo92e62c52018-10-03 14:02:54 -0400165 agent.lockLogicalDevice.Lock()
khenaidoo3d3b8c22019-05-22 18:10:39 -0400166 defer agent.lockLogicalDevice.Unlock()
khenaidoofc1314d2019-03-14 09:34:21 -0400167
Thomas Lee Se5a44012019-11-07 20:32:24 +0530168 agent.flowProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400169 ctx,
npujar1d86a522019-11-14 17:11:16 +0530170 fmt.Sprintf("/logical_devices/%s/flows", agent.logicalDeviceID),
khenaidoo19d7b632018-10-30 10:49:50 -0400171 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530172 if err != nil {
173 log.Errorw("failed-to-create-flow-proxy", log.Fields{"error": err})
174 return err
175 }
176 agent.meterProxy, err = agent.clusterDataProxy.CreateProxy(
Manikkaraj kb1a10922019-07-29 12:10:34 -0400177 ctx,
npujar1d86a522019-11-14 17:11:16 +0530178 fmt.Sprintf("/logical_devices/%s/meters", agent.logicalDeviceID),
Manikkaraj kb1a10922019-07-29 12:10:34 -0400179 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530180 if err != nil {
181 log.Errorw("failed-to-create-meter-proxy", log.Fields{"error": err})
182 return err
183 }
184 agent.groupProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400185 ctx,
npujar1d86a522019-11-14 17:11:16 +0530186 fmt.Sprintf("/logical_devices/%s/flow_groups", agent.logicalDeviceID),
khenaidoo19d7b632018-10-30 10:49:50 -0400187 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530188 if err != nil {
189 log.Errorw("failed-to-create-group-proxy", log.Fields{"error": err})
190 return err
191 }
192 agent.ldProxy, err = agent.clusterDataProxy.CreateProxy(
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400193 ctx,
npujar1d86a522019-11-14 17:11:16 +0530194 fmt.Sprintf("/logical_devices/%s", agent.logicalDeviceID),
khenaidoofc1314d2019-03-14 09:34:21 -0400195 false)
Thomas Lee Se5a44012019-11-07 20:32:24 +0530196 if err != nil {
197 log.Errorw("failed-to-create-logical-device-proxy", log.Fields{"error": err})
198 return err
199 }
khenaidoofc1314d2019-03-14 09:34:21 -0400200 // TODO: Use a port proxy once the POST_ADD is fixed
khenaidoo3d3b8c22019-05-22 18:10:39 -0400201 if agent.ldProxy != nil {
npujar9a30c702019-11-14 17:06:39 +0530202 agent.ldProxy.RegisterCallback(model.PostUpdate, agent.portUpdated)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400203 } else {
npujar1d86a522019-11-14 17:11:16 +0530204 log.Errorw("logical-device-proxy-null", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400205 return status.Error(codes.Internal, "logical-device-proxy-null")
206 }
khenaidoobcf205b2019-01-25 22:21:14 -0500207
khenaidoo4c9e5592019-09-09 16:20:41 -0400208 // Setup the device graph - run it in its own routine
209 if loadFromdB {
npujar467fe752020-01-16 20:17:45 +0530210 go agent.generateDeviceGraph(context.Background())
khenaidoo4c9e5592019-09-09 16:20:41 -0400211 }
khenaidoob9203542018-09-17 22:56:37 -0400212 return nil
213}
214
khenaidoo4d4802d2018-10-04 21:59:49 -0400215// stop stops the logical devuce agent. This removes the logical device from the data model.
Thomas Lee Se5a44012019-11-07 20:32:24 +0530216func (agent *LogicalDeviceAgent) stop(ctx context.Context) error {
khenaidoo4d4802d2018-10-04 21:59:49 -0400217 log.Info("stopping-logical_device-agent")
218 agent.lockLogicalDevice.Lock()
219 defer agent.lockLogicalDevice.Unlock()
khenaidoo8c3303d2019-02-13 14:59:39 -0500220
khenaidoo4d4802d2018-10-04 21:59:49 -0400221 //Remove the logical device from the model
Thomas Lee Se5a44012019-11-07 20:32:24 +0530222 if removed, err := agent.clusterDataProxy.Remove(ctx, "/logical_devices/"+agent.logicalDeviceID, ""); err != nil {
223 log.Errorw("failed-to-remove-device", log.Fields{"error": err})
224 return err
225 } else if removed == nil {
npujar1d86a522019-11-14 17:11:16 +0530226 log.Errorw("failed-to-remove-logical-device", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo4d4802d2018-10-04 21:59:49 -0400227 } else {
npujar1d86a522019-11-14 17:11:16 +0530228 log.Debugw("logicaldevice-removed", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo4d4802d2018-10-04 21:59:49 -0400229 }
230 agent.exitChannel <- 1
231 log.Info("logical_device-agent-stopped")
Thomas Lee Se5a44012019-11-07 20:32:24 +0530232 return nil
khenaidoo4d4802d2018-10-04 21:59:49 -0400233}
234
khenaidoo6e55d9e2019-12-12 18:26:26 -0500235// GetLogicalDevice returns the latest logical device data
236func (agent *LogicalDeviceAgent) GetLogicalDevice() *voltha.LogicalDevice {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400237 agent.lockLogicalDevice.RLock()
238 defer agent.lockLogicalDevice.RUnlock()
khenaidoo6e55d9e2019-12-12 18:26:26 -0500239
240 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400241}
242
npujar1d86a522019-11-14 17:11:16 +0530243// ListLogicalDeviceFlows returns logical device flows
khenaidoo6e55d9e2019-12-12 18:26:26 -0500244func (agent *LogicalDeviceAgent) ListLogicalDeviceFlows() *ofp.Flows {
khenaidoodd237172019-05-27 16:37:17 -0400245 log.Debug("ListLogicalDeviceFlows")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500246
247 logicalDevice := agent.GetLogicalDevice()
248 if logicalDevice.Flows == nil {
249 return &ofp.Flows{}
khenaidoodd237172019-05-27 16:37:17 -0400250 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500251 return (proto.Clone(logicalDevice.Flows)).(*ofp.Flows)
khenaidoodd237172019-05-27 16:37:17 -0400252}
253
npujar1d86a522019-11-14 17:11:16 +0530254// ListLogicalDeviceMeters returns logical device meters
khenaidoo6e55d9e2019-12-12 18:26:26 -0500255func (agent *LogicalDeviceAgent) ListLogicalDeviceMeters() *ofp.Meters {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400256 log.Debug("ListLogicalDeviceMeters")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500257
258 logicalDevice := agent.GetLogicalDevice()
259 if logicalDevice.Meters == nil {
260 return &ofp.Meters{}
Manikkaraj kb1a10922019-07-29 12:10:34 -0400261 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500262 return (proto.Clone(logicalDevice.Meters)).(*ofp.Meters)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400263}
264
npujar1d86a522019-11-14 17:11:16 +0530265// ListLogicalDeviceFlowGroups returns logical device flow groups
khenaidoo6e55d9e2019-12-12 18:26:26 -0500266func (agent *LogicalDeviceAgent) ListLogicalDeviceFlowGroups() *ofp.FlowGroups {
khenaidoodd237172019-05-27 16:37:17 -0400267 log.Debug("ListLogicalDeviceFlowGroups")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500268
269 logicalDevice := agent.GetLogicalDevice()
270 if logicalDevice.FlowGroups == nil {
271 return &ofp.FlowGroups{}
khenaidoodd237172019-05-27 16:37:17 -0400272 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500273 return (proto.Clone(logicalDevice.FlowGroups)).(*ofp.FlowGroups)
khenaidoodd237172019-05-27 16:37:17 -0400274}
275
npujar1d86a522019-11-14 17:11:16 +0530276// ListLogicalDevicePorts returns logical device ports
khenaidoo6e55d9e2019-12-12 18:26:26 -0500277func (agent *LogicalDeviceAgent) ListLogicalDevicePorts() *voltha.LogicalPorts {
khenaidoo1ce37ad2019-03-24 22:07:24 -0400278 log.Debug("ListLogicalDevicePorts")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500279 logicalDevice := agent.GetLogicalDevice()
280 lPorts := make([]*voltha.LogicalPort, 0)
281 lPorts = append(lPorts, logicalDevice.Ports...)
282 return &voltha.LogicalPorts{Items: lPorts}
khenaidoo19d7b632018-10-30 10:49:50 -0400283}
284
khenaidoo4c9e5592019-09-09 16:20:41 -0400285//updateLogicalDeviceFlowsWithoutLock updates the logical device with the latest flows in the model.
npujar467fe752020-01-16 20:17:45 +0530286func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowsWithoutLock(ctx context.Context, flows *ofp.Flows) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500287 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400288
khenaidoo6e55d9e2019-12-12 18:26:26 -0500289 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
290 ld.Flows = flows
291
npujar467fe752020-01-16 20:17:45 +0530292 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400293 log.Errorw("error-updating-logical-device-with-flows", log.Fields{"error": err})
294 return err
khenaidoo43c82122018-11-22 18:38:28 -0500295 }
khenaidoo43c82122018-11-22 18:38:28 -0500296 return nil
297}
298
khenaidoo4c9e5592019-09-09 16:20:41 -0400299//updateLogicalDeviceMetersWithoutLock updates the logical device with the meters info
npujar467fe752020-01-16 20:17:45 +0530300func (agent *LogicalDeviceAgent) updateLogicalDeviceMetersWithoutLock(ctx context.Context, meters *ofp.Meters) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500301 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400302
khenaidoo6e55d9e2019-12-12 18:26:26 -0500303 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
304 ld.Meters = meters
305
npujar467fe752020-01-16 20:17:45 +0530306 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400307 log.Errorw("error-updating-logical-device-with-meters", log.Fields{"error": err})
308 return err
Manikkaraj kb1a10922019-07-29 12:10:34 -0400309 }
310 return nil
311}
312
khenaidoo4c9e5592019-09-09 16:20:41 -0400313//updateLogicalDeviceFlowGroupsWithoutLock updates the logical device with the flow groups
npujar467fe752020-01-16 20:17:45 +0530314func (agent *LogicalDeviceAgent) updateLogicalDeviceFlowGroupsWithoutLock(ctx context.Context, flowGroups *ofp.FlowGroups) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500315 ld := agent.getLogicalDeviceWithoutLock()
khenaidoo4c9e5592019-09-09 16:20:41 -0400316
khenaidoo6e55d9e2019-12-12 18:26:26 -0500317 log.Debugw("logical-device-before", log.Fields{"lports": len(ld.Ports)})
318 ld.FlowGroups = flowGroups
319
npujar467fe752020-01-16 20:17:45 +0530320 if err := agent.updateLogicalDeviceWithoutLock(ctx, ld); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400321 log.Errorw("error-updating-logical-device-with-flowgroups", log.Fields{"error": err})
322 return err
khenaidoo43c82122018-11-22 18:38:28 -0500323 }
khenaidoo43c82122018-11-22 18:38:28 -0500324 return nil
325}
326
khenaidoo6e55d9e2019-12-12 18:26:26 -0500327// getLogicalDeviceWithoutLock returns a cloned logical device to a function that already holds the agent lock.
328func (agent *LogicalDeviceAgent) getLogicalDeviceWithoutLock() *voltha.LogicalDevice {
khenaidoo92e62c52018-10-03 14:02:54 -0400329 log.Debug("getLogicalDeviceWithoutLock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500330 return proto.Clone(agent.logicalDevice).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400331}
332
npujar467fe752020-01-16 20:17:45 +0530333func (agent *LogicalDeviceAgent) updateLogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
khenaidoo2c6a0992019-04-29 13:46:56 -0400334 log.Debugw("updateLogicalPort", log.Fields{"deviceId": device.Id, "port": port})
335 var err error
336 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530337 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400338 return err
339 }
340 agent.addLogicalPortToMap(port.PortNo, true)
341 } else if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530342 if _, err = agent.addUNILogicalPort(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400343 return err
344 }
345 agent.addLogicalPortToMap(port.PortNo, false)
346 } else {
347 // Update the device graph to ensure all routes on the logical device have been calculated
npujar467fe752020-01-16 20:17:45 +0530348 if err = agent.updateRoutes(ctx, device, port); err != nil {
khenaidoo2c6a0992019-04-29 13:46:56 -0400349 log.Errorw("failed-to-update-routes", log.Fields{"deviceId": device.Id, "port": port, "error": err})
350 return err
351 }
352 }
353 return nil
354}
355
khenaidoo3d3b8c22019-05-22 18:10:39 -0400356// setupLogicalPorts is invoked once the logical device has been created and is ready to get ports
357// added to it. While the logical device was being created we could have received requests to add
358// NNI and UNI ports which were discarded. Now is the time to add them if needed
359func (agent *LogicalDeviceAgent) setupLogicalPorts(ctx context.Context) error {
npujar1d86a522019-11-14 17:11:16 +0530360 log.Infow("setupLogicalPorts", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400361 // First add any NNI ports which could have been missing
npujar467fe752020-01-16 20:17:45 +0530362 if err := agent.setupNNILogicalPorts(ctx, agent.rootDeviceID); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530363 log.Errorw("error-setting-up-NNI-ports", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400364 return err
365 }
366
367 // Now, set up the UNI ports if needed.
npujar467fe752020-01-16 20:17:45 +0530368 children, err := agent.deviceMgr.getAllChildDevices(ctx, agent.rootDeviceID)
npujar1d86a522019-11-14 17:11:16 +0530369 if err != nil {
370 log.Errorw("error-getting-child-devices", log.Fields{"error": err, "deviceId": agent.rootDeviceID})
khenaidoo3d3b8c22019-05-22 18:10:39 -0400371 return err
npujar1d86a522019-11-14 17:11:16 +0530372 }
373 responses := make([]coreutils.Response, 0)
374 for _, child := range children.Items {
375 response := coreutils.NewResponse()
376 responses = append(responses, response)
377 go func(child *voltha.Device) {
npujar467fe752020-01-16 20:17:45 +0530378 if err = agent.setupUNILogicalPorts(ctx, child); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530379 log.Error("setting-up-UNI-ports-failed", log.Fields{"deviceID": child.Id})
380 response.Error(status.Errorf(codes.Internal, "UNI-ports-setup-failed: %s", child.Id))
381 }
382 response.Done()
383 }(child)
384 }
385 // Wait for completion
386 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
387 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo3d3b8c22019-05-22 18:10:39 -0400388 }
389 return nil
390}
391
khenaidoofc1314d2019-03-14 09:34:21 -0400392// setupNNILogicalPorts creates an NNI port on the logical device that represents an NNI interface on a root device
npujar1d86a522019-11-14 17:11:16 +0530393func (agent *LogicalDeviceAgent) setupNNILogicalPorts(ctx context.Context, deviceID string) error {
394 log.Infow("setupNNILogicalPorts-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoob9203542018-09-17 22:56:37 -0400395 // Build the logical device based on information retrieved from the device adapter
khenaidoofc1314d2019-03-14 09:34:21 -0400396 var err error
397
398 var device *voltha.Device
npujar467fe752020-01-16 20:17:45 +0530399 if device, err = agent.deviceMgr.GetDevice(ctx, deviceID); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530400 log.Errorw("error-retrieving-device", log.Fields{"error": err, "deviceId": deviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400401 return err
402 }
403
404 //Get UNI port number
khenaidoofc1314d2019-03-14 09:34:21 -0400405 for _, port := range device.Ports {
406 if port.Type == voltha.Port_ETHERNET_NNI {
npujar467fe752020-01-16 20:17:45 +0530407 if _, err = agent.addNNILogicalPort(ctx, device, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400408 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400409 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400410 agent.addLogicalPortToMap(port.PortNo, true)
khenaidoofc1314d2019-03-14 09:34:21 -0400411 }
412 }
khenaidoofc1314d2019-03-14 09:34:21 -0400413 return err
414}
415
khenaidoo171b98e2019-10-31 11:48:15 -0400416// updatePortState updates the port state of the device
npujar467fe752020-01-16 20:17:45 +0530417func (agent *LogicalDeviceAgent) updatePortState(ctx context.Context, deviceID string, portNo uint32, operStatus voltha.OperStatus_Types) error {
npujar1d86a522019-11-14 17:11:16 +0530418 log.Infow("updatePortState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "portNo": portNo, "state": operStatus})
khenaidoo171b98e2019-10-31 11:48:15 -0400419 agent.lockLogicalDevice.Lock()
420 defer agent.lockLogicalDevice.Unlock()
421 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500422 cloned := agent.getLogicalDeviceWithoutLock()
423 for idx, lPort := range cloned.Ports {
npujar1d86a522019-11-14 17:11:16 +0530424 if lPort.DeviceId == deviceID && lPort.DevicePortNo == portNo {
npujar1d86a522019-11-14 17:11:16 +0530425 if operStatus == voltha.OperStatus_ACTIVE {
426 cloned.Ports[idx].OfpPort.Config = cloned.Ports[idx].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
427 cloned.Ports[idx].OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
428 } else {
429 cloned.Ports[idx].OfpPort.Config = cloned.Ports[idx].OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
430 cloned.Ports[idx].OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
431 }
432 // Update the logical device
npujar467fe752020-01-16 20:17:45 +0530433 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530434 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
435 return err
436 }
437 return nil
438 }
439 }
440 return status.Errorf(codes.NotFound, "port-%d-not-exist", portNo)
khenaidoo171b98e2019-10-31 11:48:15 -0400441}
442
khenaidoo3ab34882019-05-02 21:33:30 -0400443// updatePortsState updates the ports state related to the device
kesavandbc2d1622020-01-21 00:42:01 -0500444func (agent *LogicalDeviceAgent) updatePortsState(ctx context.Context, device *voltha.Device, state voltha.OperStatus_Types) error {
npujar1d86a522019-11-14 17:11:16 +0530445 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo3ab34882019-05-02 21:33:30 -0400446 agent.lockLogicalDevice.Lock()
447 defer agent.lockLogicalDevice.Unlock()
448 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500449 cloned := agent.getLogicalDeviceWithoutLock()
npujar1d86a522019-11-14 17:11:16 +0530450 for _, lport := range cloned.Ports {
451 if lport.DeviceId == device.Id {
kesavandbc2d1622020-01-21 00:42:01 -0500452 if state == voltha.OperStatus_ACTIVE {
npujar1d86a522019-11-14 17:11:16 +0530453 lport.OfpPort.Config = lport.OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
454 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LIVE)
kesavandbc2d1622020-01-21 00:42:01 -0500455 } else {
npujar1d86a522019-11-14 17:11:16 +0530456 lport.OfpPort.Config = lport.OfpPort.Config | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
457 lport.OfpPort.State = uint32(ofp.OfpPortState_OFPPS_LINK_DOWN)
khenaidoo3ab34882019-05-02 21:33:30 -0400458 }
kesavandbc2d1622020-01-21 00:42:01 -0500459
khenaidoo3ab34882019-05-02 21:33:30 -0400460 }
npujar1d86a522019-11-14 17:11:16 +0530461 }
462 // Updating the logical device will trigger the poprt change events to be populated to the controller
npujar467fe752020-01-16 20:17:45 +0530463 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530464 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
465 return err
khenaidoo3ab34882019-05-02 21:33:30 -0400466 }
467 return nil
468}
469
khenaidoofc1314d2019-03-14 09:34:21 -0400470// setupUNILogicalPorts creates a UNI port on the logical device that represents a child UNI interface
471func (agent *LogicalDeviceAgent) setupUNILogicalPorts(ctx context.Context, childDevice *voltha.Device) error {
npujar1d86a522019-11-14 17:11:16 +0530472 log.Infow("setupUNILogicalPort", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoofc1314d2019-03-14 09:34:21 -0400473 // Build the logical device based on information retrieved from the device adapter
khenaidoob9203542018-09-17 22:56:37 -0400474 var err error
khenaidoo59ef7be2019-06-21 12:40:28 -0400475 var added bool
khenaidoo19d7b632018-10-30 10:49:50 -0400476 //Get UNI port number
khenaidoo19d7b632018-10-30 10:49:50 -0400477 for _, port := range childDevice.Ports {
478 if port.Type == voltha.Port_ETHERNET_UNI {
npujar467fe752020-01-16 20:17:45 +0530479 if added, err = agent.addUNILogicalPort(ctx, childDevice, port); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -0400480 log.Errorw("error-adding-UNI-port", log.Fields{"error": err})
khenaidoofc1314d2019-03-14 09:34:21 -0400481 }
khenaidoo59ef7be2019-06-21 12:40:28 -0400482 if added {
483 agent.addLogicalPortToMap(port.PortNo, false)
484 }
khenaidoo19d7b632018-10-30 10:49:50 -0400485 }
486 }
khenaidoofc1314d2019-03-14 09:34:21 -0400487 return err
khenaidoo92e62c52018-10-03 14:02:54 -0400488}
489
khenaidoo0a822f92019-05-08 15:15:57 -0400490// deleteAllLogicalPorts deletes all logical ports associated with this device
npujar467fe752020-01-16 20:17:45 +0530491func (agent *LogicalDeviceAgent) deleteAllLogicalPorts(ctx context.Context, device *voltha.Device) error {
npujar1d86a522019-11-14 17:11:16 +0530492 log.Infow("updatePortsState-start", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400493 agent.lockLogicalDevice.Lock()
494 defer agent.lockLogicalDevice.Unlock()
495 // Get the latest logical device info
khenaidoo6e55d9e2019-12-12 18:26:26 -0500496 ld := agent.getLogicalDeviceWithoutLock()
497
npujar1d86a522019-11-14 17:11:16 +0530498 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
499 updateLogicalPorts := []*voltha.LogicalPort{}
500 for _, lport := range cloned.Ports {
501 if lport.DeviceId != device.Id {
502 updateLogicalPorts = append(updateLogicalPorts, lport)
503 }
504 }
505 if len(updateLogicalPorts) < len(cloned.Ports) {
506 cloned.Ports = updateLogicalPorts
507 // Updating the logical device will trigger the poprt change events to be populated to the controller
npujar467fe752020-01-16 20:17:45 +0530508 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530509 log.Warnw("logical-device-update-failed", log.Fields{"ldeviceId": agent.logicalDeviceID, "error": err})
510 return err
511 }
khenaidoo0a822f92019-05-08 15:15:57 -0400512 } else {
npujar1d86a522019-11-14 17:11:16 +0530513 log.Debugw("no-change-required", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -0400514 }
515 return nil
516}
517
khenaidoo92e62c52018-10-03 14:02:54 -0400518//updateLogicalDeviceWithoutLock updates the model with the logical device. It clones the logicaldevice before saving it
npujar467fe752020-01-16 20:17:45 +0530519func (agent *LogicalDeviceAgent) updateLogicalDeviceWithoutLock(ctx context.Context, logicalDevice *voltha.LogicalDevice) error {
520 updateCtx := context.WithValue(ctx, model.RequestTimestamp, time.Now().UnixNano())
Thomas Lee Se5a44012019-11-07 20:32:24 +0530521 afterUpdate, err := agent.clusterDataProxy.Update(updateCtx, "/logical_devices/"+agent.logicalDeviceID, logicalDevice, false, "")
522 if err != nil {
523 log.Errorw("failed-to-update-logical-devices-to-cluster-proxy", log.Fields{"error": err})
524 return err
525 }
khenaidoo92e62c52018-10-03 14:02:54 -0400526 if afterUpdate == nil {
npujar1d86a522019-11-14 17:11:16 +0530527 return status.Errorf(codes.Internal, "failed-updating-logical-device:%s", agent.logicalDeviceID)
khenaidoo92e62c52018-10-03 14:02:54 -0400528 }
khenaidoo6e55d9e2019-12-12 18:26:26 -0500529 agent.logicalDevice = (proto.Clone(logicalDevice)).(*voltha.LogicalDevice)
khenaidoo92e62c52018-10-03 14:02:54 -0400530 return nil
531}
532
khenaidoo4c9e5592019-09-09 16:20:41 -0400533//generateDeviceGraphIfNeeded generates the device graph if the logical device has been updated since the last time
534//that device graph was generated.
npujar467fe752020-01-16 20:17:45 +0530535func (agent *LogicalDeviceAgent) generateDeviceGraphIfNeeded(ctx context.Context) error {
khenaidoo6e55d9e2019-12-12 18:26:26 -0500536 ld := agent.GetLogicalDevice()
npujar1d86a522019-11-14 17:11:16 +0530537 agent.lockDeviceGraph.Lock()
538 defer agent.lockDeviceGraph.Unlock()
539 if agent.deviceGraph != nil && agent.deviceGraph.IsUpToDate(ld) {
540 return nil
541 }
542 log.Debug("Generation of device graph required")
npujar467fe752020-01-16 20:17:45 +0530543 agent.generateDeviceGraph(ctx)
khenaidoo4c9e5592019-09-09 16:20:41 -0400544 return nil
545}
546
khenaidoo19d7b632018-10-30 10:49:50 -0400547//updateFlowTable updates the flow table of that logical device
548func (agent *LogicalDeviceAgent) updateFlowTable(ctx context.Context, flow *ofp.OfpFlowMod) error {
549 log.Debug("updateFlowTable")
550 if flow == nil {
551 return nil
552 }
npujar467fe752020-01-16 20:17:45 +0530553 if err := agent.generateDeviceGraphIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400554 return err
555 }
khenaidoo19d7b632018-10-30 10:49:50 -0400556 switch flow.GetCommand() {
557 case ofp.OfpFlowModCommand_OFPFC_ADD:
npujar467fe752020-01-16 20:17:45 +0530558 return agent.flowAdd(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400559 case ofp.OfpFlowModCommand_OFPFC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530560 return agent.flowDelete(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400561 case ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT:
npujar467fe752020-01-16 20:17:45 +0530562 return agent.flowDeleteStrict(ctx, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400563 case ofp.OfpFlowModCommand_OFPFC_MODIFY:
564 return agent.flowModify(flow)
565 case ofp.OfpFlowModCommand_OFPFC_MODIFY_STRICT:
566 return agent.flowModifyStrict(flow)
567 }
568 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530569 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, flow.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400570}
571
572//updateGroupTable updates the group table of that logical device
573func (agent *LogicalDeviceAgent) updateGroupTable(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
574 log.Debug("updateGroupTable")
575 if groupMod == nil {
576 return nil
577 }
npujar467fe752020-01-16 20:17:45 +0530578 if err := agent.generateDeviceGraphIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400579 return err
580 }
khenaidoo19d7b632018-10-30 10:49:50 -0400581 switch groupMod.GetCommand() {
582 case ofp.OfpGroupModCommand_OFPGC_ADD:
npujar467fe752020-01-16 20:17:45 +0530583 return agent.groupAdd(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400584 case ofp.OfpGroupModCommand_OFPGC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530585 return agent.groupDelete(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400586 case ofp.OfpGroupModCommand_OFPGC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530587 return agent.groupModify(ctx, groupMod)
khenaidoo19d7b632018-10-30 10:49:50 -0400588 }
589 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530590 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, groupMod.GetCommand())
khenaidoo19d7b632018-10-30 10:49:50 -0400591}
592
Manikkaraj kb1a10922019-07-29 12:10:34 -0400593// updateMeterTable updates the meter table of that logical device
594func (agent *LogicalDeviceAgent) updateMeterTable(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
595 log.Debug("updateMeterTable")
596 if meterMod == nil {
597 return nil
598 }
npujar467fe752020-01-16 20:17:45 +0530599 if err := agent.generateDeviceGraphIfNeeded(ctx); err != nil {
khenaidoo4c9e5592019-09-09 16:20:41 -0400600 return err
601 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400602 switch meterMod.GetCommand() {
603 case ofp.OfpMeterModCommand_OFPMC_ADD:
npujar467fe752020-01-16 20:17:45 +0530604 return agent.meterAdd(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400605 case ofp.OfpMeterModCommand_OFPMC_DELETE:
npujar467fe752020-01-16 20:17:45 +0530606 return agent.meterDelete(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400607 case ofp.OfpMeterModCommand_OFPMC_MODIFY:
npujar467fe752020-01-16 20:17:45 +0530608 return agent.meterModify(ctx, meterMod)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400609 }
610 return status.Errorf(codes.Internal,
npujar1d86a522019-11-14 17:11:16 +0530611 "unhandled-command: lDeviceId:%s, command:%s", agent.logicalDeviceID, meterMod.GetCommand())
Manikkaraj kb1a10922019-07-29 12:10:34 -0400612
613}
614
npujar467fe752020-01-16 20:17:45 +0530615func (agent *LogicalDeviceAgent) meterAdd(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400616 log.Debugw("meterAdd", log.Fields{"metermod": *meterMod})
617 if meterMod == nil {
618 return nil
619 }
620 log.Debug("Waiting for logical device lock!!")
621 agent.lockLogicalDevice.Lock()
622 defer agent.lockLogicalDevice.Unlock()
623 log.Debug("Acquired logical device lock")
khenaidoo6e55d9e2019-12-12 18:26:26 -0500624 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400625
626 var meters []*ofp.OfpMeterEntry
627 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
628 meters = lDevice.Meters.Items
629 }
630 log.Debugw("Available meters", log.Fields{"meters": meters})
631
632 for _, meter := range meters {
633 if meterMod.MeterId == meter.Config.MeterId {
634 log.Infow("Meter-already-exists", log.Fields{"meter": *meterMod})
635 return nil
636 }
637 }
638
639 meterEntry := fu.MeterEntryFromMeterMod(meterMod)
640 meters = append(meters, meterEntry)
641 //Update model
npujar467fe752020-01-16 20:17:45 +0530642 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, &ofp.Meters{Items: meters}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530643 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400644 return err
645 }
646 log.Debugw("Meter-added-successfully", log.Fields{"Added-meter": meterEntry, "updated-meters": lDevice.Meters})
647 return nil
648}
649
npujar467fe752020-01-16 20:17:45 +0530650func (agent *LogicalDeviceAgent) meterDelete(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400651 log.Debug("meterDelete", log.Fields{"meterMod": *meterMod})
652 if meterMod == nil {
653 return nil
654 }
655 agent.lockLogicalDevice.Lock()
656 defer agent.lockLogicalDevice.Unlock()
657
khenaidoo6e55d9e2019-12-12 18:26:26 -0500658 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400659
660 var meters []*ofp.OfpMeterEntry
661 var flows []*ofp.OfpFlowStats
662 updatedFlows := make([]*ofp.OfpFlowStats, 0)
663 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
664 meters = lDevice.Meters.Items
665 }
Manikkaraj kb1a10922019-07-29 12:10:34 -0400666
667 changedMeter := false
668 changedFow := false
669 log.Debugw("Available meters", log.Fields{"meters": meters})
670 for index, meter := range meters {
671 if meterMod.MeterId == meter.Config.MeterId {
672 flows = lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +0530673 changedFow, updatedFlows = agent.getUpdatedFlowsAfterDeletebyMeterID(flows, meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400674 meters = append(meters[:index], meters[index+1:]...)
675 log.Debugw("Meter has been deleted", log.Fields{"meter": meter, "index": index})
676 changedMeter = true
677 break
678 }
679 }
680 if changedMeter {
681 //Update model
682 metersToUpdate := &ofp.Meters{}
683 if lDevice.Meters != nil {
684 metersToUpdate = &ofp.Meters{Items: meters}
685 }
npujar467fe752020-01-16 20:17:45 +0530686 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530687 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400688 return err
689 }
690 log.Debug("Meter-deleted-from-DB-successfully", log.Fields{"updatedMeters": metersToUpdate, "no-of-meter": len(metersToUpdate.Items)})
691
692 }
693 if changedFow {
694 //Update model
npujar467fe752020-01-16 20:17:45 +0530695 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: updatedFlows}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530696 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400697 return err
698 }
699 log.Debug("Flows-associated-with-meter-deleted-from-DB-successfully",
700 log.Fields{"updated-no-of-flows": len(updatedFlows), "meter": meterMod.MeterId})
701 }
702 log.Debugw("meterDelete success", log.Fields{"meterID": meterMod.MeterId})
703 return nil
704}
705
npujar467fe752020-01-16 20:17:45 +0530706func (agent *LogicalDeviceAgent) meterModify(ctx context.Context, meterMod *ofp.OfpMeterMod) error {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400707 log.Debug("meterModify")
708 if meterMod == nil {
709 return nil
710 }
711 agent.lockLogicalDevice.Lock()
712 defer agent.lockLogicalDevice.Unlock()
713
khenaidoo6e55d9e2019-12-12 18:26:26 -0500714 lDevice := agent.getLogicalDeviceWithoutLock()
Manikkaraj kb1a10922019-07-29 12:10:34 -0400715
716 var meters []*ofp.OfpMeterEntry
717 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
718 meters = lDevice.Meters.Items
719 }
720 changedMeter := false
721 for index, meter := range meters {
722 if meterMod.MeterId == meter.Config.MeterId {
723 newmeterEntry := fu.MeterEntryFromMeterMod(meterMod)
724 newmeterEntry.Stats.FlowCount = meter.Stats.FlowCount
725 meters[index] = newmeterEntry
726 changedMeter = true
727 log.Debugw("Found meter, replaced with new meter", log.Fields{"old meter": meter, "new meter": newmeterEntry})
728 break
729 }
730 }
731 if changedMeter {
732 //Update model
733 metersToUpdate := &ofp.Meters{}
734 if lDevice.Meters != nil {
735 metersToUpdate = &ofp.Meters{Items: meters}
736 }
npujar467fe752020-01-16 20:17:45 +0530737 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530738 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400739 return err
740 }
741 log.Debugw("meter-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
742 return nil
743 }
744
745 log.Errorw("Meter not found ", log.Fields{"meter": meterMod})
npujar1d86a522019-11-14 17:11:16 +0530746 return fmt.Errorf("no-logical-device-present:%d", meterMod.MeterId)
Manikkaraj kb1a10922019-07-29 12:10:34 -0400747
748}
749
npujar1d86a522019-11-14 17:11:16 +0530750func (agent *LogicalDeviceAgent) getUpdatedFlowsAfterDeletebyMeterID(flows []*ofp.OfpFlowStats, meterID uint32) (bool, []*ofp.OfpFlowStats) {
751 log.Infow("Delete flows matching meter", log.Fields{"meter": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400752 changed := false
753 //updatedFlows := make([]*ofp.OfpFlowStats, 0)
754 for index := len(flows) - 1; index >= 0; index-- {
npujar1d86a522019-11-14 17:11:16 +0530755 if mID := fu.GetMeterIdFromFlow(flows[index]); mID != 0 && mID == meterID {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400756 log.Debugw("Flow to be deleted", log.Fields{"flow": flows[index], "index": index})
757 flows = append(flows[:index], flows[index+1:]...)
758 changed = true
759 }
760 }
761 return changed, flows
762}
763
764func (agent *LogicalDeviceAgent) updateFlowCountOfMeterStats(modCommand *ofp.OfpFlowMod, meters []*ofp.OfpMeterEntry, flow *ofp.OfpFlowStats) bool {
765
766 flowCommand := modCommand.GetCommand()
npujar1d86a522019-11-14 17:11:16 +0530767 meterID := fu.GetMeterIdFromFlow(flow)
768 log.Debugw("Meter-id-in-flow-mod", log.Fields{"meterId": meterID})
769 if meterID == 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400770 log.Debugw("No meter present in the flow", log.Fields{"flow": *flow})
771 return false
772 }
773 if meters == nil {
774 log.Debug("No meters present in logical device")
775 return false
776 }
777 changedMeter := false
778 for _, meter := range meters {
npujar1d86a522019-11-14 17:11:16 +0530779 if meterID == meter.Config.MeterId { // Found meter in Logicaldevice
Manikkaraj kb1a10922019-07-29 12:10:34 -0400780 if flowCommand == ofp.OfpFlowModCommand_OFPFC_ADD {
npujar1d86a522019-11-14 17:11:16 +0530781 meter.Stats.FlowCount++
Manikkaraj kb1a10922019-07-29 12:10:34 -0400782 changedMeter = true
783 } else if flowCommand == ofp.OfpFlowModCommand_OFPFC_DELETE_STRICT {
npujar1d86a522019-11-14 17:11:16 +0530784 meter.Stats.FlowCount--
Manikkaraj kb1a10922019-07-29 12:10:34 -0400785 changedMeter = true
786 }
npujar1d86a522019-11-14 17:11:16 +0530787 log.Debugw("Found meter, updated meter flow stats", log.Fields{" meterId": meterID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400788 break
789 }
790 }
791 return changedMeter
792}
793
khenaidoo19d7b632018-10-30 10:49:50 -0400794//flowAdd adds a flow to the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +0530795func (agent *LogicalDeviceAgent) flowAdd(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo4c9e5592019-09-09 16:20:41 -0400796 log.Debugw("flowAdd", log.Fields{"flow": mod})
khenaidoo19d7b632018-10-30 10:49:50 -0400797 if mod == nil {
798 return nil
799 }
khenaidoo92e62c52018-10-03 14:02:54 -0400800 agent.lockLogicalDevice.Lock()
801 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -0400802
khenaidoo6e55d9e2019-12-12 18:26:26 -0500803 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400804
805 var flows []*ofp.OfpFlowStats
Manikkaraj kb1a10922019-07-29 12:10:34 -0400806 var meters []*ofp.OfpMeterEntry
807 var flow *ofp.OfpFlowStats
808
khenaidoo19d7b632018-10-30 10:49:50 -0400809 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
810 flows = lDevice.Flows.Items
811 }
812
Manikkaraj kb1a10922019-07-29 12:10:34 -0400813 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
814 meters = lDevice.Meters.Items
815 }
khenaidoo2c6a0992019-04-29 13:46:56 -0400816 updatedFlows := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400817 changed := false
Manikkaraj kb1a10922019-07-29 12:10:34 -0400818 updated := false
khenaidoo19d7b632018-10-30 10:49:50 -0400819 checkOverlap := (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_CHECK_OVERLAP)) != 0
820 if checkOverlap {
821 if overlapped := fu.FindOverlappingFlows(flows, mod); len(overlapped) != 0 {
822 // TODO: should this error be notified other than being logged?
npujar1d86a522019-11-14 17:11:16 +0530823 log.Warnw("overlapped-flows", log.Fields{"logicaldeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400824 } else {
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400825 // Add flow
Manikkaraj kb1a10922019-07-29 12:10:34 -0400826 flow = fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400827 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400828 updatedFlows = append(updatedFlows, flow)
khenaidoo19d7b632018-10-30 10:49:50 -0400829 changed = true
830 }
831 } else {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400832 flow = fu.FlowStatsEntryFromFlowModMessage(mod)
khenaidoo19d7b632018-10-30 10:49:50 -0400833 idx := fu.FindFlows(flows, flow)
834 if idx >= 0 {
835 oldFlow := flows[idx]
836 if (mod.Flags & uint32(ofp.OfpFlowModFlags_OFPFF_RESET_COUNTS)) != 0 {
837 flow.ByteCount = oldFlow.ByteCount
838 flow.PacketCount = oldFlow.PacketCount
839 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400840 if !reflect.DeepEqual(oldFlow, flow) {
841 flows[idx] = flow
842 updatedFlows = append(updatedFlows, flow)
843 changed = true
844 updated = true
845 }
846 } else {
khenaidoo19d7b632018-10-30 10:49:50 -0400847 flows = append(flows, flow)
khenaidoo2c6a0992019-04-29 13:46:56 -0400848 updatedFlows = append(updatedFlows, flow)
849 changed = true
khenaidoo19d7b632018-10-30 10:49:50 -0400850 }
khenaidoo19d7b632018-10-30 10:49:50 -0400851 }
khenaidoo4c9e5592019-09-09 16:20:41 -0400852 log.Debugw("flowAdd-changed", log.Fields{"changed": changed})
853
khenaidoo19d7b632018-10-30 10:49:50 -0400854 if changed {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400855 var flowMetadata voltha.FlowMetadata
856 if err := agent.GetMeterConfig(updatedFlows, meters, &flowMetadata); err != nil { // This should never happen,meters should be installed before flow arrives
857 log.Error("Meter-referred-in-flows-not-present")
858 return err
859 }
npujar467fe752020-01-16 20:17:45 +0530860 deviceRules := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: updatedFlows}, *lDevice.FlowGroups)
khenaidoo0458db62019-06-20 08:50:36 -0400861 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
862
npujar467fe752020-01-16 20:17:45 +0530863 if err := agent.addDeviceFlowsAndGroups(ctx, deviceRules, &flowMetadata); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530864 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo2c6a0992019-04-29 13:46:56 -0400865 return err
866 }
867
khenaidoo19d7b632018-10-30 10:49:50 -0400868 // Update model
npujar467fe752020-01-16 20:17:45 +0530869 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530870 log.Errorw("db-flow-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400871 return err
872 }
Matt Jeanneret518b5a42019-10-29 10:30:46 -0400873 if !updated {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400874 changedMeterStats := agent.updateFlowCountOfMeterStats(mod, meters, flow)
875 metersToUpdate := &ofp.Meters{}
876 if lDevice.Meters != nil {
877 metersToUpdate = &ofp.Meters{Items: meters}
878 }
879 if changedMeterStats {
880 //Update model
npujar467fe752020-01-16 20:17:45 +0530881 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530882 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400883 return err
884 }
885 log.Debugw("meter-stats-updated-in-DB-successfully", log.Fields{"updated_meters": meters})
886
887 }
888 }
889
khenaidoo19d7b632018-10-30 10:49:50 -0400890 }
khenaidoo19d7b632018-10-30 10:49:50 -0400891 return nil
892}
893
npujar1d86a522019-11-14 17:11:16 +0530894// GetMeterConfig returns meter config
Manikkaraj kb1a10922019-07-29 12:10:34 -0400895func (agent *LogicalDeviceAgent) GetMeterConfig(flows []*ofp.OfpFlowStats, meters []*ofp.OfpMeterEntry, metadata *voltha.FlowMetadata) error {
896 m := make(map[uint32]bool)
897 for _, flow := range flows {
npujar1d86a522019-11-14 17:11:16 +0530898 if flowMeterID := fu.GetMeterIdFromFlow(flow); flowMeterID != 0 && !m[flowMeterID] {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400899 foundMeter := false
900 // Meter is present in the flow , Get from logical device
901 for _, meter := range meters {
902 if flowMeterID == meter.Config.MeterId {
903 metadata.Meters = append(metadata.Meters, meter.Config)
904 log.Debugw("Found meter in logical device",
905 log.Fields{"meterID": flowMeterID, "meter-band": meter.Config})
906 m[flowMeterID] = true
907 foundMeter = true
908 break
909 }
910 }
911 if !foundMeter {
912 log.Errorw("Meter-referred-by-flow-is-not-found-in-logicaldevice",
npujar1d86a522019-11-14 17:11:16 +0530913 log.Fields{"meterID": flowMeterID, "Available-meters": meters, "flow": *flow})
Manikkaraj kb1a10922019-07-29 12:10:34 -0400914 return errors.New("Meter-referred-by-flow-is-not-found-in-logicaldevice")
915 }
916 }
917 }
918 log.Debugw("meter-bands-for-flows", log.Fields{"flows": len(flows), "metadata": metadata})
919 return nil
920
921}
922
khenaidoo19d7b632018-10-30 10:49:50 -0400923//flowDelete deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +0530924func (agent *LogicalDeviceAgent) flowDelete(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -0400925 log.Debug("flowDelete")
926 if mod == nil {
927 return nil
928 }
929 agent.lockLogicalDevice.Lock()
930 defer agent.lockLogicalDevice.Unlock()
931
khenaidoo6e55d9e2019-12-12 18:26:26 -0500932 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -0400933
Manikkaraj kb1a10922019-07-29 12:10:34 -0400934 var meters []*ofp.OfpMeterEntry
935 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000936 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -0400937
938 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
939 flows = lDevice.Flows.Items
940 }
941
942 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
943 meters = lDevice.Meters.Items
944 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +0000945
946 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
947 flowGroups = lDevice.FlowGroups.Items
948 }
949
khenaidoo19d7b632018-10-30 10:49:50 -0400950 //build a list of what to keep vs what to delete
951 toKeep := make([]*ofp.OfpFlowStats, 0)
khenaidoo0458db62019-06-20 08:50:36 -0400952 toDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -0400953 for _, f := range flows {
khenaidoo0458db62019-06-20 08:50:36 -0400954 // Check whether the flow and the flowmod matches
955 if fu.FlowMatch(f, fu.FlowStatsEntryFromFlowModMessage(mod)) {
956 toDelete = append(toDelete, f)
957 continue
958 }
959 // Check wild card match
khenaidoo19d7b632018-10-30 10:49:50 -0400960 if !fu.FlowMatchesMod(f, mod) {
961 toKeep = append(toKeep, f)
khenaidoo0458db62019-06-20 08:50:36 -0400962 } else {
963 toDelete = append(toDelete, f)
khenaidoo19d7b632018-10-30 10:49:50 -0400964 }
965 }
966
npujar1d86a522019-11-14 17:11:16 +0530967 log.Debugw("flowDelete", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "toKeep": len(toKeep), "toDelete": toDelete})
khenaidoo0458db62019-06-20 08:50:36 -0400968
khenaidoo19d7b632018-10-30 10:49:50 -0400969 //Update flows
khenaidoo0458db62019-06-20 08:50:36 -0400970 if len(toDelete) > 0 {
Manikkaraj kb1a10922019-07-29 12:10:34 -0400971 var flowMetadata voltha.FlowMetadata
972 if err := agent.GetMeterConfig(toDelete, meters, &flowMetadata); err != nil { // This should never happen
973 log.Error("Meter-referred-in-flows-not-present")
974 return errors.New("Meter-referred-in-flows-not-present")
975 }
npujar467fe752020-01-16 20:17:45 +0530976 deviceRules := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: toDelete}, ofp.FlowGroups{Items: flowGroups})
khenaidoo0458db62019-06-20 08:50:36 -0400977 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
978
npujar467fe752020-01-16 20:17:45 +0530979 if err := agent.deleteDeviceFlowsAndGroups(ctx, deviceRules, &flowMetadata); err != nil {
npujar1d86a522019-11-14 17:11:16 +0530980 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -0400981 return err
982 }
983
npujar467fe752020-01-16 20:17:45 +0530984 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: toKeep}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +0530985 log.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -0400986 return err
987 }
988 }
989
990 //TODO: send announcement on delete
991 return nil
992}
993
npujar467fe752020-01-16 20:17:45 +0530994func (agent *LogicalDeviceAgent) addDeviceFlowsAndGroups(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
npujar1d86a522019-11-14 17:11:16 +0530995 log.Debugw("addDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceID, "deviceRules": deviceRules, "flowMetadata": flowMetadata})
khenaidoo19d7b632018-10-30 10:49:50 -0400996
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500997 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +0530998 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500999 response := coreutils.NewResponse()
1000 responses = append(responses, response)
1001 go func(deviceId string, value *fu.FlowsAndGroups) {
npujar467fe752020-01-16 20:17:45 +05301002 if err := agent.deviceMgr.addFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001003 log.Errorw("flow-add-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001004 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001005 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001006 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301007 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -04001008 }
khenaidoo0458db62019-06-20 08:50:36 -04001009 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001010 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001011 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -04001012 }
khenaidoo0458db62019-06-20 08:50:36 -04001013 return nil
1014}
khenaidoo19d7b632018-10-30 10:49:50 -04001015
npujar467fe752020-01-16 20:17:45 +05301016func (agent *LogicalDeviceAgent) deleteDeviceFlowsAndGroups(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
npujar1d86a522019-11-14 17:11:16 +05301017 log.Debugw("deleteDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001018
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001019 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301020 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001021 response := coreutils.NewResponse()
1022 responses = append(responses, response)
1023 go func(deviceId string, value *fu.FlowsAndGroups) {
npujar467fe752020-01-16 20:17:45 +05301024 if err := agent.deviceMgr.deleteFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001025 log.Error("flow-delete-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001026 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001027 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001028 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301029 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001030 }
1031 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001032 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001033 return status.Errorf(codes.Aborted, "errors-%s", res)
1034 }
1035 return nil
1036}
1037
npujar467fe752020-01-16 20:17:45 +05301038func (agent *LogicalDeviceAgent) updateDeviceFlowsAndGroups(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *voltha.FlowMetadata) error {
npujar1d86a522019-11-14 17:11:16 +05301039 log.Debugw("updateDeviceFlowsAndGroups", log.Fields{"logicalDeviceID": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -04001040
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001041 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +05301042 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001043 response := coreutils.NewResponse()
1044 responses = append(responses, response)
1045 go func(deviceId string, value *fu.FlowsAndGroups) {
npujar467fe752020-01-16 20:17:45 +05301046 if err := agent.deviceMgr.updateFlowsAndGroups(ctx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001047 log.Error("flow-update-failed", log.Fields{"deviceID": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001048 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -04001049 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001050 response.Done()
npujar1d86a522019-11-14 17:11:16 +05301051 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -04001052 }
1053 // Wait for completion
Kent Hagerman8da2f1e2019-11-25 17:28:09 -05001054 if res := coreutils.WaitForNilOrErrorResponses(agent.defaultTimeout, responses...); res != nil {
khenaidoo0458db62019-06-20 08:50:36 -04001055 return status.Errorf(codes.Aborted, "errors-%s", res)
khenaidoo19d7b632018-10-30 10:49:50 -04001056 }
1057 return nil
1058}
1059
1060//flowDeleteStrict deletes a flow from the flow table of that logical device
npujar467fe752020-01-16 20:17:45 +05301061func (agent *LogicalDeviceAgent) flowDeleteStrict(ctx context.Context, mod *ofp.OfpFlowMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001062 log.Debug("flowDeleteStrict")
1063 if mod == nil {
1064 return nil
1065 }
1066 agent.lockLogicalDevice.Lock()
1067 defer agent.lockLogicalDevice.Unlock()
1068
khenaidoo6e55d9e2019-12-12 18:26:26 -05001069 lDevice := agent.getLogicalDeviceWithoutLock()
1070
Manikkaraj kb1a10922019-07-29 12:10:34 -04001071 var meters []*ofp.OfpMeterEntry
1072 var flows []*ofp.OfpFlowStats
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001073 var flowGroups []*ofp.OfpGroupEntry
Manikkaraj kb1a10922019-07-29 12:10:34 -04001074 if lDevice.Meters != nil && lDevice.Meters.Items != nil {
1075 meters = lDevice.Meters.Items
1076 }
1077 if lDevice.Flows != nil && lDevice.Flows.Items != nil {
1078 flows = lDevice.Flows.Items
1079 }
Esin Karamanfc3b1af2020-01-29 16:52:00 +00001080 if lDevice.FlowGroups != nil && lDevice.FlowGroups.Items != nil {
1081 flowGroups = lDevice.FlowGroups.Items
1082 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001083
1084 changedFlow := false
1085 changedMeter := false
khenaidoo68c930b2019-05-13 11:46:51 -04001086 flow := fu.FlowStatsEntryFromFlowModMessage(mod)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001087 flowsToDelete := make([]*ofp.OfpFlowStats, 0)
khenaidoo19d7b632018-10-30 10:49:50 -04001088 idx := fu.FindFlows(flows, flow)
1089 if idx >= 0 {
Gamze Abaka6e4ac162019-10-21 11:10:10 +00001090 changedMeter = agent.updateFlowCountOfMeterStats(mod, meters, flows[idx])
Manikkaraj kb1a10922019-07-29 12:10:34 -04001091 flowsToDelete = append(flowsToDelete, flows[idx])
khenaidoo19d7b632018-10-30 10:49:50 -04001092 flows = append(flows[:idx], flows[idx+1:]...)
Manikkaraj kb1a10922019-07-29 12:10:34 -04001093 changedFlow = true
khenaidoo19d7b632018-10-30 10:49:50 -04001094 } else {
npujar1d86a522019-11-14 17:11:16 +05301095 return fmt.Errorf("Cannot delete flow - %s", flow)
khenaidoo19d7b632018-10-30 10:49:50 -04001096 }
Manikkaraj kb1a10922019-07-29 12:10:34 -04001097 if changedMeter {
1098 //Update model
1099 metersToUpdate := &ofp.Meters{}
1100 if lDevice.Meters != nil {
1101 metersToUpdate = &ofp.Meters{Items: meters}
1102 }
npujar467fe752020-01-16 20:17:45 +05301103 if err := agent.updateLogicalDeviceMetersWithoutLock(ctx, metersToUpdate); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301104 log.Errorw("db-meter-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
Manikkaraj kb1a10922019-07-29 12:10:34 -04001105 return err
1106 }
khenaidoo19d7b632018-10-30 10:49:50 -04001107
Manikkaraj kb1a10922019-07-29 12:10:34 -04001108 }
1109 if changedFlow {
1110 var flowMetadata voltha.FlowMetadata
1111 if err := agent.GetMeterConfig(flowsToDelete, meters, &flowMetadata); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301112 log.Error("meter-referred-in-flows-not-present")
Manikkaraj kb1a10922019-07-29 12:10:34 -04001113 return err
1114 }
npujar467fe752020-01-16 20:17:45 +05301115 deviceRules := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flowsToDelete}, ofp.FlowGroups{Items: flowGroups})
khenaidoo0458db62019-06-20 08:50:36 -04001116 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1117
npujar467fe752020-01-16 20:17:45 +05301118 if err := agent.deleteDeviceFlowsAndGroups(ctx, deviceRules, &flowMetadata); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301119 log.Errorw("failure-deleting-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001120 return err
1121 }
1122
npujar467fe752020-01-16 20:17:45 +05301123 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301124 log.Errorw("cannot-update-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001125 return err
1126 }
1127 }
khenaidoo19d7b632018-10-30 10:49:50 -04001128 return nil
1129}
1130
1131//flowModify modifies a flow from the flow table of that logical device
1132func (agent *LogicalDeviceAgent) flowModify(mod *ofp.OfpFlowMod) error {
1133 return errors.New("flowModify not implemented")
1134}
1135
1136//flowModifyStrict deletes a flow from the flow table of that logical device
1137func (agent *LogicalDeviceAgent) flowModifyStrict(mod *ofp.OfpFlowMod) error {
1138 return errors.New("flowModifyStrict not implemented")
1139}
1140
npujar467fe752020-01-16 20:17:45 +05301141func (agent *LogicalDeviceAgent) groupAdd(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001142 log.Debug("groupAdd")
1143 if groupMod == nil {
1144 return nil
1145 }
1146 agent.lockLogicalDevice.Lock()
1147 defer agent.lockLogicalDevice.Unlock()
1148
khenaidoo6e55d9e2019-12-12 18:26:26 -05001149 lDevice := agent.getLogicalDeviceWithoutLock()
1150
khenaidoo19d7b632018-10-30 10:49:50 -04001151 groups := lDevice.FlowGroups.Items
khenaidoo19d7b632018-10-30 10:49:50 -04001152 if fu.FindGroup(groups, groupMod.GroupId) == -1 {
khenaidoo68c930b2019-05-13 11:46:51 -04001153 groups = append(groups, fu.GroupEntryFromGroupMod(groupMod))
khenaidoo0458db62019-06-20 08:50:36 -04001154
Esin Karaman2ea59212019-12-06 11:41:58 +00001155 deviceRules := fu.NewDeviceRules()
1156 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1157 fg := fu.NewFlowsAndGroups()
1158 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1159 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
1160
1161 log.Debugw("rules", log.Fields{"rules for group-add": deviceRules.String()})
npujar467fe752020-01-16 20:17:45 +05301162 if err := agent.addDeviceFlowsAndGroups(ctx, deviceRules, &voltha.FlowMetadata{}); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301163 log.Errorw("failure-updating-device-flows", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001164 return err
1165 }
1166
npujar467fe752020-01-16 20:17:45 +05301167 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301168 log.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001169 return err
1170 }
1171 } else {
npujar1d86a522019-11-14 17:11:16 +05301172 return fmt.Errorf("Groups %d already present", groupMod.GroupId)
khenaidoo19d7b632018-10-30 10:49:50 -04001173 }
khenaidoo19d7b632018-10-30 10:49:50 -04001174 return nil
1175}
1176
npujar467fe752020-01-16 20:17:45 +05301177func (agent *LogicalDeviceAgent) groupDelete(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001178 log.Debug("groupDelete")
1179 if groupMod == nil {
1180 return nil
1181 }
1182 agent.lockLogicalDevice.Lock()
1183 defer agent.lockLogicalDevice.Unlock()
1184
khenaidoo6e55d9e2019-12-12 18:26:26 -05001185 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001186 groups := lDevice.FlowGroups.Items
1187 flows := lDevice.Flows.Items
npujar1d86a522019-11-14 17:11:16 +05301188 var groupsChanged bool
khenaidoo19d7b632018-10-30 10:49:50 -04001189 flowsChanged := false
npujar1d86a522019-11-14 17:11:16 +05301190 groupID := groupMod.GroupId
1191 if groupID == uint32(ofp.OfpGroup_OFPG_ALL) {
khenaidoo19d7b632018-10-30 10:49:50 -04001192 //TODO we must delete all flows that point to this group and
1193 //signal controller as requested by flow's flag
1194 groups = []*ofp.OfpGroupEntry{}
1195 groupsChanged = true
1196 } else {
npujar1d86a522019-11-14 17:11:16 +05301197 idx := fu.FindGroup(groups, groupID)
1198 if idx == -1 {
khenaidoo19d7b632018-10-30 10:49:50 -04001199 return nil // Valid case
khenaidoo19d7b632018-10-30 10:49:50 -04001200 }
npujar1d86a522019-11-14 17:11:16 +05301201 flowsChanged, flows = fu.FlowsDeleteByGroupId(flows, groupID)
1202 groups = append(groups[:idx], groups[idx+1:]...)
1203 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001204 }
khenaidoo0458db62019-06-20 08:50:36 -04001205 if flowsChanged || groupsChanged {
npujar467fe752020-01-16 20:17:45 +05301206 deviceRules := agent.flowDecomposer.DecomposeRules(ctx, agent, ofp.Flows{Items: flows}, ofp.FlowGroups{Items: groups})
khenaidoo0458db62019-06-20 08:50:36 -04001207 log.Debugw("rules", log.Fields{"rules": deviceRules.String()})
1208
npujar467fe752020-01-16 20:17:45 +05301209 if err := agent.updateDeviceFlowsAndGroups(ctx, deviceRules, nil); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301210 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001211 return err
1212 }
1213 }
1214
khenaidoo43c82122018-11-22 18:38:28 -05001215 if groupsChanged {
npujar467fe752020-01-16 20:17:45 +05301216 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301217 log.Errorw("cannot-update-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001218 return err
1219 }
1220 }
khenaidoo43c82122018-11-22 18:38:28 -05001221 if flowsChanged {
npujar467fe752020-01-16 20:17:45 +05301222 if err := agent.updateLogicalDeviceFlowsWithoutLock(ctx, &ofp.Flows{Items: flows}); err != nil {
Thomas Lee Se5a44012019-11-07 20:32:24 +05301223 log.Errorw("cannot-update-flow", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo43c82122018-11-22 18:38:28 -05001224 return err
1225 }
1226 }
khenaidoo19d7b632018-10-30 10:49:50 -04001227 return nil
1228}
1229
npujar467fe752020-01-16 20:17:45 +05301230func (agent *LogicalDeviceAgent) groupModify(ctx context.Context, groupMod *ofp.OfpGroupMod) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001231 log.Debug("groupModify")
1232 if groupMod == nil {
1233 return nil
1234 }
1235 agent.lockLogicalDevice.Lock()
1236 defer agent.lockLogicalDevice.Unlock()
1237
khenaidoo6e55d9e2019-12-12 18:26:26 -05001238 lDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001239 groups := lDevice.FlowGroups.Items
npujar1d86a522019-11-14 17:11:16 +05301240 var groupsChanged bool
1241 groupID := groupMod.GroupId
1242 idx := fu.FindGroup(groups, groupID)
1243 if idx == -1 {
1244 return fmt.Errorf("group-absent:%d", groupID)
khenaidoo19d7b632018-10-30 10:49:50 -04001245 }
npujar1d86a522019-11-14 17:11:16 +05301246 //replace existing group entry with new group definition
1247 groupEntry := fu.GroupEntryFromGroupMod(groupMod)
1248 groups[idx] = groupEntry
1249 groupsChanged = true
khenaidoo19d7b632018-10-30 10:49:50 -04001250 if groupsChanged {
Esin Karaman2ea59212019-12-06 11:41:58 +00001251 deviceRules := fu.NewDeviceRules()
1252 deviceRules.CreateEntryIfNotExist(agent.rootDeviceID)
1253 fg := fu.NewFlowsAndGroups()
1254 fg.AddGroup(fu.GroupEntryFromGroupMod(groupMod))
1255 deviceRules.AddFlowsAndGroup(agent.rootDeviceID, fg)
khenaidoo0458db62019-06-20 08:50:36 -04001256
Esin Karaman2ea59212019-12-06 11:41:58 +00001257 log.Debugw("rules", log.Fields{"rules for group-modify": deviceRules.String()})
npujar467fe752020-01-16 20:17:45 +05301258 if err := agent.updateDeviceFlowsAndGroups(ctx, deviceRules, &voltha.FlowMetadata{}); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301259 log.Errorw("failure-updating-device-flows-groups", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "error": err})
khenaidoo0458db62019-06-20 08:50:36 -04001260 return err
1261 }
1262
khenaidoo43c82122018-11-22 18:38:28 -05001263 //lDevice.FlowGroups.Items = groups
npujar467fe752020-01-16 20:17:45 +05301264 if err := agent.updateLogicalDeviceFlowGroupsWithoutLock(ctx, &ofp.FlowGroups{Items: groups}); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301265 log.Errorw("Cannot-update-logical-group", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo19d7b632018-10-30 10:49:50 -04001266 return err
1267 }
1268 }
1269 return nil
1270}
1271
1272// deleteLogicalPort removes the logical port
npujar467fe752020-01-16 20:17:45 +05301273func (agent *LogicalDeviceAgent) deleteLogicalPort(ctx context.Context, lPort *voltha.LogicalPort) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001274 agent.lockLogicalDevice.Lock()
1275 defer agent.lockLogicalDevice.Unlock()
1276
khenaidoo6e55d9e2019-12-12 18:26:26 -05001277 logicalDevice := agent.getLogicalDeviceWithoutLock()
1278
khenaidoo92e62c52018-10-03 14:02:54 -04001279 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001280 for i, logicalPort := range logicalDevice.Ports {
khenaidoo19d7b632018-10-30 10:49:50 -04001281 if logicalPort.Id == lPort.Id {
khenaidoo92e62c52018-10-03 14:02:54 -04001282 index = i
1283 break
1284 }
1285 }
1286 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001287 copy(logicalDevice.Ports[index:], logicalDevice.Ports[index+1:])
1288 logicalDevice.Ports[len(logicalDevice.Ports)-1] = nil
1289 logicalDevice.Ports = logicalDevice.Ports[:len(logicalDevice.Ports)-1]
npujar1d86a522019-11-14 17:11:16 +05301290 log.Debugw("logical-port-deleted", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
npujar467fe752020-01-16 20:17:45 +05301291 if err := agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301292 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001293 return err
1294 }
1295 // Reset the logical device graph
npujar467fe752020-01-16 20:17:45 +05301296 go agent.generateDeviceGraph(context.Background())
khenaidoo92e62c52018-10-03 14:02:54 -04001297 }
1298 return nil
khenaidoob9203542018-09-17 22:56:37 -04001299}
1300
khenaidoo0a822f92019-05-08 15:15:57 -04001301// deleteLogicalPorts removes the logical ports associated with that deviceId
npujar467fe752020-01-16 20:17:45 +05301302func (agent *LogicalDeviceAgent) deleteLogicalPorts(ctx context.Context, deviceID string) error {
khenaidoo0a822f92019-05-08 15:15:57 -04001303 agent.lockLogicalDevice.Lock()
1304 defer agent.lockLogicalDevice.Unlock()
1305
khenaidoo6e55d9e2019-12-12 18:26:26 -05001306 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo0a822f92019-05-08 15:15:57 -04001307 updatedLPorts := []*voltha.LogicalPort{}
khenaidoo6e55d9e2019-12-12 18:26:26 -05001308 for _, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301309 if logicalPort.DeviceId != deviceID {
khenaidoo0a822f92019-05-08 15:15:57 -04001310 updatedLPorts = append(updatedLPorts, logicalPort)
1311 }
1312 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001313 logicalDevice.Ports = updatedLPorts
khenaidoo0a822f92019-05-08 15:15:57 -04001314 log.Debugw("updated-logical-ports", log.Fields{"ports": updatedLPorts})
npujar467fe752020-01-16 20:17:45 +05301315 if err := agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301316 log.Errorw("logical-device-update-failed", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001317 return err
1318 }
1319 // Reset the logical device graph
npujar467fe752020-01-16 20:17:45 +05301320 go agent.generateDeviceGraph(context.Background())
khenaidoo0a822f92019-05-08 15:15:57 -04001321
1322 return nil
1323}
1324
khenaidoo19d7b632018-10-30 10:49:50 -04001325// enableLogicalPort enables the logical port
npujar467fe752020-01-16 20:17:45 +05301326func (agent *LogicalDeviceAgent) enableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001327 agent.lockLogicalDevice.Lock()
1328 defer agent.lockLogicalDevice.Unlock()
1329
khenaidoo6e55d9e2019-12-12 18:26:26 -05001330 logicalDevice := agent.getLogicalDeviceWithoutLock()
1331
khenaidoo19d7b632018-10-30 10:49:50 -04001332 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001333 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301334 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001335 index = i
1336 break
1337 }
1338 }
1339 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001340 logicalDevice.Ports[index].OfpPort.Config = logicalDevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
npujar467fe752020-01-16 20:17:45 +05301341 return agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -04001342 }
npujar1d86a522019-11-14 17:11:16 +05301343 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001344}
1345
1346// disableLogicalPort disabled the logical port
npujar467fe752020-01-16 20:17:45 +05301347func (agent *LogicalDeviceAgent) disableLogicalPort(ctx context.Context, lPortID string) error {
khenaidoo19d7b632018-10-30 10:49:50 -04001348 agent.lockLogicalDevice.Lock()
1349 defer agent.lockLogicalDevice.Unlock()
1350
1351 // Get the most up to date logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001352 logicalDevice := agent.getLogicalDeviceWithoutLock()
khenaidoo19d7b632018-10-30 10:49:50 -04001353 index := -1
khenaidoo6e55d9e2019-12-12 18:26:26 -05001354 for i, logicalPort := range logicalDevice.Ports {
npujar1d86a522019-11-14 17:11:16 +05301355 if logicalPort.Id == lPortID {
khenaidoo19d7b632018-10-30 10:49:50 -04001356 index = i
1357 break
1358 }
1359 }
1360 if index >= 0 {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001361 logicalDevice.Ports[index].OfpPort.Config = (logicalDevice.Ports[index].OfpPort.Config & ^uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)) | uint32(ofp.OfpPortConfig_OFPPC_PORT_DOWN)
npujar467fe752020-01-16 20:17:45 +05301362 return agent.updateLogicalDeviceWithoutLock(ctx, logicalDevice)
khenaidoo19d7b632018-10-30 10:49:50 -04001363 }
npujar1d86a522019-11-14 17:11:16 +05301364 return status.Errorf(codes.NotFound, "Port %s on Logical Device %s", lPortID, agent.logicalDeviceID)
khenaidoo19d7b632018-10-30 10:49:50 -04001365}
1366
khenaidoo89b0e942018-10-21 21:11:33 -04001367func (agent *LogicalDeviceAgent) getPreCalculatedRoute(ingress, egress uint32) []graph.RouteHop {
khenaidoo19d7b632018-10-30 10:49:50 -04001368 log.Debugw("ROUTE", log.Fields{"len": len(agent.deviceGraph.Routes)})
khenaidoo89b0e942018-10-21 21:11:33 -04001369 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001370 log.Debugw("ROUTELINKS", log.Fields{"ingress": ingress, "egress": egress, "routelink": routeLink})
khenaidoo89b0e942018-10-21 21:11:33 -04001371 if ingress == routeLink.Ingress && egress == routeLink.Egress {
1372 return route
1373 }
1374 }
npujar1d86a522019-11-14 17:11:16 +05301375 log.Warnw("no-route", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "ingress": ingress, "egress": egress})
khenaidoo89b0e942018-10-21 21:11:33 -04001376 return nil
1377}
1378
npujar1d86a522019-11-14 17:11:16 +05301379// GetRoute returns route
khenaidoo19d7b632018-10-30 10:49:50 -04001380func (agent *LogicalDeviceAgent) GetRoute(ingressPortNo uint32, egressPortNo uint32) []graph.RouteHop {
khenaidoo89b0e942018-10-21 21:11:33 -04001381 log.Debugw("getting-route", log.Fields{"ingress-port": ingressPortNo, "egress-port": egressPortNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001382 routes := make([]graph.RouteHop, 0)
khenaidoo2c6a0992019-04-29 13:46:56 -04001383
khenaidoo19d7b632018-10-30 10:49:50 -04001384 // Note: A port value of 0 is equivalent to a nil port
1385
khenaidoo89b0e942018-10-21 21:11:33 -04001386 // Consider different possibilities
khenaidoo19d7b632018-10-30 10:49:50 -04001387 if egressPortNo != 0 && ((egressPortNo & 0x7fffffff) == uint32(ofp.OfpPortNo_OFPP_CONTROLLER)) {
khenaidoo2c6a0992019-04-29 13:46:56 -04001388 log.Debugw("controller-flow", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
1389 if agent.isNNIPort(ingressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001390 //This is a trap on the NNI Port
khenaidoo8f474192019-04-03 17:20:44 -04001391 if len(agent.deviceGraph.Routes) == 0 {
1392 // 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 -04001393 // route with same IngressHop and EgressHop
npujar1d86a522019-11-14 17:11:16 +05301394 hop := graph.RouteHop{DeviceID: agent.rootDeviceID, Ingress: ingressPortNo, Egress: ingressPortNo}
khenaidoo8f474192019-04-03 17:20:44 -04001395 routes = append(routes, hop)
1396 routes = append(routes, hop)
1397 return routes
1398 }
khenaidoo89b0e942018-10-21 21:11:33 -04001399 //Return a 'half' route to make the flow decomposer logic happy
1400 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001401 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001402 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1403 routes = append(routes, route[1])
1404 return routes
1405 }
1406 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001407 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001408 return nil
1409 }
1410 //treat it as if the output port is the first NNI of the OLT
khenaidoo2c6a0992019-04-29 13:46:56 -04001411 var err error
1412 if egressPortNo, err = agent.getFirstNNIPort(); err != nil {
1413 log.Warnw("no-nni-port", log.Fields{"error": err})
1414 return nil
1415 }
khenaidoo89b0e942018-10-21 21:11:33 -04001416 }
1417 //If ingress port is not specified (nil), it may be a wildcarded
1418 //route if egress port is OFPP_CONTROLLER or a nni logical port,
1419 //in which case we need to create a half-route where only the egress
1420 //hop is filled, the first hop is nil
khenaidoo2c6a0992019-04-29 13:46:56 -04001421 if ingressPortNo == 0 && agent.isNNIPort(egressPortNo) {
khenaidoo89b0e942018-10-21 21:11:33 -04001422 // We can use the 2nd hop of any upstream route, so just find the first upstream:
1423 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo2c6a0992019-04-29 13:46:56 -04001424 if agent.isNNIPort(routeLink.Egress) {
khenaidoo89b0e942018-10-21 21:11:33 -04001425 routes = append(routes, graph.RouteHop{}) // first hop is set to empty
1426 routes = append(routes, route[1])
1427 return routes
1428 }
1429 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001430 log.Warnw("no-upstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001431 return nil
1432 }
1433 //If egress port is not specified (nil), we can also can return a "half" route
khenaidoo19d7b632018-10-30 10:49:50 -04001434 if egressPortNo == 0 {
khenaidoo89b0e942018-10-21 21:11:33 -04001435 for routeLink, route := range agent.deviceGraph.Routes {
khenaidoo19d7b632018-10-30 10:49:50 -04001436 if routeLink.Ingress == ingressPortNo {
khenaidoo89b0e942018-10-21 21:11:33 -04001437 routes = append(routes, route[0])
1438 routes = append(routes, graph.RouteHop{})
1439 return routes
1440 }
1441 }
khenaidoo2c6a0992019-04-29 13:46:56 -04001442 log.Warnw("no-downstream-route", log.Fields{"ingressPortNo": ingressPortNo, "egressPortNo": egressPortNo, "logicalPortsNo": agent.logicalPortsNo})
khenaidoo89b0e942018-10-21 21:11:33 -04001443 return nil
1444 }
khenaidoo89b0e942018-10-21 21:11:33 -04001445 // Return the pre-calculated route
khenaidoo19d7b632018-10-30 10:49:50 -04001446 return agent.getPreCalculatedRoute(ingressPortNo, egressPortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001447}
1448
khenaidoo3d3b8c22019-05-22 18:10:39 -04001449//GetWildcardInputPorts filters out the logical port number from the set of logical ports on the device and
1450//returns their port numbers. This function is invoked only during flow decomposition where the lock on the logical
1451//device is already held. Therefore it is safe to retrieve the logical device without lock.
khenaidoo89b0e942018-10-21 21:11:33 -04001452func (agent *LogicalDeviceAgent) GetWildcardInputPorts(excludePort ...uint32) []uint32 {
1453 lPorts := make([]uint32, 0)
1454 var exclPort uint32
1455 if len(excludePort) == 1 {
1456 exclPort = excludePort[0]
1457 }
khenaidoo6e55d9e2019-12-12 18:26:26 -05001458 lDevice := agent.getLogicalDeviceWithoutLock()
1459 for _, port := range lDevice.Ports {
1460 if port.OfpPort.PortNo != exclPort {
1461 lPorts = append(lPorts, port.OfpPort.PortNo)
khenaidoo89b0e942018-10-21 21:11:33 -04001462 }
1463 }
1464 return lPorts
1465}
khenaidoo19d7b632018-10-30 10:49:50 -04001466
npujar1d86a522019-11-14 17:11:16 +05301467// GetDeviceGraph returns device graph
khenaidoo19d7b632018-10-30 10:49:50 -04001468func (agent *LogicalDeviceAgent) GetDeviceGraph() *graph.DeviceGraph {
1469 return agent.deviceGraph
1470}
1471
khenaidoo3306c992019-05-24 16:57:35 -04001472//updateRoutes rebuilds the device graph if not done already
npujar467fe752020-01-16 20:17:45 +05301473func (agent *LogicalDeviceAgent) updateRoutes(ctx context.Context, device *voltha.Device, port *voltha.Port) error {
npujar1d86a522019-11-14 17:11:16 +05301474 log.Debugf("updateRoutes", log.Fields{"logicalDeviceId": agent.logicalDeviceID, "device": device.Id, "port": port})
khenaidoo910204f2019-04-08 17:56:40 -04001475 agent.lockLogicalDevice.Lock()
1476 defer agent.lockLogicalDevice.Unlock()
khenaidoo19d7b632018-10-30 10:49:50 -04001477 if agent.deviceGraph == nil {
npujar1d86a522019-11-14 17:11:16 +05301478 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo2c6a0992019-04-29 13:46:56 -04001479 }
1480 // Get all the logical ports on that logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001481 lDevice := agent.getLogicalDeviceWithoutLock()
1482
npujar1d86a522019-11-14 17:11:16 +05301483 //TODO: Find a better way to refresh only missing routes
npujar467fe752020-01-16 20:17:45 +05301484 agent.deviceGraph.ComputeRoutes(ctx, lDevice.Ports)
khenaidoo2c6a0992019-04-29 13:46:56 -04001485 agent.deviceGraph.Print()
1486 return nil
khenaidoo19d7b632018-10-30 10:49:50 -04001487}
1488
khenaidoo2c6a0992019-04-29 13:46:56 -04001489//updateDeviceGraph updates the device graph if not done already and setup the default rules as well
npujar467fe752020-01-16 20:17:45 +05301490func (agent *LogicalDeviceAgent) updateDeviceGraph(ctx context.Context, lp *voltha.LogicalPort) {
npujar1d86a522019-11-14 17:11:16 +05301491 log.Debugf("updateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo2c6a0992019-04-29 13:46:56 -04001492 agent.lockLogicalDevice.Lock()
1493 defer agent.lockLogicalDevice.Unlock()
khenaidoo910204f2019-04-08 17:56:40 -04001494 if agent.deviceGraph == nil {
npujar1d86a522019-11-14 17:11:16 +05301495 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo910204f2019-04-08 17:56:40 -04001496 }
npujar467fe752020-01-16 20:17:45 +05301497 agent.deviceGraph.AddPort(ctx, lp)
khenaidoo2c6a0992019-04-29 13:46:56 -04001498 agent.deviceGraph.Print()
khenaidoo19d7b632018-10-30 10:49:50 -04001499}
khenaidoofdbad6e2018-11-06 22:26:38 -05001500
khenaidoo3d3b8c22019-05-22 18:10:39 -04001501//generateDeviceGraph regenerates the device graph
npujar467fe752020-01-16 20:17:45 +05301502func (agent *LogicalDeviceAgent) generateDeviceGraph(ctx context.Context) {
npujar1d86a522019-11-14 17:11:16 +05301503 log.Debugw("generateDeviceGraph", log.Fields{"logicalDeviceId": agent.logicalDeviceID})
khenaidoo0a822f92019-05-08 15:15:57 -04001504 agent.lockLogicalDevice.Lock()
1505 defer agent.lockLogicalDevice.Unlock()
1506 // Get the latest logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001507 ld := agent.getLogicalDeviceWithoutLock()
1508 log.Debugw("generating-graph", log.Fields{"lDeviceId": agent.logicalDeviceID, "lPorts": len(ld.Ports)})
1509 if agent.deviceGraph == nil {
1510 agent.deviceGraph = graph.NewDeviceGraph(agent.logicalDeviceID, agent.deviceMgr.GetDevice)
khenaidoo0a822f92019-05-08 15:15:57 -04001511 }
npujar467fe752020-01-16 20:17:45 +05301512 agent.deviceGraph.ComputeRoutes(ctx, ld.Ports)
khenaidoo6e55d9e2019-12-12 18:26:26 -05001513 agent.deviceGraph.Print()
khenaidoo0a822f92019-05-08 15:15:57 -04001514}
1515
khenaidoofc1314d2019-03-14 09:34:21 -04001516// diff go over two lists of logical ports and return what's new, what's changed and what's removed.
khenaidoo910204f2019-04-08 17:56:40 -04001517func diff(oldList, newList []*voltha.LogicalPort) (newPorts, changedPorts, deletedPorts []*voltha.LogicalPort) {
khenaidoofc1314d2019-03-14 09:34:21 -04001518 newPorts = make([]*voltha.LogicalPort, 0)
1519 changedPorts = make([]*voltha.LogicalPort, 0)
1520 deletedPorts = make([]*voltha.LogicalPort, 0)
1521 for _, o := range oldList {
1522 found := false
khenaidoofc1314d2019-03-14 09:34:21 -04001523 for _, n := range newList {
1524 if o.Id == n.Id {
khenaidoofc1314d2019-03-14 09:34:21 -04001525 found = true
1526 break
1527 }
1528 }
1529 if !found {
1530 deletedPorts = append(deletedPorts, o)
1531 }
khenaidoofc1314d2019-03-14 09:34:21 -04001532 }
1533 for _, n := range newList {
1534 found := false
khenaidoo2bc48282019-07-16 18:13:46 -04001535 changed := false
khenaidoofc1314d2019-03-14 09:34:21 -04001536 for _, o := range oldList {
1537 if o.Id == n.Id {
khenaidoo2bc48282019-07-16 18:13:46 -04001538 changed = !reflect.DeepEqual(o, n)
khenaidoofc1314d2019-03-14 09:34:21 -04001539 found = true
1540 break
1541 }
1542 }
1543 if !found {
1544 newPorts = append(newPorts, n)
1545 }
khenaidoo2bc48282019-07-16 18:13:46 -04001546 if changed {
1547 changedPorts = append(changedPorts, n)
1548 }
khenaidoofc1314d2019-03-14 09:34:21 -04001549 }
1550 return
1551}
1552
1553// portUpdated is invoked when a port is updated on the logical device. Until
1554// the POST_ADD notification is fixed, we will use the logical device to
1555// update that data.
npujar467fe752020-01-16 20:17:45 +05301556func (agent *LogicalDeviceAgent) portUpdated(ctx context.Context, args ...interface{}) interface{} {
khenaidoofc1314d2019-03-14 09:34:21 -04001557 log.Debugw("portUpdated-callback", log.Fields{"argsLen": len(args)})
1558
1559 var oldLD *voltha.LogicalDevice
1560 var newlD *voltha.LogicalDevice
1561
1562 var ok bool
1563 if oldLD, ok = args[0].(*voltha.LogicalDevice); !ok {
1564 log.Errorw("invalid-args", log.Fields{"args0": args[0]})
1565 return nil
1566 }
1567 if newlD, ok = args[1].(*voltha.LogicalDevice); !ok {
1568 log.Errorw("invalid-args", log.Fields{"args1": args[1]})
1569 return nil
1570 }
1571
1572 if reflect.DeepEqual(oldLD.Ports, newlD.Ports) {
1573 log.Debug("ports-have-not-changed")
1574 return nil
1575 }
1576
1577 // Get the difference between the two list
1578 newPorts, changedPorts, deletedPorts := diff(oldLD.Ports, newlD.Ports)
1579
1580 // Send the port change events to the OF controller
khenaidoo2c6a0992019-04-29 13:46:56 -04001581 for _, newP := range newPorts {
npujar1d86a522019-11-14 17:11:16 +05301582 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo2c6a0992019-04-29 13:46:56 -04001583 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_ADD, Desc: newP.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001584 }
1585 for _, change := range changedPorts {
npujar1d86a522019-11-14 17:11:16 +05301586 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001587 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_MODIFY, Desc: change.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001588 }
1589 for _, del := range deletedPorts {
npujar1d86a522019-11-14 17:11:16 +05301590 go agent.ldeviceMgr.grpcNbiHdlr.sendChangeEvent(agent.logicalDeviceID,
khenaidoo910204f2019-04-08 17:56:40 -04001591 &ofp.OfpPortStatus{Reason: ofp.OfpPortReason_OFPPR_DELETE, Desc: del.OfpPort})
khenaidoofc1314d2019-03-14 09:34:21 -04001592 }
1593
1594 return nil
1595}
1596
khenaidoo8f474192019-04-03 17:20:44 -04001597// addNNILogicalPort adds an NNI port to the logical device. It returns a bool representing whether a port has been
1598// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1599// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1600// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301601func (agent *LogicalDeviceAgent) addNNILogicalPort(ctx context.Context, device *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoo1ce37ad2019-03-24 22:07:24 -04001602 log.Debugw("addNNILogicalPort", log.Fields{"NNI": port})
khenaidoo8f474192019-04-03 17:20:44 -04001603 if device.AdminState != voltha.AdminState_ENABLED || device.OperStatus != voltha.OperStatus_ACTIVE {
1604 log.Infow("device-not-ready", log.Fields{"deviceId": device.Id, "admin": device.AdminState, "oper": device.OperStatus})
1605 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001606 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001607 agent.lockLogicalDevice.RLock()
1608 if agent.portExist(device, port) {
1609 log.Debugw("port-already-exist", log.Fields{"port": port})
1610 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001611 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001612 }
1613 agent.lockLogicalDevice.RUnlock()
1614
khenaidoofc1314d2019-03-14 09:34:21 -04001615 var portCap *ic.PortCapability
1616 var err error
1617 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301618 if portCap, err = agent.deviceMgr.getPortCapability(ctx, device.Id, port.PortNo); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001619 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001620 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001621 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001622
1623 agent.lockLogicalDevice.Lock()
1624 defer agent.lockLogicalDevice.Unlock()
1625 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1626 if agent.portExist(device, port) {
1627 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001628 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001629 }
1630
khenaidoofc1314d2019-03-14 09:34:21 -04001631 portCap.Port.RootPort = true
1632 lp := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
1633 lp.DeviceId = device.Id
1634 lp.Id = fmt.Sprintf("nni-%d", port.PortNo)
1635 lp.OfpPort.PortNo = port.PortNo
1636 lp.OfpPort.Name = lp.Id
1637 lp.DevicePortNo = port.PortNo
1638
khenaidoo6e55d9e2019-12-12 18:26:26 -05001639 ld := agent.getLogicalDeviceWithoutLock()
1640
khenaidoofc1314d2019-03-14 09:34:21 -04001641 cloned := (proto.Clone(ld)).(*voltha.LogicalDevice)
1642 if cloned.Ports == nil {
1643 cloned.Ports = make([]*voltha.LogicalPort, 0)
1644 }
1645 cloned.Ports = append(cloned.Ports, lp)
1646
npujar467fe752020-01-16 20:17:45 +05301647 if err = agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001648 log.Errorw("error-updating-logical-device", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001649 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001650 }
khenaidoo910204f2019-04-08 17:56:40 -04001651
1652 // Update the device graph with this new logical port
1653 clonedLP := (proto.Clone(lp)).(*voltha.LogicalPort)
npujar467fe752020-01-16 20:17:45 +05301654 go agent.updateDeviceGraph(context.Background(), clonedLP)
khenaidoo910204f2019-04-08 17:56:40 -04001655
khenaidoo8f474192019-04-03 17:20:44 -04001656 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001657}
1658
khenaidoo910204f2019-04-08 17:56:40 -04001659func (agent *LogicalDeviceAgent) portExist(device *voltha.Device, port *voltha.Port) bool {
khenaidoo6e55d9e2019-12-12 18:26:26 -05001660 ldevice := agent.getLogicalDeviceWithoutLock()
1661 for _, lPort := range ldevice.Ports {
1662 if lPort.DeviceId == device.Id && lPort.DevicePortNo == port.PortNo && lPort.Id == port.Label {
1663 return true
khenaidoofc1314d2019-03-14 09:34:21 -04001664 }
1665 }
1666 return false
1667}
1668
khenaidoo8f474192019-04-03 17:20:44 -04001669// addUNILogicalPort adds an UNI port to the logical device. It returns a bool representing whether a port has been
1670// added and an eror in case a valid error is encountered. If the port was successfully added it will return
1671// (true, nil). If the device is not in the correct state it will return (false, nil) as this is a valid
1672// scenario. This also applies to the case where the port was already added.
npujar467fe752020-01-16 20:17:45 +05301673func (agent *LogicalDeviceAgent) addUNILogicalPort(ctx context.Context, childDevice *voltha.Device, port *voltha.Port) (bool, error) {
khenaidoofc1314d2019-03-14 09:34:21 -04001674 log.Debugw("addUNILogicalPort", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001675 if childDevice.AdminState != voltha.AdminState_ENABLED || childDevice.OperStatus != voltha.OperStatus_ACTIVE {
1676 log.Infow("device-not-ready", log.Fields{"deviceId": childDevice.Id, "admin": childDevice.AdminState, "oper": childDevice.OperStatus})
1677 return false, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001678 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001679 agent.lockLogicalDevice.RLock()
1680 if agent.portExist(childDevice, port) {
1681 log.Debugw("port-already-exist", log.Fields{"port": port})
1682 agent.lockLogicalDevice.RUnlock()
khenaidoo8f474192019-04-03 17:20:44 -04001683 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001684 }
1685 agent.lockLogicalDevice.RUnlock()
khenaidoofc1314d2019-03-14 09:34:21 -04001686 var portCap *ic.PortCapability
1687 var err error
1688 // First get the port capability
npujar467fe752020-01-16 20:17:45 +05301689 if portCap, err = agent.deviceMgr.getPortCapability(ctx, childDevice.Id, port.PortNo); err != nil {
khenaidoofc1314d2019-03-14 09:34:21 -04001690 log.Errorw("error-retrieving-port-capabilities", log.Fields{"error": err})
khenaidoo8f474192019-04-03 17:20:44 -04001691 return false, err
khenaidoofc1314d2019-03-14 09:34:21 -04001692 }
khenaidoo1ce37ad2019-03-24 22:07:24 -04001693 agent.lockLogicalDevice.Lock()
1694 defer agent.lockLogicalDevice.Unlock()
1695 // Double check again if this port has been already added since the getPortCapability could have taken a long time
1696 if agent.portExist(childDevice, port) {
1697 log.Debugw("port-already-exist", log.Fields{"port": port})
khenaidoo8f474192019-04-03 17:20:44 -04001698 return false, nil
khenaidoo1ce37ad2019-03-24 22:07:24 -04001699 }
khenaidoofc1314d2019-03-14 09:34:21 -04001700 // Get stored logical device
khenaidoo6e55d9e2019-12-12 18:26:26 -05001701 ldevice := agent.getLogicalDeviceWithoutLock()
1702
npujar1d86a522019-11-14 17:11:16 +05301703 log.Debugw("adding-uni", log.Fields{"deviceId": childDevice.Id})
1704 portCap.Port.RootPort = false
1705 portCap.Port.Id = port.Label
1706 portCap.Port.OfpPort.PortNo = port.PortNo
1707 portCap.Port.DeviceId = childDevice.Id
1708 portCap.Port.DevicePortNo = port.PortNo
1709 cloned := (proto.Clone(ldevice)).(*voltha.LogicalDevice)
1710 if cloned.Ports == nil {
1711 cloned.Ports = make([]*voltha.LogicalPort, 0)
1712 }
1713 cloned.Ports = append(cloned.Ports, portCap.Port)
npujar467fe752020-01-16 20:17:45 +05301714 if err := agent.updateLogicalDeviceWithoutLock(ctx, cloned); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301715 return false, err
1716 }
1717 // Update the device graph with this new logical port
1718 clonedLP := (proto.Clone(portCap.Port)).(*voltha.LogicalPort)
npujar467fe752020-01-16 20:17:45 +05301719 go agent.updateDeviceGraph(context.Background(), clonedLP)
npujar1d86a522019-11-14 17:11:16 +05301720 return true, nil
khenaidoofc1314d2019-03-14 09:34:21 -04001721}
1722
npujar467fe752020-01-16 20:17:45 +05301723func (agent *LogicalDeviceAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Matteo Scandolo360605d2019-11-05 18:29:17 -08001724 log.Debugw("packet-out", log.Fields{
1725 "packet": hex.EncodeToString(packet.Data),
1726 "inPort": packet.GetInPort(),
1727 })
khenaidoo68c930b2019-05-13 11:46:51 -04001728 outPort := fu.GetPacketOutPort(packet)
khenaidoofdbad6e2018-11-06 22:26:38 -05001729 //frame := packet.GetData()
1730 //TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +05301731 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
npujar1d86a522019-11-14 17:11:16 +05301732 log.Error("packetout-failed", log.Fields{"logicalDeviceID": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -05001733 }
khenaidoofdbad6e2018-11-06 22:26:38 -05001734}
1735
npujar1d86a522019-11-14 17:11:16 +05301736func (agent *LogicalDeviceAgent) packetIn(port uint32, transactionID string, packet []byte) {
Matteo Scandolo360605d2019-11-05 18:29:17 -08001737 log.Debugw("packet-in", log.Fields{
1738 "port": port,
1739 "packet": hex.EncodeToString(packet),
npujar1d86a522019-11-14 17:11:16 +05301740 "transactionId": transactionID,
Matteo Scandolo360605d2019-11-05 18:29:17 -08001741 })
khenaidoo68c930b2019-05-13 11:46:51 -04001742 packetIn := fu.MkPacketIn(port, packet)
npujar1d86a522019-11-14 17:11:16 +05301743 agent.ldeviceMgr.grpcNbiHdlr.sendPacketIn(agent.logicalDeviceID, transactionID, packetIn)
Matteo Scandolo360605d2019-11-05 18:29:17 -08001744 log.Debugw("sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -05001745}
khenaidoo2c6a0992019-04-29 13:46:56 -04001746
1747func (agent *LogicalDeviceAgent) addLogicalPortToMap(portNo uint32, nniPort bool) {
1748 agent.lockLogicalPortsNo.Lock()
1749 defer agent.lockLogicalPortsNo.Unlock()
1750 if exist := agent.logicalPortsNo[portNo]; !exist {
1751 agent.logicalPortsNo[portNo] = nniPort
1752 }
1753}
1754
khenaidoo3d3b8c22019-05-22 18:10:39 -04001755func (agent *LogicalDeviceAgent) addLogicalPortsToMap(lps []*voltha.LogicalPort) {
1756 agent.lockLogicalPortsNo.Lock()
1757 defer agent.lockLogicalPortsNo.Unlock()
1758 for _, lp := range lps {
1759 if exist := agent.logicalPortsNo[lp.DevicePortNo]; !exist {
1760 agent.logicalPortsNo[lp.DevicePortNo] = lp.RootPort
1761 }
1762 }
1763}
1764
khenaidoo2c6a0992019-04-29 13:46:56 -04001765func (agent *LogicalDeviceAgent) isNNIPort(portNo uint32) bool {
1766 agent.lockLogicalPortsNo.RLock()
1767 defer agent.lockLogicalPortsNo.RUnlock()
1768 if exist := agent.logicalPortsNo[portNo]; exist {
1769 return agent.logicalPortsNo[portNo]
1770 }
1771 return false
1772}
1773
1774func (agent *LogicalDeviceAgent) getFirstNNIPort() (uint32, error) {
1775 agent.lockLogicalPortsNo.RLock()
1776 defer agent.lockLogicalPortsNo.RUnlock()
1777 for portNo, nni := range agent.logicalPortsNo {
1778 if nni {
1779 return portNo, nil
1780 }
1781 }
1782 return 0, status.Error(codes.NotFound, "No NNI port found")
1783}
Esin Karaman09959ae2019-11-29 13:59:58 +00001784
1785//GetNNIPorts returns NNI ports.
1786func (agent *LogicalDeviceAgent) GetNNIPorts() []uint32 {
1787 agent.lockLogicalPortsNo.RLock()
1788 defer agent.lockLogicalPortsNo.RUnlock()
1789 nniPorts := make([]uint32, 0)
1790 for portNo, nni := range agent.logicalPortsNo {
1791 if nni {
1792 nniPorts = append(nniPorts, portNo)
1793 }
1794 }
1795 return nniPorts
1796}