blob: d42449228f47aa67e25a8f89455fb23b71f116d8 [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.
Akash Reddy Kankanala16e6c4a2026-02-09 12:52:14 +0530399func (d *VoltDevice) pushFlowsForUnis(cntx context.Context, nniPort string) {
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()
Akash Reddy Kankanala16e6c4a2026-02-09 12:52:14 +0530419 if ok, serviceNni := vpv.IsServiceActivated(cntx); ok && (nniPort == serviceNni) {
420 logger.Infow(cntx, "sending PortUpInd for Unis after nni discovery", log.Fields{"activeNni": serviceNni, "uniport": port})
421 vpv.PortUpInd(cntx, d, port, serviceNni, false)
422 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530423 vpv.VpvLock.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +0530424 }
425 return true
426 })
427}
428
429// ----------------------------------------------------------
430// VOLT Application - hosts all other objects
431// ----------------------------------------------------------
432//
433// The VOLT application is a singleton implementation where
434// there is just one instance in the system and is the gateway
435// to all other components within the controller
436// The declaration of the singleton object
437var vapplication *VoltApplication
438
Akash Soni6f369452023-09-19 11:18:28 +0530439type VoltAppInterface interface {
440 AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error
441 AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530442 AddDeviceConfig(cntx context.Context, serialNum, hardwareIdentifier, nasID, ipAddress, uplinkPort string, nniDhcpTrapID uint16, nniPorts []string) error
Akash Soni6f369452023-09-19 11:18:28 +0530443 GetFlowProvisionStatus(portNo string) FlowProvisionStatus
444 DelServiceWithPrefix(cntx context.Context, prefix string) error
445 GetDevice(device string) *VoltDevice
446 GetTaskList(device string) map[int]*TaskInfo
447 AddMeterProf(cntx context.Context, cfg VoltMeter)
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530448 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 +0530449 DelMvlanProfile(cntx context.Context, name string) error
450 GetMvlanProfileByTag(vlan of.VlanType) *MvlanProfile
451 AddMcastConfig(cntx context.Context, MvlanProfileID string, IgmpProfileID string, IgmpProxyIP string, OltSerialNum string) error
452 DelMeterProf(cntx context.Context, name string) error
453 GetMeterByName(name string) (*VoltMeter, bool)
454 UpdateDeviceConfig(cntx context.Context, deviceConfig *DeviceConfig)
455 GetDeviceConfig(serNum string) *DeviceConfig
456 GetAllocations(cntx context.Context, deviceID string) ([]DhcpAllocation, error)
457 GetAllMacLearnerInfo() ([]MacLearnerInfo, error)
458 GetMacLearnerInfo(cntx context.Context, deviceID, portNumber, vlanID string) (MacLearnerInfo, error)
459 ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error
460 DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error
461 GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error)
462 UpdateOltFlowService(cntx context.Context, oltFlowService OltFlowService)
463 GetIgnoredPorts() (map[string][]string, error)
464}
465
Naveen Sampath04696f72022-06-13 15:19:14 +0530466// VoltApplication fields :
467// ServiceByName - Stores the services by the name as key
vinokuma926cb3e2023-03-29 11:41:06 +0530468// A record of NB configuration.
Naveen Sampath04696f72022-06-13 15:19:14 +0530469// VnetsByPort - Stores the VNETs by the ports configured
vinokuma926cb3e2023-03-29 11:41:06 +0530470// from NB. A record of NB configuration.
Naveen Sampath04696f72022-06-13 15:19:14 +0530471// VnetsByTag - Stores the VNETs by the VLANS configured
vinokuma926cb3e2023-03-29 11:41:06 +0530472// from NB. A record of NB configuration.
Naveen Sampath04696f72022-06-13 15:19:14 +0530473// VnetsByName - Stores the VNETs by the name configured
vinokuma926cb3e2023-03-29 11:41:06 +0530474// from NB. A record of NB configuration.
Naveen Sampath04696f72022-06-13 15:19:14 +0530475// DevicesDisc - Stores the devices discovered from SB.
vinokuma926cb3e2023-03-29 11:41:06 +0530476// Should be updated only by events from SB
Naveen Sampath04696f72022-06-13 15:19:14 +0530477// PortsDisc - Stores the ports discovered from SB.
vinokuma926cb3e2023-03-29 11:41:06 +0530478// Should be updated only by events from SB
Naveen Sampath04696f72022-06-13 15:19:14 +0530479type VoltApplication struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530480 MeterMgr
vinokuma926cb3e2023-03-29 11:41:06 +0530481 DataMigrationInfo DataMigration
482 VnetsBySvlan *util.ConcurrentMap
483 IgmpGroupIds []*IgmpGroup
484 VoltPortVnetsToDelete map[*VoltPortVnet]bool
Akash Sonia8246972023-01-03 10:37:08 +0530485 IgmpPendingPool map[string]map[*IgmpGroup]bool //[grpkey, map[groupObj]bool] //mvlan_grpName/IP
vinokuma926cb3e2023-03-29 11:41:06 +0530486 macPortMap map[string]string
Akash Sonia8246972023-01-03 10:37:08 +0530487 VnetsToDelete map[string]bool
Akash Sonief452f12024-12-12 18:20:28 +0530488 ServicesToDelete sync.Map
489 ServicesToDeactivate sync.Map
Akash Sonia8246972023-01-03 10:37:08 +0530490 PortAlarmProfileCache map[string]map[string]int // [portAlarmID][ThresholdLevelString]ThresholdLevel
491 vendorID string
vinokuma926cb3e2023-03-29 11:41:06 +0530492 ServiceByName sync.Map // [serName]*VoltService
493 VnetsByPort sync.Map // [portName][]*VoltPortVnet
494 VnetsByTag sync.Map // [svlan-cvlan-uvlan]*VoltVnet
495 VnetsByName sync.Map // [vnetName]*VoltVnet
496 DevicesDisc sync.Map
497 PortsDisc sync.Map
498 IgmpGroups sync.Map // [grpKey]*IgmpGroup
499 MvlanProfilesByTag sync.Map
500 MvlanProfilesByName sync.Map
501 Icmpv6Receivers sync.Map
502 DeviceCounters sync.Map //[logicalDeviceId]*DeviceCounters
503 ServiceCounters sync.Map //[serviceName]*ServiceCounters
504 NbDevice sync.Map // [OLTSouthBoundID]*NbDevice
505 OltIgmpInfoBySerial sync.Map
506 McastConfigMap sync.Map //[OltSerialNo_MvlanProfileID]*McastConfig
Akash Sonia8246972023-01-03 10:37:08 +0530507 DevicesConfig sync.Map //[serialNumber]*DeviceConfig
vinokuma926cb3e2023-03-29 11:41:06 +0530508 IgmpProfilesByName sync.Map
509 IgmpTasks tasks.Tasks
510 IndicationsTasks tasks.Tasks
511 MulticastAlarmTasks tasks.Tasks
512 IgmpKPIsTasks tasks.Tasks
513 pppoeTasks tasks.Tasks
514 OltFlowServiceConfig OltFlowService
515 PendingPoolLock sync.RWMutex
516 // MacAddress-Port MAP to avoid swap of mac across ports.
517 macPortLock sync.RWMutex
518 portLock sync.Mutex
Akash Sonia8246972023-01-03 10:37:08 +0530519}
Naveen Sampath04696f72022-06-13 15:19:14 +0530520
Akash Sonia8246972023-01-03 10:37:08 +0530521type DeviceConfig struct {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530522 SerialNumber string `json:"id"`
523 HardwareIdentifier string `json:"hardwareIdentifier"`
524 IPAddress string `json:"ipAddress"`
525 UplinkPort string `json:"uplinkPort"`
526 NasID string `json:"nasId"`
527 NniPorts []string `json:"nniPorts"`
528 NniDhcpTrapVid uint16 `json:"nniDhcpTrapVid"`
Naveen Sampath04696f72022-06-13 15:19:14 +0530529}
530
531// PonPortCfg contains NB port config and activeIGMPChannels count
532type PonPortCfg struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530533 PortAlarmProfileID string
Naveen Sampath04696f72022-06-13 15:19:14 +0530534 PortID uint32
535 MaxActiveChannels uint32
536 ActiveIGMPChannels uint32
537 EnableMulticastKPI bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530538}
539
540// NbDevice OLT Device info
541type NbDevice struct {
542 SouthBoundID string
543 PonPorts sync.Map // [PortID]*PonPortCfg
544}
545
546// RestoreNbDeviceFromDb restores the NB Device in case of VGC pod restart.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530547func (va *VoltApplication) RestoreNbDeviceFromDb(cntx context.Context, deviceID string) *NbDevice {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530548 logger.Debugw(ctx, "Received Restore Nb Device From Db", log.Fields{"deviceID": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530549 nbDevice := NewNbDevice()
550 nbDevice.SouthBoundID = deviceID
551
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530552 nbPorts, _ := db.GetAllNbPorts(cntx, deviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530553
554 for key, p := range nbPorts {
555 b, ok := p.Value.([]byte)
556 if !ok {
557 logger.Warn(ctx, "The value type is not []byte")
558 continue
559 }
560 var port PonPortCfg
561 err := json.Unmarshal(b, &port)
562 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530563 logger.Warnw(ctx, "Unmarshal of PonPortCfg failed", log.Fields{"deviceID": deviceID, "port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530564 continue
565 }
566 logger.Debugw(ctx, "Port recovered", log.Fields{"port": port})
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530567 ponPortID, err := strconv.ParseUint(key, 10, 32)
568 if err != nil {
569 logger.Errorw(ctx, "Error converting string to uint32:", log.Fields{"deviceID": deviceID, "error": err})
570 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530571 nbDevice.PonPorts.Store(uint32(ponPortID), &port)
572 }
573 va.NbDevice.Store(deviceID, nbDevice)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530574 logger.Debugw(ctx, "Recovered NbDevice From Db", log.Fields{"deviceID": deviceID, "nbDevice": nbDevice})
Naveen Sampath04696f72022-06-13 15:19:14 +0530575 return nbDevice
576}
577
578// NewNbDevice Constructor for NbDevice
579func NewNbDevice() *NbDevice {
580 var nbDevice NbDevice
581 return &nbDevice
582}
583
584// WriteToDb writes nb device port config to kv store
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530585func (nbd *NbDevice) WriteToDb(cntx context.Context, portID uint32, ponPort *PonPortCfg) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530586 b, err := json.Marshal(ponPort)
587 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530588 logger.Errorw(ctx, "PonPortConfig-marshal-failed", log.Fields{"err": err, "ponPort": ponPort})
Naveen Sampath04696f72022-06-13 15:19:14 +0530589 return
590 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530591 db.PutNbDevicePort(cntx, nbd.SouthBoundID, portID, string(b))
Naveen Sampath04696f72022-06-13 15:19:14 +0530592}
593
594// AddPortToNbDevice Adds pon port to NB Device and DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530595func (nbd *NbDevice) AddPortToNbDevice(cntx context.Context, portID, allowedChannels uint32,
Naveen Sampath04696f72022-06-13 15:19:14 +0530596 enableMulticastKPI bool, portAlarmProfileID string) *PonPortCfg {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530597 logger.Debugw(ctx, "AddPortToNbDevice", log.Fields{"PortID": portID, "EnableMulticastKPI": enableMulticastKPI, "PortAlarmProfileID": portAlarmProfileID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530598 ponPort := &PonPortCfg{
599 PortID: portID,
600 MaxActiveChannels: allowedChannels,
601 EnableMulticastKPI: enableMulticastKPI,
602 PortAlarmProfileID: portAlarmProfileID,
603 }
604 nbd.PonPorts.Store(portID, ponPort)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530605 nbd.WriteToDb(cntx, portID, ponPort)
Naveen Sampath04696f72022-06-13 15:19:14 +0530606 return ponPort
607}
608
Akash Sonia8246972023-01-03 10:37:08 +0530609// RestoreDeviceConfigFromDb to restore vnet from port
610func (va *VoltApplication) RestoreDeviceConfigFromDb(cntx context.Context) {
611 // VNETS must be learnt first
612 dConfig, _ := db.GetDeviceConfig(cntx)
613 for _, device := range dConfig {
614 b, ok := device.Value.([]byte)
615 if !ok {
616 logger.Warn(ctx, "The value type is not []byte")
617 continue
618 }
619 devConfig := DeviceConfig{}
620 err := json.Unmarshal(b, &devConfig)
621 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530622 logger.Warnw(ctx, "Unmarshal of device configuration failed", log.Fields{"Device Config": devConfig})
Akash Sonia8246972023-01-03 10:37:08 +0530623 continue
624 }
625 logger.Debugw(ctx, "Retrieved device config", log.Fields{"Device Config": devConfig})
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530626 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 +0530627 logger.Warnw(ctx, "Add device config failed", log.Fields{"DeviceConfig": devConfig, "Error": err})
628 }
Akash Sonia8246972023-01-03 10:37:08 +0530629 }
630}
631
632// WriteDeviceConfigToDb writes sb device config to kv store
633func (dc *DeviceConfig) WriteDeviceConfigToDb(cntx context.Context, serialNum string, deviceConfig *DeviceConfig) error {
634 b, err := json.Marshal(deviceConfig)
635 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530636 return fmt.Errorf("deviceConfig-marshal-failed - %w ", err)
Akash Sonia8246972023-01-03 10:37:08 +0530637 }
638 dberr := db.PutDeviceConfig(cntx, serialNum, string(b))
639 if dberr != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530640 return fmt.Errorf("update device config failed - %w ", err)
Akash Sonia8246972023-01-03 10:37:08 +0530641 }
642 return nil
643}
644
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530645func (va *VoltApplication) AddDeviceConfig(cntx context.Context, serialNum, hardwareIdentifier, nasID, ipAddress, uplinkPort string, nniDhcpTrapID uint16, nniPorts []string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530646 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 +0530647 var dc *DeviceConfig
648
Akash Soni87a19072023-02-28 00:46:59 +0530649 deviceConfig := &DeviceConfig{
650 SerialNumber: serialNum,
651 HardwareIdentifier: hardwareIdentifier,
652 NasID: nasID,
653 UplinkPort: uplinkPort,
654 IPAddress: ipAddress,
vinokuma926cb3e2023-03-29 11:41:06 +0530655 NniDhcpTrapVid: nniDhcpTrapID,
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530656 NniPorts: nniPorts,
Akash Sonia8246972023-01-03 10:37:08 +0530657 }
Akash Soni87a19072023-02-28 00:46:59 +0530658 va.DevicesConfig.Store(serialNum, deviceConfig)
659 err := dc.WriteDeviceConfigToDb(cntx, serialNum, deviceConfig)
660 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530661 return fmt.Errorf("DB update for device config failed - %w ", err)
Akash Soni87a19072023-02-28 00:46:59 +0530662 }
663
664 // If device is already discovered update the VoltDevice structure
665 device, id := va.GetDeviceBySerialNo(serialNum)
666 if device != nil {
vinokuma926cb3e2023-03-29 11:41:06 +0530667 device.NniDhcpTrapVid = of.VlanType(nniDhcpTrapID)
Akash Soni87a19072023-02-28 00:46:59 +0530668 va.DevicesDisc.Store(id, device)
669 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530670 logger.Debugw(ctx, "Added device config", log.Fields{"Device Config": deviceConfig})
Akash Sonia8246972023-01-03 10:37:08 +0530671 return nil
672}
673
674// GetDeviceConfig to get a device config.
675func (va *VoltApplication) GetDeviceConfig(serNum string) *DeviceConfig {
676 if d, ok := va.DevicesConfig.Load(serNum); ok {
677 return d.(*DeviceConfig)
678 }
679 return nil
680}
681
Naveen Sampath04696f72022-06-13 15:19:14 +0530682// UpdatePortToNbDevice Adds pon port to NB Device and DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530683func (nbd *NbDevice) UpdatePortToNbDevice(cntx context.Context, portID, allowedChannels uint32, enableMulticastKPI bool, portAlarmProfileID string) *PonPortCfg {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530684 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 +0530685 p, exists := nbd.PonPorts.Load(portID)
686 if !exists {
687 logger.Errorw(ctx, "PON port not exists in nb-device", log.Fields{"portID": portID})
688 return nil
689 }
690 port := p.(*PonPortCfg)
691 if allowedChannels != 0 {
692 port.MaxActiveChannels = allowedChannels
693 port.EnableMulticastKPI = enableMulticastKPI
694 port.PortAlarmProfileID = portAlarmProfileID
695 }
696
697 nbd.PonPorts.Store(portID, port)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530698 nbd.WriteToDb(cntx, portID, port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530699 return port
700}
701
702// DeletePortFromNbDevice Deletes pon port from NB Device and DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530703func (nbd *NbDevice) DeletePortFromNbDevice(cntx context.Context, portID uint32) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530704 logger.Debugw(ctx, "Received Delete Port from NbDevice", log.Fields{"portID": portID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530705 if _, ok := nbd.PonPorts.Load(portID); ok {
706 nbd.PonPorts.Delete(portID)
707 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530708 db.DelNbDevicePort(cntx, nbd.SouthBoundID, portID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530709}
710
711// GetApplication : Interface to access the singleton object
712func GetApplication() *VoltApplication {
713 if vapplication == nil {
714 vapplication = newVoltApplication()
715 }
716 return vapplication
717}
718
719// newVoltApplication : Constructor for the singleton object. Hence this is not
720// an exported function
721func newVoltApplication() *VoltApplication {
722 var va VoltApplication
723 va.IgmpTasks.Initialize(context.TODO())
724 va.MulticastAlarmTasks.Initialize(context.TODO())
725 va.IgmpKPIsTasks.Initialize(context.TODO())
726 va.pppoeTasks.Initialize(context.TODO())
727 va.storeIgmpProfileMap(DefaultIgmpProfID, newDefaultIgmpProfile())
728 va.MeterMgr.Init()
729 va.AddIgmpGroups(5000)
730 va.macPortMap = make(map[string]string)
731 va.IgmpPendingPool = make(map[string]map[*IgmpGroup]bool)
732 va.VnetsBySvlan = util.NewConcurrentMap()
733 va.VnetsToDelete = make(map[string]bool)
Naveen Sampath04696f72022-06-13 15:19:14 +0530734 va.VoltPortVnetsToDelete = make(map[*VoltPortVnet]bool)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530735 go va.Start(context.Background(), TimerCfg{tick: 100 * time.Millisecond}, tickTimer)
736 go va.Start(context.Background(), TimerCfg{tick: time.Duration(GroupExpiryTime) * time.Minute}, pendingPoolTimer)
Naveen Sampath04696f72022-06-13 15:19:14 +0530737 InitEventFuncMapper()
738 db = database.GetDatabase()
Akash Soni6f369452023-09-19 11:18:28 +0530739
Naveen Sampath04696f72022-06-13 15:19:14 +0530740 return &va
741}
742
vinokuma926cb3e2023-03-29 11:41:06 +0530743// GetFlowEventRegister - returs the register based on flow mod type
Naveen Sampath04696f72022-06-13 15:19:14 +0530744func (d *VoltDevice) GetFlowEventRegister(flowModType of.Command) (*util.ConcurrentMap, error) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530745 switch flowModType {
746 case of.CommandDel:
747 return d.FlowDelEventMap, nil
748 case of.CommandAdd:
749 return d.FlowAddEventMap, nil
750 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530751 logger.Warnw(ctx, "Unknown Flow Mod received", log.Fields{"flowModtype": flowModType})
Naveen Sampath04696f72022-06-13 15:19:14 +0530752 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530753 return util.NewConcurrentMap(), errors.New("unknown flow mod")
Naveen Sampath04696f72022-06-13 15:19:14 +0530754}
755
756// RegisterFlowAddEvent to register a flow event.
757func (d *VoltDevice) RegisterFlowAddEvent(cookie string, event *FlowEvent) {
758 logger.Debugw(ctx, "Registered Flow Add Event", log.Fields{"Cookie": cookie, "Event": event})
759 d.FlowAddEventMap.MapLock.Lock()
760 defer d.FlowAddEventMap.MapLock.Unlock()
761 d.FlowAddEventMap.Set(cookie, event)
762}
763
764// RegisterFlowDelEvent to register a flow event.
765func (d *VoltDevice) RegisterFlowDelEvent(cookie string, event *FlowEvent) {
766 logger.Debugw(ctx, "Registered Flow Del Event", log.Fields{"Cookie": cookie, "Event": event})
767 d.FlowDelEventMap.MapLock.Lock()
768 defer d.FlowDelEventMap.MapLock.Unlock()
769 d.FlowDelEventMap.Set(cookie, event)
770}
771
772// UnRegisterFlowEvent to unregister a flow event.
773func (d *VoltDevice) UnRegisterFlowEvent(cookie string, flowModType of.Command) {
774 logger.Debugw(ctx, "UnRegistered Flow Add Event", log.Fields{"Cookie": cookie, "Type": flowModType})
775 flowEventMap, err := d.GetFlowEventRegister(flowModType)
776 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530777 logger.Warnw(ctx, "Flow event map does not exists", log.Fields{"flowMod": flowModType, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530778 return
779 }
780 flowEventMap.MapLock.Lock()
781 defer flowEventMap.MapLock.Unlock()
782 flowEventMap.Remove(cookie)
783}
784
785// AddIgmpGroups to add Igmp groups.
786func (va *VoltApplication) AddIgmpGroups(numOfGroups uint32) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530787 logger.Debugw(ctx, "AddIgmpGroups", log.Fields{"NumOfGroups": numOfGroups})
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530788 var i uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530789 //TODO: Temp change to resolve group id issue in pOLT
790 //for i := 1; uint32(i) <= numOfGroups; i++ {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530791 for i = 2; i <= (numOfGroups + 1); i++ {
Naveen Sampath04696f72022-06-13 15:19:14 +0530792 ig := IgmpGroup{}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530793 ig.GroupID = i
Naveen Sampath04696f72022-06-13 15:19:14 +0530794 va.IgmpGroupIds = append(va.IgmpGroupIds, &ig)
795 }
796}
797
798// GetAvailIgmpGroupID to get id of available igmp group.
799func (va *VoltApplication) GetAvailIgmpGroupID() *IgmpGroup {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530800 logger.Info(ctx, "GetAvailIgmpGroupID")
Naveen Sampath04696f72022-06-13 15:19:14 +0530801 var ig *IgmpGroup
802 if len(va.IgmpGroupIds) > 0 {
803 ig, va.IgmpGroupIds = va.IgmpGroupIds[0], va.IgmpGroupIds[1:]
804 return ig
805 }
806 return nil
807}
808
809// GetIgmpGroupID to get id of igmp group.
810func (va *VoltApplication) GetIgmpGroupID(gid uint32) (*IgmpGroup, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530811 logger.Info(ctx, "GetIgmpGroupID")
Naveen Sampath04696f72022-06-13 15:19:14 +0530812 for id, ig := range va.IgmpGroupIds {
813 if ig.GroupID == gid {
814 va.IgmpGroupIds = append(va.IgmpGroupIds[0:id], va.IgmpGroupIds[id+1:]...)
815 return ig, nil
816 }
817 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530818 return nil, errors.New("group id missing")
Naveen Sampath04696f72022-06-13 15:19:14 +0530819}
820
821// PutIgmpGroupID to add id of igmp group.
822func (va *VoltApplication) PutIgmpGroupID(ig *IgmpGroup) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530823 logger.Debugw(ctx, "GetIgmpGroupID", log.Fields{"GroupID": ig.GroupID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530824 va.IgmpGroupIds = append([]*IgmpGroup{ig}, va.IgmpGroupIds[0:]...)
825}
826
vinokuma926cb3e2023-03-29 11:41:06 +0530827// RestoreUpgradeStatus - gets upgrade/migration status from DB and updates local flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530828func (va *VoltApplication) RestoreUpgradeStatus(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530829 logger.Info(ctx, "Received Restore Upgrade Status")
Naveen Sampath04696f72022-06-13 15:19:14 +0530830 Migrate := new(DataMigration)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530831 if err := GetMigrationInfo(cntx, Migrate); err == nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530832 if Migrate.Status == MigrationInProgress {
833 isUpgradeComplete = false
834 return
835 }
836 }
837 isUpgradeComplete = true
838
839 logger.Infow(ctx, "Upgrade Status Restored", log.Fields{"Upgrade Completed": isUpgradeComplete})
840}
841
842// ReadAllFromDb : If we are restarted, learn from the database the current execution
843// stage
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530844func (va *VoltApplication) ReadAllFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530845 logger.Info(ctx, "Reading the meters from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530846 va.RestoreMetersFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530847 logger.Info(ctx, "Reading the VNETs from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530848 va.RestoreVnetsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530849 logger.Info(ctx, "Reading the VPVs from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530850 va.RestoreVpvsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530851 logger.Info(ctx, "Reading the Services from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530852 va.RestoreSvcsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530853 logger.Info(ctx, "Reading the MVLANs from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530854 va.RestoreMvlansFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530855 logger.Info(ctx, "Reading the IGMP profiles from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530856 va.RestoreIGMPProfilesFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530857 logger.Info(ctx, "Reading the Mcast configs from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530858 va.RestoreMcastConfigsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530859 logger.Info(ctx, "Reading the IGMP groups for DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530860 va.RestoreIgmpGroupsFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530861 logger.Info(ctx, "Reading Upgrade status from DB")
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530862 va.RestoreUpgradeStatus(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530863 logger.Info(ctx, "Reading OltFlowService from DB")
864 va.RestoreOltFlowService(cntx)
Akash Sonia8246972023-01-03 10:37:08 +0530865 logger.Info(ctx, "Reading device config from DB")
866 va.RestoreDeviceConfigFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530867 logger.Info(ctx, "Reconciled from DB")
868}
869
vinokuma926cb3e2023-03-29 11:41:06 +0530870// InitStaticConfig to initialize static config.
Naveen Sampath04696f72022-06-13 15:19:14 +0530871func (va *VoltApplication) InitStaticConfig() {
872 va.InitIgmpSrcMac()
873}
874
875// SetVendorID to set vendor id
876func (va *VoltApplication) SetVendorID(vendorID string) {
877 va.vendorID = vendorID
878}
879
880// GetVendorID to get vendor id
881func (va *VoltApplication) GetVendorID() string {
882 return va.vendorID
883}
884
885// SetRebootFlag to set reboot flag
886func (va *VoltApplication) SetRebootFlag(flag bool) {
887 vgcRebooted = flag
888}
889
890// GetUpgradeFlag to get reboot status
891func (va *VoltApplication) GetUpgradeFlag() bool {
892 return isUpgradeComplete
893}
894
895// SetUpgradeFlag to set reboot status
896func (va *VoltApplication) SetUpgradeFlag(flag bool) {
897 isUpgradeComplete = flag
898}
899
900// ------------------------------------------------------------
901// Device related functions
902
903// AddDevice : Add a device and typically the device stores the NNI port on the device
904// The NNI port is used when the packets are emitted towards the network.
905// The outport is selected as the NNI port of the device. Today, we support
906// a single NNI port per OLT. This is true whether the network uses any
907// protection mechanism (LAG, ERPS, etc.). The aggregate of the such protection
908// is represented by a single NNI port
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530909func (va *VoltApplication) AddDevice(cntx context.Context, device string, slno, southBoundID string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530910 logger.Debugw(ctx, "Received Device Ind: Add", log.Fields{"Device": device, "SrNo": slno, "southBoundID": southBoundID})
Naveen Sampath04696f72022-06-13 15:19:14 +0530911 if _, ok := va.DevicesDisc.Load(device); ok {
912 logger.Warnw(ctx, "Device Exists", log.Fields{"Device": device})
913 }
914 d := NewVoltDevice(device, slno, southBoundID)
915
916 addPort := func(key, value interface{}) bool {
917 portID := key.(uint32)
918 port := value.(*PonPortCfg)
919 va.AggActiveChannelsCountForPonPort(device, portID, port)
920 d.ActiveChannelsPerPon.Store(portID, port)
921 return true
922 }
923 if nbDevice, exists := va.NbDevice.Load(southBoundID); exists {
924 // Pon Ports added before OLT activate.
925 nbDevice.(*NbDevice).PonPorts.Range(addPort)
926 } else {
927 // Check if NbPort exists in DB. VGC restart case.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530928 nbd := va.RestoreNbDeviceFromDb(cntx, southBoundID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530929 nbd.PonPorts.Range(addPort)
930 }
931 va.DevicesDisc.Store(device, d)
932}
933
934// GetDevice to get a device.
935func (va *VoltApplication) GetDevice(device string) *VoltDevice {
936 if d, ok := va.DevicesDisc.Load(device); ok {
937 return d.(*VoltDevice)
938 }
939 return nil
940}
941
942// DelDevice to delete a device.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530943func (va *VoltApplication) DelDevice(cntx context.Context, device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530944 logger.Debugw(ctx, "Received Device Ind: Delete", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +0530945 if vdIntf, ok := va.DevicesDisc.Load(device); ok {
946 vd := vdIntf.(*VoltDevice)
947 va.DevicesDisc.Delete(device)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530948 _ = db.DelAllRoutesForDevice(cntx, device)
949 va.HandleFlowClearFlag(cntx, device, vd.SerialNum, vd.SouthBoundID)
950 _ = db.DelAllGroup(cntx, device)
951 _ = db.DelAllMeter(cntx, device)
952 _ = db.DelAllPorts(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +0530953 logger.Debugw(ctx, "Device deleted", log.Fields{"Device": device})
954 } else {
955 logger.Warnw(ctx, "Device Doesn't Exist", log.Fields{"Device": device})
956 }
957}
958
Akash Sonief452f12024-12-12 18:20:28 +0530959// CheckServiceExists to check if service exists for the given uniport and tech profile ID.
960func (va *VoltApplication) CheckServiceExists(port string, techProfID uint16) bool {
961 var serviceExists bool
962 va.ServiceByName.Range(func(key, existingServiceIntf interface{}) bool {
963 existingService := existingServiceIntf.(*VoltService)
964 if existingService.Port == port && existingService.TechProfileID == techProfID {
965 logger.Warnw(ctx, "Service already exists for same Port and TP. Ignoring add service request", log.Fields{"ExistingService": existingService.Name})
966 serviceExists = true
967 return false
968 }
969 return true
970 })
971 return serviceExists
972}
973
Naveen Sampath04696f72022-06-13 15:19:14 +0530974// GetDeviceBySerialNo to get a device by serial number.
975// TODO - Transform this into a MAP instead
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530976func (va *VoltApplication) GetDeviceBySerialNo(slno string) (*VoltDevice, string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530977 logger.Debugw(ctx, "Received Device Ind: Get", log.Fields{"Serial Num": slno})
Naveen Sampath04696f72022-06-13 15:19:14 +0530978 var device *VoltDevice
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530979 var deviceID string
Naveen Sampath04696f72022-06-13 15:19:14 +0530980 getserial := func(key interface{}, value interface{}) bool {
981 device = value.(*VoltDevice)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530982 deviceID = key.(string)
Naveen Sampath04696f72022-06-13 15:19:14 +0530983 return device.SerialNum != slno
984 }
985 va.DevicesDisc.Range(getserial)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530986 return device, deviceID
Naveen Sampath04696f72022-06-13 15:19:14 +0530987}
988
989// PortAddInd : This is a PORT add indication coming from the VPAgent, which is essentially
990// a request coming from VOLTHA. The device and identity of the port is provided
991// in this request. Add them to the application for further use
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530992func (va *VoltApplication) PortAddInd(cntx context.Context, device string, id uint32, portName string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530993 logger.Debugw(ctx, "Received Port Ind: Add", log.Fields{"Device": device, "ID": id, "Port": portName})
Naveen Sampath04696f72022-06-13 15:19:14 +0530994 va.portLock.Lock()
995 if d := va.GetDevice(device); d != nil {
996 p := d.AddPort(portName, id)
997 va.PortsDisc.Store(portName, p)
998 va.portLock.Unlock()
Akash Reddy Kankanala16e6c4a2026-02-09 12:52:14 +0530999 for _, nniPort := range d.NniPort {
1000 if nniPort == portName {
1001 logger.Debugw(cntx, "NNI Port discovered. Triggering port up for UNIs", log.Fields{"Device": device, "PortName": portName, "NNIPort": nniPort})
1002 d.pushFlowsForUnis(cntx, portName)
1003 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301004 }
1005 } else {
1006 va.portLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301007 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 +05301008 }
1009}
1010
1011// PortDelInd : Only the NNI ports are recorded in the device for now. When port delete
1012// arrives, only the NNI ports need adjustments.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301013func (va *VoltApplication) PortDelInd(cntx context.Context, device string, port string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301014 logger.Debugw(ctx, "Received Port Ind: Delete", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301015 if d := va.GetDevice(device); d != nil {
1016 p := d.GetPort(port)
1017 if p != nil && p.State == PortStateUp {
1018 logger.Infow(ctx, "Port state is UP. Trigerring Port Down Ind before deleting", log.Fields{"Port": p})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301019 va.PortDownInd(cntx, device, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301020 }
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05301021 // if RemoveFlowsOnDisable is flase, then flows will be existing till port delete. Remove the flows now
1022 if !va.OltFlowServiceConfig.RemoveFlowsOnDisable {
Akash Sonia8246972023-01-03 10:37:08 +05301023 vpvs, ok := va.VnetsByPort.Load(port)
1024 if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05301025 logger.Infow(ctx, "No VNETs on port", log.Fields{"Device": device, "Port": port})
1026 } else {
1027 for _, vpv := range vpvs.([]*VoltPortVnet) {
1028 vpv.VpvLock.Lock()
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301029 // Set delFlowsInDevice to true to delete flows only in DB/device during Port Delete.
1030 vpv.PortDownInd(cntx, device, port, true, true)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05301031 vpv.VpvLock.Unlock()
1032 }
1033 }
1034 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301035 va.portLock.Lock()
1036 defer va.portLock.Unlock()
1037 d.DelPort(port)
1038 if _, ok := va.PortsDisc.Load(port); ok {
1039 va.PortsDisc.Delete(port)
1040 }
1041 } else {
1042 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: Delete", log.Fields{"Device": device, "Port": port})
1043 }
1044}
1045
vinokuma926cb3e2023-03-29 11:41:06 +05301046// PortUpdateInd Updates port Id incase of ONU movement
Naveen Sampath04696f72022-06-13 15:19:14 +05301047func (va *VoltApplication) PortUpdateInd(device string, portName string, id uint32) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301048 logger.Debugw(ctx, "Received Port Ind: Update", log.Fields{"Device": device, "Port": portName, "ID": id})
Naveen Sampath04696f72022-06-13 15:19:14 +05301049 va.portLock.Lock()
1050 defer va.portLock.Unlock()
1051 if d := va.GetDevice(device); d != nil {
1052 vp := d.GetPort(portName)
1053 vp.ID = id
1054 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301055 logger.Warnw(ctx, "Device Not Found", log.Fields{"Device": device, "Port": portName, "ID": id})
Naveen Sampath04696f72022-06-13 15:19:14 +05301056 }
1057}
1058
1059// AddNbPonPort Add pon port to nbDevice
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301060func (va *VoltApplication) AddNbPonPort(cntx context.Context, oltSbID string, portID, maxAllowedChannels uint32,
Naveen Sampath04696f72022-06-13 15:19:14 +05301061 enableMulticastKPI bool, portAlarmProfileID string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301062 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 +05301063 var nbd *NbDevice
1064 nbDevice, ok := va.NbDevice.Load(oltSbID)
1065
1066 if !ok {
1067 nbd = NewNbDevice()
1068 nbd.SouthBoundID = oltSbID
1069 } else {
1070 nbd = nbDevice.(*NbDevice)
1071 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301072 port := nbd.AddPortToNbDevice(cntx, portID, maxAllowedChannels, enableMulticastKPI, portAlarmProfileID)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301073 logger.Debugw(ctx, "Added Port To NbDevice", log.Fields{"port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301074 // Add this port to voltDevice
1075 addPort := func(key, value interface{}) bool {
1076 voltDevice := value.(*VoltDevice)
1077 if oltSbID == voltDevice.SouthBoundID {
1078 if _, exists := voltDevice.ActiveChannelsPerPon.Load(portID); !exists {
1079 voltDevice.ActiveChannelsPerPon.Store(portID, port)
1080 }
1081 return false
1082 }
1083 return true
1084 }
1085 va.DevicesDisc.Range(addPort)
1086 va.NbDevice.Store(oltSbID, nbd)
1087
1088 return nil
1089}
1090
1091// UpdateNbPonPort update pon port to nbDevice
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301092func (va *VoltApplication) UpdateNbPonPort(cntx context.Context, oltSbID string, portID, maxAllowedChannels uint32, enableMulticastKPI bool, portAlarmProfileID string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301093 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 +05301094 var nbd *NbDevice
1095 nbDevice, ok := va.NbDevice.Load(oltSbID)
1096
1097 if !ok {
1098 logger.Errorw(ctx, "Device-doesn't-exists", log.Fields{"deviceID": oltSbID})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301099 return fmt.Errorf("device-doesn't-exists - %s", oltSbID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301100 }
1101 nbd = nbDevice.(*NbDevice)
1102
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301103 port := nbd.UpdatePortToNbDevice(cntx, portID, maxAllowedChannels, enableMulticastKPI, portAlarmProfileID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301104 if port == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301105 return fmt.Errorf("port-doesn't-exists-%d", portID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301106 }
1107 va.NbDevice.Store(oltSbID, nbd)
1108
1109 // Add this port to voltDevice
1110 updPort := func(key, value interface{}) bool {
1111 voltDevice := value.(*VoltDevice)
1112 if oltSbID == voltDevice.SouthBoundID {
1113 voltDevice.ActiveChannelCountLock.Lock()
1114 if p, exists := voltDevice.ActiveChannelsPerPon.Load(portID); exists {
1115 oldPort := p.(*PonPortCfg)
1116 if port.MaxActiveChannels != 0 {
1117 oldPort.MaxActiveChannels = port.MaxActiveChannels
1118 oldPort.EnableMulticastKPI = port.EnableMulticastKPI
1119 voltDevice.ActiveChannelsPerPon.Store(portID, oldPort)
1120 }
1121 }
1122 voltDevice.ActiveChannelCountLock.Unlock()
1123 return false
1124 }
1125 return true
1126 }
1127 va.DevicesDisc.Range(updPort)
1128
1129 return nil
1130}
1131
1132// DeleteNbPonPort Delete pon port to nbDevice
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301133func (va *VoltApplication) DeleteNbPonPort(cntx context.Context, oltSbID string, portID uint32) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301134 logger.Debugw(ctx, "Received NbPonPort Ind: Delete", log.Fields{"oltSbID": oltSbID, "portID": portID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301135 nbDevice, ok := va.NbDevice.Load(oltSbID)
1136 if ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301137 nbDevice.(*NbDevice).DeletePortFromNbDevice(cntx, portID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301138 va.NbDevice.Store(oltSbID, nbDevice.(*NbDevice))
1139 } else {
1140 logger.Warnw(ctx, "Delete pon received for unknown device", log.Fields{"oltSbID": oltSbID})
1141 return nil
1142 }
1143 // Delete this port from voltDevice
1144 delPort := func(key, value interface{}) bool {
1145 voltDevice := value.(*VoltDevice)
1146 if oltSbID == voltDevice.SouthBoundID {
1147 if _, exists := voltDevice.ActiveChannelsPerPon.Load(portID); exists {
1148 voltDevice.ActiveChannelsPerPon.Delete(portID)
1149 }
1150 return false
1151 }
1152 return true
1153 }
1154 va.DevicesDisc.Range(delPort)
1155 return nil
1156}
1157
1158// GetNniPort : Get the NNI port for a device. Called from different other applications
1159// as a port to match or destination for a packet out. The VOLT application
1160// is written with the assumption that there is a single NNI port. The OLT
1161// device is responsible for translating the combination of VLAN and the
1162// NNI port ID to identify possibly a single physical port or a logical
1163// port which is a result of protection methods applied.
1164func (va *VoltApplication) GetNniPort(device string) (string, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301165 logger.Debugw(ctx, "NNI Get Ind", log.Fields{"device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301166 d, ok := va.DevicesDisc.Load(device)
1167 if !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301168 return "", errors.New("device doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301169 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301170 devConfig := va.GetDeviceConfig(d.(*VoltDevice).SerialNum)
1171 if devConfig == nil {
1172 return "", fmt.Errorf("device config not found for serial number %s", d.(*VoltDevice).SerialNum)
1173 }
1174 if len(d.(*VoltDevice).NniPort) > 0 {
1175 for _, nniPort := range d.(*VoltDevice).NniPort {
akashreddykeb418f12025-10-30 10:58:42 +05301176 nniPortID, err := GetApplication().GetDevicePortID(device, nniPort)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301177 if err != nil {
1178 logger.Errorw(ctx, "Error getting port ID by port Name", log.Fields{"Error": err})
1179 continue
1180 }
1181 if devConfig.UplinkPort == strconv.Itoa(int(nniPortID)) {
1182 logger.Debugw(ctx, "NNI port configured from NB", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI Ports": d.(*VoltDevice).NniPort})
1183 return nniPort, nil // Match found
1184 }
1185 }
1186 }
1187 // If no matching NNI port is found, return an error
1188 return "", errors.New("nni port doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301189}
1190
1191// NniDownInd process for Nni down indication.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301192func (va *VoltApplication) NniDownInd(cntx context.Context, deviceID string, devSrNo string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301193 logger.Debugw(ctx, "NNI Down Ind", log.Fields{"DeviceID": deviceID, "Device SrNo": devSrNo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301194
1195 handleIgmpDsFlows := func(key interface{}, value interface{}) bool {
1196 mvProfile := value.(*MvlanProfile)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301197 mvProfile.removeIgmpMcastFlows(cntx, devSrNo)
Naveen Sampath04696f72022-06-13 15:19:14 +05301198 return true
1199 }
1200 va.MvlanProfilesByName.Range(handleIgmpDsFlows)
1201
1202 //Clear Static Group
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301203 va.ReceiverDownInd(cntx, deviceID, StaticPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05301204}
1205
1206// DeviceUpInd changes device state to up.
1207func (va *VoltApplication) DeviceUpInd(device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301208 logger.Infow(ctx, "Received Device Ind: UP", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301209 if d := va.GetDevice(device); d != nil {
1210 d.State = controller.DeviceStateUP
1211 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301212 logger.Warnw(ctx, "Ignoring Device indication: UP. Device Missing", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301213 }
1214}
1215
1216// DeviceDownInd changes device state to down.
1217func (va *VoltApplication) DeviceDownInd(device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301218 logger.Infow(ctx, "Received Device Ind: DOWN", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301219 if d := va.GetDevice(device); d != nil {
1220 d.State = controller.DeviceStateDOWN
1221 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301222 logger.Warnw(ctx, "Ignoring Device indication: DOWN. Device Missing", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301223 }
1224}
1225
1226// DeviceRebootInd process for handling flow clear flag for device reboot
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301227func (va *VoltApplication) DeviceRebootInd(cntx context.Context, device string, serialNum string, southBoundID string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301228 logger.Infow(ctx, "Received Device Ind: Reboot", log.Fields{"Device": device, "SerialNumber": serialNum, "SouthBoundID": southBoundID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301229
1230 if d := va.GetDevice(device); d != nil {
1231 if d.State == controller.DeviceStateREBOOTED {
1232 logger.Warnw(ctx, "Ignoring Device Ind: Reboot, Device already in Reboot state", log.Fields{"Device": device, "SerialNumber": serialNum, "State": d.State})
1233 return
1234 }
1235 d.State = controller.DeviceStateREBOOTED
1236 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301237 va.HandleFlowClearFlag(cntx, device, serialNum, southBoundID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301238}
1239
1240// DeviceDisableInd handles device deactivation process
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301241func (va *VoltApplication) DeviceDisableInd(cntx context.Context, device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301242 logger.Infow(ctx, "Received Device Ind: Disable", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301243
1244 d := va.GetDevice(device)
1245 if d == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301246 logger.Warnw(ctx, "Ignoring Device indication: DISABLED. Device Missing", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301247 return
1248 }
1249
1250 d.State = controller.DeviceStateDISABLED
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301251 va.HandleFlowClearFlag(cntx, device, d.SerialNum, d.SouthBoundID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301252}
1253
1254// ProcessIgmpDSFlowForMvlan for processing Igmp DS flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301255func (va *VoltApplication) ProcessIgmpDSFlowForMvlan(cntx context.Context, d *VoltDevice, mvp *MvlanProfile, addFlow bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301256 logger.Debugw(ctx, "Process IGMP DS Flows for MVlan", log.Fields{"device": d.Name, "Mvlan": mvp.Mvlan, "addFlow": addFlow})
1257 portState := false
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301258 nniPort, err := va.GetNniPort(d.Name)
1259 if err != nil {
1260 logger.Errorw(ctx, "Error gettin NNI port", log.Fields{"Error": err})
1261 }
1262 p := d.GetPort(nniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05301263 if p != nil && p.State == PortStateUp {
1264 portState = true
1265 }
1266
1267 if addFlow {
1268 if portState {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301269 mvp.pushIgmpMcastFlows(cntx, d.SerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301270 }
1271 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301272 mvp.removeIgmpMcastFlows(cntx, d.SerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301273 }
1274}
1275
1276// ProcessIgmpDSFlowForDevice for processing Igmp DS flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301277func (va *VoltApplication) ProcessIgmpDSFlowForDevice(cntx context.Context, d *VoltDevice, addFlow bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301278 logger.Debugw(ctx, "Process IGMP DS Flows for device", log.Fields{"device": d.Name, "addFlow": addFlow})
1279
1280 handleIgmpDsFlows := func(key interface{}, value interface{}) bool {
1281 mvProfile := value.(*MvlanProfile)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301282 va.ProcessIgmpDSFlowForMvlan(cntx, d, mvProfile, addFlow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301283 return true
1284 }
1285 va.MvlanProfilesByName.Range(handleIgmpDsFlows)
1286}
1287
1288// GetDeviceFromPort : This is suitable only for access ports as their naming convention
1289// makes them unique across all the OLTs. This must be called with
1290// port name that is an access port. Currently called from VNETs, attached
1291// only to access ports, and the services which are also attached only
1292// to access ports
1293func (va *VoltApplication) GetDeviceFromPort(port string) (*VoltDevice, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301294 logger.Debugw(ctx, "Received Get Device From Port", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301295 va.portLock.Lock()
1296 defer va.portLock.Unlock()
1297 var err error
1298 err = nil
1299 p, ok := va.PortsDisc.Load(port)
1300 if !ok {
1301 return nil, errorCodes.ErrPortNotFound
1302 }
1303 d := va.GetDevice(p.(*VoltPort).Device)
1304 if d == nil {
1305 err = errorCodes.ErrDeviceNotFound
1306 }
1307 return d, err
1308}
1309
1310// GetPortID : This too applies only to access ports. The ports can be indexed
1311// purely by their names without the device forming part of the key
1312func (va *VoltApplication) GetPortID(port string) (uint32, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301313 logger.Debugw(ctx, "Received Get Port ID", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301314 va.portLock.Lock()
1315 defer va.portLock.Unlock()
1316 p, ok := va.PortsDisc.Load(port)
1317 if !ok {
1318 return 0, errorCodes.ErrPortNotFound
1319 }
1320 return p.(*VoltPort).ID, nil
1321}
1322
1323// GetPortName : This too applies only to access ports. The ports can be indexed
1324// purely by their names without the device forming part of the key
1325func (va *VoltApplication) GetPortName(port uint32) (string, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301326 logger.Debugw(ctx, "Received Get Port Name", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301327 va.portLock.Lock()
1328 defer va.portLock.Unlock()
1329 var portName string
1330 va.PortsDisc.Range(func(key interface{}, value interface{}) bool {
1331 portInfo := value.(*VoltPort)
1332 if portInfo.ID == port {
1333 portName = portInfo.Name
1334 return false
1335 }
1336 return true
1337 })
1338 return portName, nil
1339}
1340
1341// GetPonFromUniPort to get Pon info from UniPort
1342func (va *VoltApplication) GetPonFromUniPort(port string) (string, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301343 logger.Debugw(ctx, "Received Get Pon From UniPort", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301344 uniPortID, err := va.GetPortID(port)
1345 if err == nil {
1346 ponPortID := (uniPortID & 0x0FF00000) >> 20 //pon(8) + onu(8) + uni(12)
1347 return strconv.FormatUint(uint64(ponPortID), 10), nil
1348 }
1349 return "", err
1350}
1351
1352// GetPortState : This too applies only to access ports. The ports can be indexed
1353// purely by their names without the device forming part of the key
1354func (va *VoltApplication) GetPortState(port string) (PortState, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301355 logger.Debugw(ctx, "Received Get Port State", log.Fields{"Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301356 va.portLock.Lock()
1357 defer va.portLock.Unlock()
1358 p, ok := va.PortsDisc.Load(port)
1359 if !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301360 return 0, errors.New("port not configured")
Naveen Sampath04696f72022-06-13 15:19:14 +05301361 }
1362 return p.(*VoltPort).State, nil
1363}
1364
1365// GetIcmpv6Receivers to get Icmp v6 receivers
1366func (va *VoltApplication) GetIcmpv6Receivers(device string) []uint32 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301367 logger.Debugw(ctx, "Get Icmpv6 Receivers", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301368 var receiverList []uint32
1369 receivers, _ := va.Icmpv6Receivers.Load(device)
1370 if receivers != nil {
1371 receiverList = receivers.([]uint32)
1372 }
1373 return receiverList
1374}
1375
1376// AddIcmpv6Receivers to add Icmp v6 receivers
1377func (va *VoltApplication) AddIcmpv6Receivers(device string, portID uint32) []uint32 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301378 logger.Debugw(ctx, "Received Add Icmpv6 Receivers", log.Fields{"device": device, "portID": portID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301379 var receiverList []uint32
1380 receivers, _ := va.Icmpv6Receivers.Load(device)
1381 if receivers != nil {
1382 receiverList = receivers.([]uint32)
1383 }
1384 receiverList = append(receiverList, portID)
1385 va.Icmpv6Receivers.Store(device, receiverList)
1386 logger.Debugw(ctx, "Receivers after addition", log.Fields{"Receivers": receiverList})
1387 return receiverList
1388}
1389
1390// DelIcmpv6Receivers to delete Icmp v6 receievers
1391func (va *VoltApplication) DelIcmpv6Receivers(device string, portID uint32) []uint32 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301392 logger.Debugw(ctx, "Received Add Icmpv6 Receivers", log.Fields{"device": device, "portID": portID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301393 var receiverList []uint32
1394 receivers, _ := va.Icmpv6Receivers.Load(device)
1395 if receivers != nil {
1396 receiverList = receivers.([]uint32)
1397 }
1398 for i, port := range receiverList {
1399 if port == portID {
1400 receiverList = append(receiverList[0:i], receiverList[i+1:]...)
1401 va.Icmpv6Receivers.Store(device, receiverList)
1402 break
1403 }
1404 }
1405 logger.Debugw(ctx, "Receivers After deletion", log.Fields{"Receivers": receiverList})
1406 return receiverList
1407}
1408
1409// ProcessDevFlowForDevice - Process DS ICMPv6 & ARP flow for provided device and vnet profile
1410// device - Device Obj
1411// vnet - vnet profile name
1412// enabled - vlan enabled/disabled - based on the status, the flow shall be added/removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301413func (va *VoltApplication) ProcessDevFlowForDevice(cntx context.Context, device *VoltDevice, vnet *VoltVnet, enabled bool) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301414 logger.Debugw(ctx, "Process Dev Flow For Device", log.Fields{"Device": device, "VnetName": vnet.Name, "Enabled": enabled})
Naveen Sampath04696f72022-06-13 15:19:14 +05301415 _, applied := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0))
1416 if enabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301417 va.PushDevFlowForVlan(cntx, vnet)
Naveen Sampath04696f72022-06-13 15:19:14 +05301418 } else if !enabled && applied {
1419 //va.DeleteDevFlowForVlan(vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301420 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, device.SerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301421 }
1422}
1423
vinokuma926cb3e2023-03-29 11:41:06 +05301424// NniVlanIndToIgmp - Trigger receiver up indication to all ports with igmp enabled
1425// and has the provided mvlan
Naveen Sampath04696f72022-06-13 15:19:14 +05301426func (va *VoltApplication) NniVlanIndToIgmp(device *VoltDevice, mvp *MvlanProfile) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301427 logger.Infow(ctx, "Received Nni Vlan Ind To Igmp", log.Fields{"Vlan": mvp.Mvlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301428
vinokuma926cb3e2023-03-29 11:41:06 +05301429 // Trigger nni indication for receiver only for first time
Naveen Sampath04696f72022-06-13 15:19:14 +05301430 if device.IgmpDsFlowAppliedForMvlan[uint16(mvp.Mvlan)] {
1431 return
1432 }
1433 device.Ports.Range(func(key, value interface{}) bool {
1434 port := key.(string)
1435
1436 if state, _ := va.GetPortState(port); state == PortStateUp {
1437 vpvs, _ := va.VnetsByPort.Load(port)
1438 if vpvs == nil {
1439 return true
1440 }
1441 for _, vpv := range vpvs.([]*VoltPortVnet) {
vinokuma926cb3e2023-03-29 11:41:06 +05301442 // Send indication only for subscribers with the received mvlan profile
Naveen Sampath04696f72022-06-13 15:19:14 +05301443 if vpv.IgmpEnabled && vpv.MvlanProfileName == mvp.Name {
1444 vpv.services.Range(ReceiverUpInd)
1445 }
1446 }
1447 }
1448 return true
1449 })
1450}
1451
1452// PortUpInd :
1453// -----------------------------------------------------------------------
1454// Port status change handling
1455// ----------------------------------------------------------------------
1456// Port UP indication is passed to all services associated with the port
1457// so that the services can configure flows applicable when the port goes
1458// up from down state
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +05301459func (va *VoltApplication) PortUpInd(cntx context.Context, device string, port string, skipFlowPushToVoltha bool) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301460 logger.Infow(ctx, "Received Southbound Port Ind: UP", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301461 d := va.GetDevice(device)
1462
1463 if d == nil {
1464 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: UP", log.Fields{"Device": device, "Port": port})
1465 return
1466 }
1467
vinokuma926cb3e2023-03-29 11:41:06 +05301468 // Fixme: If Port Update Comes in large numbers, this will result in slow update per device
Naveen Sampath04696f72022-06-13 15:19:14 +05301469 va.portLock.Lock()
1470 // Do not defer the port mutex unlock here
1471 // Some of the following func calls needs the port lock, so defering the lock here
1472 // may lead to dead-lock
1473 p := d.GetPort(port)
1474
1475 if p == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301476 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 +05301477 va.portLock.Unlock()
1478 return
1479 }
1480 p.State = PortStateUp
1481 va.portLock.Unlock()
1482
Naveen Sampath04696f72022-06-13 15:19:14 +05301483 if p.Type == VoltPortTypeNni {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301484 logger.Debugw(ctx, "Received NNI Port Ind: UP", log.Fields{"Device": device, "PortName": port, "PortId": p.ID})
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301485 if d.NniDhcpTrapVid == 1 {
1486 err := va.AddDefaultDhcpTrapFlow(cntx, d, p)
1487 if err != nil {
1488 logger.Errorw(ctx, "Failed adding DHCP trap flow", log.Fields{"Device": device, "PortName": port, "PortId": p.ID, "error": err})
1489 }
1490 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301491 }
1492 vpvs, ok := va.VnetsByPort.Load(port)
1493 if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301494 logger.Warnw(ctx, "No VNETs on port", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301495 //msgbus.ProcessPortInd(msgbus.PortUp, d.SerialNum, p.Name, false, getServiceList(port))
1496 return
1497 }
1498
vinokuma926cb3e2023-03-29 11:41:06 +05301499 // If NNI port is not UP, do not push Flows
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301500 if len(d.NniPort) == 0 {
Naveen Sampath04696f72022-06-13 15:19:14 +05301501 logger.Warnw(ctx, "NNI port not UP. Not sending Port UP Ind for VPVs", log.Fields{"NNI": d.NniPort})
1502 return
1503 }
1504
Naveen Sampath04696f72022-06-13 15:19:14 +05301505 for _, vpv := range vpvs.([]*VoltPortVnet) {
1506 vpv.VpvLock.Lock()
vinokuma926cb3e2023-03-29 11:41:06 +05301507 // If no service is activated drop the portUpInd
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301508 if ok, nniPort := vpv.IsServiceActivated(cntx); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301509 // Do not trigger indication for the vpv which is already removed from vpv list as
Tinoj Josephec742f62022-09-29 19:11:10 +05301510 // part of service delete (during the lock wait duration)
1511 // In that case, the services associated wil be zero
1512 if vpv.servicesCount.Load() != 0 {
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +05301513 vpv.PortUpInd(cntx, d, port, nniPort, skipFlowPushToVoltha)
Tinoj Josephec742f62022-09-29 19:11:10 +05301514 }
1515 } else {
1516 // Service not activated, still attach device to service
1517 vpv.setDevice(d.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301518 }
1519 vpv.VpvLock.Unlock()
1520 }
1521 // At the end of processing inform the other entities that
1522 // are interested in the events
1523}
1524
1525/*
1526func getServiceList(port string) map[string]bool {
1527 serviceList := make(map[string]bool)
1528
1529 getServiceNames := func(key interface{}, value interface{}) bool {
1530 serviceList[key.(string)] = value.(*VoltService).DsHSIAFlowsApplied
1531 return true
1532 }
1533
1534 if vpvs, _ := GetApplication().VnetsByPort.Load(port); vpvs != nil {
1535 vpvList := vpvs.([]*VoltPortVnet)
1536 for _, vpv := range vpvList {
1537 vpv.services.Range(getServiceNames)
1538 }
1539 }
1540 return serviceList
1541
1542}*/
1543
vinokuma926cb3e2023-03-29 11:41:06 +05301544// ReceiverUpInd - Send receiver up indication for service with Igmp enabled
Naveen Sampath04696f72022-06-13 15:19:14 +05301545func ReceiverUpInd(key, value interface{}) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301546 logger.Info(ctx, "Receiver Indication: UP")
Naveen Sampath04696f72022-06-13 15:19:14 +05301547 svc := value.(*VoltService)
1548 var vlan of.VlanType
1549
1550 if !svc.IPAssigned() {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301551 logger.Warnw(ctx, "IP Not assigned, skipping general query", log.Fields{"Service": svc})
Naveen Sampath04696f72022-06-13 15:19:14 +05301552 return false
1553 }
1554
vinokuma926cb3e2023-03-29 11:41:06 +05301555 // Send port up indication to igmp only for service with igmp enabled
Naveen Sampath04696f72022-06-13 15:19:14 +05301556 if svc.IgmpEnabled {
1557 if svc.VlanControl == ONUCVlan || svc.VlanControl == ONUCVlanOLTSVlan {
1558 vlan = svc.CVlan
1559 } else {
1560 vlan = svc.UniVlan
1561 }
1562 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
1563 GetApplication().ReceiverUpInd(device.Name, svc.Port, svc.MvlanProfileName, vlan, svc.Pbits)
1564 }
1565 return false
1566 }
1567 return true
1568}
1569
1570// PortDownInd : Port down indication is passed on to the services so that the services
1571// can make changes at this transition.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301572func (va *VoltApplication) PortDownInd(cntx context.Context, device string, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301573 logger.Infow(ctx, "Received SouthBound Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
1574 d := va.GetDevice(device)
1575
1576 if d == nil {
1577 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
1578 return
1579 }
vinokuma926cb3e2023-03-29 11:41:06 +05301580 // Fixme: If Port Update Comes in large numbers, this will result in slow update per device
Naveen Sampath04696f72022-06-13 15:19:14 +05301581 va.portLock.Lock()
1582 // Do not defer the port mutex unlock here
1583 // Some of the following func calls needs the port lock, so defering the lock here
1584 // may lead to dead-lock
1585 p := d.GetPort(port)
1586 if p == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301587 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 +05301588 va.portLock.Unlock()
1589 return
1590 }
1591 p.State = PortStateDown
1592 va.portLock.Unlock()
1593
1594 if d.State == controller.DeviceStateREBOOTED {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301595 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 +05301596 return
1597 }
1598
1599 if p.Type == VoltPortTypeNni {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301600 logger.Debugw(ctx, "Received NNI Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301601 va.DeleteDevFlowForDevice(cntx, d)
1602 va.NniDownInd(cntx, device, d.SerialNum)
1603 va.RemovePendingGroups(cntx, device, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301604 }
1605 vpvs, ok := va.VnetsByPort.Load(port)
1606 if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301607 logger.Warnw(ctx, "No VNETs on port", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301608 //msgbus.ProcessPortInd(msgbus.PortDown, d.SerialNum, p.Name, false, getServiceList(port))
1609 return
1610 }
Akash Sonia8246972023-01-03 10:37:08 +05301611
Naveen Sampath04696f72022-06-13 15:19:14 +05301612 for _, vpv := range vpvs.([]*VoltPortVnet) {
1613 vpv.VpvLock.Lock()
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301614 vpv.PortDownInd(cntx, device, port, false, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301615 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301616 va.ReceiverDownInd(cntx, device, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301617 }
1618 vpv.VpvLock.Unlock()
1619 }
1620}
1621
1622// PacketInInd :
1623// -----------------------------------------------------------------------
1624// PacketIn Processing
1625// Packet In Indication processing. It arrives with the identities of
1626// the device and port on which the packet is received. At first, the
1627// packet is decoded and the right processor is called. Currently, we
1628// plan to support only DHCP and IGMP. In future, we can add more
1629// capabilities as needed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301630func (va *VoltApplication) PacketInInd(cntx context.Context, device string, port string, pkt []byte) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301631 logger.Infow(ctx, "Received a Packet-In Indication", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301632 // Decode the incoming packet
1633 packetSide := US
1634 if strings.Contains(port, NNI) {
1635 packetSide = DS
1636 }
1637
Naveen Sampath04696f72022-06-13 15:19:14 +05301638 gopkt := gopacket.NewPacket(pkt, layers.LayerTypeEthernet, gopacket.Default)
1639
1640 var dot1qFound = false
1641 for _, l := range gopkt.Layers() {
1642 if l.LayerType() == layers.LayerTypeDot1Q {
1643 dot1qFound = true
1644 break
1645 }
1646 }
1647
1648 if !dot1qFound {
1649 logger.Debugw(ctx, "Ignoring Received Packet-In Indication without Dot1Q Header",
1650 log.Fields{"Device": device, "Port": port})
1651 return
1652 }
1653
1654 logger.Debugw(ctx, "Received Southbound Packet In", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1655
1656 // Classify the packet into packet types that we support
1657 // The supported types are DHCP and IGMP. The DHCP packet is
1658 // identified by matching the L4 protocol to UDP. The IGMP packet
1659 // is identified by matching L3 protocol to IGMP
1660 arpl := gopkt.Layer(layers.LayerTypeARP)
1661 if arpl != nil {
1662 if callBack, ok := PacketHandlers[ARP]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301663 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301664 } else {
1665 logger.Debugw(ctx, "ARP handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1666 }
1667 return
1668 }
1669 ipv4l := gopkt.Layer(layers.LayerTypeIPv4)
1670 if ipv4l != nil {
1671 ip := ipv4l.(*layers.IPv4)
1672
mgoudabb017dc2025-10-29 19:53:34 +05301673 switch ip.Protocol {
1674 case layers.IPProtocolUDP:
Naveen Sampath04696f72022-06-13 15:19:14 +05301675 logger.Debugw(ctx, "Received Southbound UDP ipv4 packet in", log.Fields{"StreamSide": packetSide})
1676 dhcpl := gopkt.Layer(layers.LayerTypeDHCPv4)
1677 if dhcpl != nil {
1678 if callBack, ok := PacketHandlers[DHCPv4]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301679 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301680 } else {
1681 logger.Debugw(ctx, "DHCPv4 handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1682 }
1683 }
mgoudabb017dc2025-10-29 19:53:34 +05301684 case layers.IPProtocolIGMP:
Naveen Sampath04696f72022-06-13 15:19:14 +05301685 logger.Debugw(ctx, "Received Southbound IGMP packet in", log.Fields{"StreamSide": packetSide})
1686 if callBack, ok := PacketHandlers[IGMP]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301687 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301688 } else {
1689 logger.Debugw(ctx, "IGMP handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1690 }
1691 }
1692 return
1693 }
1694 ipv6l := gopkt.Layer(layers.LayerTypeIPv6)
1695 if ipv6l != nil {
1696 ip := ipv6l.(*layers.IPv6)
1697 if ip.NextHeader == layers.IPProtocolUDP {
1698 logger.Debug(ctx, "Received Southbound UDP ipv6 packet in")
1699 dhcpl := gopkt.Layer(layers.LayerTypeDHCPv6)
1700 if dhcpl != nil {
1701 if callBack, ok := PacketHandlers[DHCPv6]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301702 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301703 } else {
1704 logger.Debugw(ctx, "DHCPv6 handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1705 }
1706 }
1707 }
1708 return
1709 }
1710
1711 pppoel := gopkt.Layer(layers.LayerTypePPPoE)
1712 if pppoel != nil {
1713 logger.Debugw(ctx, "Received Southbound PPPoE packet in", log.Fields{"StreamSide": packetSide})
1714 if callBack, ok := PacketHandlers[PPPOE]; ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301715 callBack(cntx, device, port, gopkt)
Naveen Sampath04696f72022-06-13 15:19:14 +05301716 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301717 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 +05301718 }
1719 }
1720}
1721
1722// GetVlans : This utility gets the VLANs from the packet. The VLANs are
1723// used to identify the right service that must process the incoming
1724// packet
1725func GetVlans(pkt gopacket.Packet) []of.VlanType {
1726 var vlans []of.VlanType
1727 for _, l := range pkt.Layers() {
1728 if l.LayerType() == layers.LayerTypeDot1Q {
1729 q, ok := l.(*layers.Dot1Q)
1730 if ok {
1731 vlans = append(vlans, of.VlanType(q.VLANIdentifier))
1732 }
1733 }
1734 }
1735 return vlans
1736}
1737
1738// GetPriority to get priority
1739func GetPriority(pkt gopacket.Packet) uint8 {
1740 for _, l := range pkt.Layers() {
1741 if l.LayerType() == layers.LayerTypeDot1Q {
1742 q, ok := l.(*layers.Dot1Q)
1743 if ok {
1744 return q.Priority
1745 }
1746 }
1747 }
1748 return PriorityNone
1749}
1750
1751// HandleFlowClearFlag to handle flow clear flag during reboot
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301752func (va *VoltApplication) HandleFlowClearFlag(cntx context.Context, deviceID string, serialNum, southBoundID string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301753 logger.Infow(ctx, "Clear All flags for Device", log.Fields{"Device": deviceID, "SerialNum": serialNum, "SBID": southBoundID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301754 dev, ok := va.DevicesDisc.Load(deviceID)
1755 if ok && dev != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301756 logger.Debugw(ctx, "Clear Flags for device", log.Fields{"voltDevice": dev.(*VoltDevice).Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301757 dev.(*VoltDevice).icmpv6GroupAdded = false
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301758 logger.Debugw(ctx, "Clearing DS Icmpv6 Map",
Naveen Sampath04696f72022-06-13 15:19:14 +05301759 log.Fields{"voltDevice": dev.(*VoltDevice).Name})
1760 dev.(*VoltDevice).ConfiguredVlanForDeviceFlows = util.NewConcurrentMap()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301761 logger.Debugw(ctx, "Clearing DS IGMP Map",
Naveen Sampath04696f72022-06-13 15:19:14 +05301762 log.Fields{"voltDevice": dev.(*VoltDevice).Name})
1763 for k := range dev.(*VoltDevice).IgmpDsFlowAppliedForMvlan {
1764 delete(dev.(*VoltDevice).IgmpDsFlowAppliedForMvlan, k)
1765 }
vinokuma926cb3e2023-03-29 11:41:06 +05301766 // Delete group 1 - ICMPv6/ARP group
Naveen Sampath04696f72022-06-13 15:19:14 +05301767 if err := ProcessIcmpv6McGroup(deviceID, true); err != nil {
1768 logger.Errorw(ctx, "ProcessIcmpv6McGroup failed", log.Fields{"Device": deviceID, "Error": err})
1769 }
1770 } else {
1771 logger.Warnw(ctx, "VoltDevice not found for device ", log.Fields{"deviceID": deviceID})
1772 }
1773
1774 getVpvs := func(key interface{}, value interface{}) bool {
1775 vpvs := value.([]*VoltPortVnet)
1776 for _, vpv := range vpvs {
1777 if vpv.Device == deviceID {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301778 logger.Debugw(ctx, "Clear Flags for vpv",
Naveen Sampath04696f72022-06-13 15:19:14 +05301779 log.Fields{"device": vpv.Device, "port": vpv.Port,
1780 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301781 vpv.ClearAllServiceFlags(cntx)
1782 vpv.ClearAllVpvFlags(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301783
1784 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301785 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05301786 // Also clear service igmp stats
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301787 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301788 }
1789 }
1790 }
1791 return true
1792 }
1793 va.VnetsByPort.Range(getVpvs)
1794
vinokuma926cb3e2023-03-29 11:41:06 +05301795 // Clear Static Group
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301796 va.ReceiverDownInd(cntx, deviceID, StaticPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05301797
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301798 logger.Infow(ctx, "All flags cleared for device", log.Fields{"Device": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301799
vinokuma926cb3e2023-03-29 11:41:06 +05301800 // Reset pending group pool
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301801 va.RemovePendingGroups(cntx, deviceID, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301802
vinokuma926cb3e2023-03-29 11:41:06 +05301803 // Process all Migrate Service Request - force udpate all profiles since resources are already cleaned up
Naveen Sampath04696f72022-06-13 15:19:14 +05301804 if dev != nil {
1805 triggerForceUpdate := func(key, value interface{}) bool {
1806 msrList := value.(*util.ConcurrentMap)
1807 forceUpdateServices := func(key, value interface{}) bool {
1808 msr := value.(*MigrateServicesRequest)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301809 forceUpdateAllServices(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301810 return true
1811 }
1812 msrList.Range(forceUpdateServices)
1813 return true
1814 }
1815 dev.(*VoltDevice).MigratingServices.Range(triggerForceUpdate)
1816 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301817 va.FetchAndProcessAllMigrateServicesReq(cntx, deviceID, forceUpdateAllServices)
Naveen Sampath04696f72022-06-13 15:19:14 +05301818 }
1819}
1820
vinokuma926cb3e2023-03-29 11:41:06 +05301821// GetPonPortIDFromUNIPort to get pon port id from uni port
Naveen Sampath04696f72022-06-13 15:19:14 +05301822func GetPonPortIDFromUNIPort(uniPortID uint32) uint32 {
1823 ponPortID := (uniPortID & 0x0FF00000) >> 20
1824 return ponPortID
1825}
1826
vinokuma926cb3e2023-03-29 11:41:06 +05301827// ProcessFlowModResultIndication - Processes Flow mod operation indications from controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301828func (va *VoltApplication) ProcessFlowModResultIndication(cntx context.Context, flowStatus intf.FlowStatus) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301829 logger.Debugw(ctx, "Received Flow Mod Result Indication.", log.Fields{"Cookie": flowStatus.Cookie, "Device": flowStatus.Device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301830 d := va.GetDevice(flowStatus.Device)
1831 if d == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301832 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 +05301833 return
1834 }
1835
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301836 cookieExists := ExecuteFlowEvent(cntx, d, flowStatus.Cookie, flowStatus)
Naveen Sampath04696f72022-06-13 15:19:14 +05301837
1838 if flowStatus.Flow != nil {
1839 flowAdd := (flowStatus.FlowModType == of.CommandAdd)
1840 if !cookieExists && !isFlowStatusSuccess(flowStatus.Status, flowAdd) {
1841 pushFlowFailureNotif(flowStatus)
1842 }
1843 }
1844}
1845
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +05301846func (va *VoltApplication) GetAllFlowsForSvc(cntx context.Context, flow *of.VoltSubFlow, devID string, devSerialNum string) []uint64 {
1847 devConfig := va.GetDeviceConfig(devSerialNum)
1848 portNo := util.GetUniPortFromFlow(devConfig.UplinkPort, devConfig.NniPorts, flow)
1849 portName, err := va.GetPortName(portNo)
1850
1851 if err != nil {
1852 logger.Warnw(ctx, "Error getting port name", log.Fields{"Reason": err.Error(), "PortID": flow.Match.InPort})
1853 return nil
1854 } else if portName == "" {
1855 logger.Warnw(ctx, "Port does not exist", log.Fields{"PortID": flow.Match.InPort})
1856 return nil
1857 }
1858 svc := va.GetServiceNameFromCookie(flow.Cookie, portName, uint8(of.PbitMatchNone), devID, flow.Match.TableMetadata)
1859 if svc != nil {
1860 dsFlows := make([]uint64, 0)
1861 for cookie, ok := range svc.AssociatedFlows {
1862 if ok {
1863 if val, err := strconv.ParseUint(cookie, 10, 64); err == nil {
1864 dsFlows = append(dsFlows, val)
1865 }
1866 }
1867 }
1868 return dsFlows
1869 }
1870 return nil
1871}
1872
Akash Sonief452f12024-12-12 18:20:28 +05301873// CheckAndDeactivateService - check if the attempts for flow delete has reached threshold or not
1874func (va *VoltApplication) CheckAndDeactivateService(ctx context.Context, flow *of.VoltSubFlow, devSerialNum string, devID string) {
1875 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 +05301876 if flow.FlowCount >= uint32(controller.GetController().GetMaxFlowRetryAttempt()) {
Akash Sonief452f12024-12-12 18:20:28 +05301877 devConfig := va.GetDeviceConfig(devSerialNum)
1878 if devConfig != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301879 portNo := util.GetUniPortFromFlow(devConfig.UplinkPort, devConfig.NniPorts, flow)
Akash Sonief452f12024-12-12 18:20:28 +05301880 portName, err := va.GetPortName(portNo)
1881 if err != nil {
1882 logger.Warnw(ctx, "Error getting port name", log.Fields{"Reason": err.Error(), "PortID": portNo})
1883 return
1884 } else if portName == "" {
1885 logger.Warnw(ctx, "Port does not exist", log.Fields{"PortID": portNo})
1886 return
1887 }
1888 svc := va.GetServiceNameFromCookie(flow.Cookie, portName, uint8(of.PbitMatchNone), devID, flow.Match.TableMetadata)
1889 if svc != nil {
1890 va.DeactivateServiceForPort(ctx, svc, devID, portName)
1891 }
1892 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301893 }
Akash Sonief452f12024-12-12 18:20:28 +05301894}
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301895
Akash Sonief452f12024-12-12 18:20:28 +05301896// DeactivateServiceForPort - deactivate service for given UNI and remove flows from DB, after max flow install threshold has reached
1897func (va *VoltApplication) DeactivateServiceForPort(cntx context.Context, vs *VoltService, devID string, portName string) {
1898 logger.Debugw(ctx, "Flow install threshold reached. Deactivating service", log.Fields{"Service": vs.Name, "Port": portName})
1899
1900 if devID == vs.Device && portName == vs.Port && vs.IsActivated {
1901 vs.SetSvcDeactivationFlags(SvcDeacRsn_Controller)
1902 va.ServiceByName.Store(vs.Name, vs)
1903 vs.WriteToDb(cntx)
1904 device, err := va.GetDeviceFromPort(portName)
1905 if err != nil {
1906 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
1907 // So no error is returned
1908 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portName})
1909 }
1910 p := device.GetPort(vs.Port)
1911 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
1912 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
1913 // Port down call internally deletes all the flows
1914 vpv.PortDownInd(cntx, device.Name, portName, true, true)
1915 if vpv.IgmpEnabled {
1916 va.ReceiverDownInd(cntx, device.Name, portName)
1917 }
1918 } else {
1919 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": device.Name, "port": portName, "SvcName": vs.Name})
1920 }
1921 logger.Infow(ctx, "Service deactivated after flow install threshold", log.Fields{"Device": device.Name, "Service": vs.Name, "Port": portName})
1922 }
1923 vs.DeactivateInProgress = false
1924 va.ServiceByName.Store(vs.Name, vs)
1925 vs.WriteToDb(cntx)
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301926 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301927}
1928
Naveen Sampath04696f72022-06-13 15:19:14 +05301929func pushFlowFailureNotif(flowStatus intf.FlowStatus) {
1930 subFlow := flowStatus.Flow
1931 cookie := subFlow.Cookie
1932 uniPort := cookie >> 16 & 0xFFFFFFFF
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301933 logger.Warnw(ctx, "Flow Failure Notification", log.Fields{"uniPort": uniPort, "Cookie": cookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301934}
1935
vinokuma926cb3e2023-03-29 11:41:06 +05301936// UpdateMvlanProfilesForDevice to update mvlan profile for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301937func (va *VoltApplication) UpdateMvlanProfilesForDevice(cntx context.Context, device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301938 logger.Debugw(ctx, "Received Update Mvlan Profiles For Device", log.Fields{"device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301939 checkAndAddMvlanUpdateTask := func(key, value interface{}) bool {
1940 mvp := value.(*MvlanProfile)
1941 if mvp.IsUpdateInProgressForDevice(device) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301942 mvp.UpdateProfile(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301943 }
1944 return true
1945 }
1946 va.MvlanProfilesByName.Range(checkAndAddMvlanUpdateTask)
1947}
1948
1949// TaskInfo structure that is used to store the task Info.
1950type TaskInfo struct {
1951 ID string
1952 Name string
1953 Timestamp string
1954}
1955
1956// GetTaskList to get task list information.
1957func (va *VoltApplication) GetTaskList(device string) map[int]*TaskInfo {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301958 logger.Debugw(ctx, "Received Get Task List", log.Fields{"device": device})
mgoudabb017dc2025-10-29 19:53:34 +05301959 taskList := controller.GetController().GetTaskList(device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301960 taskMap := make(map[int]*TaskInfo)
1961 for i, task := range taskList {
1962 taskID := strconv.Itoa(int(task.TaskID()))
1963 name := task.Name()
1964 timestamp := task.Timestamp()
1965 taskInfo := &TaskInfo{ID: taskID, Name: name, Timestamp: timestamp}
1966 taskMap[i] = taskInfo
1967 }
1968 return taskMap
1969}
1970
1971// UpdateDeviceSerialNumberList to update the device serial number list after device serial number is updated for vnet and mvlan
1972func (va *VoltApplication) UpdateDeviceSerialNumberList(oldOltSlNo string, newOltSlNo string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301973 logger.Debugw(ctx, "Update Device Serial Number List", log.Fields{"oldOltSlNo": oldOltSlNo, "newOltSlNo": newOltSlNo})
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301974 voltDevice, _ := va.GetDeviceBySerialNo(oldOltSlNo)
Naveen Sampath04696f72022-06-13 15:19:14 +05301975
1976 if voltDevice != nil {
1977 // Device is present with old serial number ID
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301978 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 +05301979 } else {
1980 logger.Infow(ctx, "No device present with old serial number", log.Fields{"Serial Number": oldOltSlNo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301981 // Add Serial Number to Blocked Devices List.
mgoudabb017dc2025-10-29 19:53:34 +05301982 controller.GetController().AddBlockedDevices(oldOltSlNo)
1983 controller.GetController().AddBlockedDevices(newOltSlNo)
Naveen Sampath04696f72022-06-13 15:19:14 +05301984
1985 updateSlNoForVnet := func(key, value interface{}) bool {
1986 vnet := value.(*VoltVnet)
1987 for i, deviceSlNo := range vnet.VnetConfig.DevicesList {
1988 if deviceSlNo == oldOltSlNo {
1989 vnet.VnetConfig.DevicesList[i] = newOltSlNo
1990 logger.Infow(ctx, "device serial number updated for vnet profile", log.Fields{"Updated Serial Number": deviceSlNo, "Previous Serial Number": oldOltSlNo})
1991 break
1992 }
1993 }
1994 return true
1995 }
1996
1997 updateSlNoforMvlan := func(key interface{}, value interface{}) bool {
1998 mvProfile := value.(*MvlanProfile)
1999 for deviceSlNo := range mvProfile.DevicesList {
2000 if deviceSlNo == oldOltSlNo {
2001 mvProfile.DevicesList[newOltSlNo] = mvProfile.DevicesList[oldOltSlNo]
2002 delete(mvProfile.DevicesList, oldOltSlNo)
2003 logger.Infow(ctx, "device serial number updated for mvlan profile", log.Fields{"Updated Serial Number": deviceSlNo, "Previous Serial Number": oldOltSlNo})
2004 break
2005 }
2006 }
2007 return true
2008 }
2009
2010 va.VnetsByName.Range(updateSlNoForVnet)
2011 va.MvlanProfilesByName.Range(updateSlNoforMvlan)
2012
2013 // Clear the serial number from Blocked Devices List
mgoudabb017dc2025-10-29 19:53:34 +05302014 controller.GetController().DelBlockedDevices(oldOltSlNo)
2015 controller.GetController().DelBlockedDevices(newOltSlNo)
Naveen Sampath04696f72022-06-13 15:19:14 +05302016 }
2017}
2018
2019// GetVpvsForDsPkt to get vpv for downstream packets
2020func (va *VoltApplication) GetVpvsForDsPkt(cvlan of.VlanType, svlan of.VlanType, clientMAC net.HardwareAddr,
2021 pbit uint8) ([]*VoltPortVnet, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302022 logger.Debugw(ctx, "Received Get Vpvs For Ds Pkt", log.Fields{"Cvlan": cvlan, "Svlan": svlan, "Mac": clientMAC})
Naveen Sampath04696f72022-06-13 15:19:14 +05302023 var matchVPVs []*VoltPortVnet
2024 findVpv := func(key, value interface{}) bool {
2025 vpvs := value.([]*VoltPortVnet)
2026 for _, vpv := range vpvs {
2027 if vpv.isVlanMatching(cvlan, svlan) && vpv.MatchesPriority(pbit) != nil {
2028 var subMac net.HardwareAddr
2029 if NonZeroMacAddress(vpv.MacAddr) {
2030 subMac = vpv.MacAddr
2031 } else if vpv.LearntMacAddr != nil && NonZeroMacAddress(vpv.LearntMacAddr) {
2032 subMac = vpv.LearntMacAddr
2033 } else {
2034 matchVPVs = append(matchVPVs, vpv)
2035 continue
2036 }
2037 if util.MacAddrsMatch(subMac, clientMAC) {
2038 matchVPVs = append([]*VoltPortVnet{}, vpv)
2039 logger.Infow(ctx, "Matching VPV found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "MAC": clientMAC})
2040 return false
2041 }
2042 }
2043 }
2044 return true
2045 }
2046 va.VnetsByPort.Range(findVpv)
2047
2048 if len(matchVPVs) != 1 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302049 logger.Errorw(ctx, "No matching VPV found or multiple vpvs found", log.Fields{"Match VPVs": matchVPVs, "MAC": clientMAC})
2050 return nil, errors.New("no matching VPV found or multiple vpvs found")
Naveen Sampath04696f72022-06-13 15:19:14 +05302051 }
2052 return matchVPVs, nil
2053}
2054
2055// GetMacInPortMap to get PORT value based on MAC key
2056func (va *VoltApplication) GetMacInPortMap(macAddr net.HardwareAddr) string {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302057 logger.Debugw(ctx, "Received Get PORT value based on MAC key", log.Fields{"MacAddr": macAddr.String()})
Naveen Sampath04696f72022-06-13 15:19:14 +05302058 if NonZeroMacAddress(macAddr) {
2059 va.macPortLock.Lock()
2060 defer va.macPortLock.Unlock()
2061 if port, ok := va.macPortMap[macAddr.String()]; ok {
2062 logger.Debugw(ctx, "found-entry-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
2063 return port
2064 }
2065 }
2066 logger.Infow(ctx, "entry-not-found-macportmap", log.Fields{"MacAddr": macAddr.String()})
2067 return ""
2068}
2069
2070// UpdateMacInPortMap to update MAC PORT (key value) information in MacPortMap
2071func (va *VoltApplication) UpdateMacInPortMap(macAddr net.HardwareAddr, port string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302072 logger.Debugw(ctx, "Update Macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05302073 if NonZeroMacAddress(macAddr) {
2074 va.macPortLock.Lock()
2075 va.macPortMap[macAddr.String()] = port
2076 va.macPortLock.Unlock()
2077 logger.Debugw(ctx, "updated-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
2078 }
2079}
2080
2081// DeleteMacInPortMap to remove MAC key from MacPortMap
2082func (va *VoltApplication) DeleteMacInPortMap(macAddr net.HardwareAddr) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302083 logger.Debugw(ctx, "Delete Mac from Macportmap", log.Fields{"MacAddr": macAddr.String()})
Naveen Sampath04696f72022-06-13 15:19:14 +05302084 if NonZeroMacAddress(macAddr) {
2085 port := va.GetMacInPortMap(macAddr)
2086 va.macPortLock.Lock()
2087 delete(va.macPortMap, macAddr.String())
2088 va.macPortLock.Unlock()
2089 logger.Debugw(ctx, "deleted-from-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
2090 }
2091}
2092
vinokuma926cb3e2023-03-29 11:41:06 +05302093// AddGroupToPendingPool - adds the IgmpGroup with active group table entry to global pending pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302094func (va *VoltApplication) AddGroupToPendingPool(ig *IgmpGroup) {
2095 var grpMap map[*IgmpGroup]bool
2096 var ok bool
2097
2098 va.PendingPoolLock.Lock()
2099 defer va.PendingPoolLock.Unlock()
2100
2101 logger.Infow(ctx, "Adding IgmpGroup to Global Pending Pool", log.Fields{"GroupID": ig.GroupID, "GroupName": ig.GroupName, "GroupAddr": ig.GroupAddr, "PendingDevices": len(ig.Devices)})
2102 // Do Not Reset any current profile info since group table entry tied to mvlan profile
2103 // The PonVlan is part of set field in group installed
2104 // Hence, Group created is always tied to the same mvlan profile until deleted
2105
2106 for device := range ig.Devices {
2107 key := getPendingPoolKey(ig.Mvlan, device)
2108
2109 if grpMap, ok = va.IgmpPendingPool[key]; !ok {
2110 grpMap = make(map[*IgmpGroup]bool)
2111 }
2112 grpMap[ig] = true
2113
2114 //Add grpObj reference to all associated devices
2115 va.IgmpPendingPool[key] = grpMap
2116 }
2117}
2118
vinokuma926cb3e2023-03-29 11:41:06 +05302119// RemoveGroupFromPendingPool - removes the group from global pending group pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302120func (va *VoltApplication) RemoveGroupFromPendingPool(device string, ig *IgmpGroup) bool {
2121 GetApplication().PendingPoolLock.Lock()
2122 defer GetApplication().PendingPoolLock.Unlock()
2123
2124 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)})
2125
2126 key := getPendingPoolKey(ig.Mvlan, device)
2127 if _, ok := va.IgmpPendingPool[key]; ok {
2128 delete(va.IgmpPendingPool[key], ig)
2129 return true
2130 }
2131 return false
2132}
2133
vinokuma926cb3e2023-03-29 11:41:06 +05302134// RemoveGroupsFromPendingPool - removes the group from global pending group pool
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302135func (va *VoltApplication) RemoveGroupsFromPendingPool(cntx context.Context, device string, mvlan of.VlanType) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302136 GetApplication().PendingPoolLock.Lock()
2137 defer GetApplication().PendingPoolLock.Unlock()
2138
2139 logger.Infow(ctx, "Removing IgmpGroups from Global Pending Pool for given Deivce & Mvlan", log.Fields{"Device": device, "Mvlan": mvlan.String()})
2140
2141 key := getPendingPoolKey(mvlan, device)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302142 va.RemoveGroupListFromPendingPool(cntx, key)
Naveen Sampath04696f72022-06-13 15:19:14 +05302143}
2144
vinokuma926cb3e2023-03-29 11:41:06 +05302145// RemoveGroupListFromPendingPool - removes the groups for provided key
Naveen Sampath04696f72022-06-13 15:19:14 +05302146// 1. Deletes the group from device
2147// 2. Delete the IgmpGroup obj and release the group ID to pool
2148// Note: Make sure to obtain PendingPoolLock lock before calling this func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302149func (va *VoltApplication) RemoveGroupListFromPendingPool(cntx context.Context, key string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302150 logger.Infow(ctx, "Remove GroupList from Pending Pool for ", log.Fields{"key": key})
Naveen Sampath04696f72022-06-13 15:19:14 +05302151 if grpMap, ok := va.IgmpPendingPool[key]; ok {
2152 delete(va.IgmpPendingPool, key)
2153 for ig := range grpMap {
2154 for device := range ig.Devices {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302155 ig.DeleteIgmpGroupDevice(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05302156 }
2157 }
2158 }
2159}
2160
vinokuma926cb3e2023-03-29 11:41:06 +05302161// RemoveGroupDevicesFromPendingPool - removes the group from global pending group pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302162func (va *VoltApplication) RemoveGroupDevicesFromPendingPool(ig *IgmpGroup) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302163 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)})
2164 for device := range ig.PendingGroupForDevice {
2165 va.RemoveGroupFromPendingPool(device, ig)
2166 }
2167}
2168
vinokuma926cb3e2023-03-29 11:41:06 +05302169// GetGroupFromPendingPool - Returns IgmpGroup obj from global pending pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302170func (va *VoltApplication) GetGroupFromPendingPool(mvlan of.VlanType, device string) *IgmpGroup {
Naveen Sampath04696f72022-06-13 15:19:14 +05302171 var ig *IgmpGroup
2172
2173 va.PendingPoolLock.Lock()
2174 defer va.PendingPoolLock.Unlock()
2175
2176 key := getPendingPoolKey(mvlan, device)
2177 logger.Infow(ctx, "Getting IgmpGroup from Global Pending Pool", log.Fields{"Device": device, "Mvlan": mvlan.String(), "Key": key})
2178
vinokuma926cb3e2023-03-29 11:41:06 +05302179 // Gets all IgmpGrp Obj for the device
Naveen Sampath04696f72022-06-13 15:19:14 +05302180 grpMap, ok := va.IgmpPendingPool[key]
2181 if !ok || len(grpMap) == 0 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302182 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 +05302183 return nil
2184 }
2185
vinokuma926cb3e2023-03-29 11:41:06 +05302186 // Gets a random obj from available grps
Naveen Sampath04696f72022-06-13 15:19:14 +05302187 for ig = range grpMap {
vinokuma926cb3e2023-03-29 11:41:06 +05302188 // Remove grp obj reference from all devices associated in pending pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302189 for dev := range ig.Devices {
2190 key := getPendingPoolKey(mvlan, dev)
2191 delete(va.IgmpPendingPool[key], ig)
2192 }
2193
vinokuma926cb3e2023-03-29 11:41:06 +05302194 // Safety check to avoid re-allocating group already in use
Naveen Sampath04696f72022-06-13 15:19:14 +05302195 if ig.NumDevicesActive() == 0 {
2196 return ig
2197 }
2198
vinokuma926cb3e2023-03-29 11:41:06 +05302199 // Iteration will continue only if IG is not allocated
Naveen Sampath04696f72022-06-13 15:19:14 +05302200 }
2201 return nil
2202}
2203
vinokuma926cb3e2023-03-29 11:41:06 +05302204// RemovePendingGroups - removes all pending groups for provided reference from global pending pool
Naveen Sampath04696f72022-06-13 15:19:14 +05302205// reference - mvlan/device ID
2206// isRefDevice - true - Device as reference
vinokuma926cb3e2023-03-29 11:41:06 +05302207// false - Mvlan as reference
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302208func (va *VoltApplication) RemovePendingGroups(cntx context.Context, reference string, isRefDevice bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302209 va.PendingPoolLock.Lock()
2210 defer va.PendingPoolLock.Unlock()
2211
2212 logger.Infow(ctx, "Removing IgmpGroups from Global Pending Pool", log.Fields{"Reference": reference, "isRefDevice": isRefDevice})
2213
vinokuma926cb3e2023-03-29 11:41:06 +05302214 // Pending Pool key: "<mvlan>_<DeviceID>""
Naveen Sampath04696f72022-06-13 15:19:14 +05302215 paramPosition := 0
2216 if isRefDevice {
2217 paramPosition = 1
2218 }
2219
2220 // 1.Remove the Entry from pending pool
2221 // 2.Deletes the group from device
2222 // 3.Delete the IgmpGroup obj and release the group ID to pool
2223 for key := range va.IgmpPendingPool {
2224 keyParams := strings.Split(key, "_")
2225 if keyParams[paramPosition] == reference {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302226 va.RemoveGroupListFromPendingPool(cntx, key)
Naveen Sampath04696f72022-06-13 15:19:14 +05302227 }
2228 }
2229}
2230
2231func getPendingPoolKey(mvlan of.VlanType, device string) string {
2232 return mvlan.String() + "_" + device
2233}
2234
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302235func (va *VoltApplication) removeExpiredGroups(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302236 logger.Info(ctx, "Remove expired Igmp Groups")
Naveen Sampath04696f72022-06-13 15:19:14 +05302237 removeExpiredGroups := func(key interface{}, value interface{}) bool {
2238 ig := value.(*IgmpGroup)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302239 ig.removeExpiredGroupFromDevice(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302240 return true
2241 }
2242 va.IgmpGroups.Range(removeExpiredGroups)
2243}
2244
vinokuma926cb3e2023-03-29 11:41:06 +05302245// TriggerPendingProfileDeleteReq - trigger pending profile delete request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302246func (va *VoltApplication) TriggerPendingProfileDeleteReq(cntx context.Context, device string) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302247 logger.Debugw(ctx, "Trigger Pending Profile Delete for device", log.Fields{"Device": device})
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302248 va.TriggerPendingServiceDeactivateReq(cntx, device)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302249 va.TriggerPendingServiceDeleteReq(cntx, device)
2250 va.TriggerPendingVpvDeleteReq(cntx, device)
2251 va.TriggerPendingVnetDeleteReq(cntx, device)
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302252 logger.Debugw(ctx, "All Pending Profile Delete triggered for device", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302253}
2254
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302255// TriggerPendingServiceDeactivateReq - trigger pending service deactivate request
2256func (va *VoltApplication) TriggerPendingServiceDeactivateReq(cntx context.Context, device string) {
Akash Sonief452f12024-12-12 18:20:28 +05302257 va.ServicesToDeactivate.Range(func(key, value interface{}) bool {
2258 serviceName := key.(string)
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302259 if vs := va.GetService(serviceName); vs != nil {
2260 if vs.Device == device {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302261 logger.Infow(ctx, "Triggering Pending Service Deactivate", log.Fields{"Service": vs.Name})
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302262 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
2263 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302264 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 +05302265 return true
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302266 }
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302267 vpv.DelTrapFlows(cntx)
2268 vs.DelHsiaFlows(cntx)
Akash Sonief452f12024-12-12 18:20:28 +05302269 // Set the flag to false and clear the SevicesToDeactivate map entry so that when core restarts, VGC will not
2270 // try to deactivate the service again
2271 vs.DeactivateInProgress = false
2272 va.ServicesToDeactivate.Delete(serviceName)
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302273 vs.WriteToDb(cntx)
2274 vpv.ClearServiceCounters(cntx)
2275 }
2276 } else {
Akash Sonief452f12024-12-12 18:20:28 +05302277 logger.Warnw(ctx, "Pending Service Not found during Deactivate", log.Fields{"Service": serviceName})
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302278 }
Akash Sonief452f12024-12-12 18:20:28 +05302279 return true
2280 })
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302281}
2282
vinokuma926cb3e2023-03-29 11:41:06 +05302283// TriggerPendingServiceDeleteReq - trigger pending service delete request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302284func (va *VoltApplication) TriggerPendingServiceDeleteReq(cntx context.Context, device string) {
Akash Sonief452f12024-12-12 18:20:28 +05302285 va.ServicesToDelete.Range(func(key, value interface{}) bool {
2286 serviceName := key.(string)
Naveen Sampath04696f72022-06-13 15:19:14 +05302287 if vs := va.GetService(serviceName); vs != nil {
2288 if vs.Device == device {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302289 logger.Infow(ctx, "Triggering Pending Service delete", log.Fields{"Service": vs.Name})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302290 vs.DelHsiaFlows(cntx)
Akash Sonief452f12024-12-12 18:20:28 +05302291 // Clear the SevicesToDelete map so that when core restarts, VGC will not try to deactivate the service again
2292 va.ServicesToDelete.Delete(serviceName)
Naveen Sampath04696f72022-06-13 15:19:14 +05302293 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302294 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302295 }
2296 }
2297 } else {
Akash Sonief452f12024-12-12 18:20:28 +05302298 logger.Warnw(ctx, "Pending Service Not found during Delete", log.Fields{"Service": serviceName})
Naveen Sampath04696f72022-06-13 15:19:14 +05302299 }
Akash Sonief452f12024-12-12 18:20:28 +05302300 return true
2301 })
Naveen Sampath04696f72022-06-13 15:19:14 +05302302}
2303
vinokuma926cb3e2023-03-29 11:41:06 +05302304// TriggerPendingVpvDeleteReq - trigger pending VPV delete request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302305func (va *VoltApplication) TriggerPendingVpvDeleteReq(cntx context.Context, device string) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302306 logger.Debugw(ctx, "Pending VPVs to be deleted", log.Fields{"Count": len(va.VoltPortVnetsToDelete)})
Naveen Sampath04696f72022-06-13 15:19:14 +05302307 for vpv := range va.VoltPortVnetsToDelete {
2308 if vpv.Device == device {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302309 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 +05302310 va.DelVnetFromPort(cntx, vpv.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05302311 }
2312 }
2313}
2314
vinokuma926cb3e2023-03-29 11:41:06 +05302315// TriggerPendingVnetDeleteReq - trigger pending vnet delete request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302316func (va *VoltApplication) TriggerPendingVnetDeleteReq(cntx context.Context, device string) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302317 logger.Debugw(ctx, "Pending Vnets to be deleted", log.Fields{"Count": len(va.VnetsToDelete)})
Naveen Sampath04696f72022-06-13 15:19:14 +05302318 for vnetName := range va.VnetsToDelete {
2319 if vnetIntf, _ := va.VnetsByName.Load(vnetName); vnetIntf != nil {
2320 vnet := vnetIntf.(*VoltVnet)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302321 if d, _ := va.GetDeviceBySerialNo(vnet.PendingDeviceToDelete); d != nil && d.SerialNum == vnet.PendingDeviceToDelete {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302322 logger.Infow(ctx, "Triggering Pending Vnet flows delete", log.Fields{"Vnet": vnet.Name, "Device": vnet.PendingDeviceToDelete})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302323 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, vnet.PendingDeviceToDelete)
Naveen Sampath04696f72022-06-13 15:19:14 +05302324 va.deleteVnetConfig(vnet)
2325 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302326 logger.Warnw(ctx, "Vnet Delete Failed : Device Not Found", log.Fields{"Vnet": vnet.Name, "Device": vnet.PendingDeviceToDelete})
Naveen Sampath04696f72022-06-13 15:19:14 +05302327 }
2328 }
2329 }
2330}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302331
2332type OltFlowService struct {
vinokuma926cb3e2023-03-29 11:41:06 +05302333 DefaultTechProfileID int `json:"defaultTechProfileId"`
Akash Sonia8246972023-01-03 10:37:08 +05302334 EnableDhcpOnNni bool `json:"enableDhcpOnNni"`
Akash Sonia8246972023-01-03 10:37:08 +05302335 EnableIgmpOnNni bool `json:"enableIgmpOnNni"`
2336 EnableEapol bool `json:"enableEapol"`
2337 EnableDhcpV6 bool `json:"enableDhcpV6"`
2338 EnableDhcpV4 bool `json:"enableDhcpV4"`
2339 RemoveFlowsOnDisable bool `json:"removeFlowsOnDisable"`
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302340}
2341
2342func (va *VoltApplication) UpdateOltFlowService(cntx context.Context, oltFlowService OltFlowService) {
2343 logger.Infow(ctx, "UpdateOltFlowService", log.Fields{"oldValue": va.OltFlowServiceConfig, "newValue": oltFlowService})
2344 va.OltFlowServiceConfig = oltFlowService
2345 b, err := json.Marshal(va.OltFlowServiceConfig)
2346 if err != nil {
2347 logger.Warnw(ctx, "Failed to Marshal OltFlowServiceConfig", log.Fields{"OltFlowServiceConfig": va.OltFlowServiceConfig})
2348 return
2349 }
2350 _ = db.PutOltFlowService(cntx, string(b))
2351}
Akash Sonia8246972023-01-03 10:37:08 +05302352
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302353// RestoreOltFlowService to read from the DB and restore olt flow service config
2354func (va *VoltApplication) RestoreOltFlowService(cntx context.Context) {
2355 oltflowService, err := db.GetOltFlowService(cntx)
2356 if err != nil {
2357 logger.Warnw(ctx, "Failed to Get OltFlowServiceConfig from DB", log.Fields{"Error": err})
2358 return
2359 }
2360 err = json.Unmarshal([]byte(oltflowService), &va.OltFlowServiceConfig)
2361 if err != nil {
2362 logger.Warn(ctx, "Unmarshal of oltflowService failed")
2363 return
2364 }
2365 logger.Infow(ctx, "updated OltFlowServiceConfig from DB", log.Fields{"OltFlowServiceConfig": va.OltFlowServiceConfig})
2366}
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302367
Akash Soni87a19072023-02-28 00:46:59 +05302368func (va *VoltApplication) UpdateDeviceConfig(cntx context.Context, deviceConfig *DeviceConfig) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302369 logger.Infow(ctx, "Received UpdateDeviceConfig", log.Fields{"DeviceInfo": deviceConfig})
Akash Soni87a19072023-02-28 00:46:59 +05302370 var dc *DeviceConfig
2371 va.DevicesConfig.Store(deviceConfig.SerialNumber, deviceConfig)
2372 err := dc.WriteDeviceConfigToDb(cntx, deviceConfig.SerialNumber, deviceConfig)
2373 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302374 logger.Warnw(ctx, "DB update for device config failed", log.Fields{"err": err})
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302375 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302376 logger.Debugw(ctx, "Added OLT configurations", log.Fields{"DeviceInfo": deviceConfig})
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302377 // If device is already discovered update the VoltDevice structure
Akash Soni87a19072023-02-28 00:46:59 +05302378 device, id := va.GetDeviceBySerialNo(deviceConfig.SerialNumber)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302379 if device != nil {
Akash Soni87a19072023-02-28 00:46:59 +05302380 device.NniDhcpTrapVid = of.VlanType(deviceConfig.NniDhcpTrapVid)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302381 va.DevicesDisc.Store(id, device)
2382 }
2383}
akashreddykeb418f12025-10-30 10:58:42 +05302384
2385func (va *VoltApplication) GetDevicePortID(device, port string) (uint32, error) {
2386 logger.Debugw(ctx, "Received Get Device Port ID", log.Fields{"Port": port})
2387 d := va.GetDevice(device)
2388 if d == nil {
2389 return 0, fmt.Errorf("device not found: %s", device)
2390 }
2391 value, ok := d.Ports.Load(port)
2392 if !ok {
2393 return 0, fmt.Errorf("port not found: %s", port)
2394 }
2395 return value.(*VoltPort).ID, nil
2396}