blob: e8bc66398f3d755744c792bcb65da2e7977944ab [file] [log] [blame]
Joey Armstrongaca03cf2024-04-23 09:29:52 -04001/* -----------------------------------------------------------------------
2 * Copyright 2022-2024 Open Networking Foundation Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 * -----------------------------------------------------------------------
16 * SPDX-FileCopyrightText: 2022-2024 Open Networking Foundation Contributors
17 * SPDX-License-Identifier: Apache-2.0
18 * -----------------------------------------------------------------------
Naveen Sampath04696f72022-06-13 15:19:14 +053019 */
20
21package application
22
23import (
24 "context"
25 "encoding/hex"
26 "encoding/json"
27 "errors"
28 "fmt"
29 "net"
30 "strconv"
31 "strings"
32 "sync"
33 "time"
34
35 "github.com/google/gopacket"
36 "github.com/google/gopacket/layers"
37
Akash Sonia8246972023-01-03 10:37:08 +053038 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053039 "voltha-go-controller/internal/pkg/controller"
Akash Sonia8246972023-01-03 10:37:08 +053040 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053041 "voltha-go-controller/internal/pkg/intf"
42 "voltha-go-controller/internal/pkg/of"
43 "voltha-go-controller/internal/pkg/tasks"
Akash Soni6f369452023-09-19 11:18:28 +053044 common "voltha-go-controller/internal/pkg/types"
Naveen Sampath04696f72022-06-13 15:19:14 +053045 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053046 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053047)
48
49var logger log.CLogger
50var ctx = context.TODO()
51
52func init() {
53 // Setup this package so that it's log level can be modified at run time
54 var err error
Tinoj Joseph1d108322022-07-13 10:07:39 +053055 logger, err = log.AddPackageWithDefaultParam()
Naveen Sampath04696f72022-06-13 15:19:14 +053056 if err != nil {
57 panic(err)
58 }
59}
60
61const (
62 // TODO - Need to identify a right place for this
63
64 // PriorityNone constant.
65 PriorityNone uint8 = 8
66 // AnyVlan constant.
67 AnyVlan uint16 = 0xFFFF
68)
69
70// List of Mac Learning Type
71const (
Tinoj Joseph1d108322022-07-13 10:07:39 +053072 MacLearningNone MacLearningType = iota
73 Learn
74 ReLearn
Naveen Sampath04696f72022-06-13 15:19:14 +053075)
76
77// MacLearningType represents Mac Learning Type
78type MacLearningType int
79
80var (
81 tickCount uint16
82 vgcRebooted bool
83 isUpgradeComplete bool
84)
85
86var db database.DBIntf
87
88// PacketHandlers : packet handler for different protocols
89var PacketHandlers map[string]CallBack
90
91// CallBack : registered call back function for different protocol packets
Tinoj Joseph07cc5372022-07-18 22:53:51 +053092type CallBack func(cntx context.Context, device string, port string, pkt gopacket.Packet)
Naveen Sampath04696f72022-06-13 15:19:14 +053093
94const (
95 // ARP packet
96 ARP string = "ARP"
97 // DHCPv4 packet
98 DHCPv4 string = "DHCPv4"
99 // DHCPv6 packet
100 DHCPv6 string = "DHCPv6"
101 // IGMP packet
102 IGMP string = "IGMP"
103 // PPPOE packet
104 PPPOE string = "PPPOE"
105 // US packet side
106 US string = "US"
107 // DS packet side
108 DS string = "DS"
109 // NNI port name
110 NNI string = "nni"
111)
112
113// RegisterPacketHandler : API to register callback function for every protocol
114func RegisterPacketHandler(protocol string, callback CallBack) {
115 if PacketHandlers == nil {
116 PacketHandlers = make(map[string]CallBack)
117 }
118 PacketHandlers[protocol] = callback
119}
120
121// ---------------------------------------------------------------------
122// VOLT Ports
123// ---------------------------------------------------------------------
124// VOLT Ports are ports associated with VOLT devices. Each port is classified into
125// Access/NNI. Each port is identified by Name (Identity known to the NB) and
126// Id (Identity used on the SB). Both identities are presented when a port is
127// discovered in the SB.
128
129// VoltPortType type for Port Type
130type VoltPortType uint8
131
132const (
133 // VoltPortTypeAccess constant.
134 VoltPortTypeAccess VoltPortType = 0
135 // VoltPortTypeNni constant.
136 VoltPortTypeNni VoltPortType = 1
137)
138
139// PortState type for Port State.
140type PortState uint8
141
142const (
143 // PortStateDown constant.
144 PortStateDown PortState = 0
145 // PortStateUp constant.
146 PortStateUp PortState = 1
147)
148
149// VoltPort structure that is used to store the ports. The name is the
150// the main identity used by the application. The SB and NB both present name
151// as the identity. The SB is abstracted by VPAgent and the VPAgent transacts
152// using name as identity
153type VoltPort struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530154 Name string
155 Device string
156 PonPort uint32
vinokuma926cb3e2023-03-29 11:41:06 +0530157 ActiveChannels uint32
158 ID uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530159 Type VoltPortType
160 State PortState
Naveen Sampath04696f72022-06-13 15:19:14 +0530161 ChannelPerSubAlarmRaised bool
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530162 NniDhcpTrapFlowAdded bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530163}
164
165// NewVoltPort : Constructor for the port.
166func NewVoltPort(device string, name string, id uint32) *VoltPort {
167 var vp VoltPort
168 vp.Device = device
169 vp.Name = name
170 vp.ID = id
171 if util.IsNniPort(id) {
172 vp.Type = VoltPortTypeNni
173 } else {
174 vp.PonPort = GetPonPortIDFromUNIPort(id)
175 }
176 vp.State = PortStateDown
177 vp.ChannelPerSubAlarmRaised = false
178 return &vp
179}
180
181// SetPortID : The ID is used when constructing flows as the flows require ID.
182func (vp *VoltPort) SetPortID(id uint32) {
183 vp.ID = id
184 if util.IsNniPort(id) {
185 vp.Type = VoltPortTypeNni
186 }
187}
188
189// ---------------------------------------------------------------------
190// VOLT Device
191// ---------------------------------------------------------------------
192//
193// VoltDevice is an OLT which contains ports of type access and NNI. Each OLT
194// can only have one NNI port in the current release. The NNI port always uses
195// identity 65536 and all the access ports use identities less than 65535. The
196// identification of NNI is done by comparing the port identity with 65535
197
198// VoltDevice fields :
199// Name: This is the name presented by the device/VOLTHA. This doesn't
vinokuma926cb3e2023-03-29 11:41:06 +0530200// have any relation to the physical device
Naveen Sampath04696f72022-06-13 15:19:14 +0530201// SerialNum: This is the serial number of the device and can be used to
vinokuma926cb3e2023-03-29 11:41:06 +0530202// correlate the devices
Naveen Sampath04696f72022-06-13 15:19:14 +0530203// NniPort: The identity of the NNI port
204// Ports: List of all ports added to the device
205type VoltDevice struct {
Akash Sonief452f12024-12-12 18:20:28 +0530206 VoltDeviceIntr VoltDevInterface
Naveen Sampath04696f72022-06-13 15:19:14 +0530207 FlowAddEventMap *util.ConcurrentMap //map[string]*FlowEvent
208 FlowDelEventMap *util.ConcurrentMap //map[string]*FlowEvent
209 MigratingServices *util.ConcurrentMap //<vnetID,<RequestID, MigrateServicesRequest>>
vinokuma926cb3e2023-03-29 11:41:06 +0530210 VpvsBySvlan *util.ConcurrentMap // map[svlan]map[vnet_port]*VoltPortVnet
211 ConfiguredVlanForDeviceFlows *util.ConcurrentMap //map[string]map[string]bool
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530212 IgmpDsFlowAppliedForMvlan map[uint16]bool
213 Ports sync.Map
214 VlanPortStatus sync.Map
215 ActiveChannelsPerPon sync.Map // [PonPortID]*PonPortCfg
216 PonPortList sync.Map // [PonPortID]map[string]string
217 State controller.DeviceState
218 SouthBoundID string
219 Name string
220 SerialNum string
221 NniPort []string
222 ActiveChannelCountLock sync.Mutex // This lock is used to update ActiveIGMPChannels
223 NniDhcpTrapVid of.VlanType
224 GlobalDhcpFlowAdded bool
225 icmpv6GroupAdded bool
Akash Soni6f369452023-09-19 11:18:28 +0530226}
227
228type VoltDevInterface interface {
229 GetPortNameFromPortID(portID uint32) string
Naveen Sampath04696f72022-06-13 15:19:14 +0530230}
231
232// NewVoltDevice : Constructor for the device
233func NewVoltDevice(name string, slno, southBoundID string) *VoltDevice {
234 var d VoltDevice
235 d.Name = name
236 d.SouthBoundID = southBoundID
237 d.State = controller.DeviceStateDOWN
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530238 d.NniPort = make([]string, 0)
Naveen Sampath04696f72022-06-13 15:19:14 +0530239 d.SouthBoundID = southBoundID
240 d.SerialNum = slno
241 d.icmpv6GroupAdded = false
242 d.IgmpDsFlowAppliedForMvlan = make(map[uint16]bool)
243 d.ConfiguredVlanForDeviceFlows = util.NewConcurrentMap()
244 d.MigratingServices = util.NewConcurrentMap()
245 d.VpvsBySvlan = util.NewConcurrentMap()
246 d.FlowAddEventMap = util.NewConcurrentMap()
247 d.FlowDelEventMap = util.NewConcurrentMap()
248 d.GlobalDhcpFlowAdded = false
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530249 if config, ok := GetApplication().DevicesConfig.Load(slno); ok {
250 //Update nni dhcp vid
Akash Soni53da2852023-03-15 00:31:31 +0530251 deviceConfig := config.(*DeviceConfig)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530252 d.NniDhcpTrapVid = of.VlanType(deviceConfig.NniDhcpTrapVid)
253 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530254 return &d
255}
256
vinokuma926cb3e2023-03-29 11:41:06 +0530257// GetAssociatedVpvsForDevice - return the associated VPVs for given device & svlan
Naveen Sampath04696f72022-06-13 15:19:14 +0530258func (va *VoltApplication) GetAssociatedVpvsForDevice(device string, svlan of.VlanType) *util.ConcurrentMap {
259 if d := va.GetDevice(device); d != nil {
260 return d.GetAssociatedVpvs(svlan)
261 }
262 return nil
263}
264
vinokuma926cb3e2023-03-29 11:41:06 +0530265// AssociateVpvsToDevice - updates the associated VPVs for given device & svlan
Naveen Sampath04696f72022-06-13 15:19:14 +0530266func (va *VoltApplication) AssociateVpvsToDevice(device string, vpv *VoltPortVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530267 logger.Debugw(ctx, "AssociateVpvsToDevice", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +0530268 if d := va.GetDevice(device); d != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530269 vpvMap := d.GetAssociatedVpvs(vpv.SVlan)
270 vpvMap.Set(vpv, true)
271 d.VpvsBySvlan.Set(vpv.SVlan, vpvMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530272 logger.Debugw(ctx, "VPVMap: SET", log.Fields{"Map": vpvMap.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530273 return
274 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530275 logger.Warnw(ctx, "Set VPVMap failed: Device Not Found", log.Fields{"Svlan": vpv.SVlan, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +0530276}
277
vinokuma926cb3e2023-03-29 11:41:06 +0530278// DisassociateVpvsFromDevice - disassociated VPVs from given device & svlan
Naveen Sampath04696f72022-06-13 15:19:14 +0530279func (va *VoltApplication) DisassociateVpvsFromDevice(device string, vpv *VoltPortVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530280 logger.Debugw(ctx, "DisassociateVpvsToDevice", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +0530281 if d := va.GetDevice(device); d != nil {
282 vpvMap := d.GetAssociatedVpvs(vpv.SVlan)
283 vpvMap.Remove(vpv)
284 d.VpvsBySvlan.Set(vpv.SVlan, vpvMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530285 logger.Debugw(ctx, "VPVMap: Remove", log.Fields{"Map": vpvMap.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530286 return
287 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530288 logger.Warnw(ctx, "Remove VPVMap failed: Device Not Found", log.Fields{"Svlan": vpv.SVlan, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +0530289}
290
vinokuma926cb3e2023-03-29 11:41:06 +0530291// GetAssociatedVpvs - returns the associated VPVs for the given Svlan
Naveen Sampath04696f72022-06-13 15:19:14 +0530292func (d *VoltDevice) GetAssociatedVpvs(svlan of.VlanType) *util.ConcurrentMap {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530293 logger.Debugw(ctx, "Received Get Associated Vpvs", log.Fields{"svlan": svlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530294 var vpvMap *util.ConcurrentMap
295 var mapIntf interface{}
296 var ok bool
297
298 if mapIntf, ok = d.VpvsBySvlan.Get(svlan); ok {
299 vpvMap = mapIntf.(*util.ConcurrentMap)
300 } else {
301 vpvMap = util.NewConcurrentMap()
302 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530303 logger.Debugw(ctx, "VPVMap: GET", log.Fields{"Map": vpvMap.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530304 return vpvMap
305}
306
307// AddPort add port to the device.
308func (d *VoltDevice) AddPort(port string, id uint32) *VoltPort {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530309 logger.Debugw(ctx, "Add Port", log.Fields{"Port": port, "ID": id})
Naveen Sampath04696f72022-06-13 15:19:14 +0530310 addPonPortFromUniPort := func(vPort *VoltPort) {
311 if vPort.Type == VoltPortTypeAccess {
312 ponPortID := GetPonPortIDFromUNIPort(vPort.ID)
313
314 if ponPortUniList, ok := d.PonPortList.Load(ponPortID); !ok {
315 uniList := make(map[string]uint32)
316 uniList[port] = vPort.ID
317 d.PonPortList.Store(ponPortID, uniList)
318 } else {
319 ponPortUniList.(map[string]uint32)[port] = vPort.ID
320 d.PonPortList.Store(ponPortID, ponPortUniList)
321 }
322 }
323 }
324 va := GetApplication()
325 if pIntf, ok := d.Ports.Load(port); ok {
326 voltPort := pIntf.(*VoltPort)
327 addPonPortFromUniPort(voltPort)
328 va.AggActiveChannelsCountPerSub(d.Name, port, voltPort)
329 d.Ports.Store(port, voltPort)
330 return voltPort
331 }
332 p := NewVoltPort(d.Name, port, id)
333 va.AggActiveChannelsCountPerSub(d.Name, port, p)
334 d.Ports.Store(port, p)
335 if util.IsNniPort(id) {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530336 d.NniPort = append(d.NniPort, port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530337 }
338 addPonPortFromUniPort(p)
339 return p
340}
341
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530342func (d *VoltDevice) IsPortNni(port string) bool {
343 for _, nniPort := range d.NniPort {
344 if nniPort == port {
345 return true
346 }
347 }
348 return false
349}
350
Naveen Sampath04696f72022-06-13 15:19:14 +0530351// GetPort to get port information from the device.
352func (d *VoltDevice) GetPort(port string) *VoltPort {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530353 logger.Debugw(ctx, "Get Port", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530354 if pIntf, ok := d.Ports.Load(port); ok {
355 return pIntf.(*VoltPort)
356 }
357 return nil
358}
359
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530360// GetPortNameFromPortID to get port information from the device.
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530361func (d *VoltDevice) GetPortNameFromPortID(portID uint32) string {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530362 logger.Debugw(ctx, "Get Port Name from the device", log.Fields{"PortID": portID})
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530363 portName := ""
364 d.Ports.Range(func(key, value interface{}) bool {
365 vp := value.(*VoltPort)
366 if vp.ID == portID {
367 portName = vp.Name
368 }
369 return true
370 })
371 return portName
372}
373
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530374// GetPortIDFromPortName to get port information from the device.
375func (d *VoltDevice) GetPortIDFromPortName(portName string) uint32 {
376 logger.Debugw(ctx, "Get Port ID from the device", log.Fields{"PortName": portName})
377 var portID uint32
378 d.Ports.Range(func(key, value interface{}) bool {
379 vp := value.(*VoltPort)
380 if vp.Name == portName {
381 portID = vp.ID
382 }
383 return true
384 })
385 return portID
386}
387
Naveen Sampath04696f72022-06-13 15:19:14 +0530388// DelPort to delete port from the device
389func (d *VoltDevice) DelPort(port string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530390 logger.Debugw(ctx, "Delete Port from the device", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530391 if _, ok := d.Ports.Load(port); ok {
392 d.Ports.Delete(port)
393 } else {
394 logger.Warnw(ctx, "Port doesn't exist", log.Fields{"Device": d.Name, "Port": port})
395 }
396}
397
398// pushFlowsForUnis to send port-up-indication for uni ports.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530399func (d *VoltDevice) pushFlowsForUnis(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530400 logger.Info(ctx, "NNI Discovered, Sending Port UP Ind for UNIs")
401 d.Ports.Range(func(key, value interface{}) bool {
402 port := key.(string)
403 vp := value.(*VoltPort)
404
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530405 logger.Debugw(ctx, "NNI Discovered. Sending Port UP Ind for UNI", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530406 //Ignore if UNI port is not UP
407 if vp.State != PortStateUp {
408 return true
409 }
410
411 //Obtain all VPVs associated with the port
412 vnets, ok := GetApplication().VnetsByPort.Load(port)
413 if !ok {
414 return true
415 }
416
417 for _, vpv := range vnets.([]*VoltPortVnet) {
418 vpv.VpvLock.Lock()
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530419 vpv.PortUpInd(cntx, d, port, "")
Naveen Sampath04696f72022-06-13 15:19:14 +0530420 vpv.VpvLock.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +0530421 }
422 return true
423 })
424}
425
426// ----------------------------------------------------------
427// VOLT Application - hosts all other objects
428// ----------------------------------------------------------
429//
430// The VOLT application is a singleton implementation where
431// there is just one instance in the system and is the gateway
432// to all other components within the controller
433// The declaration of the singleton object
434var vapplication *VoltApplication
435
Akash Soni6f369452023-09-19 11:18:28 +0530436type VoltAppInterface interface {
437 AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error
438 AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530439 AddDeviceConfig(cntx context.Context, serialNum, hardwareIdentifier, nasID, ipAddress, uplinkPort string, nniDhcpTrapID uint16, nniPorts []string) error
Akash Soni6f369452023-09-19 11:18:28 +0530440 GetFlowProvisionStatus(portNo string) FlowProvisionStatus
441 DelServiceWithPrefix(cntx context.Context, prefix string) error
442 GetDevice(device string) *VoltDevice
443 GetTaskList(device string) map[int]*TaskInfo
444 AddMeterProf(cntx context.Context, cfg VoltMeter)
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530445 AddMvlanProfile(cntx context.Context, name string, mvlan of.VlanType, ponVlan of.VlanType, groups map[string][]string, isChannelBasedGroup bool, OLTSerialNum []string, activeChannelsPerPon uint32, proxy map[string]common.MulticastGroupProxy) error
Akash Soni6f369452023-09-19 11:18:28 +0530446 DelMvlanProfile(cntx context.Context, name string) error
447 GetMvlanProfileByTag(vlan of.VlanType) *MvlanProfile
448 AddMcastConfig(cntx context.Context, MvlanProfileID string, IgmpProfileID string, IgmpProxyIP string, OltSerialNum string) error
449 DelMeterProf(cntx context.Context, name string) error
450 GetMeterByName(name string) (*VoltMeter, bool)
451 UpdateDeviceConfig(cntx context.Context, deviceConfig *DeviceConfig)
452 GetDeviceConfig(serNum string) *DeviceConfig
453 GetAllocations(cntx context.Context, deviceID string) ([]DhcpAllocation, error)
454 GetAllMacLearnerInfo() ([]MacLearnerInfo, error)
455 GetMacLearnerInfo(cntx context.Context, deviceID, portNumber, vlanID string) (MacLearnerInfo, error)
456 ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error
457 DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error
458 GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error)
459 UpdateOltFlowService(cntx context.Context, oltFlowService OltFlowService)
460 GetIgnoredPorts() (map[string][]string, error)
461}
462
Naveen Sampath04696f72022-06-13 15:19:14 +0530463// VoltApplication fields :
464// ServiceByName - Stores the services by the name as key
vinokuma926cb3e2023-03-29 11:41:06 +0530465// A record of NB configuration.
Naveen Sampath04696f72022-06-13 15:19:14 +0530466// VnetsByPort - Stores the VNETs by the ports configured
vinokuma926cb3e2023-03-29 11:41:06 +0530467// from NB. A record of NB configuration.
Naveen Sampath04696f72022-06-13 15:19:14 +0530468// VnetsByTag - Stores the VNETs by the VLANS configured
vinokuma926cb3e2023-03-29 11:41:06 +0530469// from NB. A record of NB configuration.
Naveen Sampath04696f72022-06-13 15:19:14 +0530470// VnetsByName - Stores the VNETs by the name configured
vinokuma926cb3e2023-03-29 11:41:06 +0530471// from NB. A record of NB configuration.
Naveen Sampath04696f72022-06-13 15:19:14 +0530472// DevicesDisc - Stores the devices discovered from SB.
vinokuma926cb3e2023-03-29 11:41:06 +0530473// Should be updated only by events from SB
Naveen Sampath04696f72022-06-13 15:19:14 +0530474// PortsDisc - Stores the ports discovered from SB.
vinokuma926cb3e2023-03-29 11:41:06 +0530475// Should be updated only by events from SB
Naveen Sampath04696f72022-06-13 15:19:14 +0530476type VoltApplication struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530477 MeterMgr
vinokuma926cb3e2023-03-29 11:41:06 +0530478 DataMigrationInfo DataMigration
479 VnetsBySvlan *util.ConcurrentMap
480 IgmpGroupIds []*IgmpGroup
481 VoltPortVnetsToDelete map[*VoltPortVnet]bool
Akash Sonia8246972023-01-03 10:37:08 +0530482 IgmpPendingPool map[string]map[*IgmpGroup]bool //[grpkey, map[groupObj]bool] //mvlan_grpName/IP
vinokuma926cb3e2023-03-29 11:41:06 +0530483 macPortMap map[string]string
Akash Sonia8246972023-01-03 10:37:08 +0530484 VnetsToDelete map[string]bool
Akash Sonief452f12024-12-12 18:20:28 +0530485 ServicesToDelete sync.Map
486 ServicesToDeactivate sync.Map
Akash Sonia8246972023-01-03 10:37:08 +0530487 PortAlarmProfileCache map[string]map[string]int // [portAlarmID][ThresholdLevelString]ThresholdLevel
488 vendorID string
vinokuma926cb3e2023-03-29 11:41:06 +0530489 ServiceByName sync.Map // [serName]*VoltService
490 VnetsByPort sync.Map // [portName][]*VoltPortVnet
491 VnetsByTag sync.Map // [svlan-cvlan-uvlan]*VoltVnet
492 VnetsByName sync.Map // [vnetName]*VoltVnet
493 DevicesDisc sync.Map
494 PortsDisc sync.Map
495 IgmpGroups sync.Map // [grpKey]*IgmpGroup
496 MvlanProfilesByTag sync.Map
497 MvlanProfilesByName sync.Map
498 Icmpv6Receivers sync.Map
499 DeviceCounters sync.Map //[logicalDeviceId]*DeviceCounters
500 ServiceCounters sync.Map //[serviceName]*ServiceCounters
501 NbDevice sync.Map // [OLTSouthBoundID]*NbDevice
502 OltIgmpInfoBySerial sync.Map
503 McastConfigMap sync.Map //[OltSerialNo_MvlanProfileID]*McastConfig
Akash Sonia8246972023-01-03 10:37:08 +0530504 DevicesConfig sync.Map //[serialNumber]*DeviceConfig
vinokuma926cb3e2023-03-29 11:41:06 +0530505 IgmpProfilesByName sync.Map
506 IgmpTasks tasks.Tasks
507 IndicationsTasks tasks.Tasks
508 MulticastAlarmTasks tasks.Tasks
509 IgmpKPIsTasks tasks.Tasks
510 pppoeTasks tasks.Tasks
511 OltFlowServiceConfig OltFlowService
512 PendingPoolLock sync.RWMutex
513 // MacAddress-Port MAP to avoid swap of mac across ports.
514 macPortLock sync.RWMutex
515 portLock sync.Mutex
Akash Sonia8246972023-01-03 10:37:08 +0530516}
Naveen Sampath04696f72022-06-13 15:19:14 +0530517
Akash Sonia8246972023-01-03 10:37:08 +0530518type DeviceConfig struct {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530519 SerialNumber string `json:"id"`
520 HardwareIdentifier string `json:"hardwareIdentifier"`
521 IPAddress string `json:"ipAddress"`
522 UplinkPort string `json:"uplinkPort"`
523 NasID string `json:"nasId"`
524 NniPorts []string `json:"nniPorts"`
525 NniDhcpTrapVid uint16 `json:"nniDhcpTrapVid"`
Naveen Sampath04696f72022-06-13 15:19:14 +0530526}
527
528// PonPortCfg contains NB port config and activeIGMPChannels count
529type PonPortCfg struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530530 PortAlarmProfileID string
Naveen Sampath04696f72022-06-13 15:19:14 +0530531 PortID uint32
532 MaxActiveChannels uint32
533 ActiveIGMPChannels uint32
534 EnableMulticastKPI bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530535}
536
537// NbDevice OLT Device info
538type NbDevice struct {
539 SouthBoundID string
540 PonPorts sync.Map // [PortID]*PonPortCfg
541}
542
543// RestoreNbDeviceFromDb restores the NB Device in case of VGC pod restart.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530544func (va *VoltApplication) RestoreNbDeviceFromDb(cntx context.Context, deviceID string) *NbDevice {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530545 logger.Debugw(ctx, "Received Restore Nb Device From Db", log.Fields{"deviceID": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530546 nbDevice := NewNbDevice()
547 nbDevice.SouthBoundID = deviceID
548
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530549 nbPorts, _ := db.GetAllNbPorts(cntx, deviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530550
551 for key, p := range nbPorts {
552 b, ok := p.Value.([]byte)
553 if !ok {
554 logger.Warn(ctx, "The value type is not []byte")
555 continue
556 }
557 var port PonPortCfg
558 err := json.Unmarshal(b, &port)
559 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530560 logger.Warnw(ctx, "Unmarshal of PonPortCfg failed", log.Fields{"deviceID": deviceID, "port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530561 continue
562 }
563 logger.Debugw(ctx, "Port recovered", log.Fields{"port": port})
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530564 ponPortID, err := strconv.ParseUint(key, 10, 32)
565 if err != nil {
566 logger.Errorw(ctx, "Error converting string to uint32:", log.Fields{"deviceID": deviceID, "error": err})
567 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530568 nbDevice.PonPorts.Store(uint32(ponPortID), &port)
569 }
570 va.NbDevice.Store(deviceID, nbDevice)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530571 logger.Debugw(ctx, "Recovered NbDevice From Db", log.Fields{"deviceID": deviceID, "nbDevice": nbDevice})
Naveen Sampath04696f72022-06-13 15:19:14 +0530572 return nbDevice
573}
574
575// NewNbDevice Constructor for NbDevice
576func NewNbDevice() *NbDevice {
577 var nbDevice NbDevice
578 return &nbDevice
579}
580
581// WriteToDb writes nb device port config to kv store
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530582func (nbd *NbDevice) WriteToDb(cntx context.Context, portID uint32, ponPort *PonPortCfg) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530583 b, err := json.Marshal(ponPort)
584 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530585 logger.Errorw(ctx, "PonPortConfig-marshal-failed", log.Fields{"err": err, "ponPort": ponPort})
Naveen Sampath04696f72022-06-13 15:19:14 +0530586 return
587 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530588 db.PutNbDevicePort(cntx, nbd.SouthBoundID, portID, string(b))
Naveen Sampath04696f72022-06-13 15:19:14 +0530589}
590
591// AddPortToNbDevice Adds pon port to NB Device and DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530592func (nbd *NbDevice) AddPortToNbDevice(cntx context.Context, portID, allowedChannels uint32,
Naveen Sampath04696f72022-06-13 15:19:14 +0530593 enableMulticastKPI bool, portAlarmProfileID string) *PonPortCfg {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530594 logger.Debugw(ctx, "AddPortToNbDevice", log.Fields{"PortID": portID, "EnableMulticastKPI": enableMulticastKPI, "PortAlarmProfileID": portAlarmProfileID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530595 ponPort := &PonPortCfg{
596 PortID: portID,
597 MaxActiveChannels: allowedChannels,
598 EnableMulticastKPI: enableMulticastKPI,
599 PortAlarmProfileID: portAlarmProfileID,
600 }
601 nbd.PonPorts.Store(portID, ponPort)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530602 nbd.WriteToDb(cntx, portID, ponPort)
Naveen Sampath04696f72022-06-13 15:19:14 +0530603 return ponPort
604}
605
Akash Sonia8246972023-01-03 10:37:08 +0530606// RestoreDeviceConfigFromDb to restore vnet from port
607func (va *VoltApplication) RestoreDeviceConfigFromDb(cntx context.Context) {
608 // VNETS must be learnt first
609 dConfig, _ := db.GetDeviceConfig(cntx)
610 for _, device := range dConfig {
611 b, ok := device.Value.([]byte)
612 if !ok {
613 logger.Warn(ctx, "The value type is not []byte")
614 continue
615 }
616 devConfig := DeviceConfig{}
617 err := json.Unmarshal(b, &devConfig)
618 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530619 logger.Warnw(ctx, "Unmarshal of device configuration failed", log.Fields{"Device Config": devConfig})
Akash Sonia8246972023-01-03 10:37:08 +0530620 continue
621 }
622 logger.Debugw(ctx, "Retrieved device config", log.Fields{"Device Config": devConfig})
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530623 if err := va.AddDeviceConfig(cntx, devConfig.SerialNumber, devConfig.HardwareIdentifier, devConfig.NasID, devConfig.IPAddress, devConfig.UplinkPort, devConfig.NniDhcpTrapVid, devConfig.NniPorts); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530624 logger.Warnw(ctx, "Add device config failed", log.Fields{"DeviceConfig": devConfig, "Error": err})
625 }
Akash Sonia8246972023-01-03 10:37:08 +0530626 }
627}
628
629// WriteDeviceConfigToDb writes sb device config to kv store
630func (dc *DeviceConfig) WriteDeviceConfigToDb(cntx context.Context, serialNum string, deviceConfig *DeviceConfig) error {
631 b, err := json.Marshal(deviceConfig)
632 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530633 return fmt.Errorf("deviceConfig-marshal-failed - %w ", err)
Akash Sonia8246972023-01-03 10:37:08 +0530634 }
635 dberr := db.PutDeviceConfig(cntx, serialNum, string(b))
636 if dberr != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530637 return fmt.Errorf("update device config failed - %w ", err)
Akash Sonia8246972023-01-03 10:37:08 +0530638 }
639 return nil
640}
641
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530642func (va *VoltApplication) AddDeviceConfig(cntx context.Context, serialNum, hardwareIdentifier, nasID, ipAddress, uplinkPort string, nniDhcpTrapID uint16, nniPorts []string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530643 logger.Debugw(ctx, "Received Add device config", log.Fields{"SerialNumber": serialNum, "HardwareIdentifier": hardwareIdentifier, "NasID": nasID, "IPAddress": ipAddress, "UplinkPort": uplinkPort, "NniDhcpTrapID": nniDhcpTrapID})
Akash Sonia8246972023-01-03 10:37:08 +0530644 var dc *DeviceConfig
645
Akash Soni87a19072023-02-28 00:46:59 +0530646 deviceConfig := &DeviceConfig{
647 SerialNumber: serialNum,
648 HardwareIdentifier: hardwareIdentifier,
649 NasID: nasID,
650 UplinkPort: uplinkPort,
651 IPAddress: ipAddress,
vinokuma926cb3e2023-03-29 11:41:06 +0530652 NniDhcpTrapVid: nniDhcpTrapID,
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530653 NniPorts: nniPorts,
Akash Sonia8246972023-01-03 10:37:08 +0530654 }
Akash Soni87a19072023-02-28 00:46:59 +0530655 va.DevicesConfig.Store(serialNum, deviceConfig)
656 err := dc.WriteDeviceConfigToDb(cntx, serialNum, deviceConfig)
657 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530658 return fmt.Errorf("DB update for device config failed - %w ", err)
Akash Soni87a19072023-02-28 00:46:59 +0530659 }
660
661 // If device is already discovered update the VoltDevice structure
662 device, id := va.GetDeviceBySerialNo(serialNum)
663 if device != nil {
vinokuma926cb3e2023-03-29 11:41:06 +0530664 device.NniDhcpTrapVid = of.VlanType(nniDhcpTrapID)
Akash Soni87a19072023-02-28 00:46:59 +0530665 va.DevicesDisc.Store(id, device)
666 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530667 logger.Debugw(ctx, "Added device config", log.Fields{"Device Config": deviceConfig})
Akash Sonia8246972023-01-03 10:37:08 +0530668 return nil
669}
670
671// GetDeviceConfig to get a device config.
672func (va *VoltApplication) GetDeviceConfig(serNum string) *DeviceConfig {
673 if d, ok := va.DevicesConfig.Load(serNum); ok {
674 return d.(*DeviceConfig)
675 }
676 return nil
677}
678
Naveen Sampath04696f72022-06-13 15:19:14 +0530679// UpdatePortToNbDevice Adds pon port to NB Device and DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530680func (nbd *NbDevice) UpdatePortToNbDevice(cntx context.Context, portID, allowedChannels uint32, enableMulticastKPI bool, portAlarmProfileID string) *PonPortCfg {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530681 logger.Debugw(ctx, "Received Update Port To NbDevice", log.Fields{"portID": portID, "AllowedChannels": allowedChannels, "EnableMulticastKPI": enableMulticastKPI, "PortAlarmProfileID": portAlarmProfileID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530682 p, exists := nbd.PonPorts.Load(portID)
683 if !exists {
684 logger.Errorw(ctx, "PON port not exists in nb-device", log.Fields{"portID": portID})
685 return nil
686 }
687 port := p.(*PonPortCfg)
688 if allowedChannels != 0 {
689 port.MaxActiveChannels = allowedChannels
690 port.EnableMulticastKPI = enableMulticastKPI
691 port.PortAlarmProfileID = portAlarmProfileID
692 }
693
694 nbd.PonPorts.Store(portID, port)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530695 nbd.WriteToDb(cntx, portID, port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530696 return port
697}
698
699// DeletePortFromNbDevice Deletes pon port from NB Device and DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530700func (nbd *NbDevice) DeletePortFromNbDevice(cntx context.Context, portID uint32) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530701 logger.Debugw(ctx, "Received Delete Port from NbDevice", log.Fields{"portID": portID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530702 if _, ok := nbd.PonPorts.Load(portID); ok {
703 nbd.PonPorts.Delete(portID)
704 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530705 db.DelNbDevicePort(cntx, nbd.SouthBoundID, portID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530706}
707
708// GetApplication : Interface to access the singleton object
709func GetApplication() *VoltApplication {
710 if vapplication == nil {
711 vapplication = newVoltApplication()
712 }
713 return vapplication
714}
715
716// newVoltApplication : Constructor for the singleton object. Hence this is not
717// an exported function
718func newVoltApplication() *VoltApplication {
719 var va VoltApplication
720 va.IgmpTasks.Initialize(context.TODO())
721 va.MulticastAlarmTasks.Initialize(context.TODO())
722 va.IgmpKPIsTasks.Initialize(context.TODO())
723 va.pppoeTasks.Initialize(context.TODO())
724 va.storeIgmpProfileMap(DefaultIgmpProfID, newDefaultIgmpProfile())
725 va.MeterMgr.Init()
726 va.AddIgmpGroups(5000)
727 va.macPortMap = make(map[string]string)
728 va.IgmpPendingPool = make(map[string]map[*IgmpGroup]bool)
729 va.VnetsBySvlan = util.NewConcurrentMap()
730 va.VnetsToDelete = make(map[string]bool)
Naveen Sampath04696f72022-06-13 15:19:14 +0530731 va.VoltPortVnetsToDelete = make(map[*VoltPortVnet]bool)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530732 go va.Start(context.Background(), TimerCfg{tick: 100 * time.Millisecond}, tickTimer)
733 go va.Start(context.Background(), TimerCfg{tick: time.Duration(GroupExpiryTime) * time.Minute}, pendingPoolTimer)
Naveen Sampath04696f72022-06-13 15:19:14 +0530734 InitEventFuncMapper()
735 db = database.GetDatabase()
Akash Soni6f369452023-09-19 11:18:28 +0530736
Naveen Sampath04696f72022-06-13 15:19:14 +0530737 return &va
738}
739
vinokuma926cb3e2023-03-29 11:41:06 +0530740// GetFlowEventRegister - returs the register based on flow mod type
Naveen Sampath04696f72022-06-13 15:19:14 +0530741func (d *VoltDevice) GetFlowEventRegister(flowModType of.Command) (*util.ConcurrentMap, error) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530742 switch flowModType {
743 case of.CommandDel:
744 return d.FlowDelEventMap, nil
745 case of.CommandAdd:
746 return d.FlowAddEventMap, nil
747 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530748 logger.Warnw(ctx, "Unknown Flow Mod received", log.Fields{"flowModtype": flowModType})
Naveen Sampath04696f72022-06-13 15:19:14 +0530749 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530750 return util.NewConcurrentMap(), errors.New("unknown flow mod")
Naveen Sampath04696f72022-06-13 15:19:14 +0530751}
752
753// RegisterFlowAddEvent to register a flow event.
754func (d *VoltDevice) RegisterFlowAddEvent(cookie string, event *FlowEvent) {
755 logger.Debugw(ctx, "Registered Flow Add Event", log.Fields{"Cookie": cookie, "Event": event})
756 d.FlowAddEventMap.MapLock.Lock()
757 defer d.FlowAddEventMap.MapLock.Unlock()
758 d.FlowAddEventMap.Set(cookie, event)
759}
760
761// RegisterFlowDelEvent to register a flow event.
762func (d *VoltDevice) RegisterFlowDelEvent(cookie string, event *FlowEvent) {
763 logger.Debugw(ctx, "Registered Flow Del Event", log.Fields{"Cookie": cookie, "Event": event})
764 d.FlowDelEventMap.MapLock.Lock()
765 defer d.FlowDelEventMap.MapLock.Unlock()
766 d.FlowDelEventMap.Set(cookie, event)
767}
768
769// UnRegisterFlowEvent to unregister a flow event.
770func (d *VoltDevice) UnRegisterFlowEvent(cookie string, flowModType of.Command) {
771 logger.Debugw(ctx, "UnRegistered Flow Add Event", log.Fields{"Cookie": cookie, "Type": flowModType})
772 flowEventMap, err := d.GetFlowEventRegister(flowModType)
773 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530774 logger.Warnw(ctx, "Flow event map does not exists", log.Fields{"flowMod": flowModType, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530775 return
776 }
777 flowEventMap.MapLock.Lock()
778 defer flowEventMap.MapLock.Unlock()
779 flowEventMap.Remove(cookie)
780}
781
782// AddIgmpGroups to add Igmp groups.
783func (va *VoltApplication) AddIgmpGroups(numOfGroups uint32) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530784 logger.Debugw(ctx, "AddIgmpGroups", log.Fields{"NumOfGroups": numOfGroups})
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530785 var i uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530786 //TODO: Temp change to resolve group id issue in pOLT
787 //for i := 1; uint32(i) <= numOfGroups; i++ {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530788 for i = 2; i <= (numOfGroups + 1); i++ {
Naveen Sampath04696f72022-06-13 15:19:14 +0530789 ig := IgmpGroup{}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530790 ig.GroupID = i
Naveen Sampath04696f72022-06-13 15:19:14 +0530791 va.IgmpGroupIds = append(va.IgmpGroupIds, &ig)
792 }
793}
794
795// GetAvailIgmpGroupID to get id of available igmp group.
796func (va *VoltApplication) GetAvailIgmpGroupID() *IgmpGroup {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530797 logger.Info(ctx, "GetAvailIgmpGroupID")
Naveen Sampath04696f72022-06-13 15:19:14 +0530798 var ig *IgmpGroup
799 if len(va.IgmpGroupIds) > 0 {
800 ig, va.IgmpGroupIds = va.IgmpGroupIds[0], va.IgmpGroupIds[1:]
801 return ig
802 }
803 return nil
804}
805
806// GetIgmpGroupID to get id of igmp group.
807func (va *VoltApplication) GetIgmpGroupID(gid uint32) (*IgmpGroup, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530808 logger.Info(ctx, "GetIgmpGroupID")
Naveen Sampath04696f72022-06-13 15:19:14 +0530809 for id, ig := range va.IgmpGroupIds {
810 if ig.GroupID == gid {
811 va.IgmpGroupIds = append(va.IgmpGroupIds[0:id], va.IgmpGroupIds[id+1:]...)
812 return ig, nil
813 }
814 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530815 return nil, errors.New("group id missing")
Naveen Sampath04696f72022-06-13 15:19:14 +0530816}
817
818// PutIgmpGroupID to add id of igmp group.
819func (va *VoltApplication) PutIgmpGroupID(ig *IgmpGroup) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530820 logger.Debugw(ctx, "GetIgmpGroupID", log.Fields{"GroupID": ig.GroupID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530821 va.IgmpGroupIds = append([]*IgmpGroup{ig}, va.IgmpGroupIds[0:]...)
822}
823
vinokuma926cb3e2023-03-29 11:41:06 +0530824// RestoreUpgradeStatus - gets upgrade/migration status from DB and updates local flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530825func (va *VoltApplication) RestoreUpgradeStatus(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530826 logger.Info(ctx, "Received Restore Upgrade Status")
Naveen Sampath04696f72022-06-13 15:19:14 +0530827 Migrate := new(DataMigration)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530828 if err := GetMigrationInfo(cntx, Migrate); err == nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530829 if Migrate.Status == MigrationInProgress {
830 isUpgradeComplete = false
831 return
832 }
833 }
834 isUpgradeComplete = true
835
836 logger.Infow(ctx, "Upgrade Status Restored", log.Fields{"Upgrade Completed": isUpgradeComplete})
837}
838
839// ReadAllFromDb : If we are restarted, learn from the database the current execution
840// stage
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530841func (va *VoltApplication) ReadAllFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530842 logger.Info(ctx, "Reading the meters from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530843 va.RestoreMetersFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530844 logger.Info(ctx, "Reading the VNETs from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530845 va.RestoreVnetsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530846 logger.Info(ctx, "Reading the VPVs from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530847 va.RestoreVpvsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530848 logger.Info(ctx, "Reading the Services from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530849 va.RestoreSvcsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530850 logger.Info(ctx, "Reading the MVLANs from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530851 va.RestoreMvlansFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530852 logger.Info(ctx, "Reading the IGMP profiles from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530853 va.RestoreIGMPProfilesFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530854 logger.Info(ctx, "Reading the Mcast configs from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530855 va.RestoreMcastConfigsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530856 logger.Info(ctx, "Reading the IGMP groups for DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530857 va.RestoreIgmpGroupsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530858 logger.Info(ctx, "Reading Upgrade status from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530859 va.RestoreUpgradeStatus(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530860 logger.Info(ctx, "Reading OltFlowService from DB")
861 va.RestoreOltFlowService(cntx)
Akash Sonia8246972023-01-03 10:37:08 +0530862 logger.Info(ctx, "Reading device config from DB")
863 va.RestoreDeviceConfigFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530864 logger.Info(ctx, "Reconciled from DB")
865}
866
vinokuma926cb3e2023-03-29 11:41:06 +0530867// InitStaticConfig to initialize static config.
Naveen Sampath04696f72022-06-13 15:19:14 +0530868func (va *VoltApplication) InitStaticConfig() {
869 va.InitIgmpSrcMac()
870}
871
872// SetVendorID to set vendor id
873func (va *VoltApplication) SetVendorID(vendorID string) {
874 va.vendorID = vendorID
875}
876
877// GetVendorID to get vendor id
878func (va *VoltApplication) GetVendorID() string {
879 return va.vendorID
880}
881
882// SetRebootFlag to set reboot flag
883func (va *VoltApplication) SetRebootFlag(flag bool) {
884 vgcRebooted = flag
885}
886
887// GetUpgradeFlag to get reboot status
888func (va *VoltApplication) GetUpgradeFlag() bool {
889 return isUpgradeComplete
890}
891
892// SetUpgradeFlag to set reboot status
893func (va *VoltApplication) SetUpgradeFlag(flag bool) {
894 isUpgradeComplete = flag
895}
896
897// ------------------------------------------------------------
898// Device related functions
899
900// AddDevice : Add a device and typically the device stores the NNI port on the device
901// The NNI port is used when the packets are emitted towards the network.
902// The outport is selected as the NNI port of the device. Today, we support
903// a single NNI port per OLT. This is true whether the network uses any
904// protection mechanism (LAG, ERPS, etc.). The aggregate of the such protection
905// is represented by a single NNI port
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530906func (va *VoltApplication) AddDevice(cntx context.Context, device string, slno, southBoundID string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530907 logger.Debugw(ctx, "Received Device Ind: Add", log.Fields{"Device": device, "SrNo": slno, "southBoundID": southBoundID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530908 if _, ok := va.DevicesDisc.Load(device); ok {
909 logger.Warnw(ctx, "Device Exists", log.Fields{"Device": device})
910 }
911 d := NewVoltDevice(device, slno, southBoundID)
912
913 addPort := func(key, value interface{}) bool {
914 portID := key.(uint32)
915 port := value.(*PonPortCfg)
916 va.AggActiveChannelsCountForPonPort(device, portID, port)
917 d.ActiveChannelsPerPon.Store(portID, port)
918 return true
919 }
920 if nbDevice, exists := va.NbDevice.Load(southBoundID); exists {
921 // Pon Ports added before OLT activate.
922 nbDevice.(*NbDevice).PonPorts.Range(addPort)
923 } else {
924 // Check if NbPort exists in DB. VGC restart case.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530925 nbd := va.RestoreNbDeviceFromDb(cntx, southBoundID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530926 nbd.PonPorts.Range(addPort)
927 }
928 va.DevicesDisc.Store(device, d)
929}
930
931// GetDevice to get a device.
932func (va *VoltApplication) GetDevice(device string) *VoltDevice {
933 if d, ok := va.DevicesDisc.Load(device); ok {
934 return d.(*VoltDevice)
935 }
936 return nil
937}
938
939// DelDevice to delete a device.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530940func (va *VoltApplication) DelDevice(cntx context.Context, device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530941 logger.Debugw(ctx, "Received Device Ind: Delete", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +0530942 if vdIntf, ok := va.DevicesDisc.Load(device); ok {
943 vd := vdIntf.(*VoltDevice)
944 va.DevicesDisc.Delete(device)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530945 _ = db.DelAllRoutesForDevice(cntx, device)
946 va.HandleFlowClearFlag(cntx, device, vd.SerialNum, vd.SouthBoundID)
947 _ = db.DelAllGroup(cntx, device)
948 _ = db.DelAllMeter(cntx, device)
949 _ = db.DelAllPorts(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +0530950 logger.Debugw(ctx, "Device deleted", log.Fields{"Device": device})
951 } else {
952 logger.Warnw(ctx, "Device Doesn't Exist", log.Fields{"Device": device})
953 }
954}
955
Akash Sonief452f12024-12-12 18:20:28 +0530956// CheckServiceExists to check if service exists for the given uniport and tech profile ID.
957func (va *VoltApplication) CheckServiceExists(port string, techProfID uint16) bool {
958 var serviceExists bool
959 va.ServiceByName.Range(func(key, existingServiceIntf interface{}) bool {
960 existingService := existingServiceIntf.(*VoltService)
961 if existingService.Port == port && existingService.TechProfileID == techProfID {
962 logger.Warnw(ctx, "Service already exists for same Port and TP. Ignoring add service request", log.Fields{"ExistingService": existingService.Name})
963 serviceExists = true
964 return false
965 }
966 return true
967 })
968 return serviceExists
969}
970
Naveen Sampath04696f72022-06-13 15:19:14 +0530971// GetDeviceBySerialNo to get a device by serial number.
972// TODO - Transform this into a MAP instead
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530973func (va *VoltApplication) GetDeviceBySerialNo(slno string) (*VoltDevice, string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530974 logger.Debugw(ctx, "Received Device Ind: Get", log.Fields{"Serial Num": slno})
Naveen Sampath04696f72022-06-13 15:19:14 +0530975 var device *VoltDevice
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530976 var deviceID string
Naveen Sampath04696f72022-06-13 15:19:14 +0530977 getserial := func(key interface{}, value interface{}) bool {
978 device = value.(*VoltDevice)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530979 deviceID = key.(string)
Naveen Sampath04696f72022-06-13 15:19:14 +0530980 return device.SerialNum != slno
981 }
982 va.DevicesDisc.Range(getserial)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530983 return device, deviceID
Naveen Sampath04696f72022-06-13 15:19:14 +0530984}
985
986// PortAddInd : This is a PORT add indication coming from the VPAgent, which is essentially
987// a request coming from VOLTHA. The device and identity of the port is provided
988// in this request. Add them to the application for further use
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530989func (va *VoltApplication) PortAddInd(cntx context.Context, device string, id uint32, portName string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530990 logger.Debugw(ctx, "Received Port Ind: Add", log.Fields{"Device": device, "ID": id, "Port": portName})
Naveen Sampath04696f72022-06-13 15:19:14 +0530991 va.portLock.Lock()
992 if d := va.GetDevice(device); d != nil {
993 p := d.AddPort(portName, id)
994 va.PortsDisc.Store(portName, p)
995 va.portLock.Unlock()
996 nni, _ := va.GetNniPort(device)
997 if nni == portName {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530998 d.pushFlowsForUnis(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530999 }
1000 } else {
1001 va.portLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301002 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: Add", log.Fields{"Device": device, "ID": id, "Port": portName})
Naveen Sampath04696f72022-06-13 15:19:14 +05301003 }
1004}
1005
1006// PortDelInd : Only the NNI ports are recorded in the device for now. When port delete
1007// arrives, only the NNI ports need adjustments.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301008func (va *VoltApplication) PortDelInd(cntx context.Context, device string, port string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301009 logger.Debugw(ctx, "Received Port Ind: Delete", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301010 if d := va.GetDevice(device); d != nil {
1011 p := d.GetPort(port)
1012 if p != nil && p.State == PortStateUp {
1013 logger.Infow(ctx, "Port state is UP. Trigerring Port Down Ind before deleting", log.Fields{"Port": p})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301014 va.PortDownInd(cntx, device, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301015 }
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05301016 // if RemoveFlowsOnDisable is flase, then flows will be existing till port delete. Remove the flows now
1017 if !va.OltFlowServiceConfig.RemoveFlowsOnDisable {
Akash Sonia8246972023-01-03 10:37:08 +05301018 vpvs, ok := va.VnetsByPort.Load(port)
1019 if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05301020 logger.Infow(ctx, "No VNETs on port", log.Fields{"Device": device, "Port": port})
1021 } else {
1022 for _, vpv := range vpvs.([]*VoltPortVnet) {
1023 vpv.VpvLock.Lock()
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301024 // Set delFlowsInDevice to true to delete flows only in DB/device during Port Delete.
1025 vpv.PortDownInd(cntx, device, port, true, true)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05301026 vpv.VpvLock.Unlock()
1027 }
1028 }
1029 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301030 va.portLock.Lock()
1031 defer va.portLock.Unlock()
1032 d.DelPort(port)
1033 if _, ok := va.PortsDisc.Load(port); ok {
1034 va.PortsDisc.Delete(port)
1035 }
1036 } else {
1037 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: Delete", log.Fields{"Device": device, "Port": port})
1038 }
1039}
1040
vinokuma926cb3e2023-03-29 11:41:06 +05301041// PortUpdateInd Updates port Id incase of ONU movement
Naveen Sampath04696f72022-06-13 15:19:14 +05301042func (va *VoltApplication) PortUpdateInd(device string, portName string, id uint32) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301043 logger.Debugw(ctx, "Received Port Ind: Update", log.Fields{"Device": device, "Port": portName, "ID": id})
Naveen Sampath04696f72022-06-13 15:19:14 +05301044 va.portLock.Lock()
1045 defer va.portLock.Unlock()
1046 if d := va.GetDevice(device); d != nil {
1047 vp := d.GetPort(portName)
1048 vp.ID = id
1049 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301050 logger.Warnw(ctx, "Device Not Found", log.Fields{"Device": device, "Port": portName, "ID": id})
Naveen Sampath04696f72022-06-13 15:19:14 +05301051 }
1052}
1053
1054// AddNbPonPort Add pon port to nbDevice
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301055func (va *VoltApplication) AddNbPonPort(cntx context.Context, oltSbID string, portID, maxAllowedChannels uint32,
Naveen Sampath04696f72022-06-13 15:19:14 +05301056 enableMulticastKPI bool, portAlarmProfileID string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301057 logger.Debugw(ctx, "Received NbPonPort Ind: Add", log.Fields{"oltSbID": oltSbID, "portID": portID, "maxAllowedChannels": maxAllowedChannels, "enableMulticastKPI": enableMulticastKPI, "portAlarmProfileID": portAlarmProfileID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301058 var nbd *NbDevice
1059 nbDevice, ok := va.NbDevice.Load(oltSbID)
1060
1061 if !ok {
1062 nbd = NewNbDevice()
1063 nbd.SouthBoundID = oltSbID
1064 } else {
1065 nbd = nbDevice.(*NbDevice)
1066 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301067 port := nbd.AddPortToNbDevice(cntx, portID, maxAllowedChannels, enableMulticastKPI, portAlarmProfileID)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301068 logger.Debugw(ctx, "Added Port To NbDevice", log.Fields{"port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301069 // Add this port to voltDevice
1070 addPort := func(key, value interface{}) bool {
1071 voltDevice := value.(*VoltDevice)
1072 if oltSbID == voltDevice.SouthBoundID {
1073 if _, exists := voltDevice.ActiveChannelsPerPon.Load(portID); !exists {
1074 voltDevice.ActiveChannelsPerPon.Store(portID, port)
1075 }
1076 return false
1077 }
1078 return true
1079 }
1080 va.DevicesDisc.Range(addPort)
1081 va.NbDevice.Store(oltSbID, nbd)
1082
1083 return nil
1084}
1085
1086// UpdateNbPonPort update pon port to nbDevice
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301087func (va *VoltApplication) UpdateNbPonPort(cntx context.Context, oltSbID string, portID, maxAllowedChannels uint32, enableMulticastKPI bool, portAlarmProfileID string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301088 logger.Debugw(ctx, "Received NbPonPort Ind: Update", log.Fields{"oltSbID": oltSbID, "portID": portID, "maxAllowedChannels": maxAllowedChannels, "enableMulticastKPI": enableMulticastKPI, "portAlarmProfileID": portAlarmProfileID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301089 var nbd *NbDevice
1090 nbDevice, ok := va.NbDevice.Load(oltSbID)
1091
1092 if !ok {
1093 logger.Errorw(ctx, "Device-doesn't-exists", log.Fields{"deviceID": oltSbID})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301094 return fmt.Errorf("device-doesn't-exists - %s", oltSbID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301095 }
1096 nbd = nbDevice.(*NbDevice)
1097
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301098 port := nbd.UpdatePortToNbDevice(cntx, portID, maxAllowedChannels, enableMulticastKPI, portAlarmProfileID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301099 if port == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301100 return fmt.Errorf("port-doesn't-exists-%d", portID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301101 }
1102 va.NbDevice.Store(oltSbID, nbd)
1103
1104 // Add this port to voltDevice
1105 updPort := func(key, value interface{}) bool {
1106 voltDevice := value.(*VoltDevice)
1107 if oltSbID == voltDevice.SouthBoundID {
1108 voltDevice.ActiveChannelCountLock.Lock()
1109 if p, exists := voltDevice.ActiveChannelsPerPon.Load(portID); exists {
1110 oldPort := p.(*PonPortCfg)
1111 if port.MaxActiveChannels != 0 {
1112 oldPort.MaxActiveChannels = port.MaxActiveChannels
1113 oldPort.EnableMulticastKPI = port.EnableMulticastKPI
1114 voltDevice.ActiveChannelsPerPon.Store(portID, oldPort)
1115 }
1116 }
1117 voltDevice.ActiveChannelCountLock.Unlock()
1118 return false
1119 }
1120 return true
1121 }
1122 va.DevicesDisc.Range(updPort)
1123
1124 return nil
1125}
1126
1127// DeleteNbPonPort Delete pon port to nbDevice
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301128func (va *VoltApplication) DeleteNbPonPort(cntx context.Context, oltSbID string, portID uint32) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301129 logger.Debugw(ctx, "Received NbPonPort Ind: Delete", log.Fields{"oltSbID": oltSbID, "portID": portID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301130 nbDevice, ok := va.NbDevice.Load(oltSbID)
1131 if ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301132 nbDevice.(*NbDevice).DeletePortFromNbDevice(cntx, portID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301133 va.NbDevice.Store(oltSbID, nbDevice.(*NbDevice))
1134 } else {
1135 logger.Warnw(ctx, "Delete pon received for unknown device", log.Fields{"oltSbID": oltSbID})
1136 return nil
1137 }
1138 // Delete this port from voltDevice
1139 delPort := func(key, value interface{}) bool {
1140 voltDevice := value.(*VoltDevice)
1141 if oltSbID == voltDevice.SouthBoundID {
1142 if _, exists := voltDevice.ActiveChannelsPerPon.Load(portID); exists {
1143 voltDevice.ActiveChannelsPerPon.Delete(portID)
1144 }
1145 return false
1146 }
1147 return true
1148 }
1149 va.DevicesDisc.Range(delPort)
1150 return nil
1151}
1152
1153// GetNniPort : Get the NNI port for a device. Called from different other applications
1154// as a port to match or destination for a packet out. The VOLT application
1155// is written with the assumption that there is a single NNI port. The OLT
1156// device is responsible for translating the combination of VLAN and the
1157// NNI port ID to identify possibly a single physical port or a logical
1158// port which is a result of protection methods applied.
1159func (va *VoltApplication) GetNniPort(device string) (string, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301160 logger.Debugw(ctx, "NNI Get Ind", log.Fields{"device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301161 d, ok := va.DevicesDisc.Load(device)
1162 if !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301163 return "", errors.New("device doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301164 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301165 devConfig := va.GetDeviceConfig(d.(*VoltDevice).SerialNum)
1166 if devConfig == nil {
1167 return "", fmt.Errorf("device config not found for serial number %s", d.(*VoltDevice).SerialNum)
1168 }
1169 if len(d.(*VoltDevice).NniPort) > 0 {
1170 for _, nniPort := range d.(*VoltDevice).NniPort {
1171 nniPortID, err := GetApplication().GetPortID(nniPort)
1172 if err != nil {
1173 logger.Errorw(ctx, "Error getting port ID by port Name", log.Fields{"Error": err})
1174 continue
1175 }
1176 if devConfig.UplinkPort == strconv.Itoa(int(nniPortID)) {
1177 logger.Debugw(ctx, "NNI port configured from NB", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI Ports": d.(*VoltDevice).NniPort})
1178 return nniPort, nil // Match found
1179 }
1180 }
1181 }
1182 // If no matching NNI port is found, return an error
1183 return "", errors.New("nni port doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301184}
1185
1186// NniDownInd process for Nni down indication.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301187func (va *VoltApplication) NniDownInd(cntx context.Context, deviceID string, devSrNo string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301188 logger.Debugw(ctx, "NNI Down Ind", log.Fields{"DeviceID": deviceID, "Device SrNo": devSrNo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301189
1190 handleIgmpDsFlows := func(key interface{}, value interface{}) bool {
1191 mvProfile := value.(*MvlanProfile)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301192 mvProfile.removeIgmpMcastFlows(cntx, devSrNo)
Naveen Sampath04696f72022-06-13 15:19:14 +05301193 return true
1194 }
1195 va.MvlanProfilesByName.Range(handleIgmpDsFlows)
1196
1197 //Clear Static Group
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301198 va.ReceiverDownInd(cntx, deviceID, StaticPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05301199}
1200
1201// DeviceUpInd changes device state to up.
1202func (va *VoltApplication) DeviceUpInd(device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301203 logger.Infow(ctx, "Received Device Ind: UP", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301204 if d := va.GetDevice(device); d != nil {
1205 d.State = controller.DeviceStateUP
1206 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301207 logger.Warnw(ctx, "Ignoring Device indication: UP. Device Missing", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301208 }
1209}
1210
1211// DeviceDownInd changes device state to down.
1212func (va *VoltApplication) DeviceDownInd(device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301213 logger.Infow(ctx, "Received Device Ind: DOWN", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301214 if d := va.GetDevice(device); d != nil {
1215 d.State = controller.DeviceStateDOWN
1216 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301217 logger.Warnw(ctx, "Ignoring Device indication: DOWN. Device Missing", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301218 }
1219}
1220
1221// DeviceRebootInd process for handling flow clear flag for device reboot
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301222func (va *VoltApplication) DeviceRebootInd(cntx context.Context, device string, serialNum string, southBoundID string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301223 logger.Infow(ctx, "Received Device Ind: Reboot", log.Fields{"Device": device, "SerialNumber": serialNum, "SouthBoundID": southBoundID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301224
1225 if d := va.GetDevice(device); d != nil {
1226 if d.State == controller.DeviceStateREBOOTED {
1227 logger.Warnw(ctx, "Ignoring Device Ind: Reboot, Device already in Reboot state", log.Fields{"Device": device, "SerialNumber": serialNum, "State": d.State})
1228 return
1229 }
1230 d.State = controller.DeviceStateREBOOTED
1231 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301232 va.HandleFlowClearFlag(cntx, device, serialNum, southBoundID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301233}
1234
1235// DeviceDisableInd handles device deactivation process
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301236func (va *VoltApplication) DeviceDisableInd(cntx context.Context, device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301237 logger.Infow(ctx, "Received Device Ind: Disable", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301238
1239 d := va.GetDevice(device)
1240 if d == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301241 logger.Warnw(ctx, "Ignoring Device indication: DISABLED. Device Missing", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301242 return
1243 }
1244
1245 d.State = controller.DeviceStateDISABLED
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301246 va.HandleFlowClearFlag(cntx, device, d.SerialNum, d.SouthBoundID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301247}
1248
1249// ProcessIgmpDSFlowForMvlan for processing Igmp DS flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301250func (va *VoltApplication) ProcessIgmpDSFlowForMvlan(cntx context.Context, d *VoltDevice, mvp *MvlanProfile, addFlow bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301251 logger.Debugw(ctx, "Process IGMP DS Flows for MVlan", log.Fields{"device": d.Name, "Mvlan": mvp.Mvlan, "addFlow": addFlow})
1252 portState := false
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301253 nniPort, err := va.GetNniPort(d.Name)
1254 if err != nil {
1255 logger.Errorw(ctx, "Error gettin NNI port", log.Fields{"Error": err})
1256 }
1257 p := d.GetPort(nniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05301258 if p != nil && p.State == PortStateUp {
1259 portState = true
1260 }
1261
1262 if addFlow {
1263 if portState {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301264 mvp.pushIgmpMcastFlows(cntx, d.SerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301265 }
1266 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301267 mvp.removeIgmpMcastFlows(cntx, d.SerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301268 }
1269}
1270
1271// ProcessIgmpDSFlowForDevice for processing Igmp DS flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301272func (va *VoltApplication) ProcessIgmpDSFlowForDevice(cntx context.Context, d *VoltDevice, addFlow bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301273 logger.Debugw(ctx, "Process IGMP DS Flows for device", log.Fields{"device": d.Name, "addFlow": addFlow})
1274
1275 handleIgmpDsFlows := func(key interface{}, value interface{}) bool {
1276 mvProfile := value.(*MvlanProfile)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301277 va.ProcessIgmpDSFlowForMvlan(cntx, d, mvProfile, addFlow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301278 return true
1279 }
1280 va.MvlanProfilesByName.Range(handleIgmpDsFlows)
1281}
1282
1283// GetDeviceFromPort : This is suitable only for access ports as their naming convention
1284// makes them unique across all the OLTs. This must be called with
1285// port name that is an access port. Currently called from VNETs, attached
1286// only to access ports, and the services which are also attached only
1287// to access ports
1288func (va *VoltApplication) GetDeviceFromPort(port string) (*VoltDevice, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301289 logger.Debugw(ctx, "Received Get Device From Port", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301290 va.portLock.Lock()
1291 defer va.portLock.Unlock()
1292 var err error
1293 err = nil
1294 p, ok := va.PortsDisc.Load(port)
1295 if !ok {
1296 return nil, errorCodes.ErrPortNotFound
1297 }
1298 d := va.GetDevice(p.(*VoltPort).Device)
1299 if d == nil {
1300 err = errorCodes.ErrDeviceNotFound
1301 }
1302 return d, err
1303}
1304
1305// GetPortID : This too applies only to access ports. The ports can be indexed
1306// purely by their names without the device forming part of the key
1307func (va *VoltApplication) GetPortID(port string) (uint32, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301308 logger.Debugw(ctx, "Received Get Port ID", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301309 va.portLock.Lock()
1310 defer va.portLock.Unlock()
1311 p, ok := va.PortsDisc.Load(port)
1312 if !ok {
1313 return 0, errorCodes.ErrPortNotFound
1314 }
1315 return p.(*VoltPort).ID, nil
1316}
1317
1318// GetPortName : This too applies only to access ports. The ports can be indexed
1319// purely by their names without the device forming part of the key
1320func (va *VoltApplication) GetPortName(port uint32) (string, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301321 logger.Debugw(ctx, "Received Get Port Name", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301322 va.portLock.Lock()
1323 defer va.portLock.Unlock()
1324 var portName string
1325 va.PortsDisc.Range(func(key interface{}, value interface{}) bool {
1326 portInfo := value.(*VoltPort)
1327 if portInfo.ID == port {
1328 portName = portInfo.Name
1329 return false
1330 }
1331 return true
1332 })
1333 return portName, nil
1334}
1335
1336// GetPonFromUniPort to get Pon info from UniPort
1337func (va *VoltApplication) GetPonFromUniPort(port string) (string, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301338 logger.Debugw(ctx, "Received Get Pon From UniPort", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301339 uniPortID, err := va.GetPortID(port)
1340 if err == nil {
1341 ponPortID := (uniPortID & 0x0FF00000) >> 20 //pon(8) + onu(8) + uni(12)
1342 return strconv.FormatUint(uint64(ponPortID), 10), nil
1343 }
1344 return "", err
1345}
1346
1347// GetPortState : This too applies only to access ports. The ports can be indexed
1348// purely by their names without the device forming part of the key
1349func (va *VoltApplication) GetPortState(port string) (PortState, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301350 logger.Debugw(ctx, "Received Get Port State", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301351 va.portLock.Lock()
1352 defer va.portLock.Unlock()
1353 p, ok := va.PortsDisc.Load(port)
1354 if !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301355 return 0, errors.New("port not configured")
Naveen Sampath04696f72022-06-13 15:19:14 +05301356 }
1357 return p.(*VoltPort).State, nil
1358}
1359
1360// GetIcmpv6Receivers to get Icmp v6 receivers
1361func (va *VoltApplication) GetIcmpv6Receivers(device string) []uint32 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301362 logger.Debugw(ctx, "Get Icmpv6 Receivers", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301363 var receiverList []uint32
1364 receivers, _ := va.Icmpv6Receivers.Load(device)
1365 if receivers != nil {
1366 receiverList = receivers.([]uint32)
1367 }
1368 return receiverList
1369}
1370
1371// AddIcmpv6Receivers to add Icmp v6 receivers
1372func (va *VoltApplication) AddIcmpv6Receivers(device string, portID uint32) []uint32 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301373 logger.Debugw(ctx, "Received Add Icmpv6 Receivers", log.Fields{"device": device, "portID": portID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301374 var receiverList []uint32
1375 receivers, _ := va.Icmpv6Receivers.Load(device)
1376 if receivers != nil {
1377 receiverList = receivers.([]uint32)
1378 }
1379 receiverList = append(receiverList, portID)
1380 va.Icmpv6Receivers.Store(device, receiverList)
1381 logger.Debugw(ctx, "Receivers after addition", log.Fields{"Receivers": receiverList})
1382 return receiverList
1383}
1384
1385// DelIcmpv6Receivers to delete Icmp v6 receievers
1386func (va *VoltApplication) DelIcmpv6Receivers(device string, portID uint32) []uint32 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301387 logger.Debugw(ctx, "Received Add Icmpv6 Receivers", log.Fields{"device": device, "portID": portID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301388 var receiverList []uint32
1389 receivers, _ := va.Icmpv6Receivers.Load(device)
1390 if receivers != nil {
1391 receiverList = receivers.([]uint32)
1392 }
1393 for i, port := range receiverList {
1394 if port == portID {
1395 receiverList = append(receiverList[0:i], receiverList[i+1:]...)
1396 va.Icmpv6Receivers.Store(device, receiverList)
1397 break
1398 }
1399 }
1400 logger.Debugw(ctx, "Receivers After deletion", log.Fields{"Receivers": receiverList})
1401 return receiverList
1402}
1403
1404// ProcessDevFlowForDevice - Process DS ICMPv6 & ARP flow for provided device and vnet profile
1405// device - Device Obj
1406// vnet - vnet profile name
1407// enabled - vlan enabled/disabled - based on the status, the flow shall be added/removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301408func (va *VoltApplication) ProcessDevFlowForDevice(cntx context.Context, device *VoltDevice, vnet *VoltVnet, enabled bool) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301409 logger.Debugw(ctx, "Process Dev Flow For Device", log.Fields{"Device": device, "VnetName": vnet.Name, "Enabled": enabled})
Naveen Sampath04696f72022-06-13 15:19:14 +05301410 _, applied := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0))
1411 if enabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301412 va.PushDevFlowForVlan(cntx, vnet)
Naveen Sampath04696f72022-06-13 15:19:14 +05301413 } else if !enabled && applied {
1414 //va.DeleteDevFlowForVlan(vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301415 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, device.SerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301416 }
1417}
1418
vinokuma926cb3e2023-03-29 11:41:06 +05301419// NniVlanIndToIgmp - Trigger receiver up indication to all ports with igmp enabled
1420// and has the provided mvlan
Naveen Sampath04696f72022-06-13 15:19:14 +05301421func (va *VoltApplication) NniVlanIndToIgmp(device *VoltDevice, mvp *MvlanProfile) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301422 logger.Infow(ctx, "Received Nni Vlan Ind To Igmp", log.Fields{"Vlan": mvp.Mvlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301423
vinokuma926cb3e2023-03-29 11:41:06 +05301424 // Trigger nni indication for receiver only for first time
Naveen Sampath04696f72022-06-13 15:19:14 +05301425 if device.IgmpDsFlowAppliedForMvlan[uint16(mvp.Mvlan)] {
1426 return
1427 }
1428 device.Ports.Range(func(key, value interface{}) bool {
1429 port := key.(string)
1430
1431 if state, _ := va.GetPortState(port); state == PortStateUp {
1432 vpvs, _ := va.VnetsByPort.Load(port)
1433 if vpvs == nil {
1434 return true
1435 }
1436 for _, vpv := range vpvs.([]*VoltPortVnet) {
vinokuma926cb3e2023-03-29 11:41:06 +05301437 // Send indication only for subscribers with the received mvlan profile
Naveen Sampath04696f72022-06-13 15:19:14 +05301438 if vpv.IgmpEnabled && vpv.MvlanProfileName == mvp.Name {
1439 vpv.services.Range(ReceiverUpInd)
1440 }
1441 }
1442 }
1443 return true
1444 })
1445}
1446
1447// PortUpInd :
1448// -----------------------------------------------------------------------
1449// Port status change handling
1450// ----------------------------------------------------------------------
1451// Port UP indication is passed to all services associated with the port
1452// so that the services can configure flows applicable when the port goes
1453// up from down state
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301454func (va *VoltApplication) PortUpInd(cntx context.Context, device string, port string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301455 logger.Infow(ctx, "Received Southbound Port Ind: UP", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301456 d := va.GetDevice(device)
1457
1458 if d == nil {
1459 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: UP", log.Fields{"Device": device, "Port": port})
1460 return
1461 }
1462
vinokuma926cb3e2023-03-29 11:41:06 +05301463 // Fixme: If Port Update Comes in large numbers, this will result in slow update per device
Naveen Sampath04696f72022-06-13 15:19:14 +05301464 va.portLock.Lock()
1465 // Do not defer the port mutex unlock here
1466 // Some of the following func calls needs the port lock, so defering the lock here
1467 // may lead to dead-lock
1468 p := d.GetPort(port)
1469
1470 if p == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301471 logger.Warnw(ctx, "Ignoring Port Ind: UP, Port doesnt exist", log.Fields{"Device": device, "PortName": port, "PortId": p})
Naveen Sampath04696f72022-06-13 15:19:14 +05301472 va.portLock.Unlock()
1473 return
1474 }
1475 p.State = PortStateUp
1476 va.portLock.Unlock()
1477
Naveen Sampath04696f72022-06-13 15:19:14 +05301478 if p.Type == VoltPortTypeNni {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301479 logger.Debugw(ctx, "Received NNI Port Ind: UP", log.Fields{"Device": device, "PortName": port, "PortId": p.ID})
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301480 if d.NniDhcpTrapVid == 1 {
1481 err := va.AddDefaultDhcpTrapFlow(cntx, d, p)
1482 if err != nil {
1483 logger.Errorw(ctx, "Failed adding DHCP trap flow", log.Fields{"Device": device, "PortName": port, "PortId": p.ID, "error": err})
1484 }
1485 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301486 }
1487 vpvs, ok := va.VnetsByPort.Load(port)
1488 if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301489 logger.Warnw(ctx, "No VNETs on port", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301490 //msgbus.ProcessPortInd(msgbus.PortUp, d.SerialNum, p.Name, false, getServiceList(port))
1491 return
1492 }
1493
vinokuma926cb3e2023-03-29 11:41:06 +05301494 // If NNI port is not UP, do not push Flows
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301495 if len(d.NniPort) == 0 {
Naveen Sampath04696f72022-06-13 15:19:14 +05301496 logger.Warnw(ctx, "NNI port not UP. Not sending Port UP Ind for VPVs", log.Fields{"NNI": d.NniPort})
1497 return
1498 }
1499
Naveen Sampath04696f72022-06-13 15:19:14 +05301500 for _, vpv := range vpvs.([]*VoltPortVnet) {
1501 vpv.VpvLock.Lock()
vinokuma926cb3e2023-03-29 11:41:06 +05301502 // If no service is activated drop the portUpInd
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301503 if ok, nniPort := vpv.IsServiceActivated(cntx); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301504 // Do not trigger indication for the vpv which is already removed from vpv list as
Tinoj Josephec742f62022-09-29 19:11:10 +05301505 // part of service delete (during the lock wait duration)
1506 // In that case, the services associated wil be zero
1507 if vpv.servicesCount.Load() != 0 {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301508 vpv.PortUpInd(cntx, d, port, nniPort)
Tinoj Josephec742f62022-09-29 19:11:10 +05301509 }
1510 } else {
1511 // Service not activated, still attach device to service
1512 vpv.setDevice(d.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301513 }
1514 vpv.VpvLock.Unlock()
1515 }
1516 // At the end of processing inform the other entities that
1517 // are interested in the events
1518}
1519
1520/*
1521func getServiceList(port string) map[string]bool {
1522 serviceList := make(map[string]bool)
1523
1524 getServiceNames := func(key interface{}, value interface{}) bool {
1525 serviceList[key.(string)] = value.(*VoltService).DsHSIAFlowsApplied
1526 return true
1527 }
1528
1529 if vpvs, _ := GetApplication().VnetsByPort.Load(port); vpvs != nil {
1530 vpvList := vpvs.([]*VoltPortVnet)
1531 for _, vpv := range vpvList {
1532 vpv.services.Range(getServiceNames)
1533 }
1534 }
1535 return serviceList
1536
1537}*/
1538
vinokuma926cb3e2023-03-29 11:41:06 +05301539// ReceiverUpInd - Send receiver up indication for service with Igmp enabled
Naveen Sampath04696f72022-06-13 15:19:14 +05301540func ReceiverUpInd(key, value interface{}) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301541 logger.Info(ctx, "Receiver Indication: UP")
Naveen Sampath04696f72022-06-13 15:19:14 +05301542 svc := value.(*VoltService)
1543 var vlan of.VlanType
1544
1545 if !svc.IPAssigned() {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301546 logger.Warnw(ctx, "IP Not assigned, skipping general query", log.Fields{"Service": svc})
Naveen Sampath04696f72022-06-13 15:19:14 +05301547 return false
1548 }
1549
vinokuma926cb3e2023-03-29 11:41:06 +05301550 // Send port up indication to igmp only for service with igmp enabled
Naveen Sampath04696f72022-06-13 15:19:14 +05301551 if svc.IgmpEnabled {
1552 if svc.VlanControl == ONUCVlan || svc.VlanControl == ONUCVlanOLTSVlan {
1553 vlan = svc.CVlan
1554 } else {
1555 vlan = svc.UniVlan
1556 }
1557 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
1558 GetApplication().ReceiverUpInd(device.Name, svc.Port, svc.MvlanProfileName, vlan, svc.Pbits)
1559 }
1560 return false
1561 }
1562 return true
1563}
1564
1565// PortDownInd : Port down indication is passed on to the services so that the services
1566// can make changes at this transition.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301567func (va *VoltApplication) PortDownInd(cntx context.Context, device string, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301568 logger.Infow(ctx, "Received SouthBound Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
1569 d := va.GetDevice(device)
1570
1571 if d == nil {
1572 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
1573 return
1574 }
vinokuma926cb3e2023-03-29 11:41:06 +05301575 // Fixme: If Port Update Comes in large numbers, this will result in slow update per device
Naveen Sampath04696f72022-06-13 15:19:14 +05301576 va.portLock.Lock()
1577 // Do not defer the port mutex unlock here
1578 // Some of the following func calls needs the port lock, so defering the lock here
1579 // may lead to dead-lock
1580 p := d.GetPort(port)
1581 if p == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301582 logger.Warnw(ctx, "Ignoring Port Ind: Down, Port doesnt exist", log.Fields{"Device": device, "PortName": port, "PortId": p})
Naveen Sampath04696f72022-06-13 15:19:14 +05301583 va.portLock.Unlock()
1584 return
1585 }
1586 p.State = PortStateDown
1587 va.portLock.Unlock()
1588
1589 if d.State == controller.DeviceStateREBOOTED {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301590 logger.Warnw(ctx, "Ignoring Port Ind: Down, Device has been Rebooted", log.Fields{"Device": device, "PortName": port, "PortId": p})
Naveen Sampath04696f72022-06-13 15:19:14 +05301591 return
1592 }
1593
1594 if p.Type == VoltPortTypeNni {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301595 logger.Debugw(ctx, "Received NNI Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301596 va.DeleteDevFlowForDevice(cntx, d)
1597 va.NniDownInd(cntx, device, d.SerialNum)
1598 va.RemovePendingGroups(cntx, device, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301599 }
1600 vpvs, ok := va.VnetsByPort.Load(port)
1601 if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301602 logger.Warnw(ctx, "No VNETs on port", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301603 //msgbus.ProcessPortInd(msgbus.PortDown, d.SerialNum, p.Name, false, getServiceList(port))
1604 return
1605 }
Akash Sonia8246972023-01-03 10:37:08 +05301606
Naveen Sampath04696f72022-06-13 15:19:14 +05301607 for _, vpv := range vpvs.([]*VoltPortVnet) {
1608 vpv.VpvLock.Lock()
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301609 vpv.PortDownInd(cntx, device, port, false, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301610 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301611 va.ReceiverDownInd(cntx, device, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301612 }
1613 vpv.VpvLock.Unlock()
1614 }
1615}
1616
1617// PacketInInd :
1618// -----------------------------------------------------------------------
1619// PacketIn Processing
1620// Packet In Indication processing. It arrives with the identities of
1621// the device and port on which the packet is received. At first, the
1622// packet is decoded and the right processor is called. Currently, we
1623// plan to support only DHCP and IGMP. In future, we can add more
1624// capabilities as needed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301625func (va *VoltApplication) PacketInInd(cntx context.Context, device string, port string, pkt []byte) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301626 logger.Infow(ctx, "Received a Packet-In Indication", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301627 // Decode the incoming packet
1628 packetSide := US
1629 if strings.Contains(port, NNI) {
1630 packetSide = DS
1631 }
1632
Naveen Sampath04696f72022-06-13 15:19:14 +05301633 gopkt := gopacket.NewPacket(pkt, layers.LayerTypeEthernet, gopacket.Default)
1634
1635 var dot1qFound = false
1636 for _, l := range gopkt.Layers() {
1637 if l.LayerType() == layers.LayerTypeDot1Q {
1638 dot1qFound = true
1639 break
1640 }
1641 }
1642
1643 if !dot1qFound {
1644 logger.Debugw(ctx, "Ignoring Received Packet-In Indication without Dot1Q Header",
1645 log.Fields{"Device": device, "Port": port})
1646 return
1647 }
1648
1649 logger.Debugw(ctx, "Received Southbound Packet In", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1650
1651 // Classify the packet into packet types that we support
1652 // The supported types are DHCP and IGMP. The DHCP packet is
1653 // identified by matching the L4 protocol to UDP. The IGMP packet
1654 // is identified by matching L3 protocol to IGMP
1655 arpl := gopkt.Layer(layers.LayerTypeARP)
1656 if arpl != nil {
1657 if callBack, ok := PacketHandlers[ARP]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301658 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301659 } else {
1660 logger.Debugw(ctx, "ARP handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1661 }
1662 return
1663 }
1664 ipv4l := gopkt.Layer(layers.LayerTypeIPv4)
1665 if ipv4l != nil {
1666 ip := ipv4l.(*layers.IPv4)
1667
mgoudabb017dc2025-10-29 19:53:34 +05301668 switch ip.Protocol {
1669 case layers.IPProtocolUDP:
Naveen Sampath04696f72022-06-13 15:19:14 +05301670 logger.Debugw(ctx, "Received Southbound UDP ipv4 packet in", log.Fields{"StreamSide": packetSide})
1671 dhcpl := gopkt.Layer(layers.LayerTypeDHCPv4)
1672 if dhcpl != nil {
1673 if callBack, ok := PacketHandlers[DHCPv4]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301674 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301675 } else {
1676 logger.Debugw(ctx, "DHCPv4 handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1677 }
1678 }
mgoudabb017dc2025-10-29 19:53:34 +05301679 case layers.IPProtocolIGMP:
Naveen Sampath04696f72022-06-13 15:19:14 +05301680 logger.Debugw(ctx, "Received Southbound IGMP packet in", log.Fields{"StreamSide": packetSide})
1681 if callBack, ok := PacketHandlers[IGMP]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301682 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301683 } else {
1684 logger.Debugw(ctx, "IGMP handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1685 }
1686 }
1687 return
1688 }
1689 ipv6l := gopkt.Layer(layers.LayerTypeIPv6)
1690 if ipv6l != nil {
1691 ip := ipv6l.(*layers.IPv6)
1692 if ip.NextHeader == layers.IPProtocolUDP {
1693 logger.Debug(ctx, "Received Southbound UDP ipv6 packet in")
1694 dhcpl := gopkt.Layer(layers.LayerTypeDHCPv6)
1695 if dhcpl != nil {
1696 if callBack, ok := PacketHandlers[DHCPv6]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301697 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301698 } else {
1699 logger.Debugw(ctx, "DHCPv6 handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1700 }
1701 }
1702 }
1703 return
1704 }
1705
1706 pppoel := gopkt.Layer(layers.LayerTypePPPoE)
1707 if pppoel != nil {
1708 logger.Debugw(ctx, "Received Southbound PPPoE packet in", log.Fields{"StreamSide": packetSide})
1709 if callBack, ok := PacketHandlers[PPPOE]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301710 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301711 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301712 logger.Warnw(ctx, "PPPoE handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
Naveen Sampath04696f72022-06-13 15:19:14 +05301713 }
1714 }
1715}
1716
1717// GetVlans : This utility gets the VLANs from the packet. The VLANs are
1718// used to identify the right service that must process the incoming
1719// packet
1720func GetVlans(pkt gopacket.Packet) []of.VlanType {
1721 var vlans []of.VlanType
1722 for _, l := range pkt.Layers() {
1723 if l.LayerType() == layers.LayerTypeDot1Q {
1724 q, ok := l.(*layers.Dot1Q)
1725 if ok {
1726 vlans = append(vlans, of.VlanType(q.VLANIdentifier))
1727 }
1728 }
1729 }
1730 return vlans
1731}
1732
1733// GetPriority to get priority
1734func GetPriority(pkt gopacket.Packet) uint8 {
1735 for _, l := range pkt.Layers() {
1736 if l.LayerType() == layers.LayerTypeDot1Q {
1737 q, ok := l.(*layers.Dot1Q)
1738 if ok {
1739 return q.Priority
1740 }
1741 }
1742 }
1743 return PriorityNone
1744}
1745
1746// HandleFlowClearFlag to handle flow clear flag during reboot
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301747func (va *VoltApplication) HandleFlowClearFlag(cntx context.Context, deviceID string, serialNum, southBoundID string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301748 logger.Infow(ctx, "Clear All flags for Device", log.Fields{"Device": deviceID, "SerialNum": serialNum, "SBID": southBoundID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301749 dev, ok := va.DevicesDisc.Load(deviceID)
1750 if ok && dev != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301751 logger.Debugw(ctx, "Clear Flags for device", log.Fields{"voltDevice": dev.(*VoltDevice).Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301752 dev.(*VoltDevice).icmpv6GroupAdded = false
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301753 logger.Debugw(ctx, "Clearing DS Icmpv6 Map",
Naveen Sampath04696f72022-06-13 15:19:14 +05301754 log.Fields{"voltDevice": dev.(*VoltDevice).Name})
1755 dev.(*VoltDevice).ConfiguredVlanForDeviceFlows = util.NewConcurrentMap()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301756 logger.Debugw(ctx, "Clearing DS IGMP Map",
Naveen Sampath04696f72022-06-13 15:19:14 +05301757 log.Fields{"voltDevice": dev.(*VoltDevice).Name})
1758 for k := range dev.(*VoltDevice).IgmpDsFlowAppliedForMvlan {
1759 delete(dev.(*VoltDevice).IgmpDsFlowAppliedForMvlan, k)
1760 }
vinokuma926cb3e2023-03-29 11:41:06 +05301761 // Delete group 1 - ICMPv6/ARP group
Naveen Sampath04696f72022-06-13 15:19:14 +05301762 if err := ProcessIcmpv6McGroup(deviceID, true); err != nil {
1763 logger.Errorw(ctx, "ProcessIcmpv6McGroup failed", log.Fields{"Device": deviceID, "Error": err})
1764 }
1765 } else {
1766 logger.Warnw(ctx, "VoltDevice not found for device ", log.Fields{"deviceID": deviceID})
1767 }
1768
1769 getVpvs := func(key interface{}, value interface{}) bool {
1770 vpvs := value.([]*VoltPortVnet)
1771 for _, vpv := range vpvs {
1772 if vpv.Device == deviceID {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301773 logger.Debugw(ctx, "Clear Flags for vpv",
Naveen Sampath04696f72022-06-13 15:19:14 +05301774 log.Fields{"device": vpv.Device, "port": vpv.Port,
1775 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301776 vpv.ClearAllServiceFlags(cntx)
1777 vpv.ClearAllVpvFlags(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301778
1779 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301780 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05301781 // Also clear service igmp stats
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301782 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301783 }
1784 }
1785 }
1786 return true
1787 }
1788 va.VnetsByPort.Range(getVpvs)
1789
vinokuma926cb3e2023-03-29 11:41:06 +05301790 // Clear Static Group
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301791 va.ReceiverDownInd(cntx, deviceID, StaticPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05301792
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301793 logger.Infow(ctx, "All flags cleared for device", log.Fields{"Device": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301794
vinokuma926cb3e2023-03-29 11:41:06 +05301795 // Reset pending group pool
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301796 va.RemovePendingGroups(cntx, deviceID, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301797
vinokuma926cb3e2023-03-29 11:41:06 +05301798 // Process all Migrate Service Request - force udpate all profiles since resources are already cleaned up
Naveen Sampath04696f72022-06-13 15:19:14 +05301799 if dev != nil {
1800 triggerForceUpdate := func(key, value interface{}) bool {
1801 msrList := value.(*util.ConcurrentMap)
1802 forceUpdateServices := func(key, value interface{}) bool {
1803 msr := value.(*MigrateServicesRequest)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301804 forceUpdateAllServices(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301805 return true
1806 }
1807 msrList.Range(forceUpdateServices)
1808 return true
1809 }
1810 dev.(*VoltDevice).MigratingServices.Range(triggerForceUpdate)
1811 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301812 va.FetchAndProcessAllMigrateServicesReq(cntx, deviceID, forceUpdateAllServices)
Naveen Sampath04696f72022-06-13 15:19:14 +05301813 }
1814}
1815
vinokuma926cb3e2023-03-29 11:41:06 +05301816// GetPonPortIDFromUNIPort to get pon port id from uni port
Naveen Sampath04696f72022-06-13 15:19:14 +05301817func GetPonPortIDFromUNIPort(uniPortID uint32) uint32 {
1818 ponPortID := (uniPortID & 0x0FF00000) >> 20
1819 return ponPortID
1820}
1821
vinokuma926cb3e2023-03-29 11:41:06 +05301822// ProcessFlowModResultIndication - Processes Flow mod operation indications from controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301823func (va *VoltApplication) ProcessFlowModResultIndication(cntx context.Context, flowStatus intf.FlowStatus) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301824 logger.Debugw(ctx, "Received Flow Mod Result Indication.", log.Fields{"Cookie": flowStatus.Cookie, "Device": flowStatus.Device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301825 d := va.GetDevice(flowStatus.Device)
1826 if d == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301827 logger.Warnw(ctx, "Dropping Flow Mod Indication. Device not found", log.Fields{"Cookie": flowStatus.Cookie, "Device": flowStatus.Device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301828 return
1829 }
1830
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301831 cookieExists := ExecuteFlowEvent(cntx, d, flowStatus.Cookie, flowStatus)
Naveen Sampath04696f72022-06-13 15:19:14 +05301832
1833 if flowStatus.Flow != nil {
1834 flowAdd := (flowStatus.FlowModType == of.CommandAdd)
1835 if !cookieExists && !isFlowStatusSuccess(flowStatus.Status, flowAdd) {
1836 pushFlowFailureNotif(flowStatus)
1837 }
1838 }
1839}
1840
Akash Sonief452f12024-12-12 18:20:28 +05301841// CheckAndDeactivateService - check if the attempts for flow delete has reached threshold or not
1842func (va *VoltApplication) CheckAndDeactivateService(ctx context.Context, flow *of.VoltSubFlow, devSerialNum string, devID string) {
1843 logger.Debugw(ctx, "Check and Deactivate service", log.Fields{"Cookie": flow.Cookie, "FlowCount": flow.FlowCount, "DeviceSerial": devSerialNum})
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +05301844 if flow.FlowCount >= uint32(controller.GetController().GetMaxFlowRetryAttempt()) {
Akash Sonief452f12024-12-12 18:20:28 +05301845 devConfig := va.GetDeviceConfig(devSerialNum)
1846 if devConfig != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301847 portNo := util.GetUniPortFromFlow(devConfig.UplinkPort, devConfig.NniPorts, flow)
Akash Sonief452f12024-12-12 18:20:28 +05301848 portName, err := va.GetPortName(portNo)
1849 if err != nil {
1850 logger.Warnw(ctx, "Error getting port name", log.Fields{"Reason": err.Error(), "PortID": portNo})
1851 return
1852 } else if portName == "" {
1853 logger.Warnw(ctx, "Port does not exist", log.Fields{"PortID": portNo})
1854 return
1855 }
1856 svc := va.GetServiceNameFromCookie(flow.Cookie, portName, uint8(of.PbitMatchNone), devID, flow.Match.TableMetadata)
1857 if svc != nil {
1858 va.DeactivateServiceForPort(ctx, svc, devID, portName)
1859 }
1860 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301861 }
Akash Sonief452f12024-12-12 18:20:28 +05301862}
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301863
Akash Sonief452f12024-12-12 18:20:28 +05301864// DeactivateServiceForPort - deactivate service for given UNI and remove flows from DB, after max flow install threshold has reached
1865func (va *VoltApplication) DeactivateServiceForPort(cntx context.Context, vs *VoltService, devID string, portName string) {
1866 logger.Debugw(ctx, "Flow install threshold reached. Deactivating service", log.Fields{"Service": vs.Name, "Port": portName})
1867
1868 if devID == vs.Device && portName == vs.Port && vs.IsActivated {
1869 vs.SetSvcDeactivationFlags(SvcDeacRsn_Controller)
1870 va.ServiceByName.Store(vs.Name, vs)
1871 vs.WriteToDb(cntx)
1872 device, err := va.GetDeviceFromPort(portName)
1873 if err != nil {
1874 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
1875 // So no error is returned
1876 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portName})
1877 }
1878 p := device.GetPort(vs.Port)
1879 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
1880 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
1881 // Port down call internally deletes all the flows
1882 vpv.PortDownInd(cntx, device.Name, portName, true, true)
1883 if vpv.IgmpEnabled {
1884 va.ReceiverDownInd(cntx, device.Name, portName)
1885 }
1886 } else {
1887 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": device.Name, "port": portName, "SvcName": vs.Name})
1888 }
1889 logger.Infow(ctx, "Service deactivated after flow install threshold", log.Fields{"Device": device.Name, "Service": vs.Name, "Port": portName})
1890 }
1891 vs.DeactivateInProgress = false
1892 va.ServiceByName.Store(vs.Name, vs)
1893 vs.WriteToDb(cntx)
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301894 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301895}
1896
Naveen Sampath04696f72022-06-13 15:19:14 +05301897func pushFlowFailureNotif(flowStatus intf.FlowStatus) {
1898 subFlow := flowStatus.Flow
1899 cookie := subFlow.Cookie
1900 uniPort := cookie >> 16 & 0xFFFFFFFF
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301901 logger.Warnw(ctx, "Flow Failure Notification", log.Fields{"uniPort": uniPort, "Cookie": cookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301902}
1903
vinokuma926cb3e2023-03-29 11:41:06 +05301904// UpdateMvlanProfilesForDevice to update mvlan profile for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301905func (va *VoltApplication) UpdateMvlanProfilesForDevice(cntx context.Context, device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301906 logger.Debugw(ctx, "Received Update Mvlan Profiles For Device", log.Fields{"device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301907 checkAndAddMvlanUpdateTask := func(key, value interface{}) bool {
1908 mvp := value.(*MvlanProfile)
1909 if mvp.IsUpdateInProgressForDevice(device) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301910 mvp.UpdateProfile(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301911 }
1912 return true
1913 }
1914 va.MvlanProfilesByName.Range(checkAndAddMvlanUpdateTask)
1915}
1916
1917// TaskInfo structure that is used to store the task Info.
1918type TaskInfo struct {
1919 ID string
1920 Name string
1921 Timestamp string
1922}
1923
1924// GetTaskList to get task list information.
1925func (va *VoltApplication) GetTaskList(device string) map[int]*TaskInfo {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301926 logger.Debugw(ctx, "Received Get Task List", log.Fields{"device": device})
mgoudabb017dc2025-10-29 19:53:34 +05301927 taskList := controller.GetController().GetTaskList(device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301928 taskMap := make(map[int]*TaskInfo)
1929 for i, task := range taskList {
1930 taskID := strconv.Itoa(int(task.TaskID()))
1931 name := task.Name()
1932 timestamp := task.Timestamp()
1933 taskInfo := &TaskInfo{ID: taskID, Name: name, Timestamp: timestamp}
1934 taskMap[i] = taskInfo
1935 }
1936 return taskMap
1937}
1938
1939// UpdateDeviceSerialNumberList to update the device serial number list after device serial number is updated for vnet and mvlan
1940func (va *VoltApplication) UpdateDeviceSerialNumberList(oldOltSlNo string, newOltSlNo string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301941 logger.Debugw(ctx, "Update Device Serial Number List", log.Fields{"oldOltSlNo": oldOltSlNo, "newOltSlNo": newOltSlNo})
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301942 voltDevice, _ := va.GetDeviceBySerialNo(oldOltSlNo)
Naveen Sampath04696f72022-06-13 15:19:14 +05301943
1944 if voltDevice != nil {
1945 // Device is present with old serial number ID
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301946 logger.Warnw(ctx, "OLT Migration cannot be completed as there are dangling devices", log.Fields{"Serial Number": oldOltSlNo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301947 } else {
1948 logger.Infow(ctx, "No device present with old serial number", log.Fields{"Serial Number": oldOltSlNo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301949 // Add Serial Number to Blocked Devices List.
mgoudabb017dc2025-10-29 19:53:34 +05301950 controller.GetController().AddBlockedDevices(oldOltSlNo)
1951 controller.GetController().AddBlockedDevices(newOltSlNo)
Naveen Sampath04696f72022-06-13 15:19:14 +05301952
1953 updateSlNoForVnet := func(key, value interface{}) bool {
1954 vnet := value.(*VoltVnet)
1955 for i, deviceSlNo := range vnet.VnetConfig.DevicesList {
1956 if deviceSlNo == oldOltSlNo {
1957 vnet.VnetConfig.DevicesList[i] = newOltSlNo
1958 logger.Infow(ctx, "device serial number updated for vnet profile", log.Fields{"Updated Serial Number": deviceSlNo, "Previous Serial Number": oldOltSlNo})
1959 break
1960 }
1961 }
1962 return true
1963 }
1964
1965 updateSlNoforMvlan := func(key interface{}, value interface{}) bool {
1966 mvProfile := value.(*MvlanProfile)
1967 for deviceSlNo := range mvProfile.DevicesList {
1968 if deviceSlNo == oldOltSlNo {
1969 mvProfile.DevicesList[newOltSlNo] = mvProfile.DevicesList[oldOltSlNo]
1970 delete(mvProfile.DevicesList, oldOltSlNo)
1971 logger.Infow(ctx, "device serial number updated for mvlan profile", log.Fields{"Updated Serial Number": deviceSlNo, "Previous Serial Number": oldOltSlNo})
1972 break
1973 }
1974 }
1975 return true
1976 }
1977
1978 va.VnetsByName.Range(updateSlNoForVnet)
1979 va.MvlanProfilesByName.Range(updateSlNoforMvlan)
1980
1981 // Clear the serial number from Blocked Devices List
mgoudabb017dc2025-10-29 19:53:34 +05301982 controller.GetController().DelBlockedDevices(oldOltSlNo)
1983 controller.GetController().DelBlockedDevices(newOltSlNo)
Naveen Sampath04696f72022-06-13 15:19:14 +05301984 }
1985}
1986
1987// GetVpvsForDsPkt to get vpv for downstream packets
1988func (va *VoltApplication) GetVpvsForDsPkt(cvlan of.VlanType, svlan of.VlanType, clientMAC net.HardwareAddr,
1989 pbit uint8) ([]*VoltPortVnet, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301990 logger.Debugw(ctx, "Received Get Vpvs For Ds Pkt", log.Fields{"Cvlan": cvlan, "Svlan": svlan, "Mac": clientMAC})
Naveen Sampath04696f72022-06-13 15:19:14 +05301991 var matchVPVs []*VoltPortVnet
1992 findVpv := func(key, value interface{}) bool {
1993 vpvs := value.([]*VoltPortVnet)
1994 for _, vpv := range vpvs {
1995 if vpv.isVlanMatching(cvlan, svlan) && vpv.MatchesPriority(pbit) != nil {
1996 var subMac net.HardwareAddr
1997 if NonZeroMacAddress(vpv.MacAddr) {
1998 subMac = vpv.MacAddr
1999 } else if vpv.LearntMacAddr != nil && NonZeroMacAddress(vpv.LearntMacAddr) {
2000 subMac = vpv.LearntMacAddr
2001 } else {
2002 matchVPVs = append(matchVPVs, vpv)
2003 continue
2004 }
2005 if util.MacAddrsMatch(subMac, clientMAC) {
2006 matchVPVs = append([]*VoltPortVnet{}, vpv)
2007 logger.Infow(ctx, "Matching VPV found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "MAC": clientMAC})
2008 return false
2009 }
2010 }
2011 }
2012 return true
2013 }
2014 va.VnetsByPort.Range(findVpv)
2015
2016 if len(matchVPVs) != 1 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302017 logger.Errorw(ctx, "No matching VPV found or multiple vpvs found", log.Fields{"Match VPVs": matchVPVs, "MAC": clientMAC})
2018 return nil, errors.New("no matching VPV found or multiple vpvs found")
Naveen Sampath04696f72022-06-13 15:19:14 +05302019 }
2020 return matchVPVs, nil
2021}
2022
2023// GetMacInPortMap to get PORT value based on MAC key
2024func (va *VoltApplication) GetMacInPortMap(macAddr net.HardwareAddr) string {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302025 logger.Debugw(ctx, "Received Get PORT value based on MAC key", log.Fields{"MacAddr": macAddr.String()})
Naveen Sampath04696f72022-06-13 15:19:14 +05302026 if NonZeroMacAddress(macAddr) {
2027 va.macPortLock.Lock()
2028 defer va.macPortLock.Unlock()
2029 if port, ok := va.macPortMap[macAddr.String()]; ok {
2030 logger.Debugw(ctx, "found-entry-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
2031 return port
2032 }
2033 }
2034 logger.Infow(ctx, "entry-not-found-macportmap", log.Fields{"MacAddr": macAddr.String()})
2035 return ""
2036}
2037
2038// UpdateMacInPortMap to update MAC PORT (key value) information in MacPortMap
2039func (va *VoltApplication) UpdateMacInPortMap(macAddr net.HardwareAddr, port string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302040 logger.Debugw(ctx, "Update Macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05302041 if NonZeroMacAddress(macAddr) {
2042 va.macPortLock.Lock()
2043 va.macPortMap[macAddr.String()] = port
2044 va.macPortLock.Unlock()
2045 logger.Debugw(ctx, "updated-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
2046 }
2047}
2048
2049// DeleteMacInPortMap to remove MAC key from MacPortMap
2050func (va *VoltApplication) DeleteMacInPortMap(macAddr net.HardwareAddr) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302051 logger.Debugw(ctx, "Delete Mac from Macportmap", log.Fields{"MacAddr": macAddr.String()})
Naveen Sampath04696f72022-06-13 15:19:14 +05302052 if NonZeroMacAddress(macAddr) {
2053 port := va.GetMacInPortMap(macAddr)
2054 va.macPortLock.Lock()
2055 delete(va.macPortMap, macAddr.String())
2056 va.macPortLock.Unlock()
2057 logger.Debugw(ctx, "deleted-from-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
2058 }
2059}
2060
vinokuma926cb3e2023-03-29 11:41:06 +05302061// AddGroupToPendingPool - adds the IgmpGroup with active group table entry to global pending pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302062func (va *VoltApplication) AddGroupToPendingPool(ig *IgmpGroup) {
2063 var grpMap map[*IgmpGroup]bool
2064 var ok bool
2065
2066 va.PendingPoolLock.Lock()
2067 defer va.PendingPoolLock.Unlock()
2068
2069 logger.Infow(ctx, "Adding IgmpGroup to Global Pending Pool", log.Fields{"GroupID": ig.GroupID, "GroupName": ig.GroupName, "GroupAddr": ig.GroupAddr, "PendingDevices": len(ig.Devices)})
2070 // Do Not Reset any current profile info since group table entry tied to mvlan profile
2071 // The PonVlan is part of set field in group installed
2072 // Hence, Group created is always tied to the same mvlan profile until deleted
2073
2074 for device := range ig.Devices {
2075 key := getPendingPoolKey(ig.Mvlan, device)
2076
2077 if grpMap, ok = va.IgmpPendingPool[key]; !ok {
2078 grpMap = make(map[*IgmpGroup]bool)
2079 }
2080 grpMap[ig] = true
2081
2082 //Add grpObj reference to all associated devices
2083 va.IgmpPendingPool[key] = grpMap
2084 }
2085}
2086
vinokuma926cb3e2023-03-29 11:41:06 +05302087// RemoveGroupFromPendingPool - removes the group from global pending group pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302088func (va *VoltApplication) RemoveGroupFromPendingPool(device string, ig *IgmpGroup) bool {
2089 GetApplication().PendingPoolLock.Lock()
2090 defer GetApplication().PendingPoolLock.Unlock()
2091
2092 logger.Infow(ctx, "Removing IgmpGroup from Global Pending Pool", log.Fields{"Device": device, "GroupID": ig.GroupID, "GroupName": ig.GroupName, "GroupAddr": ig.GroupAddr, "PendingDevices": len(ig.Devices)})
2093
2094 key := getPendingPoolKey(ig.Mvlan, device)
2095 if _, ok := va.IgmpPendingPool[key]; ok {
2096 delete(va.IgmpPendingPool[key], ig)
2097 return true
2098 }
2099 return false
2100}
2101
vinokuma926cb3e2023-03-29 11:41:06 +05302102// RemoveGroupsFromPendingPool - removes the group from global pending group pool
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302103func (va *VoltApplication) RemoveGroupsFromPendingPool(cntx context.Context, device string, mvlan of.VlanType) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302104 GetApplication().PendingPoolLock.Lock()
2105 defer GetApplication().PendingPoolLock.Unlock()
2106
2107 logger.Infow(ctx, "Removing IgmpGroups from Global Pending Pool for given Deivce & Mvlan", log.Fields{"Device": device, "Mvlan": mvlan.String()})
2108
2109 key := getPendingPoolKey(mvlan, device)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302110 va.RemoveGroupListFromPendingPool(cntx, key)
Naveen Sampath04696f72022-06-13 15:19:14 +05302111}
2112
vinokuma926cb3e2023-03-29 11:41:06 +05302113// RemoveGroupListFromPendingPool - removes the groups for provided key
Naveen Sampath04696f72022-06-13 15:19:14 +05302114// 1. Deletes the group from device
2115// 2. Delete the IgmpGroup obj and release the group ID to pool
2116// Note: Make sure to obtain PendingPoolLock lock before calling this func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302117func (va *VoltApplication) RemoveGroupListFromPendingPool(cntx context.Context, key string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302118 logger.Infow(ctx, "Remove GroupList from Pending Pool for ", log.Fields{"key": key})
Naveen Sampath04696f72022-06-13 15:19:14 +05302119 if grpMap, ok := va.IgmpPendingPool[key]; ok {
2120 delete(va.IgmpPendingPool, key)
2121 for ig := range grpMap {
2122 for device := range ig.Devices {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302123 ig.DeleteIgmpGroupDevice(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05302124 }
2125 }
2126 }
2127}
2128
vinokuma926cb3e2023-03-29 11:41:06 +05302129// RemoveGroupDevicesFromPendingPool - removes the group from global pending group pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302130func (va *VoltApplication) RemoveGroupDevicesFromPendingPool(ig *IgmpGroup) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302131 logger.Infow(ctx, "Removing IgmpGroup for all devices from Global Pending Pool", log.Fields{"GroupID": ig.GroupID, "GroupName": ig.GroupName, "GroupAddr": ig.GroupAddr, "PendingDevices": len(ig.Devices)})
2132 for device := range ig.PendingGroupForDevice {
2133 va.RemoveGroupFromPendingPool(device, ig)
2134 }
2135}
2136
vinokuma926cb3e2023-03-29 11:41:06 +05302137// GetGroupFromPendingPool - Returns IgmpGroup obj from global pending pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302138func (va *VoltApplication) GetGroupFromPendingPool(mvlan of.VlanType, device string) *IgmpGroup {
Naveen Sampath04696f72022-06-13 15:19:14 +05302139 var ig *IgmpGroup
2140
2141 va.PendingPoolLock.Lock()
2142 defer va.PendingPoolLock.Unlock()
2143
2144 key := getPendingPoolKey(mvlan, device)
2145 logger.Infow(ctx, "Getting IgmpGroup from Global Pending Pool", log.Fields{"Device": device, "Mvlan": mvlan.String(), "Key": key})
2146
vinokuma926cb3e2023-03-29 11:41:06 +05302147 // Gets all IgmpGrp Obj for the device
Naveen Sampath04696f72022-06-13 15:19:14 +05302148 grpMap, ok := va.IgmpPendingPool[key]
2149 if !ok || len(grpMap) == 0 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302150 logger.Warnw(ctx, "Matching IgmpGroup not found in Global Pending Pool", log.Fields{"Device": device, "Mvlan": mvlan.String()})
Naveen Sampath04696f72022-06-13 15:19:14 +05302151 return nil
2152 }
2153
vinokuma926cb3e2023-03-29 11:41:06 +05302154 // Gets a random obj from available grps
Naveen Sampath04696f72022-06-13 15:19:14 +05302155 for ig = range grpMap {
vinokuma926cb3e2023-03-29 11:41:06 +05302156 // Remove grp obj reference from all devices associated in pending pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302157 for dev := range ig.Devices {
2158 key := getPendingPoolKey(mvlan, dev)
2159 delete(va.IgmpPendingPool[key], ig)
2160 }
2161
vinokuma926cb3e2023-03-29 11:41:06 +05302162 // Safety check to avoid re-allocating group already in use
Naveen Sampath04696f72022-06-13 15:19:14 +05302163 if ig.NumDevicesActive() == 0 {
2164 return ig
2165 }
2166
vinokuma926cb3e2023-03-29 11:41:06 +05302167 // Iteration will continue only if IG is not allocated
Naveen Sampath04696f72022-06-13 15:19:14 +05302168 }
2169 return nil
2170}
2171
vinokuma926cb3e2023-03-29 11:41:06 +05302172// RemovePendingGroups - removes all pending groups for provided reference from global pending pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302173// reference - mvlan/device ID
2174// isRefDevice - true - Device as reference
vinokuma926cb3e2023-03-29 11:41:06 +05302175// false - Mvlan as reference
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302176func (va *VoltApplication) RemovePendingGroups(cntx context.Context, reference string, isRefDevice bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302177 va.PendingPoolLock.Lock()
2178 defer va.PendingPoolLock.Unlock()
2179
2180 logger.Infow(ctx, "Removing IgmpGroups from Global Pending Pool", log.Fields{"Reference": reference, "isRefDevice": isRefDevice})
2181
vinokuma926cb3e2023-03-29 11:41:06 +05302182 // Pending Pool key: "<mvlan>_<DeviceID>""
Naveen Sampath04696f72022-06-13 15:19:14 +05302183 paramPosition := 0
2184 if isRefDevice {
2185 paramPosition = 1
2186 }
2187
2188 // 1.Remove the Entry from pending pool
2189 // 2.Deletes the group from device
2190 // 3.Delete the IgmpGroup obj and release the group ID to pool
2191 for key := range va.IgmpPendingPool {
2192 keyParams := strings.Split(key, "_")
2193 if keyParams[paramPosition] == reference {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302194 va.RemoveGroupListFromPendingPool(cntx, key)
Naveen Sampath04696f72022-06-13 15:19:14 +05302195 }
2196 }
2197}
2198
2199func getPendingPoolKey(mvlan of.VlanType, device string) string {
2200 return mvlan.String() + "_" + device
2201}
2202
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302203func (va *VoltApplication) removeExpiredGroups(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302204 logger.Info(ctx, "Remove expired Igmp Groups")
Naveen Sampath04696f72022-06-13 15:19:14 +05302205 removeExpiredGroups := func(key interface{}, value interface{}) bool {
2206 ig := value.(*IgmpGroup)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302207 ig.removeExpiredGroupFromDevice(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302208 return true
2209 }
2210 va.IgmpGroups.Range(removeExpiredGroups)
2211}
2212
vinokuma926cb3e2023-03-29 11:41:06 +05302213// TriggerPendingProfileDeleteReq - trigger pending profile delete request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302214func (va *VoltApplication) TriggerPendingProfileDeleteReq(cntx context.Context, device string) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302215 logger.Debugw(ctx, "Trigger Pending Profile Delete for device", log.Fields{"Device": device})
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302216 va.TriggerPendingServiceDeactivateReq(cntx, device)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302217 va.TriggerPendingServiceDeleteReq(cntx, device)
2218 va.TriggerPendingVpvDeleteReq(cntx, device)
2219 va.TriggerPendingVnetDeleteReq(cntx, device)
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302220 logger.Debugw(ctx, "All Pending Profile Delete triggered for device", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302221}
2222
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302223// TriggerPendingServiceDeactivateReq - trigger pending service deactivate request
2224func (va *VoltApplication) TriggerPendingServiceDeactivateReq(cntx context.Context, device string) {
Akash Sonief452f12024-12-12 18:20:28 +05302225 va.ServicesToDeactivate.Range(func(key, value interface{}) bool {
2226 serviceName := key.(string)
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302227 if vs := va.GetService(serviceName); vs != nil {
2228 if vs.Device == device {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302229 logger.Infow(ctx, "Triggering Pending Service Deactivate", log.Fields{"Service": vs.Name})
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302230 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
2231 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302232 logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
Akash Sonief452f12024-12-12 18:20:28 +05302233 return true
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302234 }
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302235 vpv.DelTrapFlows(cntx)
2236 vs.DelHsiaFlows(cntx)
Akash Sonief452f12024-12-12 18:20:28 +05302237 // Set the flag to false and clear the SevicesToDeactivate map entry so that when core restarts, VGC will not
2238 // try to deactivate the service again
2239 vs.DeactivateInProgress = false
2240 va.ServicesToDeactivate.Delete(serviceName)
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302241 vs.WriteToDb(cntx)
2242 vpv.ClearServiceCounters(cntx)
2243 }
2244 } else {
Akash Sonief452f12024-12-12 18:20:28 +05302245 logger.Warnw(ctx, "Pending Service Not found during Deactivate", log.Fields{"Service": serviceName})
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302246 }
Akash Sonief452f12024-12-12 18:20:28 +05302247 return true
2248 })
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302249}
2250
vinokuma926cb3e2023-03-29 11:41:06 +05302251// TriggerPendingServiceDeleteReq - trigger pending service delete request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302252func (va *VoltApplication) TriggerPendingServiceDeleteReq(cntx context.Context, device string) {
Akash Sonief452f12024-12-12 18:20:28 +05302253 va.ServicesToDelete.Range(func(key, value interface{}) bool {
2254 serviceName := key.(string)
Naveen Sampath04696f72022-06-13 15:19:14 +05302255 if vs := va.GetService(serviceName); vs != nil {
2256 if vs.Device == device {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302257 logger.Infow(ctx, "Triggering Pending Service delete", log.Fields{"Service": vs.Name})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302258 vs.DelHsiaFlows(cntx)
Akash Sonief452f12024-12-12 18:20:28 +05302259 // Clear the SevicesToDelete map so that when core restarts, VGC will not try to deactivate the service again
2260 va.ServicesToDelete.Delete(serviceName)
Naveen Sampath04696f72022-06-13 15:19:14 +05302261 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302262 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302263 }
2264 }
2265 } else {
Akash Sonief452f12024-12-12 18:20:28 +05302266 logger.Warnw(ctx, "Pending Service Not found during Delete", log.Fields{"Service": serviceName})
Naveen Sampath04696f72022-06-13 15:19:14 +05302267 }
Akash Sonief452f12024-12-12 18:20:28 +05302268 return true
2269 })
Naveen Sampath04696f72022-06-13 15:19:14 +05302270}
2271
vinokuma926cb3e2023-03-29 11:41:06 +05302272// TriggerPendingVpvDeleteReq - trigger pending VPV delete request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302273func (va *VoltApplication) TriggerPendingVpvDeleteReq(cntx context.Context, device string) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302274 logger.Debugw(ctx, "Pending VPVs to be deleted", log.Fields{"Count": len(va.VoltPortVnetsToDelete)})
Naveen Sampath04696f72022-06-13 15:19:14 +05302275 for vpv := range va.VoltPortVnetsToDelete {
2276 if vpv.Device == device {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302277 logger.Debugw(ctx, "Triggering Pending VPv flow delete", log.Fields{"Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302278 va.DelVnetFromPort(cntx, vpv.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05302279 }
2280 }
2281}
2282
vinokuma926cb3e2023-03-29 11:41:06 +05302283// TriggerPendingVnetDeleteReq - trigger pending vnet delete request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302284func (va *VoltApplication) TriggerPendingVnetDeleteReq(cntx context.Context, device string) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302285 logger.Debugw(ctx, "Pending Vnets to be deleted", log.Fields{"Count": len(va.VnetsToDelete)})
Naveen Sampath04696f72022-06-13 15:19:14 +05302286 for vnetName := range va.VnetsToDelete {
2287 if vnetIntf, _ := va.VnetsByName.Load(vnetName); vnetIntf != nil {
2288 vnet := vnetIntf.(*VoltVnet)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302289 if d, _ := va.GetDeviceBySerialNo(vnet.PendingDeviceToDelete); d != nil && d.SerialNum == vnet.PendingDeviceToDelete {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302290 logger.Infow(ctx, "Triggering Pending Vnet flows delete", log.Fields{"Vnet": vnet.Name, "Device": vnet.PendingDeviceToDelete})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302291 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, vnet.PendingDeviceToDelete)
Naveen Sampath04696f72022-06-13 15:19:14 +05302292 va.deleteVnetConfig(vnet)
2293 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302294 logger.Warnw(ctx, "Vnet Delete Failed : Device Not Found", log.Fields{"Vnet": vnet.Name, "Device": vnet.PendingDeviceToDelete})
Naveen Sampath04696f72022-06-13 15:19:14 +05302295 }
2296 }
2297 }
2298}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302299
2300type OltFlowService struct {
vinokuma926cb3e2023-03-29 11:41:06 +05302301 DefaultTechProfileID int `json:"defaultTechProfileId"`
Akash Sonia8246972023-01-03 10:37:08 +05302302 EnableDhcpOnNni bool `json:"enableDhcpOnNni"`
Akash Sonia8246972023-01-03 10:37:08 +05302303 EnableIgmpOnNni bool `json:"enableIgmpOnNni"`
2304 EnableEapol bool `json:"enableEapol"`
2305 EnableDhcpV6 bool `json:"enableDhcpV6"`
2306 EnableDhcpV4 bool `json:"enableDhcpV4"`
2307 RemoveFlowsOnDisable bool `json:"removeFlowsOnDisable"`
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302308}
2309
2310func (va *VoltApplication) UpdateOltFlowService(cntx context.Context, oltFlowService OltFlowService) {
2311 logger.Infow(ctx, "UpdateOltFlowService", log.Fields{"oldValue": va.OltFlowServiceConfig, "newValue": oltFlowService})
2312 va.OltFlowServiceConfig = oltFlowService
2313 b, err := json.Marshal(va.OltFlowServiceConfig)
2314 if err != nil {
2315 logger.Warnw(ctx, "Failed to Marshal OltFlowServiceConfig", log.Fields{"OltFlowServiceConfig": va.OltFlowServiceConfig})
2316 return
2317 }
2318 _ = db.PutOltFlowService(cntx, string(b))
2319}
Akash Sonia8246972023-01-03 10:37:08 +05302320
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302321// RestoreOltFlowService to read from the DB and restore olt flow service config
2322func (va *VoltApplication) RestoreOltFlowService(cntx context.Context) {
2323 oltflowService, err := db.GetOltFlowService(cntx)
2324 if err != nil {
2325 logger.Warnw(ctx, "Failed to Get OltFlowServiceConfig from DB", log.Fields{"Error": err})
2326 return
2327 }
2328 err = json.Unmarshal([]byte(oltflowService), &va.OltFlowServiceConfig)
2329 if err != nil {
2330 logger.Warn(ctx, "Unmarshal of oltflowService failed")
2331 return
2332 }
2333 logger.Infow(ctx, "updated OltFlowServiceConfig from DB", log.Fields{"OltFlowServiceConfig": va.OltFlowServiceConfig})
2334}
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302335
Akash Soni87a19072023-02-28 00:46:59 +05302336func (va *VoltApplication) UpdateDeviceConfig(cntx context.Context, deviceConfig *DeviceConfig) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302337 logger.Infow(ctx, "Received UpdateDeviceConfig", log.Fields{"DeviceInfo": deviceConfig})
Akash Soni87a19072023-02-28 00:46:59 +05302338 var dc *DeviceConfig
2339 va.DevicesConfig.Store(deviceConfig.SerialNumber, deviceConfig)
2340 err := dc.WriteDeviceConfigToDb(cntx, deviceConfig.SerialNumber, deviceConfig)
2341 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302342 logger.Warnw(ctx, "DB update for device config failed", log.Fields{"err": err})
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302343 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302344 logger.Debugw(ctx, "Added OLT configurations", log.Fields{"DeviceInfo": deviceConfig})
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302345 // If device is already discovered update the VoltDevice structure
Akash Soni87a19072023-02-28 00:46:59 +05302346 device, id := va.GetDeviceBySerialNo(deviceConfig.SerialNumber)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302347 if device != nil {
Akash Soni87a19072023-02-28 00:46:59 +05302348 device.NniDhcpTrapVid = of.VlanType(deviceConfig.NniDhcpTrapVid)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302349 va.DevicesDisc.Store(id, device)
2350 }
2351}