blob: adcaba38a6022ecf5d7a85dcea337f95efa11f37 [file] [log] [blame]
khenaidoob9203542018-09-17 22:56:37 -04001/*
Joey Armstrong7a9af442024-01-03 19:26:36 -05002 * Copyright 2018-2024 Open Networking Foundation (ONF) and the ONF Contributors
khenaidoob9203542018-09-17 22:56:37 -04003
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
npujar1d86a522019-11-14 17:11:16 +053016
Kent Hagerman2b216042020-04-03 18:28:56 -040017package device
khenaidoob9203542018-09-17 22:56:37 -040018
19import (
20 "context"
Matteo Scandolo360605d2019-11-05 18:29:17 -080021 "encoding/hex"
David Bainbridged1afd662020-03-26 18:27:41 -070022 "sync"
23 "time"
24
khenaidoob9203542018-09-17 22:56:37 -040025 "github.com/gogo/protobuf/proto"
sbarbari17d7e222019-11-05 10:02:29 -050026 "github.com/opencord/voltha-go/db/model"
Kent Hagerman433a31a2020-05-20 19:04:48 -040027 "github.com/opencord/voltha-go/rw_core/core/device/flow"
28 "github.com/opencord/voltha-go/rw_core/core/device/group"
khenaidood948f772021-08-11 17:49:24 -040029 lp "github.com/opencord/voltha-go/rw_core/core/device/logical_port"
Kent Hagerman433a31a2020-05-20 19:04:48 -040030 "github.com/opencord/voltha-go/rw_core/core/device/meter"
npujar1d86a522019-11-14 17:11:16 +053031 fd "github.com/opencord/voltha-go/rw_core/flowdecomposition"
khenaidoo442e7c72020-03-10 16:13:48 -040032 "github.com/opencord/voltha-go/rw_core/route"
Scott Bakerb671a862019-10-24 10:53:40 -070033 coreutils "github.com/opencord/voltha-go/rw_core/utils"
khenaidood948f772021-08-11 17:49:24 -040034 fu "github.com/opencord/voltha-lib-go/v7/pkg/flows"
35 "github.com/opencord/voltha-lib-go/v7/pkg/log"
khenaidoo9beaaf12021-10-19 17:32:01 -040036 ca "github.com/opencord/voltha-protos/v5/go/core_adapter"
khenaidood948f772021-08-11 17:49:24 -040037 ofp "github.com/opencord/voltha-protos/v5/go/openflow_13"
38 "github.com/opencord/voltha-protos/v5/go/voltha"
khenaidoob9203542018-09-17 22:56:37 -040039 "google.golang.org/grpc/codes"
40 "google.golang.org/grpc/status"
khenaidoo442e7c72020-03-10 16:13:48 -040041)
42
Kent Hagerman2b216042020-04-03 18:28:56 -040043// LogicalAgent represent attributes of logical device agent
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +053044//
45//nolint:govet
Kent Hagerman2b216042020-04-03 18:28:56 -040046type LogicalAgent struct {
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +053047 orderedEvents orderedEvents
48 deviceMgr *Manager
49 ldeviceMgr *LogicalManager
50 ldProxy *model.Proxy
51 deviceRoutes *route.DeviceRoutes
52 flowDecomposer *fd.FlowDecomposer
53 logicalDevice *voltha.LogicalDevice
54 requestQueue *coreutils.RequestQueue
55
56 flowCache *flow.Cache
57 meterLoader *meter.Loader
58 groupCache *group.Cache
59 portLoader *lp.Loader
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040060 logicalDeviceID string
61 serialNumber string
62 rootDeviceID string
khenaidood948f772021-08-11 17:49:24 -040063 internalTimeout time.Duration
Kent Hagermanfa9d6d42020-05-25 11:49:40 -040064 startOnce sync.Once
65 stopOnce sync.Once
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +053066 exitChannel chan int
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070067
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +053068 stopped bool
Mahir Gunyeladdb66a2020-04-29 18:08:50 -070069}
70
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +053071func newLogicalAgent(id string, sn string, deviceID string, ldeviceMgr *LogicalManager,
khenaidood948f772021-08-11 17:49:24 -040072 deviceMgr *Manager, dbProxy *model.Path, ldProxy *model.Proxy, internalTimeout time.Duration) *LogicalAgent {
Kent Hagerman2a07b862020-06-19 15:23:07 -040073 return &LogicalAgent{
Kent Hagermanf5a67352020-04-30 15:15:26 -040074 logicalDeviceID: id,
75 serialNumber: sn,
76 rootDeviceID: deviceID,
77 deviceMgr: deviceMgr,
78 ldProxy: ldProxy,
79 ldeviceMgr: ldeviceMgr,
Kent Hagerman2a07b862020-06-19 15:23:07 -040080 deviceRoutes: route.NewDeviceRoutes(id, deviceID, deviceMgr.listDevicePorts),
Kent Hagerman6031aad2020-07-29 16:36:33 -040081 flowDecomposer: fd.NewFlowDecomposer(deviceMgr.getDeviceReadOnly),
khenaidood948f772021-08-11 17:49:24 -040082 internalTimeout: internalTimeout,
Kent Hagermanf5a67352020-04-30 15:15:26 -040083 requestQueue: coreutils.NewRequestQueue(),
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +053084 exitChannel: make(chan int, 1),
Kent Hagerman433a31a2020-05-20 19:04:48 -040085
khenaidoo1a0d6222021-06-30 16:48:44 -040086 flowCache: flow.NewCache(),
87 groupCache: group.NewCache(),
88 meterLoader: meter.NewLoader(dbProxy.SubPath("logical_meters").Proxy(id)),
khenaidood948f772021-08-11 17:49:24 -040089 portLoader: lp.NewLoader(dbProxy.SubPath("logical_ports").Proxy(id)),
Kent Hagerman433a31a2020-05-20 19:04:48 -040090 }
khenaidoob9203542018-09-17 22:56:37 -040091}
92
khenaidoo4d4802d2018-10-04 21:59:49 -040093// start creates the logical device and add it to the data model
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +053094func (agent *LogicalAgent) start(ctx context.Context, logicalDeviceExist bool, logicalDevice *voltha.LogicalDevice) {
khenaidoo442e7c72020-03-10 16:13:48 -040095 needToStart := false
96 if agent.startOnce.Do(func() { needToStart = true }); !needToStart {
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +053097 logger.Debug(ctx, "starting-logical-device-agent already running")
98 return
khenaidoo442e7c72020-03-10 16:13:48 -040099 }
100
khenaidoo7585a962021-06-10 16:15:38 -0400101 logger.Infow(ctx, "starting-logical-device-agent", log.Fields{"logical-device-id": agent.logicalDeviceID, "load-from-db": logicalDeviceExist})
khenaidoo442e7c72020-03-10 16:13:48 -0400102
103 var startSucceeded bool
104 defer func() {
105 if !startSucceeded {
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530106 if stopErr := agent.stop(ctx); stopErr != nil {
107 logger.Errorw(ctx, "failed-to-cleanup-after-unsuccessful-start", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": stopErr})
khenaidoo442e7c72020-03-10 16:13:48 -0400108 }
109 }
110 }()
111
khenaidoo297cd252019-02-07 22:10:23 -0500112 var ld *voltha.LogicalDevice
khenaidoo7585a962021-06-10 16:15:38 -0400113 if !logicalDeviceExist {
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +0530114 // Build the logical device based on information retrieved from the device adapter
khenaidoo9beaaf12021-10-19 17:32:01 -0400115 var switchCap *ca.SwitchCapability
khenaidoo297cd252019-02-07 22:10:23 -0500116 var err error
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530117
npujar1d86a522019-11-14 17:11:16 +0530118 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err != nil {
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530119 logger.Warnw(ctx, "failed-to-get-switch-capability", log.Fields{"root-device-id": agent.rootDeviceID, "error": err})
120 switchCapTicker := time.NewTicker(time.Second * 2)
121 defer switchCapTicker.Stop()
122
123 // Start a retry loop to get switch capability of the OLT device from adapter
124 for {
125 select {
126 case <-switchCapTicker.C:
127 if switchCap, err = agent.deviceMgr.getSwitchCapability(ctx, agent.rootDeviceID); err == nil {
128 logger.Infow(ctx, "received switch capability, proceeding to start logical device agent", log.Fields{"root-device-id": agent.rootDeviceID})
129 }
130 // Before retrying, check if the agent has stopped
131 case _, ok := (<-agent.exitChannel):
132 if !ok {
133 logger.Warnw(ctx, "agent stopped, exit retrying get-switch-capability", log.Fields{"root-device-id": agent.rootDeviceID})
134 return
135 }
136 }
137 // Break the for loop as we have received the switch capability from adapter
138 if err == nil {
139 break
140 }
141 logger.Warnw(ctx, "retrying get-switch-capability", log.Fields{"root-device-id": agent.rootDeviceID, "error": err})
142 }
khenaidoo7e3d8f12019-08-02 16:06:30 -0400143 }
npujar1d86a522019-11-14 17:11:16 +0530144 ld = &voltha.LogicalDevice{Id: agent.logicalDeviceID, RootDeviceId: agent.rootDeviceID}
khenaidoo297cd252019-02-07 22:10:23 -0500145
146 // Create the datapath ID (uint64) using the logical device ID (based on the MAC Address)
147 var datapathID uint64
Kent Hagerman2b216042020-04-03 18:28:56 -0400148 if datapathID, err = coreutils.CreateDataPathID(agent.serialNumber); err != nil {
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530149 logger.Errorw(ctx, "failed-to-create-datapath-id", log.Fields{"serial-number": agent.serialNumber, "error": err})
150 return
khenaidoo297cd252019-02-07 22:10:23 -0500151 }
152 ld.DatapathId = datapathID
khenaidoo7e3d8f12019-08-02 16:06:30 -0400153 ld.Desc = (proto.Clone(switchCap.Desc)).(*ofp.OfpDesc)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000154 logger.Debugw(ctx, "Switch-capability", log.Fields{"Desc": ld.Desc, "fromAd": switchCap.Desc})
khenaidoo7e3d8f12019-08-02 16:06:30 -0400155 ld.SwitchFeatures = (proto.Clone(switchCap.SwitchFeatures)).(*ofp.OfpSwitchFeatures)
khenaidoo297cd252019-02-07 22:10:23 -0500156
khenaidoo297cd252019-02-07 22:10:23 -0500157 // Save the logical device
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +0530158 if err = agent.ldProxy.Set(ctx, ld.Id, ld); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000159 logger.Errorw(ctx, "failed-to-add-logical-device", log.Fields{"logical-device-id": agent.logicalDeviceID})
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530160 return
Thomas Lee Se5a44012019-11-07 20:32:24 +0530161 }
Himani Chawlab4c25912020-11-12 17:16:38 +0530162 logger.Debugw(ctx, "logical-device-created", log.Fields{"logical-device-id": agent.logicalDeviceID, "root-id": ld.RootDeviceId})
khenaidoo6e55d9e2019-12-12 18:26:26 -0500163
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400164 agent.logicalDevice = ld
khenaidoofc1314d2019-03-14 09:34:21 -0400165
khenaidoo442e7c72020-03-10 16:13:48 -0400166 // Setup the logicalports - internal processing, no need to propagate the client context
nikesh.krishnan95142d52023-02-24 15:32:11 +0530167
168 err = agent.setupLogicalPorts(ctx)
169 if err != nil {
170 logger.Errorw(ctx, "unable-to-setup-logical-ports", log.Fields{"error": err})
171 }
172
khenaidoo297cd252019-02-07 22:10:23 -0500173 } else {
khenaidoo7585a962021-06-10 16:15:38 -0400174 // Check to see if we need to load from dB
175 ld = logicalDevice
176 if logicalDevice == nil {
177 // load from dB
178 ld = &voltha.LogicalDevice{}
179 have, err := agent.ldProxy.Get(ctx, agent.logicalDeviceID, ld)
180 if err != nil {
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530181 logger.Errorw(ctx, "failed-to-load-logical-device-from-db", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
182 return
khenaidoo7585a962021-06-10 16:15:38 -0400183 } else if !have {
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530184 err := status.Errorf(codes.NotFound, "logical_device-%s", agent.logicalDeviceID)
185 logger.Errorw(ctx, "logical-device-not-found-in-db", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
186 return
khenaidoo7585a962021-06-10 16:15:38 -0400187 }
khenaidoo297cd252019-02-07 22:10:23 -0500188 }
Kent Hagerman4f355f52020-03-30 16:01:33 -0400189
khenaidoo8c3303d2019-02-13 14:59:39 -0500190 // Update the root device Id
npujar1d86a522019-11-14 17:11:16 +0530191 agent.rootDeviceID = ld.RootDeviceId
khenaidoo3d3b8c22019-05-22 18:10:39 -0400192
khenaidoo6e55d9e2019-12-12 18:26:26 -0500193 // Update the last data
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400194 agent.logicalDevice = ld
khenaidoo6e55d9e2019-12-12 18:26:26 -0500195
Kent Hagerman2a07b862020-06-19 15:23:07 -0400196 // now that the root device is known, create DeviceRoutes with it
197 agent.deviceRoutes = route.NewDeviceRoutes(agent.logicalDeviceID, agent.rootDeviceID, agent.deviceMgr.listDevicePorts)
198
khenaidoo1a0d6222021-06-30 16:48:44 -0400199 // load the meters from KV to cache
200 agent.meterLoader.Load(ctx)
201
khenaidoo7585a962021-06-10 16:15:38 -0400202 // load the logical ports from KV to cache
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400203 agent.portLoader.Load(ctx)
khenaidoob9203542018-09-17 22:56:37 -0400204 }
khenaidoofc1314d2019-03-14 09:34:21 -0400205
khenaidoo820197c2020-02-13 16:35:33 -0500206 // Setup the device routes. Building routes may fail if the pre-conditions are not satisfied (e.g. no PON ports present)
khenaidoo7585a962021-06-10 16:15:38 -0400207 if logicalDeviceExist {
nikesh.krishnan95142d52023-02-24 15:32:11 +0530208
209 if err := agent.buildRoutes(ctx); err != nil {
210 logger.Warn(ctx, "routes-not-ready", log.Fields{"logical-device-id": agent.logicalDeviceID, "error": err})
211 }
212
khenaidoo4c9e5592019-09-09 16:20:41 -0400213 }
khenaidoo442e7c72020-03-10 16:13:48 -0400214 startSucceeded = true
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530215 agent.ldeviceMgr.addLogicalDeviceAgentToMap(agent)
khenaidoob9203542018-09-17 22:56:37 -0400216}
217
khenaidoo442e7c72020-03-10 16:13:48 -0400218// stop stops the logical device agent. This removes the logical device from the data model.
Kent Hagerman2b216042020-04-03 18:28:56 -0400219func (agent *LogicalAgent) stop(ctx context.Context) error {
khenaidoo442e7c72020-03-10 16:13:48 -0400220 var returnErr error
221 agent.stopOnce.Do(func() {
Himani Chawlab4c25912020-11-12 17:16:38 +0530222 logger.Info(ctx, "stopping-logical-device-agent")
khenaidoo8c3303d2019-02-13 14:59:39 -0500223
khenaidoo442e7c72020-03-10 16:13:48 -0400224 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
225 // This should never happen - an error is returned only if the agent is stopped and an agent is only stopped once.
226 returnErr = err
227 return
228 }
229 defer agent.requestQueue.RequestComplete()
khenaidood948f772021-08-11 17:49:24 -0400230 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.internalTimeout)
Himani Chawla40af2702021-01-27 15:06:30 +0530231 // Before deletion of the logical agent, make sure all events for ldagent are sent to avoid race conditions
232 if err := agent.orderedEvents.waitForAllEventsToBeSent(subCtx, cancel); err != nil {
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +0530233 // Log the error here
Himani Chawla40af2702021-01-27 15:06:30 +0530234 logger.Errorw(ctx, "failed-to-send-all-events-on-the-logical-device-before-deletion",
235 log.Fields{"error": err, "logical-device-id": agent.logicalDeviceID})
236 }
Girish Gowdra3d922b62021-12-06 15:27:02 +0530237
Girish Gowdra06a0ce22021-12-14 11:09:10 +0530238 if err := agent.ldeviceMgr.deleteAllLogicalMetersForLogicalDevice(ctx, agent.logicalDeviceID); err != nil {
239 // Just log the error. The logical device or port may already have been deleted before this callback is invoked.
240 logger.Warnw(ctx, "delete-logical-meters-error", log.Fields{"device-id": agent.logicalDeviceID, "error": err})
241 }
242
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +0530243 // Remove the logical device from the model
Kent Hagermanf5a67352020-04-30 15:15:26 -0400244 if err := agent.ldProxy.Remove(ctx, agent.logicalDeviceID); err != nil {
khenaidoo442e7c72020-03-10 16:13:48 -0400245 returnErr = err
khenaidoo442e7c72020-03-10 16:13:48 -0400246 } else {
Himani Chawlab4c25912020-11-12 17:16:38 +0530247 logger.Debugw(ctx, "logical-device-removed", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo442e7c72020-03-10 16:13:48 -0400248 }
Girish Gowdra3d922b62021-12-06 15:27:02 +0530249
Kent Hagermanfa9d6d42020-05-25 11:49:40 -0400250 // TODO: remove all entries from all loaders
251 // TODO: don't allow any more modifications to flows/groups/meters/ports or to any logical device field
khenaidoo442e7c72020-03-10 16:13:48 -0400252
Sridhar Ravindra7cb6eda2024-12-06 07:53:51 +0530253 close(agent.exitChannel)
Kent Hagerman4f355f52020-03-30 16:01:33 -0400254 agent.stopped = true
khenaidoo442e7c72020-03-10 16:13:48 -0400255
Himani Chawlab4c25912020-11-12 17:16:38 +0530256 logger.Info(ctx, "logical-device-agent-stopped")
khenaidoo442e7c72020-03-10 16:13:48 -0400257 })
258 return returnErr
khenaidoo4d4802d2018-10-04 21:59:49 -0400259}
260
Kent Hagermancba2f302020-07-28 13:37:36 -0400261// GetLogicalDeviceReadOnly returns the latest logical device data
262func (agent *LogicalAgent) GetLogicalDeviceReadOnly(ctx context.Context) (*voltha.LogicalDevice, error) {
khenaidoo442e7c72020-03-10 16:13:48 -0400263 if err := agent.requestQueue.WaitForGreenLight(ctx); err != nil {
264 return nil, err
265 }
266 defer agent.requestQueue.RequestComplete()
Kent Hagermancba2f302020-07-28 13:37:36 -0400267 return agent.logicalDevice, nil
khenaidoo92e62c52018-10-03 14:02:54 -0400268}
269
Gamze Abakafac8c192021-06-28 12:04:32 +0000270func (agent *LogicalAgent) addFlowsAndGroupsToDevices(ctx context.Context, deviceRules *fu.DeviceRules) []coreutils.Response {
271 logger.Debugw(ctx, "send-add-flows-to-device-manager", log.Fields{"logical-device-id": agent.logicalDeviceID, "device-rules": deviceRules})
khenaidoo19d7b632018-10-30 10:49:50 -0400272
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500273 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +0530274 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500275 response := coreutils.NewResponse()
276 responses = append(responses, response)
277 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidood948f772021-08-11 17:49:24 -0400278 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.internalTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530279 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400280 defer cancel()
Gamze Abakafac8c192021-06-28 12:04:32 +0000281
282 flowMeterConfig, err := agent.GetMeterConfig(ctx, value.ListFlows())
283 if err != nil {
284 logger.Error(ctx, "meter-referred-in-flow-not-present")
285 response.Error(status.Errorf(codes.NotFound, "meter-referred-in-flow-not-present"))
286 return
287 }
khenaidoo0db4c812020-05-27 15:27:30 -0400288 start := time.Now()
Gamze Abakafac8c192021-06-28 12:04:32 +0000289 if err := agent.deviceMgr.addFlowsAndGroups(subCtx, deviceId, value.ListFlows(), value.ListGroups(), toMetadata(flowMeterConfig)); err != nil {
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700290 logger.Errorw(ctx, "flow-add-failed", log.Fields{
divyadesaicb8b59d2020-08-18 09:55:47 +0000291 "device-id": deviceId,
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700292 "error": err,
293 "wait-time": time.Since(start),
294 "flows": value.ListFlows(),
295 "groups": value.ListGroups(),
296 })
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500297 response.Error(status.Errorf(codes.Internal, "flow-add-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -0400298 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500299 response.Done()
npujar1d86a522019-11-14 17:11:16 +0530300 }(deviceID, value)
khenaidoo19d7b632018-10-30 10:49:50 -0400301 }
khenaidoo442e7c72020-03-10 16:13:48 -0400302 // Return responses (an array of channels) for the caller to wait for a response from the far end.
303 return responses
khenaidoo0458db62019-06-20 08:50:36 -0400304}
khenaidoo19d7b632018-10-30 10:49:50 -0400305
Gamze Abakafac8c192021-06-28 12:04:32 +0000306func (agent *LogicalAgent) deleteFlowsAndGroupsFromDevices(ctx context.Context, deviceRules *fu.DeviceRules, mod *ofp.OfpFlowMod) []coreutils.Response {
divyadesaicb8b59d2020-08-18 09:55:47 +0000307 logger.Debugw(ctx, "send-delete-flows-to-device-manager", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -0400308
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500309 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +0530310 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500311 response := coreutils.NewResponse()
312 responses = append(responses, response)
313 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidood948f772021-08-11 17:49:24 -0400314 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.internalTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530315 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
khenaidoo442e7c72020-03-10 16:13:48 -0400316 defer cancel()
Gamze Abakafac8c192021-06-28 12:04:32 +0000317
318 flowMeterConfig, err := agent.GetMeterConfig(ctx, value.ListFlows())
319 if err != nil {
320 logger.Error(ctx, "meter-referred-in-flow-not-present")
321 response.Error(status.Errorf(codes.NotFound, "meter-referred-in-flow-not-present"))
322 return
323 }
khenaidoo0db4c812020-05-27 15:27:30 -0400324 start := time.Now()
Gamze Abakafac8c192021-06-28 12:04:32 +0000325 if err := agent.deviceMgr.deleteFlowsAndGroups(subCtx, deviceId, value.ListFlows(), value.ListGroups(), toMetadata(flowMeterConfig)); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000326 logger.Errorw(ctx, "flows-and-groups-delete-failed", log.Fields{
Matteo Scandolo367162b2020-06-22 15:07:33 -0700327 "device-id": deviceId,
328 "error": err,
329 "flow-cookie": mod.Cookie,
330 "wait-time": time.Since(start),
331 })
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500332 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -0400333 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500334 response.Done()
npujar1d86a522019-11-14 17:11:16 +0530335 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -0400336 }
khenaidoo442e7c72020-03-10 16:13:48 -0400337 return responses
khenaidoo0458db62019-06-20 08:50:36 -0400338}
339
khenaidoo9beaaf12021-10-19 17:32:01 -0400340func (agent *LogicalAgent) updateFlowsAndGroupsOfDevice(ctx context.Context, deviceRules *fu.DeviceRules, flowMetadata *ofp.FlowMetadata) []coreutils.Response {
divyadesaicb8b59d2020-08-18 09:55:47 +0000341 logger.Debugw(ctx, "send-update-flows-to-device-manager", log.Fields{"logical-device-id": agent.logicalDeviceID})
khenaidoo0458db62019-06-20 08:50:36 -0400342
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500343 responses := make([]coreutils.Response, 0)
npujar1d86a522019-11-14 17:11:16 +0530344 for deviceID, value := range deviceRules.GetRules() {
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500345 response := coreutils.NewResponse()
346 responses = append(responses, response)
347 go func(deviceId string, value *fu.FlowsAndGroups) {
khenaidood948f772021-08-11 17:49:24 -0400348 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.internalTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530349 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
350
khenaidoo442e7c72020-03-10 16:13:48 -0400351 defer cancel()
khenaidoo0db4c812020-05-27 15:27:30 -0400352 if err := agent.deviceMgr.updateFlowsAndGroups(subCtx, deviceId, value.ListFlows(), value.ListGroups(), flowMetadata); err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000353 logger.Errorw(ctx, "flow-update-failed", log.Fields{"device-id": deviceId, "error": err})
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500354 response.Error(status.Errorf(codes.Internal, "flow-update-failed: %s", deviceId))
khenaidoo0458db62019-06-20 08:50:36 -0400355 }
Kent Hagerman8da2f1e2019-11-25 17:28:09 -0500356 response.Done()
npujar1d86a522019-11-14 17:11:16 +0530357 }(deviceID, value)
khenaidoo0458db62019-06-20 08:50:36 -0400358 }
khenaidoo442e7c72020-03-10 16:13:48 -0400359 return responses
khenaidoo19d7b632018-10-30 10:49:50 -0400360}
361
Gamze Abakafac8c192021-06-28 12:04:32 +0000362func (agent *LogicalAgent) deleteFlowsFromParentDevice(ctx context.Context, flows map[uint64]*ofp.OfpFlowStats, mod *ofp.OfpFlowMod) []coreutils.Response {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000363 logger.Debugw(ctx, "deleting-flows-from-parent-device", log.Fields{"logical-device-id": agent.logicalDeviceID, "flows": flows})
khenaidoo787224a2020-04-16 18:08:47 -0400364 responses := make([]coreutils.Response, 0)
Kent Hagerman433a31a2020-05-20 19:04:48 -0400365 for _, flow := range flows {
khenaidoo787224a2020-04-16 18:08:47 -0400366 response := coreutils.NewResponse()
367 responses = append(responses, response)
Gamze Abakafac8c192021-06-28 12:04:32 +0000368
369 flowMeterConfig, err := agent.GetMeterConfig(ctx, []*ofp.OfpFlowStats{flow})
370 if err != nil {
371 logger.Error(ctx, "meter-referred-in-flow-not-present")
372 response.Error(status.Errorf(codes.NotFound, "meter-referred-in-flow-not-present"))
373 return responses
374 }
khenaidoo787224a2020-04-16 18:08:47 -0400375 uniPort, err := agent.getUNILogicalPortNo(flow)
376 if err != nil {
divyadesaicb8b59d2020-08-18 09:55:47 +0000377 logger.Error(ctx, "no-uni-port-in-flow", log.Fields{"device-id": agent.rootDeviceID, "flow": flow, "error": err})
khenaidoo787224a2020-04-16 18:08:47 -0400378 response.Error(err)
379 response.Done()
380 continue
381 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000382 logger.Debugw(ctx, "uni-port", log.Fields{"flows": flows, "uni-port": uniPort})
khenaidoo9beaaf12021-10-19 17:32:01 -0400383 go func(uniPort uint32, metadata *ofp.FlowMetadata) {
khenaidood948f772021-08-11 17:49:24 -0400384 subCtx, cancel := context.WithTimeout(log.WithSpanFromContext(context.Background(), ctx), agent.internalTimeout)
Himani Chawlab4c25912020-11-12 17:16:38 +0530385 subCtx = coreutils.WithRPCMetadataFromContext(subCtx, ctx)
386
khenaidoo787224a2020-04-16 18:08:47 -0400387 defer cancel()
khenaidoo0db4c812020-05-27 15:27:30 -0400388 if err := agent.deviceMgr.deleteParentFlows(subCtx, agent.rootDeviceID, uniPort, metadata); err != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000389 logger.Error(ctx, "flow-delete-failed-from-parent-device", log.Fields{
Matteo Scandolo367162b2020-06-22 15:07:33 -0700390 "device-id": agent.rootDeviceID,
391 "error": err,
392 "flow-cookie": mod.Cookie,
393 })
khenaidoo787224a2020-04-16 18:08:47 -0400394 response.Error(status.Errorf(codes.Internal, "flow-delete-failed: %s %v", agent.rootDeviceID, err))
395 }
396 response.Done()
Gamze Abakafac8c192021-06-28 12:04:32 +0000397 }(uniPort, toMetadata(flowMeterConfig))
khenaidoo787224a2020-04-16 18:08:47 -0400398 }
399 return responses
400}
401
Kent Hagerman2b216042020-04-03 18:28:56 -0400402func (agent *LogicalAgent) packetOut(ctx context.Context, packet *ofp.OfpPacketOut) {
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700403 if logger.V(log.InfoLevel) {
404 logger.Infow(ctx, "packet-out", log.Fields{
Himani Chawlab4c25912020-11-12 17:16:38 +0530405 "packet": hex.EncodeToString(packet.Data),
406 "in-port": packet.GetInPort(),
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700407 })
408 }
khenaidoo68c930b2019-05-13 11:46:51 -0400409 outPort := fu.GetPacketOutPort(packet)
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +0530410 // frame := packet.GetData()
411 // TODO: Use a channel between the logical agent and the device agent
npujar467fe752020-01-16 20:17:45 +0530412 if err := agent.deviceMgr.packetOut(ctx, agent.rootDeviceID, outPort, packet); err != nil {
Himani Chawlab4c25912020-11-12 17:16:38 +0530413 logger.Error(ctx, "packet-out-failed", log.Fields{"logical-device-id": agent.rootDeviceID})
khenaidooca301322019-01-09 23:06:32 -0500414 }
khenaidoofdbad6e2018-11-06 22:26:38 -0500415}
416
khenaidood948f772021-08-11 17:49:24 -0400417func (agent *LogicalAgent) packetIn(ctx context.Context, port uint32, packet []byte) {
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700418 if logger.V(log.InfoLevel) {
khenaidood948f772021-08-11 17:49:24 -0400419 logger.Infow(ctx, "packet-in", log.Fields{
420 "port": port,
421 "packet": hex.EncodeToString(packet),
Matteo Scandolo45e514a2020-08-05 15:27:10 -0700422 })
423 }
424
khenaidoo68c930b2019-05-13 11:46:51 -0400425 packetIn := fu.MkPacketIn(port, packet)
khenaidood948f772021-08-11 17:49:24 -0400426 agent.ldeviceMgr.SendPacketIn(ctx, agent.logicalDeviceID, packetIn)
Rohan Agrawal31f21802020-06-12 05:38:46 +0000427 logger.Debugw(ctx, "sending-packet-in", log.Fields{"packet": hex.EncodeToString(packetIn.Data)})
khenaidoofdbad6e2018-11-06 22:26:38 -0500428}