blob: ba33d780ad8f5e1ee8f4a21c2310801c5e1eaae6 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14 */
15
16package controller
17
18import (
19 "context"
20 "errors"
21 "sync"
22 "time"
23
24 "encoding/hex"
25
26 "voltha-go-controller/database"
27 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
28 "voltha-go-controller/internal/pkg/intf"
29 "voltha-go-controller/internal/pkg/of"
30 "voltha-go-controller/internal/pkg/tasks"
31 "voltha-go-controller/internal/pkg/util"
32 "voltha-go-controller/internal/pkg/vpagent"
33
Tinoj Joseph1d108322022-07-13 10:07:39 +053034 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053035)
36
37var logger log.CLogger
38var ctx = context.TODO()
39
40func init() {
41 // Setup this package so that it's log level can be modified at run time
42 var err error
Tinoj Joseph1d108322022-07-13 10:07:39 +053043 logger, err = log.AddPackageWithDefaultParam()
Naveen Sampath04696f72022-06-13 15:19:14 +053044 if err != nil {
45 panic(err)
46 }
47}
48
49var db database.DBIntf
50
Akash Soni6f369452023-09-19 11:18:28 +053051type VoltControllerInterface interface {
52 GetDevice(id string) (*Device, error)
53 GetAllPendingFlows() ([]*of.VoltSubFlow, error)
54 GetAllFlows() ([]*of.VoltSubFlow, error)
55 GetFlows(deviceID string) ([]*of.VoltSubFlow, error)
56 GetFlow(deviceID string, cookie uint64) (*of.VoltSubFlow, error)
57 GetGroups(cntx context.Context, id uint32) (*of.Group, error)
58 GetGroupList() ([]*of.Group, error)
59 GetMeterInfo(cntx context.Context, id uint32) (map[string]*of.Meter, error)
60 GetAllMeterInfo() (map[string][]*of.Meter, error)
61 GetTaskList(device string) []tasks.Task
62}
63
Naveen Sampath04696f72022-06-13 15:19:14 +053064// VoltController structure
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053065//
66//nolint:govet
Naveen Sampath04696f72022-06-13 15:19:14 +053067type VoltController struct {
Naveen Sampath04696f72022-06-13 15:19:14 +053068 ctx context.Context
69 app intf.App
Naveen Sampath04696f72022-06-13 15:19:14 +053070 BlockedDeviceList *util.ConcurrentMap
71 deviceTaskQueue *util.ConcurrentMap
vinokuma926cb3e2023-03-29 11:41:06 +053072 vagent map[string]*vpagent.VPAgent
bseenivaa8cb94c2024-12-16 13:37:17 +053073 Devices sync.Map
vinokuma926cb3e2023-03-29 11:41:06 +053074 rebootInProgressDevices map[string]string
75 deviceLock sync.RWMutex
76 rebootLock sync.Mutex
Sridhar Ravindra3ec14232024-01-01 19:11:48 +053077 deviceTableSyncDuration time.Duration // Time interval between each cycle of audit task
78 maxFlowRetryDuration time.Duration // Maximum duration for which flows will be retried upon failures
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053079 maxFlowRetryAttempts int64 // maxFlowRetryAttempt = maxFlowRetryDuration / deviceTableSyncDuration
vinokuma926cb3e2023-03-29 11:41:06 +053080 RebootFlow bool
Naveen Sampath04696f72022-06-13 15:19:14 +053081}
82
83var vcontroller *VoltController
84
85// NewController is the constructor for VoltController
86func NewController(ctx context.Context, app intf.App) intf.IVPClientAgent {
87 var controller VoltController
88
89 controller.rebootInProgressDevices = make(map[string]string)
Naveen Sampath04696f72022-06-13 15:19:14 +053090 controller.deviceLock = sync.RWMutex{}
91 controller.ctx = ctx
92 controller.app = app
93 controller.BlockedDeviceList = util.NewConcurrentMap()
94 controller.deviceTaskQueue = util.NewConcurrentMap()
95 db = database.GetDatabase()
96 vcontroller = &controller
97 return &controller
98}
99
vinokuma926cb3e2023-03-29 11:41:06 +0530100// SetDeviceTableSyncDuration - sets interval between device table sync up activity
101// duration - in minutes
Tinoj Josephaf37ce82022-12-28 11:59:43 +0530102func (v *VoltController) SetDeviceTableSyncDuration(duration int) {
103 v.deviceTableSyncDuration = time.Duration(duration) * time.Second
104}
105
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530106// SetMaxFlowRetryDuration - sets max flow retry interval
107func (v *VoltController) SetMaxFlowRetryDuration(duration int) {
108 v.maxFlowRetryDuration = time.Duration(duration) * time.Second
109}
110
111// SetMaxFlowRetryAttempts - sets max flow retry attempts
112func (v *VoltController) SetMaxFlowRetryAttempts() {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530113 v.maxFlowRetryAttempts = int64((v.maxFlowRetryDuration / v.deviceTableSyncDuration))
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530114}
115
vinokuma926cb3e2023-03-29 11:41:06 +0530116// GetDeviceTableSyncDuration - returns configured device table sync duration
Tinoj Josephaf37ce82022-12-28 11:59:43 +0530117func (v *VoltController) GetDeviceTableSyncDuration() time.Duration {
118 return v.deviceTableSyncDuration
119}
120
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530121// GetMaxFlowRetryAttempt - returns max flow retry attempst
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530122func (v *VoltController) GetMaxFlowRetryAttempt() int64 {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530123 return v.maxFlowRetryAttempts
124}
125
Naveen Sampath04696f72022-06-13 15:19:14 +0530126// AddDevice to add device
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530127func (v *VoltController) AddDevice(cntx context.Context, config *intf.VPClientCfg) intf.IVPClient {
Tinoj Joseph429b9d92022-11-16 18:51:05 +0530128 d := NewDevice(cntx, config.DeviceID, config.SerialNum, config.VolthaClient, config.SouthBoundID, config.MfrDesc, config.HwDesc, config.SwDesc)
bseenivaa8cb94c2024-12-16 13:37:17 +0530129 v.Devices.Store(config.DeviceID, d)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530130 v.app.AddDevice(cntx, d.ID, d.SerialNum, config.SouthBoundID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530131
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530132 d.RestoreMetersFromDb(cntx)
133 d.RestoreGroupsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530134 d.ConnectInd(context.TODO(), intf.DeviceDisc)
135 d.packetOutChannel = config.PacketOutChannel
136
Akash Soni6168f312023-05-18 20:57:33 +0530137 logger.Debugw(ctx, "Added device", log.Fields{"Device": config.DeviceID, "SerialNo": d.SerialNum, "State": d.State})
Naveen Sampath04696f72022-06-13 15:19:14 +0530138
139 return d
140}
141
142// DelDevice to delete device
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530143func (v *VoltController) DelDevice(cntx context.Context, id string) {
bseenivaa8cb94c2024-12-16 13:37:17 +0530144 var device *Device
145 d, ok := v.Devices.Load(id)
Naveen Sampath04696f72022-06-13 15:19:14 +0530146 if ok {
bseenivaa8cb94c2024-12-16 13:37:17 +0530147 v.Devices.Delete(id)
148 device, ok = d.(*Device)
149 if ok {
150 device.Delete()
151 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530152 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530153 v.app.DelDevice(cntx, id)
bseenivaa8cb94c2024-12-16 13:37:17 +0530154 device.cancel() // To stop the device tables sync routine
Akash Soni6168f312023-05-18 20:57:33 +0530155 logger.Debugw(ctx, "Deleted device", log.Fields{"Device": id})
Naveen Sampath04696f72022-06-13 15:19:14 +0530156}
157
vinokuma926cb3e2023-03-29 11:41:06 +0530158// AddControllerTask - add task to controller queue
Naveen Sampath04696f72022-06-13 15:19:14 +0530159func (v *VoltController) AddControllerTask(device string, task tasks.Task) {
160 var taskQueueIntf interface{}
161 var taskQueue *tasks.Tasks
162 var found bool
163 if taskQueueIntf, found = v.deviceTaskQueue.Get(device); !found {
164 taskQueue = tasks.NewTasks(context.TODO())
165 v.deviceTaskQueue.Set(device, taskQueue)
166 } else {
167 taskQueue = taskQueueIntf.(*tasks.Tasks)
168 }
169 taskQueue.AddTask(task)
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530170 logger.Debugw(ctx, "Task Added to Controller Task List", log.Fields{"Len": taskQueue.NumPendingTasks(), "Total": taskQueue.TotalTasks()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530171}
172
vinokuma926cb3e2023-03-29 11:41:06 +0530173// AddNewDevice - called when new device is discovered. This will be
174// processed as part of controller queue
Naveen Sampath04696f72022-06-13 15:19:14 +0530175func (v *VoltController) AddNewDevice(config *intf.VPClientCfg) {
176 adt := NewAddDeviceTask(config)
177 v.AddControllerTask(config.DeviceID, adt)
178}
179
180// GetDevice to get device info
181func (v *VoltController) GetDevice(id string) (*Device, error) {
bseenivaa8cb94c2024-12-16 13:37:17 +0530182 var device *Device
183 d, ok := v.Devices.Load(id)
184 if !ok {
185 return nil, errorCodes.ErrDeviceNotFound
186 }
187 device, ok = d.(*Device)
Naveen Sampath04696f72022-06-13 15:19:14 +0530188 if ok {
bseenivaa8cb94c2024-12-16 13:37:17 +0530189 return device, nil
Naveen Sampath04696f72022-06-13 15:19:14 +0530190 }
191 return nil, errorCodes.ErrDeviceNotFound
192}
193
194// IsRebootInProgressForDevice to check if reboot is in progress for the device
195func (v *VoltController) IsRebootInProgressForDevice(device string) bool {
196 v.rebootLock.Lock()
197 defer v.rebootLock.Unlock()
198 _, ok := v.rebootInProgressDevices[device]
199 return ok
200}
201
202// SetRebootInProgressForDevice to set reboot in progress for the device
203func (v *VoltController) SetRebootInProgressForDevice(device string) bool {
204 v.rebootLock.Lock()
205 defer v.rebootLock.Unlock()
206 _, ok := v.rebootInProgressDevices[device]
207 if ok {
208 return true
209 }
210 v.rebootInProgressDevices[device] = device
211 logger.Warnw(ctx, "Setted Reboot-In-Progress flag", log.Fields{"Device": device})
212
213 d, err := v.GetDevice(device)
214 if err == nil {
215 d.ResetCache()
216 } else {
217 logger.Errorw(ctx, "Failed to get device", log.Fields{"Device": device, "Error": err})
218 }
219
220 return true
221}
222
223// ReSetRebootInProgressForDevice to reset reboot in progress for the device
224func (v *VoltController) ReSetRebootInProgressForDevice(device string) bool {
225 v.rebootLock.Lock()
226 defer v.rebootLock.Unlock()
227 _, ok := v.rebootInProgressDevices[device]
228 if !ok {
229 return true
230 }
231 delete(v.rebootInProgressDevices, device)
232 logger.Warnw(ctx, "Resetted Reboot-In-Progress flag", log.Fields{"Device": device})
233 return true
234}
235
236// DeviceRebootInd is device reboot indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530237func (v *VoltController) DeviceRebootInd(cntx context.Context, dID string, srNo string, sbID string) {
238 v.app.DeviceRebootInd(cntx, dID, srNo, sbID)
239 _ = db.DelAllRoutesForDevice(cntx, dID)
240 _ = db.DelAllGroup(cntx, dID)
241 _ = db.DelAllMeter(cntx, dID)
242 _ = db.DelAllPONCounters(cntx, dID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530243}
244
245// DeviceDisableInd is device deactivation indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530246func (v *VoltController) DeviceDisableInd(cntx context.Context, dID string) {
247 v.app.DeviceDisableInd(cntx, dID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530248}
249
vinokuma926cb3e2023-03-29 11:41:06 +0530250// TriggerPendingProfileDeleteReq - trigger pending profile delete requests
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530251func (v *VoltController) TriggerPendingProfileDeleteReq(cntx context.Context, device string) {
252 v.app.TriggerPendingProfileDeleteReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +0530253}
254
vinokuma926cb3e2023-03-29 11:41:06 +0530255// TriggerPendingMigrateServicesReq - trigger pending services migration requests
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530256func (v *VoltController) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
257 v.app.TriggerPendingMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +0530258}
259
260// SetAuditFlags to set the audit flags
261func (v *VoltController) SetAuditFlags(device *Device) {
262 v.app.SetRebootFlag(true)
263 device.auditInProgress = true
264}
265
266// ResetAuditFlags to reset the audit flags
267func (v *VoltController) ResetAuditFlags(device *Device) {
268 v.app.SetRebootFlag(false)
269 device.auditInProgress = false
270}
271
vinokuma926cb3e2023-03-29 11:41:06 +0530272// ProcessFlowModResultIndication - send flow mod result notification
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530273func (v *VoltController) ProcessFlowModResultIndication(cntx context.Context, flowStatus intf.FlowStatus) {
274 v.app.ProcessFlowModResultIndication(cntx, flowStatus)
Naveen Sampath04696f72022-06-13 15:19:14 +0530275}
276
Akash Sonief452f12024-12-12 18:20:28 +0530277func (v *VoltController) CheckAndDeactivateService(ctx context.Context, flow *of.VoltSubFlow, devSerialNum string, devID string) {
278 v.app.CheckAndDeactivateService(ctx, flow, devSerialNum, devID)
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530279}
280
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530281func (v *VoltController) GetAllFlowsForSvc(ctx context.Context, flow *of.VoltSubFlow, devID string, devSerialNum string) []uint64 {
282 return v.app.GetAllFlowsForSvc(ctx, flow, devID, devSerialNum)
283}
284
Naveen Sampath04696f72022-06-13 15:19:14 +0530285// AddVPAgent to add the vpagent
286func (v *VoltController) AddVPAgent(vep string, vpa *vpagent.VPAgent) {
287 v.vagent[vep] = vpa
288}
289
290// VPAgent to get vpagent info
291func (v *VoltController) VPAgent(vep string) (*vpagent.VPAgent, error) {
292 vpa, ok := v.vagent[vep]
293 if ok {
294 return vpa, nil
295 }
296 return nil, errors.New("VPA Not Registered")
297}
298
299// PacketOutReq for packet out request
300func (v *VoltController) PacketOutReq(device string, inport string, outport string, pkt []byte, isCustomPkt bool) error {
301 logger.Debugw(ctx, "Packet Out Req", log.Fields{"Device": device, "OutPort": outport})
302 d, err := v.GetDevice(device)
303 if err != nil {
304 return err
305 }
306 logger.Debugw(ctx, "Packet Out Pkt", log.Fields{"Pkt": hex.EncodeToString(pkt)})
307 return d.PacketOutReq(inport, outport, pkt, isCustomPkt)
308}
309
310// AddFlows to add flows
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530311func (v *VoltController) AddFlows(cntx context.Context, port string, device string, flow *of.VoltFlow, skipFlowPushToVoltha bool) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530312 d, err := v.GetDevice(device)
313 if err != nil {
314 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": device})
315 return err
316 }
317 devPort := d.GetPortByName(port)
318 if devPort == nil {
319 logger.Errorw(ctx, "Port Not Found", log.Fields{"Device": device})
320 return errorCodes.ErrPortNotFound
321 }
322 if d.ctx == nil {
vinokuma926cb3e2023-03-29 11:41:06 +0530323 // FIXME: Application should know the context before it could submit task. Handle at application level
Naveen Sampath04696f72022-06-13 15:19:14 +0530324 logger.Errorw(ctx, "Context is missing. AddFlow Operation Not added to Task", log.Fields{"Device": device})
325 return errorCodes.ErrInvalidParamInRequest
326 }
327
328 var isMigrationRequired bool
329 if flow.MigrateCookie {
330 // flow migration to new cookie must be done only during the audit. Migration for all subflows must be done if
331 // atlease one subflow with old cookie found in the device.
332 for _, subFlow := range flow.SubFlows {
333 if isMigrationRequired = d.IsFlowPresentWithOldCookie(subFlow); isMigrationRequired {
334 break
335 }
336 }
337 }
338
339 if isMigrationRequired {
340 // In this case, the flow is updated in local cache and db here.
341 // Actual flow deletion and addition at voltha will happen during flow tables audit.
342 for _, subFlow := range flow.SubFlows {
343 logger.Debugw(ctx, "Cookie Migration Required", log.Fields{"OldCookie": subFlow.OldCookie, "NewCookie": subFlow.Cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530344 if err := d.DelFlowWithOldCookie(cntx, subFlow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530345 logger.Errorw(ctx, "Delete flow with old cookie failed", log.Fields{"Error": err, "OldCookie": subFlow.OldCookie})
346 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530347 if err := d.AddFlow(cntx, subFlow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530348 logger.Errorw(ctx, "Flow Add Failed", log.Fields{"Error": err, "Cookie": subFlow.Cookie})
349 }
350 }
351 } else {
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530352 flowsToVoltha := &of.VoltFlow{}
353 flowsToVoltha.SubFlows = make(map[uint64]*of.VoltSubFlow)
354 // During VGC restart, build and add flows only to cache.
355 // No need to push flows to voltha now as it will be audited later
356 for _, subFlow := range flow.SubFlows {
357 logger.Debugw(ctx, "Adding flows to device cache", log.Fields{"Cookie": subFlow.Cookie})
358 if !skipFlowPushToVoltha {
359 subFlow.State = of.FlowAddPending
360 }
361 if err := d.AddFlow(cntx, subFlow); err != nil {
362 logger.Warnw(ctx, "Add Flow Error", log.Fields{"Cookie": subFlow.Cookie, "Reason": err.Error()})
363 } else {
364 flowsToVoltha.SubFlows[subFlow.Cookie] = subFlow
365 }
366 }
367
368 if !skipFlowPushToVoltha {
369 flowsToVoltha.Command = of.CommandAdd
370 d.UpdateFlows(flowsToVoltha, devPort)
371 for cookie := range flowsToVoltha.SubFlows {
372 logger.Debugw(ctx, "Flow Add added to queue", log.Fields{"Cookie": cookie, "Device": device, "Port": port})
373 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530374 }
375 }
376 return nil
377}
378
379// DelFlows to delete flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530380// delFlowsOnlyInDevice flag indicates that flows should be deleted only in DB/device and should not be forwarded to core
381func (v *VoltController) DelFlows(cntx context.Context, port string, device string, flow *of.VoltFlow, delFlowsOnlyInDevice bool) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530382 d, err := v.GetDevice(device)
383 if err != nil {
384 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": device})
385 return err
386 }
387 devPort := d.GetPortByName(port)
388 if devPort == nil {
389 logger.Errorw(ctx, "Port Not Found", log.Fields{"Device": device})
390 return errorCodes.ErrPortNotFound
391 }
392 if d.ctx == nil {
vinokuma926cb3e2023-03-29 11:41:06 +0530393 // FIXME: Application should know the context before it could submit task. Handle at application level
Naveen Sampath04696f72022-06-13 15:19:14 +0530394 logger.Errorw(ctx, "Context is missing. DelFlow Operation Not added to Task", log.Fields{"Device": device})
395 return errorCodes.ErrInvalidParamInRequest
396 }
397
398 var isMigrationRequired bool
399 if flow.MigrateCookie {
400 // flow migration to new cookie must be done only during the audit. Migration for all subflows must be done if
401 // atlease one subflow with old cookie found in the device.
402 for _, subFlow := range flow.SubFlows {
403 if isMigrationRequired = d.IsFlowPresentWithOldCookie(subFlow); isMigrationRequired {
404 break
405 }
406 }
407 }
408
409 if isMigrationRequired {
410 // In this case, the flow is deleted from local cache and db here.
411 // Actual flow deletion at voltha will happen during flow tables audit.
412 for _, subFlow := range flow.SubFlows {
413 logger.Debugw(ctx, "Old Cookie delete Required", log.Fields{"OldCookie": subFlow.OldCookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530414 if err := d.DelFlowWithOldCookie(cntx, subFlow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530415 logger.Errorw(ctx, "DelFlowWithOldCookie failed", log.Fields{"OldCookie": subFlow.OldCookie, "Error": err})
416 }
417 }
418 } else {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530419 // Delete flows only in DB/device when Port Delete has come. Do not send flows to core during Port Delete
420 if delFlowsOnlyInDevice {
421 for cookie, subFlow := range flow.SubFlows {
422 err := d.DelFlow(ctx, subFlow)
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530423 logger.Debugw(ctx, "Flow Deleted from device/DB", log.Fields{"Cookie": cookie, "Device": device, "Port": port, "Error": err})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530424 }
425 } else {
426 flow.Command = of.CommandDel
427 d.UpdateFlows(flow, devPort)
428 for cookie := range flow.SubFlows {
429 logger.Debugw(ctx, "Flow Del added to queue", log.Fields{"Cookie": cookie, "Device": device, "Port": port})
430 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530431 }
432 }
433 return nil
434}
435
436// GroupUpdate for group update
437func (v *VoltController) GroupUpdate(port string, device string, group *of.Group) error {
438 d, err := v.GetDevice(device)
439 if err != nil {
440 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": device})
441 return err
442 }
443
444 devPort := d.GetPortByName(port)
445 if devPort == nil {
446 logger.Errorw(ctx, "Port Not Found", log.Fields{"Device": device})
447 return errorCodes.ErrPortNotFound
448 }
449
450 if d.ctx == nil {
vinokuma926cb3e2023-03-29 11:41:06 +0530451 // FIXME: Application should know the context before it could submit task. Handle at application level
Naveen Sampath04696f72022-06-13 15:19:14 +0530452 logger.Errorw(ctx, "Context is missing. GroupMod Operation Not added to task", log.Fields{"Device": device})
453 return errorCodes.ErrInvalidParamInRequest
454 }
455
456 d.UpdateGroup(group, devPort)
457 return nil
458}
459
460// ModMeter to get mod meter info
461func (v *VoltController) ModMeter(port string, device string, command of.MeterCommand, meter *of.Meter) error {
462 d, err := v.GetDevice(device)
463 if err != nil {
464 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": device})
465 return err
466 }
467
468 devPort := d.GetPortByName(port)
469 if devPort == nil {
470 logger.Errorw(ctx, "Port Not Found", log.Fields{"Device": device})
471 return errorCodes.ErrPortNotFound
472 }
473
474 d.ModMeter(command, meter, devPort)
475 return nil
476}
477
478// PortAddInd for port add indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530479func (v *VoltController) PortAddInd(cntx context.Context, device string, id uint32, name string) {
480 v.app.PortAddInd(cntx, device, id, name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530481}
482
483// PortDelInd for port delete indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530484func (v *VoltController) PortDelInd(cntx context.Context, device string, port string) {
485 v.app.PortDelInd(cntx, device, port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530486}
487
488// PortUpdateInd for port update indication
489func (v *VoltController) PortUpdateInd(device string, name string, id uint32) {
490 v.app.PortUpdateInd(device, name, id)
491}
492
493// PortUpInd for port up indication
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530494func (v *VoltController) PortUpInd(cntx context.Context, device string, port string, flag bool) {
495 v.app.PortUpInd(cntx, device, port, flag)
Naveen Sampath04696f72022-06-13 15:19:14 +0530496}
497
498// PortDownInd for port down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530499func (v *VoltController) PortDownInd(cntx context.Context, device string, port string) {
500 v.app.PortDownInd(cntx, device, port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530501}
502
503// DeviceUpInd for device up indication
504func (v *VoltController) DeviceUpInd(device string) {
505 v.app.DeviceUpInd(device)
506}
507
508// DeviceDownInd for device down indication
509func (v *VoltController) DeviceDownInd(device string) {
510 v.app.DeviceDownInd(device)
511}
512
513// PacketInInd for packet in indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530514func (v *VoltController) PacketInInd(cntx context.Context, device string, port string, data []byte) {
515 v.app.PacketInInd(cntx, device, port, data)
Naveen Sampath04696f72022-06-13 15:19:14 +0530516}
517
518// GetPortState to get port status
519func (v *VoltController) GetPortState(device string, name string) (PortState, error) {
520 d, err := v.GetDevice(device)
521 if err != nil {
522 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": device})
523 return PortStateDown, err
524 }
525 return d.GetPortState(name)
526}
527
528// UpdateMvlanProfiles for update mvlan profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530529func (v *VoltController) UpdateMvlanProfiles(cntx context.Context, device string) {
530 v.app.UpdateMvlanProfilesForDevice(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +0530531}
532
533// GetController to get controller
534func GetController() *VoltController {
535 return vcontroller
536}
537
538/*
539// PostIndication to post indication
540func (v *VoltController) PostIndication(device string, task interface{}) error {
541 var srvTask AddServiceIndTask
542 var portTask AddPortIndTask
543 var taskCommon tasks.Task
544 var isSvcTask bool
545
546 switch data := task.(type) {
547 case *AddServiceIndTask:
548 srvTask = *data
549 taskCommon = data
550 isSvcTask = true
551 case *AddPortIndTask:
552 portTask = *data
553 taskCommon = data
554 }
555
556 d, err := v.GetDevice(device)
557 if err != nil {
558 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": device})
559 //It means device itself it not present so just post the indication directly
560 if isSvcTask {
561 msgbus.PostAccessConfigInd(srvTask.result, d.SerialNum, srvTask.indicationType, srvTask.serviceName, 0, srvTask.reason, srvTask.trigger, srvTask.portState)
562 } else {
563 msgbus.ProcessPortInd(portTask.indicationType, d.SerialNum, portTask.portName, portTask.accessConfig, portTask.serviceList)
564 }
565 return err
566 }
567 if taskCommon != nil {
568 d.AddTask(taskCommon)
569 }
570 return nil
571}
572*/
573
574// GetTaskList to get the task list
575func (v *VoltController) GetTaskList(device string) []tasks.Task {
576 d, err := v.GetDevice(device)
577 if err != nil || d.ctx == nil {
578 logger.Errorw(ctx, "Device Not Connected/Found", log.Fields{"Device": device, "Dev Obj": d})
579 return []tasks.Task{}
580 }
581 return d.GetTaskList()
Naveen Sampath04696f72022-06-13 15:19:14 +0530582}
583
Akash Soni6f369452023-09-19 11:18:28 +0530584// AddBlockedDevices to add Devices to blocked Devices list
Naveen Sampath04696f72022-06-13 15:19:14 +0530585func (v *VoltController) AddBlockedDevices(deviceSerialNumber string) {
586 v.BlockedDeviceList.Set(deviceSerialNumber, deviceSerialNumber)
587}
588
589// DelBlockedDevices to remove device from blocked device list
590func (v *VoltController) DelBlockedDevices(deviceSerialNumber string) {
591 v.BlockedDeviceList.Remove(deviceSerialNumber)
592}
593
594// IsBlockedDevice to check if device is blocked
595func (v *VoltController) IsBlockedDevice(deviceSerialNumber string) bool {
596 _, ifPresent := v.BlockedDeviceList.Get(deviceSerialNumber)
597 return ifPresent
598}
Tinoj Josephec742f62022-09-29 19:11:10 +0530599
600// GetFlows returns flow specific to device and flowID
601func (v *VoltController) GetFlow(deviceID string, cookie uint64) (*of.VoltSubFlow, error) {
602 d, err := v.GetDevice(deviceID)
603 if err != nil {
604 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID, "Error": err})
605 return nil, err
606 }
607 if flow, ok := d.GetFlow(cookie); ok {
608 return flow, nil
609 }
610 return nil, nil
611}
612
613// GetFlows returns list of flows for a particular device
614func (v *VoltController) GetFlows(deviceID string) ([]*of.VoltSubFlow, error) {
615 d, err := v.GetDevice(deviceID)
616 if err != nil {
617 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID, "Error": err})
Akash Sonia8246972023-01-03 10:37:08 +0530618 return nil, nil
Tinoj Josephec742f62022-09-29 19:11:10 +0530619 }
620 return d.GetAllFlows(), nil
621}
622
623// GetAllFlows returns list of all flows
624func (v *VoltController) GetAllFlows() ([]*of.VoltSubFlow, error) {
625 var flows []*of.VoltSubFlow
bseenivaa8cb94c2024-12-16 13:37:17 +0530626 v.Devices.Range(func(_, value interface{}) bool {
627 d, ok := value.(*Device)
628 if ok {
629 flows = append(flows, d.GetAllFlows()...)
630 }
631 return true
632 })
Tinoj Josephec742f62022-09-29 19:11:10 +0530633 return flows, nil
634}
635
636// GetAllPendingFlows returns list of all flows
637func (v *VoltController) GetAllPendingFlows() ([]*of.VoltSubFlow, error) {
638 var flows []*of.VoltSubFlow
bseenivaa8cb94c2024-12-16 13:37:17 +0530639 v.Devices.Range(func(_, value interface{}) bool {
640 d, ok := value.(*Device)
641 if ok {
642 flows = append(flows, d.GetAllPendingFlows()...)
643 }
644 return true
645 })
Tinoj Josephec742f62022-09-29 19:11:10 +0530646 return flows, nil
647}
Akash Sonib3abf522022-12-19 13:20:02 +0530648func (v *VoltController) GetAllMeterInfo() (map[string][]*of.Meter, error) {
649 logger.Info(ctx, "Entering into GetAllMeterInfo method")
650 meters := map[string][]*of.Meter{}
bseenivaa8cb94c2024-12-16 13:37:17 +0530651 v.Devices.Range(func(_, value interface{}) bool {
652 device, ok := value.(*Device)
653 if ok {
654 logger.Debugw(ctx, "Inside GetAllMeterInfo method", log.Fields{"deviceId": device.ID, "southbound": device.SouthBoundID, "serial no": device.SerialNum})
655 for _, meter := range device.meters {
656 meters[device.ID] = append(meters[device.ID], meter)
657 }
658 logger.Debugw(ctx, "Inside GetAllMeterInfo method", log.Fields{"meters": meters})
Akash Sonib3abf522022-12-19 13:20:02 +0530659 }
bseenivaa8cb94c2024-12-16 13:37:17 +0530660 return true
661 })
Akash Sonib3abf522022-12-19 13:20:02 +0530662 return meters, nil
663}
664
665func (v *VoltController) GetMeterInfo(cntx context.Context, id uint32) (map[string]*of.Meter, error) {
666 logger.Info(ctx, "Entering into GetMeterInfo method")
667 meters := map[string]*of.Meter{}
bseenivaa8cb94c2024-12-16 13:37:17 +0530668 var errResult error
669 v.Devices.Range(func(_, value interface{}) bool {
670 device, ok := value.(*Device)
671 if ok {
672 logger.Debugw(ctx, "Inside GetMeterInfo method", log.Fields{"deviceId": device.ID})
673 meter, err := device.GetMeter(id)
674 if err != nil {
675 logger.Errorw(ctx, "Failed to fetch the meter", log.Fields{"Reason": err.Error()})
676 errResult = err
677 return false
678 }
679 meters[device.ID] = meter
680 logger.Debugw(ctx, "meters", log.Fields{"Meter": meters})
Akash Sonib3abf522022-12-19 13:20:02 +0530681 }
bseenivaa8cb94c2024-12-16 13:37:17 +0530682 return true
683 })
684 if errResult != nil {
685 return nil, errResult
Akash Sonib3abf522022-12-19 13:20:02 +0530686 }
687 return meters, nil
688}
689
690func (v *VoltController) GetGroupList() ([]*of.Group, error) {
691 logger.Info(ctx, "Entering into GetGroupList method")
692 groups := []*of.Group{}
bseenivaa8cb94c2024-12-16 13:37:17 +0530693 v.Devices.Range(func(_, value interface{}) bool {
694 device, ok := value.(*Device)
695 if ok {
696 device.groups.Range(func(key, value interface{}) bool {
697 groupID := key.(uint32)
698 logger.Debugw(ctx, "Inside GetGroupList method", log.Fields{"groupID": groupID})
699 //Obtain all groups associated with the device
700 grps, ok := device.groups.Load(groupID)
701 if !ok {
702 return true
703 }
704 grp := grps.(*of.Group)
705 groups = append(groups, grp)
Akash Sonib3abf522022-12-19 13:20:02 +0530706 return true
bseenivaa8cb94c2024-12-16 13:37:17 +0530707 })
708 }
709 return true
710 })
Akash Sonib3abf522022-12-19 13:20:02 +0530711 logger.Debugw(ctx, "Groups", log.Fields{"groups": groups})
712 return groups, nil
713}
714
715func (v *VoltController) GetGroups(cntx context.Context, id uint32) (*of.Group, error) {
Akash Sonib3abf522022-12-19 13:20:02 +0530716 logger.Info(ctx, "Entering into GetGroupList method")
717 var groups *of.Group
bseenivaa8cb94c2024-12-16 13:37:17 +0530718 var err error
719 v.Devices.Range(func(_, value interface{}) bool {
720 device, ok := value.(*Device)
721 if ok {
722 logger.Debugw(ctx, "Inside GetGroupList method", log.Fields{"groupID": id})
723 grps, ok := device.groups.Load(id)
724 if !ok {
725 err = errors.New("group not found")
726 return false
727 }
728 groups = grps.(*of.Group)
729 logger.Debugw(ctx, "Groups", log.Fields{"groups": groups})
Akash Sonib3abf522022-12-19 13:20:02 +0530730 }
bseenivaa8cb94c2024-12-16 13:37:17 +0530731 return true
732 })
733 if err != nil {
734 return nil, err
Akash Sonib3abf522022-12-19 13:20:02 +0530735 }
736 return groups, nil
737}