blob: 9476e55c9ee6d13dd0ca3591bcc6b31578b57d97 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14 */
15
16package application
17
18import (
19 "context"
20 "encoding/hex"
21 "encoding/json"
22 "errors"
23 "fmt"
24 "net"
25 "strconv"
26 "strings"
27 "sync"
28 "time"
29
30 "github.com/google/gopacket"
31 "github.com/google/gopacket/layers"
32
33 "voltha-go-controller/internal/pkg/controller"
34 cntlr "voltha-go-controller/internal/pkg/controller"
35 "voltha-go-controller/database"
36 "voltha-go-controller/internal/pkg/intf"
37 "voltha-go-controller/internal/pkg/of"
38 "voltha-go-controller/internal/pkg/tasks"
39 "voltha-go-controller/internal/pkg/util"
40 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Tinoj Joseph1d108322022-07-13 10:07:39 +053041 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053042)
43
44var logger log.CLogger
45var ctx = context.TODO()
46
47func init() {
48 // Setup this package so that it's log level can be modified at run time
49 var err error
Tinoj Joseph1d108322022-07-13 10:07:39 +053050 logger, err = log.AddPackageWithDefaultParam()
Naveen Sampath04696f72022-06-13 15:19:14 +053051 if err != nil {
52 panic(err)
53 }
54}
55
56const (
57 // TODO - Need to identify a right place for this
58
59 // PriorityNone constant.
60 PriorityNone uint8 = 8
61 // AnyVlan constant.
62 AnyVlan uint16 = 0xFFFF
63)
64
65// List of Mac Learning Type
66const (
Tinoj Joseph1d108322022-07-13 10:07:39 +053067 MacLearningNone MacLearningType = iota
68 Learn
69 ReLearn
Naveen Sampath04696f72022-06-13 15:19:14 +053070)
71
72// MacLearningType represents Mac Learning Type
73type MacLearningType int
74
75var (
76 tickCount uint16
77 vgcRebooted bool
78 isUpgradeComplete bool
79)
80
81var db database.DBIntf
82
83// PacketHandlers : packet handler for different protocols
84var PacketHandlers map[string]CallBack
85
86// CallBack : registered call back function for different protocol packets
87type CallBack func(device string, port string, pkt gopacket.Packet)
88
89const (
90 // ARP packet
91 ARP string = "ARP"
92 // DHCPv4 packet
93 DHCPv4 string = "DHCPv4"
94 // DHCPv6 packet
95 DHCPv6 string = "DHCPv6"
96 // IGMP packet
97 IGMP string = "IGMP"
98 // PPPOE packet
99 PPPOE string = "PPPOE"
100 // US packet side
101 US string = "US"
102 // DS packet side
103 DS string = "DS"
104 // NNI port name
105 NNI string = "nni"
106)
107
108// RegisterPacketHandler : API to register callback function for every protocol
109func RegisterPacketHandler(protocol string, callback CallBack) {
110 if PacketHandlers == nil {
111 PacketHandlers = make(map[string]CallBack)
112 }
113 PacketHandlers[protocol] = callback
114}
115
116// ---------------------------------------------------------------------
117// VOLT Ports
118// ---------------------------------------------------------------------
119// VOLT Ports are ports associated with VOLT devices. Each port is classified into
120// Access/NNI. Each port is identified by Name (Identity known to the NB) and
121// Id (Identity used on the SB). Both identities are presented when a port is
122// discovered in the SB.
123
124// VoltPortType type for Port Type
125type VoltPortType uint8
126
127const (
128 // VoltPortTypeAccess constant.
129 VoltPortTypeAccess VoltPortType = 0
130 // VoltPortTypeNni constant.
131 VoltPortTypeNni VoltPortType = 1
132)
133
134// PortState type for Port State.
135type PortState uint8
136
137const (
138 // PortStateDown constant.
139 PortStateDown PortState = 0
140 // PortStateUp constant.
141 PortStateUp PortState = 1
142)
143
144// VoltPort structure that is used to store the ports. The name is the
145// the main identity used by the application. The SB and NB both present name
146// as the identity. The SB is abstracted by VPAgent and the VPAgent transacts
147// using name as identity
148type VoltPort struct {
149 ID uint32
150 Name string
151 Device string
152 PonPort uint32
153 Type VoltPortType
154 State PortState
155 ActiveChannels uint32
156 ChannelPerSubAlarmRaised bool
157}
158
159// NewVoltPort : Constructor for the port.
160func NewVoltPort(device string, name string, id uint32) *VoltPort {
161 var vp VoltPort
162 vp.Device = device
163 vp.Name = name
164 vp.ID = id
165 if util.IsNniPort(id) {
166 vp.Type = VoltPortTypeNni
167 } else {
168 vp.PonPort = GetPonPortIDFromUNIPort(id)
169 }
170 vp.State = PortStateDown
171 vp.ChannelPerSubAlarmRaised = false
172 return &vp
173}
174
175// SetPortID : The ID is used when constructing flows as the flows require ID.
176func (vp *VoltPort) SetPortID(id uint32) {
177 vp.ID = id
178 if util.IsNniPort(id) {
179 vp.Type = VoltPortTypeNni
180 }
181}
182
183// ---------------------------------------------------------------------
184// VOLT Device
185// ---------------------------------------------------------------------
186//
187// VoltDevice is an OLT which contains ports of type access and NNI. Each OLT
188// can only have one NNI port in the current release. The NNI port always uses
189// identity 65536 and all the access ports use identities less than 65535. The
190// identification of NNI is done by comparing the port identity with 65535
191
192// VoltDevice fields :
193// Name: This is the name presented by the device/VOLTHA. This doesn't
194// have any relation to the physical device
195// SerialNum: This is the serial number of the device and can be used to
196// correlate the devices
197// NniPort: The identity of the NNI port
198// Ports: List of all ports added to the device
199type VoltDevice struct {
200 Name string
201 SerialNum string
202 State controller.DeviceState
203 SouthBoundID string
204 NniPort string
205 Ports sync.Map
206 VlanPortStatus sync.Map
207 VpvsBySvlan *util.ConcurrentMap // map[svlan]map[vnet_port]*VoltPortVnet
208 IgmpDsFlowAppliedForMvlan map[uint16]bool
209 ConfiguredVlanForDeviceFlows *util.ConcurrentMap //map[string]map[string]bool
210 icmpv6GroupAdded bool
211 ActiveChannelsPerPon sync.Map // [PonPortID]*PonPortCfg
212 ActiveChannelCountLock sync.Mutex // This lock is used to update ActiveIGMPChannels
213 PonPortList sync.Map // [PonPortID]map[string]string
214 FlowAddEventMap *util.ConcurrentMap //map[string]*FlowEvent
215 FlowDelEventMap *util.ConcurrentMap //map[string]*FlowEvent
216 MigratingServices *util.ConcurrentMap //<vnetID,<RequestID, MigrateServicesRequest>>
217 GlobalDhcpFlowAdded bool
218}
219
220// NewVoltDevice : Constructor for the device
221func NewVoltDevice(name string, slno, southBoundID string) *VoltDevice {
222 var d VoltDevice
223 d.Name = name
224 d.SouthBoundID = southBoundID
225 d.State = controller.DeviceStateDOWN
226 d.NniPort = ""
227 d.SouthBoundID = southBoundID
228 d.SerialNum = slno
229 d.icmpv6GroupAdded = false
230 d.IgmpDsFlowAppliedForMvlan = make(map[uint16]bool)
231 d.ConfiguredVlanForDeviceFlows = util.NewConcurrentMap()
232 d.MigratingServices = util.NewConcurrentMap()
233 d.VpvsBySvlan = util.NewConcurrentMap()
234 d.FlowAddEventMap = util.NewConcurrentMap()
235 d.FlowDelEventMap = util.NewConcurrentMap()
236 d.GlobalDhcpFlowAdded = false
237 return &d
238}
239
240//GetAssociatedVpvsForDevice - return the associated VPVs for given device & svlan
241func (va *VoltApplication) GetAssociatedVpvsForDevice(device string, svlan of.VlanType) *util.ConcurrentMap {
242 if d := va.GetDevice(device); d != nil {
243 return d.GetAssociatedVpvs(svlan)
244 }
245 return nil
246}
247
248//AssociateVpvsToDevice - updates the associated VPVs for given device & svlan
249func (va *VoltApplication) AssociateVpvsToDevice(device string, vpv *VoltPortVnet) {
250 if d := va.GetDevice(device); d != nil {
251
252 vpvMap := d.GetAssociatedVpvs(vpv.SVlan)
253 vpvMap.Set(vpv, true)
254 d.VpvsBySvlan.Set(vpv.SVlan, vpvMap)
255 logger.Infow(ctx, "VPVMap: SET", log.Fields{"Map": vpvMap.Length()})
256 return
257 }
258 logger.Errorw(ctx, "Set VPVMap failed: Device Not Found", log.Fields{"Svlan": vpv.SVlan, "Device": device})
259}
260
261//DisassociateVpvsFromDevice - disassociated VPVs from given device & svlan
262func (va *VoltApplication) DisassociateVpvsFromDevice(device string, vpv *VoltPortVnet) {
263 if d := va.GetDevice(device); d != nil {
264 vpvMap := d.GetAssociatedVpvs(vpv.SVlan)
265 vpvMap.Remove(vpv)
266 d.VpvsBySvlan.Set(vpv.SVlan, vpvMap)
267 logger.Infow(ctx, "VPVMap: Remove", log.Fields{"Map": vpvMap.Length()})
268 return
269 }
270 logger.Errorw(ctx, "Remove VPVMap failed: Device Not Found", log.Fields{"Svlan": vpv.SVlan, "Device": device})
271}
272
273//GetAssociatedVpvs - returns the associated VPVs for the given Svlan
274func (d *VoltDevice) GetAssociatedVpvs(svlan of.VlanType) *util.ConcurrentMap {
275
276 var vpvMap *util.ConcurrentMap
277 var mapIntf interface{}
278 var ok bool
279
280 if mapIntf, ok = d.VpvsBySvlan.Get(svlan); ok {
281 vpvMap = mapIntf.(*util.ConcurrentMap)
282 } else {
283 vpvMap = util.NewConcurrentMap()
284 }
285 logger.Infow(ctx, "VPVMap: GET", log.Fields{"Map": vpvMap.Length()})
286 return vpvMap
287}
288
289// AddPort add port to the device.
290func (d *VoltDevice) AddPort(port string, id uint32) *VoltPort {
291 addPonPortFromUniPort := func(vPort *VoltPort) {
292 if vPort.Type == VoltPortTypeAccess {
293 ponPortID := GetPonPortIDFromUNIPort(vPort.ID)
294
295 if ponPortUniList, ok := d.PonPortList.Load(ponPortID); !ok {
296 uniList := make(map[string]uint32)
297 uniList[port] = vPort.ID
298 d.PonPortList.Store(ponPortID, uniList)
299 } else {
300 ponPortUniList.(map[string]uint32)[port] = vPort.ID
301 d.PonPortList.Store(ponPortID, ponPortUniList)
302 }
303 }
304 }
305 va := GetApplication()
306 if pIntf, ok := d.Ports.Load(port); ok {
307 voltPort := pIntf.(*VoltPort)
308 addPonPortFromUniPort(voltPort)
309 va.AggActiveChannelsCountPerSub(d.Name, port, voltPort)
310 d.Ports.Store(port, voltPort)
311 return voltPort
312 }
313 p := NewVoltPort(d.Name, port, id)
314 va.AggActiveChannelsCountPerSub(d.Name, port, p)
315 d.Ports.Store(port, p)
316 if util.IsNniPort(id) {
317 d.NniPort = port
318 }
319 addPonPortFromUniPort(p)
320 return p
321}
322
323// GetPort to get port information from the device.
324func (d *VoltDevice) GetPort(port string) *VoltPort {
325 if pIntf, ok := d.Ports.Load(port); ok {
326 return pIntf.(*VoltPort)
327 }
328 return nil
329}
330
331// DelPort to delete port from the device
332func (d *VoltDevice) DelPort(port string) {
333 if _, ok := d.Ports.Load(port); ok {
334 d.Ports.Delete(port)
335 } else {
336 logger.Warnw(ctx, "Port doesn't exist", log.Fields{"Device": d.Name, "Port": port})
337 }
338}
339
340// pushFlowsForUnis to send port-up-indication for uni ports.
341func (d *VoltDevice) pushFlowsForUnis() {
342
343 logger.Info(ctx, "NNI Discovered, Sending Port UP Ind for UNIs")
344 d.Ports.Range(func(key, value interface{}) bool {
345 port := key.(string)
346 vp := value.(*VoltPort)
347
348 logger.Infow(ctx, "NNI Discovered. Sending Port UP Ind for UNI", log.Fields{"Port" : port})
349 //Ignore if UNI port is not UP
350 if vp.State != PortStateUp {
351 return true
352 }
353
354 //Obtain all VPVs associated with the port
355 vnets, ok := GetApplication().VnetsByPort.Load(port)
356 if !ok {
357 return true
358 }
359
360 for _, vpv := range vnets.([]*VoltPortVnet) {
361 vpv.VpvLock.Lock()
362 vpv.PortUpInd(d, port)
363 vpv.VpvLock.Unlock()
364
365 }
366 return true
367 })
368}
369
370// ----------------------------------------------------------
371// VOLT Application - hosts all other objects
372// ----------------------------------------------------------
373//
374// The VOLT application is a singleton implementation where
375// there is just one instance in the system and is the gateway
376// to all other components within the controller
377// The declaration of the singleton object
378var vapplication *VoltApplication
379
380// VoltApplication fields :
381// ServiceByName - Stores the services by the name as key
382// A record of NB configuration.
383// VnetsByPort - Stores the VNETs by the ports configured
384// from NB. A record of NB configuration.
385// VnetsByTag - Stores the VNETs by the VLANS configured
386// from NB. A record of NB configuration.
387// VnetsByName - Stores the VNETs by the name configured
388// from NB. A record of NB configuration.
389// DevicesDisc - Stores the devices discovered from SB.
390// Should be updated only by events from SB
391// PortsDisc - Stores the ports discovered from SB.
392// Should be updated only by events from SB
393type VoltApplication struct {
394 ServiceByName sync.Map // [serName]*VoltService
395 VnetsByPort sync.Map // [portName][]*VoltPortVnet
396 VnetsByTag sync.Map // [svlan-cvlan-uvlan]*VoltVnet
397 VnetsByName sync.Map // [vnetName]*VoltVnet
398 VnetsBySvlan *util.ConcurrentMap
399 DevicesDisc sync.Map
400 PortsDisc sync.Map
401 IgmpGroups sync.Map // [grpKey]*IgmpGroup
402 IgmpGroupIds []*IgmpGroup
403 MvlanProfilesByTag sync.Map
404 MvlanProfilesByName sync.Map
405 Icmpv6Receivers sync.Map
406 MeterMgr
407 IgmpTasks tasks.Tasks
408 IndicationsTasks tasks.Tasks
409 MulticastAlarmTasks tasks.Tasks
410 portLock sync.Mutex
411 DataMigrationInfo DataMigration
412 DeviceCounters sync.Map //[logicalDeviceId]*DeviceCounters
413 ServiceCounters sync.Map //[serviceName]*ServiceCounters
414 NbDevice sync.Map // [OLTSouthBoundID]*NbDevice
415 IgmpKPIsTasks tasks.Tasks
416 pppoeTasks tasks.Tasks
417 IgmpProfilesByName sync.Map
418 OltIgmpInfoBySerial sync.Map
419 McastConfigMap sync.Map //[OltSerialNo_MvlanProfileID]*McastConfig
420 // MacAddress-Port MAP to avoid swap of mac accross ports.
421 macPortLock sync.RWMutex
422 macPortMap map[string]string
423
424 IgmpPendingPool map[string]map[*IgmpGroup]bool //[grpkey, map[groupObj]bool] //mvlan_grpName/IP
425 PendingPoolLock sync.RWMutex
426
427 VnetsToDelete map[string]bool
428 ServicesToDelete map[string]bool
429 VoltPortVnetsToDelete map[*VoltPortVnet]bool
430 PortAlarmProfileCache map[string]map[string]int // [portAlarmID][ThresholdLevelString]ThresholdLevel
431 vendorID string
432}
433
434// PonPortCfg contains NB port config and activeIGMPChannels count
435type PonPortCfg struct {
436 PortID uint32
437 MaxActiveChannels uint32
438 ActiveIGMPChannels uint32
439 EnableMulticastKPI bool
440 PortAlarmProfileID string
441}
442
443// NbDevice OLT Device info
444type NbDevice struct {
445 SouthBoundID string
446 PonPorts sync.Map // [PortID]*PonPortCfg
447}
448
449// RestoreNbDeviceFromDb restores the NB Device in case of VGC pod restart.
450func (va *VoltApplication) RestoreNbDeviceFromDb(deviceID string) *NbDevice {
451
452 nbDevice := NewNbDevice()
453 nbDevice.SouthBoundID = deviceID
454
455 nbPorts, _ := db.GetAllNbPorts(deviceID)
456
457 for key, p := range nbPorts {
458 b, ok := p.Value.([]byte)
459 if !ok {
460 logger.Warn(ctx, "The value type is not []byte")
461 continue
462 }
463 var port PonPortCfg
464 err := json.Unmarshal(b, &port)
465 if err != nil {
466 logger.Warn(ctx, "Unmarshal of PonPortCfg failed")
467 continue
468 }
469 logger.Debugw(ctx, "Port recovered", log.Fields{"port": port})
470 ponPortID, _ := strconv.Atoi(key)
471 nbDevice.PonPorts.Store(uint32(ponPortID), &port)
472 }
473 va.NbDevice.Store(deviceID, nbDevice)
474 return nbDevice
475}
476
477// NewNbDevice Constructor for NbDevice
478func NewNbDevice() *NbDevice {
479 var nbDevice NbDevice
480 return &nbDevice
481}
482
483// WriteToDb writes nb device port config to kv store
484func (nbd *NbDevice) WriteToDb(portID uint32, ponPort *PonPortCfg) {
485 b, err := json.Marshal(ponPort)
486 if err != nil {
487 logger.Errorw(ctx, "PonPortConfig-marshal-failed", log.Fields{"err": err})
488 return
489 }
490 db.PutNbDevicePort(nbd.SouthBoundID, portID, string(b))
491}
492
493// AddPortToNbDevice Adds pon port to NB Device and DB
494func (nbd *NbDevice) AddPortToNbDevice(portID, allowedChannels uint32,
495 enableMulticastKPI bool, portAlarmProfileID string) *PonPortCfg {
496
497 ponPort := &PonPortCfg{
498 PortID: portID,
499 MaxActiveChannels: allowedChannels,
500 EnableMulticastKPI: enableMulticastKPI,
501 PortAlarmProfileID: portAlarmProfileID,
502 }
503 nbd.PonPorts.Store(portID, ponPort)
504 nbd.WriteToDb(portID, ponPort)
505 return ponPort
506}
507
508// UpdatePortToNbDevice Adds pon port to NB Device and DB
509func (nbd *NbDevice) UpdatePortToNbDevice(portID, allowedChannels uint32, enableMulticastKPI bool, portAlarmProfileID string) *PonPortCfg {
510
511 p, exists := nbd.PonPorts.Load(portID)
512 if !exists {
513 logger.Errorw(ctx, "PON port not exists in nb-device", log.Fields{"portID": portID})
514 return nil
515 }
516 port := p.(*PonPortCfg)
517 if allowedChannels != 0 {
518 port.MaxActiveChannels = allowedChannels
519 port.EnableMulticastKPI = enableMulticastKPI
520 port.PortAlarmProfileID = portAlarmProfileID
521 }
522
523 nbd.PonPorts.Store(portID, port)
524 nbd.WriteToDb(portID, port)
525 return port
526}
527
528// DeletePortFromNbDevice Deletes pon port from NB Device and DB
529func (nbd *NbDevice) DeletePortFromNbDevice(portID uint32) {
530
531 if _, ok := nbd.PonPorts.Load(portID); ok {
532 nbd.PonPorts.Delete(portID)
533 }
534 db.DelNbDevicePort(nbd.SouthBoundID, portID)
535}
536
537// GetApplication : Interface to access the singleton object
538func GetApplication() *VoltApplication {
539 if vapplication == nil {
540 vapplication = newVoltApplication()
541 }
542 return vapplication
543}
544
545// newVoltApplication : Constructor for the singleton object. Hence this is not
546// an exported function
547func newVoltApplication() *VoltApplication {
548 var va VoltApplication
549 va.IgmpTasks.Initialize(context.TODO())
550 va.MulticastAlarmTasks.Initialize(context.TODO())
551 va.IgmpKPIsTasks.Initialize(context.TODO())
552 va.pppoeTasks.Initialize(context.TODO())
553 va.storeIgmpProfileMap(DefaultIgmpProfID, newDefaultIgmpProfile())
554 va.MeterMgr.Init()
555 va.AddIgmpGroups(5000)
556 va.macPortMap = make(map[string]string)
557 va.IgmpPendingPool = make(map[string]map[*IgmpGroup]bool)
558 va.VnetsBySvlan = util.NewConcurrentMap()
559 va.VnetsToDelete = make(map[string]bool)
560 va.ServicesToDelete = make(map[string]bool)
561 va.VoltPortVnetsToDelete = make(map[*VoltPortVnet]bool)
562 go va.Start(TimerCfg{tick: 100 * time.Millisecond}, tickTimer)
563 go va.Start(TimerCfg{tick: time.Duration(GroupExpiryTime) * time.Minute}, pendingPoolTimer)
564 InitEventFuncMapper()
565 db = database.GetDatabase()
566 return &va
567}
568
569//GetFlowEventRegister - returs the register based on flow mod type
570func (d *VoltDevice) GetFlowEventRegister(flowModType of.Command) (*util.ConcurrentMap, error) {
571
572 switch flowModType {
573 case of.CommandDel:
574 return d.FlowDelEventMap, nil
575 case of.CommandAdd:
576 return d.FlowAddEventMap, nil
577 default:
578 logger.Error(ctx, "Unknown Flow Mod received")
579 }
580 return util.NewConcurrentMap(), errors.New("Unknown Flow Mod")
581}
582
583// RegisterFlowAddEvent to register a flow event.
584func (d *VoltDevice) RegisterFlowAddEvent(cookie string, event *FlowEvent) {
585 logger.Debugw(ctx, "Registered Flow Add Event", log.Fields{"Cookie": cookie, "Event": event})
586 d.FlowAddEventMap.MapLock.Lock()
587 defer d.FlowAddEventMap.MapLock.Unlock()
588 d.FlowAddEventMap.Set(cookie, event)
589}
590
591// RegisterFlowDelEvent to register a flow event.
592func (d *VoltDevice) RegisterFlowDelEvent(cookie string, event *FlowEvent) {
593 logger.Debugw(ctx, "Registered Flow Del Event", log.Fields{"Cookie": cookie, "Event": event})
594 d.FlowDelEventMap.MapLock.Lock()
595 defer d.FlowDelEventMap.MapLock.Unlock()
596 d.FlowDelEventMap.Set(cookie, event)
597}
598
599// UnRegisterFlowEvent to unregister a flow event.
600func (d *VoltDevice) UnRegisterFlowEvent(cookie string, flowModType of.Command) {
601 logger.Debugw(ctx, "UnRegistered Flow Add Event", log.Fields{"Cookie": cookie, "Type": flowModType})
602 flowEventMap, err := d.GetFlowEventRegister(flowModType)
603 if err != nil {
604 logger.Debugw(ctx, "Flow event map does not exists", log.Fields{"flowMod": flowModType, "Error": err})
605 return
606 }
607 flowEventMap.MapLock.Lock()
608 defer flowEventMap.MapLock.Unlock()
609 flowEventMap.Remove(cookie)
610}
611
612// AddIgmpGroups to add Igmp groups.
613func (va *VoltApplication) AddIgmpGroups(numOfGroups uint32) {
614 //TODO: Temp change to resolve group id issue in pOLT
615 //for i := 1; uint32(i) <= numOfGroups; i++ {
616 for i := 2; uint32(i) <= (numOfGroups + 1); i++ {
617 ig := IgmpGroup{}
618 ig.GroupID = uint32(i)
619 va.IgmpGroupIds = append(va.IgmpGroupIds, &ig)
620 }
621}
622
623// GetAvailIgmpGroupID to get id of available igmp group.
624func (va *VoltApplication) GetAvailIgmpGroupID() *IgmpGroup {
625 var ig *IgmpGroup
626 if len(va.IgmpGroupIds) > 0 {
627 ig, va.IgmpGroupIds = va.IgmpGroupIds[0], va.IgmpGroupIds[1:]
628 return ig
629 }
630 return nil
631}
632
633// GetIgmpGroupID to get id of igmp group.
634func (va *VoltApplication) GetIgmpGroupID(gid uint32) (*IgmpGroup, error) {
635 for id, ig := range va.IgmpGroupIds {
636 if ig.GroupID == gid {
637 va.IgmpGroupIds = append(va.IgmpGroupIds[0:id], va.IgmpGroupIds[id+1:]...)
638 return ig, nil
639 }
640 }
641 return nil, errors.New("Group Id Missing")
642}
643
644// PutIgmpGroupID to add id of igmp group.
645func (va *VoltApplication) PutIgmpGroupID(ig *IgmpGroup) {
646 va.IgmpGroupIds = append([]*IgmpGroup{ig}, va.IgmpGroupIds[0:]...)
647}
648
649//RestoreUpgradeStatus - gets upgrade/migration status from DB and updates local flags
650func (va *VoltApplication) RestoreUpgradeStatus() {
651 Migrate := new(DataMigration)
652 if err := GetMigrationInfo(Migrate); err == nil {
653 if Migrate.Status == MigrationInProgress {
654 isUpgradeComplete = false
655 return
656 }
657 }
658 isUpgradeComplete = true
659
660 logger.Infow(ctx, "Upgrade Status Restored", log.Fields{"Upgrade Completed": isUpgradeComplete})
661}
662
663// ReadAllFromDb : If we are restarted, learn from the database the current execution
664// stage
665func (va *VoltApplication) ReadAllFromDb() {
666 logger.Info(ctx, "Reading the meters from DB")
667 va.RestoreMetersFromDb()
668 logger.Info(ctx, "Reading the VNETs from DB")
669 va.RestoreVnetsFromDb()
670 logger.Info(ctx, "Reading the VPVs from DB")
671 va.RestoreVpvsFromDb()
672 logger.Info(ctx, "Reading the Services from DB")
673 va.RestoreSvcsFromDb()
674 logger.Info(ctx, "Reading the MVLANs from DB")
675 va.RestoreMvlansFromDb()
676 logger.Info(ctx, "Reading the IGMP profiles from DB")
677 va.RestoreIGMPProfilesFromDb()
678 logger.Info(ctx, "Reading the Mcast configs from DB")
679 va.RestoreMcastConfigsFromDb()
680 logger.Info(ctx, "Reading the IGMP groups for DB")
681 va.RestoreIgmpGroupsFromDb()
682 logger.Info(ctx, "Reading Upgrade status from DB")
683 va.RestoreUpgradeStatus()
684 logger.Info(ctx, "Reconciled from DB")
685}
686
687// InitStaticConfig to initialise static config.
688func (va *VoltApplication) InitStaticConfig() {
689 va.InitIgmpSrcMac()
690}
691
692// SetVendorID to set vendor id
693func (va *VoltApplication) SetVendorID(vendorID string) {
694 va.vendorID = vendorID
695}
696
697// GetVendorID to get vendor id
698func (va *VoltApplication) GetVendorID() string {
699 return va.vendorID
700}
701
702// SetRebootFlag to set reboot flag
703func (va *VoltApplication) SetRebootFlag(flag bool) {
704 vgcRebooted = flag
705}
706
707// GetUpgradeFlag to get reboot status
708func (va *VoltApplication) GetUpgradeFlag() bool {
709 return isUpgradeComplete
710}
711
712// SetUpgradeFlag to set reboot status
713func (va *VoltApplication) SetUpgradeFlag(flag bool) {
714 isUpgradeComplete = flag
715}
716
717// ------------------------------------------------------------
718// Device related functions
719
720// AddDevice : Add a device and typically the device stores the NNI port on the device
721// The NNI port is used when the packets are emitted towards the network.
722// The outport is selected as the NNI port of the device. Today, we support
723// a single NNI port per OLT. This is true whether the network uses any
724// protection mechanism (LAG, ERPS, etc.). The aggregate of the such protection
725// is represented by a single NNI port
726func (va *VoltApplication) AddDevice(device string, slno, southBoundID string) {
727 logger.Warnw(ctx, "Received Device Ind: Add", log.Fields{"Device": device, "SrNo": slno})
728 if _, ok := va.DevicesDisc.Load(device); ok {
729 logger.Warnw(ctx, "Device Exists", log.Fields{"Device": device})
730 }
731 d := NewVoltDevice(device, slno, southBoundID)
732
733 addPort := func(key, value interface{}) bool {
734 portID := key.(uint32)
735 port := value.(*PonPortCfg)
736 va.AggActiveChannelsCountForPonPort(device, portID, port)
737 d.ActiveChannelsPerPon.Store(portID, port)
738 return true
739 }
740 if nbDevice, exists := va.NbDevice.Load(southBoundID); exists {
741 // Pon Ports added before OLT activate.
742 nbDevice.(*NbDevice).PonPorts.Range(addPort)
743 } else {
744 // Check if NbPort exists in DB. VGC restart case.
745 nbd := va.RestoreNbDeviceFromDb(southBoundID)
746 nbd.PonPorts.Range(addPort)
747 }
748 va.DevicesDisc.Store(device, d)
749}
750
751// GetDevice to get a device.
752func (va *VoltApplication) GetDevice(device string) *VoltDevice {
753 if d, ok := va.DevicesDisc.Load(device); ok {
754 return d.(*VoltDevice)
755 }
756 return nil
757}
758
759// DelDevice to delete a device.
760func (va *VoltApplication) DelDevice(device string) {
761 logger.Warnw(ctx, "Received Device Ind: Delete", log.Fields{"Device": device})
762 if vdIntf, ok := va.DevicesDisc.Load(device); ok {
763 vd := vdIntf.(*VoltDevice)
764 va.DevicesDisc.Delete(device)
765 _ = db.DelAllRoutesForDevice(device)
766 va.HandleFlowClearFlag(device, vd.SerialNum, vd.SouthBoundID)
767 _ = db.DelAllGroup(device)
768 _ = db.DelAllMeter(device)
769 _ = db.DelAllPorts(device)
770 logger.Debugw(ctx, "Device deleted", log.Fields{"Device": device})
771 } else {
772 logger.Warnw(ctx, "Device Doesn't Exist", log.Fields{"Device": device})
773 }
774}
775
776// GetDeviceBySerialNo to get a device by serial number.
777// TODO - Transform this into a MAP instead
778func (va *VoltApplication) GetDeviceBySerialNo(slno string) *VoltDevice {
779 var device *VoltDevice
780 getserial := func(key interface{}, value interface{}) bool {
781 device = value.(*VoltDevice)
782 return device.SerialNum != slno
783 }
784 va.DevicesDisc.Range(getserial)
785 return device
786}
787
788// PortAddInd : This is a PORT add indication coming from the VPAgent, which is essentially
789// a request coming from VOLTHA. The device and identity of the port is provided
790// in this request. Add them to the application for further use
791func (va *VoltApplication) PortAddInd(device string, id uint32, portName string) {
792 logger.Infow(ctx, "Received Port Ind: Add", log.Fields{"Device": device, "Port": portName})
793 va.portLock.Lock()
794 if d := va.GetDevice(device); d != nil {
795 p := d.AddPort(portName, id)
796 va.PortsDisc.Store(portName, p)
797 va.portLock.Unlock()
798 nni, _ := va.GetNniPort(device)
799 if nni == portName {
800 d.pushFlowsForUnis()
801 }
802 } else {
803 va.portLock.Unlock()
804 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: Add", log.Fields{"Device": device, "Port": portName})
805 }
806}
807
808// PortDelInd : Only the NNI ports are recorded in the device for now. When port delete
809// arrives, only the NNI ports need adjustments.
810func (va *VoltApplication) PortDelInd(device string, port string) {
811 logger.Infow(ctx, "Received Port Ind: Delete", log.Fields{"Device": device, "Port": port})
812 if d := va.GetDevice(device); d != nil {
813 p := d.GetPort(port)
814 if p != nil && p.State == PortStateUp {
815 logger.Infow(ctx, "Port state is UP. Trigerring Port Down Ind before deleting", log.Fields{"Port": p})
816 va.PortDownInd(device, port)
817 }
818 va.portLock.Lock()
819 defer va.portLock.Unlock()
820 d.DelPort(port)
821 if _, ok := va.PortsDisc.Load(port); ok {
822 va.PortsDisc.Delete(port)
823 }
824 } else {
825 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: Delete", log.Fields{"Device": device, "Port": port})
826 }
827}
828
829//PortUpdateInd Updates port Id incase of ONU movement
830func (va *VoltApplication) PortUpdateInd(device string, portName string, id uint32) {
831 logger.Infow(ctx, "Received Port Ind: Update", log.Fields{"Device": device, "Port": portName})
832 va.portLock.Lock()
833 defer va.portLock.Unlock()
834 if d := va.GetDevice(device); d != nil {
835 vp := d.GetPort(portName)
836 vp.ID = id
837 } else {
838 logger.Warnw(ctx, "Device Not Found", log.Fields{"Device": device, "Port": portName})
839 }
840}
841
842// AddNbPonPort Add pon port to nbDevice
843func (va *VoltApplication) AddNbPonPort(oltSbID string, portID, maxAllowedChannels uint32,
844 enableMulticastKPI bool, portAlarmProfileID string) error {
845
846 var nbd *NbDevice
847 nbDevice, ok := va.NbDevice.Load(oltSbID)
848
849 if !ok {
850 nbd = NewNbDevice()
851 nbd.SouthBoundID = oltSbID
852 } else {
853 nbd = nbDevice.(*NbDevice)
854 }
855 port := nbd.AddPortToNbDevice(portID, maxAllowedChannels, enableMulticastKPI, portAlarmProfileID)
856
857 // Add this port to voltDevice
858 addPort := func(key, value interface{}) bool {
859 voltDevice := value.(*VoltDevice)
860 if oltSbID == voltDevice.SouthBoundID {
861 if _, exists := voltDevice.ActiveChannelsPerPon.Load(portID); !exists {
862 voltDevice.ActiveChannelsPerPon.Store(portID, port)
863 }
864 return false
865 }
866 return true
867 }
868 va.DevicesDisc.Range(addPort)
869 va.NbDevice.Store(oltSbID, nbd)
870
871 return nil
872}
873
874// UpdateNbPonPort update pon port to nbDevice
875func (va *VoltApplication) UpdateNbPonPort(oltSbID string, portID, maxAllowedChannels uint32, enableMulticastKPI bool, portAlarmProfileID string) error {
876
877 var nbd *NbDevice
878 nbDevice, ok := va.NbDevice.Load(oltSbID)
879
880 if !ok {
881 logger.Errorw(ctx, "Device-doesn't-exists", log.Fields{"deviceID": oltSbID})
882 return fmt.Errorf("Device-doesn't-exists-%v", oltSbID)
883 }
884 nbd = nbDevice.(*NbDevice)
885
886 port := nbd.UpdatePortToNbDevice(portID, maxAllowedChannels, enableMulticastKPI, portAlarmProfileID)
887 if port == nil {
888 return fmt.Errorf("Port-doesn't-exists-%v", portID)
889 }
890 va.NbDevice.Store(oltSbID, nbd)
891
892 // Add this port to voltDevice
893 updPort := func(key, value interface{}) bool {
894 voltDevice := value.(*VoltDevice)
895 if oltSbID == voltDevice.SouthBoundID {
896 voltDevice.ActiveChannelCountLock.Lock()
897 if p, exists := voltDevice.ActiveChannelsPerPon.Load(portID); exists {
898 oldPort := p.(*PonPortCfg)
899 if port.MaxActiveChannels != 0 {
900 oldPort.MaxActiveChannels = port.MaxActiveChannels
901 oldPort.EnableMulticastKPI = port.EnableMulticastKPI
902 voltDevice.ActiveChannelsPerPon.Store(portID, oldPort)
903 }
904 }
905 voltDevice.ActiveChannelCountLock.Unlock()
906 return false
907 }
908 return true
909 }
910 va.DevicesDisc.Range(updPort)
911
912 return nil
913}
914
915// DeleteNbPonPort Delete pon port to nbDevice
916func (va *VoltApplication) DeleteNbPonPort(oltSbID string, portID uint32) error {
917 nbDevice, ok := va.NbDevice.Load(oltSbID)
918 if ok {
919 nbDevice.(*NbDevice).DeletePortFromNbDevice(portID)
920 va.NbDevice.Store(oltSbID, nbDevice.(*NbDevice))
921 } else {
922 logger.Warnw(ctx, "Delete pon received for unknown device", log.Fields{"oltSbID": oltSbID})
923 return nil
924 }
925 // Delete this port from voltDevice
926 delPort := func(key, value interface{}) bool {
927 voltDevice := value.(*VoltDevice)
928 if oltSbID == voltDevice.SouthBoundID {
929 if _, exists := voltDevice.ActiveChannelsPerPon.Load(portID); exists {
930 voltDevice.ActiveChannelsPerPon.Delete(portID)
931 }
932 return false
933 }
934 return true
935 }
936 va.DevicesDisc.Range(delPort)
937 return nil
938}
939
940// GetNniPort : Get the NNI port for a device. Called from different other applications
941// as a port to match or destination for a packet out. The VOLT application
942// is written with the assumption that there is a single NNI port. The OLT
943// device is responsible for translating the combination of VLAN and the
944// NNI port ID to identify possibly a single physical port or a logical
945// port which is a result of protection methods applied.
946func (va *VoltApplication) GetNniPort(device string) (string, error) {
947 va.portLock.Lock()
948 defer va.portLock.Unlock()
949 d, ok := va.DevicesDisc.Load(device)
950 if !ok {
951 return "", errors.New("Device Doesn't Exist")
952 }
953 return d.(*VoltDevice).NniPort, nil
954}
955
956// NniDownInd process for Nni down indication.
957func (va *VoltApplication) NniDownInd(deviceID string, devSrNo string) {
958
959 logger.Debugw(ctx, "NNI Down Ind", log.Fields{"device": devSrNo})
960
961 handleIgmpDsFlows := func(key interface{}, value interface{}) bool {
962 mvProfile := value.(*MvlanProfile)
963 mvProfile.removeIgmpMcastFlows(devSrNo)
964 return true
965 }
966 va.MvlanProfilesByName.Range(handleIgmpDsFlows)
967
968 //Clear Static Group
969 va.ReceiverDownInd(deviceID, StaticPort)
970}
971
972// DeviceUpInd changes device state to up.
973func (va *VoltApplication) DeviceUpInd(device string) {
974 logger.Warnw(ctx, "Received Device Ind: UP", log.Fields{"Device": device})
975 if d := va.GetDevice(device); d != nil {
976 d.State = controller.DeviceStateUP
977 } else {
978 logger.Errorw(ctx, "Ignoring Device indication: UP. Device Missing", log.Fields{"Device": device})
979 }
980}
981
982// DeviceDownInd changes device state to down.
983func (va *VoltApplication) DeviceDownInd(device string) {
984 logger.Warnw(ctx, "Received Device Ind: DOWN", log.Fields{"Device": device})
985 if d := va.GetDevice(device); d != nil {
986 d.State = controller.DeviceStateDOWN
987 } else {
988 logger.Errorw(ctx, "Ignoring Device indication: DOWN. Device Missing", log.Fields{"Device": device})
989 }
990}
991
992// DeviceRebootInd process for handling flow clear flag for device reboot
993func (va *VoltApplication) DeviceRebootInd(device string, serialNum string, southBoundID string) {
994 logger.Warnw(ctx, "Received Device Ind: Reboot", log.Fields{"Device": device, "SerialNumber": serialNum})
995
996 if d := va.GetDevice(device); d != nil {
997 if d.State == controller.DeviceStateREBOOTED {
998 logger.Warnw(ctx, "Ignoring Device Ind: Reboot, Device already in Reboot state", log.Fields{"Device": device, "SerialNumber": serialNum, "State": d.State})
999 return
1000 }
1001 d.State = controller.DeviceStateREBOOTED
1002 }
1003 va.HandleFlowClearFlag(device, serialNum, southBoundID)
1004
1005}
1006
1007// DeviceDisableInd handles device deactivation process
1008func (va *VoltApplication) DeviceDisableInd(device string) {
1009 logger.Warnw(ctx, "Received Device Ind: Disable", log.Fields{"Device": device})
1010
1011 d := va.GetDevice(device)
1012 if d == nil {
1013 logger.Errorw(ctx, "Ignoring Device indication: DISABLED. Device Missing", log.Fields{"Device": device})
1014 return
1015 }
1016
1017 d.State = controller.DeviceStateDISABLED
1018 va.HandleFlowClearFlag(device, d.SerialNum, d.SouthBoundID)
1019}
1020
1021// ProcessIgmpDSFlowForMvlan for processing Igmp DS flow for device
1022func (va *VoltApplication) ProcessIgmpDSFlowForMvlan(d *VoltDevice, mvp *MvlanProfile, addFlow bool) {
1023
1024 logger.Debugw(ctx, "Process IGMP DS Flows for MVlan", log.Fields{"device": d.Name, "Mvlan": mvp.Mvlan, "addFlow": addFlow})
1025 portState := false
1026 p := d.GetPort(d.NniPort)
1027 if p != nil && p.State == PortStateUp {
1028 portState = true
1029 }
1030
1031 if addFlow {
1032 if portState {
1033 mvp.pushIgmpMcastFlows(d.SerialNum)
1034 }
1035 } else {
1036 mvp.removeIgmpMcastFlows(d.SerialNum)
1037 }
1038}
1039
1040// ProcessIgmpDSFlowForDevice for processing Igmp DS flow for device
1041func (va *VoltApplication) ProcessIgmpDSFlowForDevice(d *VoltDevice, addFlow bool) {
1042 logger.Debugw(ctx, "Process IGMP DS Flows for device", log.Fields{"device": d.Name, "addFlow": addFlow})
1043
1044 handleIgmpDsFlows := func(key interface{}, value interface{}) bool {
1045 mvProfile := value.(*MvlanProfile)
1046 va.ProcessIgmpDSFlowForMvlan(d, mvProfile, addFlow)
1047 return true
1048 }
1049 va.MvlanProfilesByName.Range(handleIgmpDsFlows)
1050}
1051
1052// GetDeviceFromPort : This is suitable only for access ports as their naming convention
1053// makes them unique across all the OLTs. This must be called with
1054// port name that is an access port. Currently called from VNETs, attached
1055// only to access ports, and the services which are also attached only
1056// to access ports
1057func (va *VoltApplication) GetDeviceFromPort(port string) (*VoltDevice, error) {
1058 va.portLock.Lock()
1059 defer va.portLock.Unlock()
1060 var err error
1061 err = nil
1062 p, ok := va.PortsDisc.Load(port)
1063 if !ok {
1064 return nil, errorCodes.ErrPortNotFound
1065 }
1066 d := va.GetDevice(p.(*VoltPort).Device)
1067 if d == nil {
1068 err = errorCodes.ErrDeviceNotFound
1069 }
1070 return d, err
1071}
1072
1073// GetPortID : This too applies only to access ports. The ports can be indexed
1074// purely by their names without the device forming part of the key
1075func (va *VoltApplication) GetPortID(port string) (uint32, error) {
1076 va.portLock.Lock()
1077 defer va.portLock.Unlock()
1078 p, ok := va.PortsDisc.Load(port)
1079 if !ok {
1080 return 0, errorCodes.ErrPortNotFound
1081 }
1082 return p.(*VoltPort).ID, nil
1083}
1084
1085// GetPortName : This too applies only to access ports. The ports can be indexed
1086// purely by their names without the device forming part of the key
1087func (va *VoltApplication) GetPortName(port uint32) (string, error) {
1088 va.portLock.Lock()
1089 defer va.portLock.Unlock()
1090 var portName string
1091 va.PortsDisc.Range(func(key interface{}, value interface{}) bool {
1092 portInfo := value.(*VoltPort)
1093 if portInfo.ID == port {
1094 portName = portInfo.Name
1095 return false
1096 }
1097 return true
1098 })
1099 return portName, nil
1100}
1101
1102// GetPonFromUniPort to get Pon info from UniPort
1103func (va *VoltApplication) GetPonFromUniPort(port string) (string, error) {
1104 uniPortID, err := va.GetPortID(port)
1105 if err == nil {
1106 ponPortID := (uniPortID & 0x0FF00000) >> 20 //pon(8) + onu(8) + uni(12)
1107 return strconv.FormatUint(uint64(ponPortID), 10), nil
1108 }
1109 return "", err
1110}
1111
1112// GetPortState : This too applies only to access ports. The ports can be indexed
1113// purely by their names without the device forming part of the key
1114func (va *VoltApplication) GetPortState(port string) (PortState, error) {
1115 va.portLock.Lock()
1116 defer va.portLock.Unlock()
1117 p, ok := va.PortsDisc.Load(port)
1118 if !ok {
1119 return 0, errors.New("Port not configured")
1120 }
1121 return p.(*VoltPort).State, nil
1122}
1123
1124// GetIcmpv6Receivers to get Icmp v6 receivers
1125func (va *VoltApplication) GetIcmpv6Receivers(device string) []uint32 {
1126 var receiverList []uint32
1127 receivers, _ := va.Icmpv6Receivers.Load(device)
1128 if receivers != nil {
1129 receiverList = receivers.([]uint32)
1130 }
1131 return receiverList
1132}
1133
1134// AddIcmpv6Receivers to add Icmp v6 receivers
1135func (va *VoltApplication) AddIcmpv6Receivers(device string, portID uint32) []uint32 {
1136 var receiverList []uint32
1137 receivers, _ := va.Icmpv6Receivers.Load(device)
1138 if receivers != nil {
1139 receiverList = receivers.([]uint32)
1140 }
1141 receiverList = append(receiverList, portID)
1142 va.Icmpv6Receivers.Store(device, receiverList)
1143 logger.Debugw(ctx, "Receivers after addition", log.Fields{"Receivers": receiverList})
1144 return receiverList
1145}
1146
1147// DelIcmpv6Receivers to delete Icmp v6 receievers
1148func (va *VoltApplication) DelIcmpv6Receivers(device string, portID uint32) []uint32 {
1149 var receiverList []uint32
1150 receivers, _ := va.Icmpv6Receivers.Load(device)
1151 if receivers != nil {
1152 receiverList = receivers.([]uint32)
1153 }
1154 for i, port := range receiverList {
1155 if port == portID {
1156 receiverList = append(receiverList[0:i], receiverList[i+1:]...)
1157 va.Icmpv6Receivers.Store(device, receiverList)
1158 break
1159 }
1160 }
1161 logger.Debugw(ctx, "Receivers After deletion", log.Fields{"Receivers": receiverList})
1162 return receiverList
1163}
1164
1165// ProcessDevFlowForDevice - Process DS ICMPv6 & ARP flow for provided device and vnet profile
1166// device - Device Obj
1167// vnet - vnet profile name
1168// enabled - vlan enabled/disabled - based on the status, the flow shall be added/removed
1169func (va *VoltApplication) ProcessDevFlowForDevice(device *VoltDevice, vnet *VoltVnet, enabled bool) {
1170 _, applied := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0))
1171 if enabled {
1172 va.PushDevFlowForVlan(vnet)
1173 } else if !enabled && applied {
1174 //va.DeleteDevFlowForVlan(vnet)
1175 va.DeleteDevFlowForVlanFromDevice(vnet, device.SerialNum)
1176 }
1177}
1178
1179//NniVlanIndToIgmp - Trigger receiver up indication to all ports with igmp enabled
1180//and has the provided mvlan
1181func (va *VoltApplication) NniVlanIndToIgmp(device *VoltDevice, mvp *MvlanProfile) {
1182
1183 logger.Infow(ctx, "Sending Igmp Receiver UP indication for all Services", log.Fields{"Vlan": mvp.Mvlan})
1184
1185 //Trigger nni indication for receiver only for first time
1186 if device.IgmpDsFlowAppliedForMvlan[uint16(mvp.Mvlan)] {
1187 return
1188 }
1189 device.Ports.Range(func(key, value interface{}) bool {
1190 port := key.(string)
1191
1192 if state, _ := va.GetPortState(port); state == PortStateUp {
1193 vpvs, _ := va.VnetsByPort.Load(port)
1194 if vpvs == nil {
1195 return true
1196 }
1197 for _, vpv := range vpvs.([]*VoltPortVnet) {
1198 //Send indication only for subscribers with the received mvlan profile
1199 if vpv.IgmpEnabled && vpv.MvlanProfileName == mvp.Name {
1200 vpv.services.Range(ReceiverUpInd)
1201 }
1202 }
1203 }
1204 return true
1205 })
1206}
1207
1208// PortUpInd :
1209// -----------------------------------------------------------------------
1210// Port status change handling
1211// ----------------------------------------------------------------------
1212// Port UP indication is passed to all services associated with the port
1213// so that the services can configure flows applicable when the port goes
1214// up from down state
1215func (va *VoltApplication) PortUpInd(device string, port string) {
1216 d := va.GetDevice(device)
1217
1218 if d == nil {
1219 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: UP", log.Fields{"Device": device, "Port": port})
1220 return
1221 }
1222
1223 //Fixme: If Port Update Comes in large numbers, this will result in slow update per device
1224 va.portLock.Lock()
1225 // Do not defer the port mutex unlock here
1226 // Some of the following func calls needs the port lock, so defering the lock here
1227 // may lead to dead-lock
1228 p := d.GetPort(port)
1229
1230 if p == nil {
1231 logger.Infow(ctx, "Ignoring Port Ind: UP, Port doesnt exist", log.Fields{"Device": device, "PortName": port, "PortId": p})
1232 va.portLock.Unlock()
1233 return
1234 }
1235 p.State = PortStateUp
1236 va.portLock.Unlock()
1237
1238 logger.Infow(ctx, "Received SouthBound Port Ind: UP", log.Fields{"Device": device, "PortName": port, "PortId": p.ID})
1239 if p.Type == VoltPortTypeNni {
1240
1241 logger.Warnw(ctx, "Received NNI Port Ind: UP", log.Fields{"Device": device, "PortName": port, "PortId": p.ID})
1242 //va.PushDevFlowForDevice(d)
1243 //Build Igmp TrapFlowRule
1244 //va.ProcessIgmpDSFlowForDevice(d, true)
1245 }
1246 vpvs, ok := va.VnetsByPort.Load(port)
1247 if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
1248 logger.Infow(ctx, "No VNETs on port", log.Fields{"Device": device, "Port": port})
1249 //msgbus.ProcessPortInd(msgbus.PortUp, d.SerialNum, p.Name, false, getServiceList(port))
1250 return
1251 }
1252
1253 //If NNI port is not UP, do not push Flows
1254 if d.NniPort == "" {
1255 logger.Warnw(ctx, "NNI port not UP. Not sending Port UP Ind for VPVs", log.Fields{"NNI": d.NniPort})
1256 return
1257 }
1258
1259 vpvList := vpvs.([]*VoltPortVnet)
1260 if vpvList[0].PonPort != 0xFF && vpvList[0].PonPort != p.PonPort {
1261 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Port Indication", log.Fields{"Device": device, "Port": port, "DetectedPon": p.PonPort, "ExpectedPon": vpvList[0].PonPort})
1262
1263 //Remove the flow (if any) which are already installed - Valid for PON switching when VGC pod is DOWN
1264 for _, vpv := range vpvs.([]*VoltPortVnet) {
1265 vpv.VpvLock.Lock()
1266 logger.Warnw(ctx, "Removing existing VPVs/Services flows for for Subscriber: UNI Detected on wrong PON", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
1267 vpv.PortDownInd(device, port)
1268 if vpv.IgmpEnabled {
1269 va.ReceiverDownInd(device, port)
1270 }
1271 vpv.VpvLock.Unlock()
1272 }
1273 return
1274 }
1275
1276/*
1277 if p.Type != VoltPortTypeNni {
1278 // Process port up indication
1279 indTask := cntlr.NewAddPortInd(p.Name, msgbus.PortUp, d.SerialNum, true, getServiceList(port))
1280 cntlr.GetController().PostIndication(device, indTask)
1281 }
1282*/
1283
1284 for _, vpv := range vpvs.([]*VoltPortVnet) {
1285 vpv.VpvLock.Lock()
1286
1287 //Do not trigger indication for the vpv which is already removed from vpv list as
1288 // part of service delete (during the lock wait duration)
1289 // In that case, the services associated wil be zero
1290 if vpv.servicesCount.Load() != 0 {
1291 vpv.PortUpInd(d, port)
1292 }
1293 vpv.VpvLock.Unlock()
1294 }
1295 // At the end of processing inform the other entities that
1296 // are interested in the events
1297}
1298
1299/*
1300func getServiceList(port string) map[string]bool {
1301 serviceList := make(map[string]bool)
1302
1303 getServiceNames := func(key interface{}, value interface{}) bool {
1304 serviceList[key.(string)] = value.(*VoltService).DsHSIAFlowsApplied
1305 return true
1306 }
1307
1308 if vpvs, _ := GetApplication().VnetsByPort.Load(port); vpvs != nil {
1309 vpvList := vpvs.([]*VoltPortVnet)
1310 for _, vpv := range vpvList {
1311 vpv.services.Range(getServiceNames)
1312 }
1313 }
1314 return serviceList
1315
1316}*/
1317
1318//ReceiverUpInd - Send receiver up indication for service with Igmp enabled
1319func ReceiverUpInd(key, value interface{}) bool {
1320 svc := value.(*VoltService)
1321 var vlan of.VlanType
1322
1323 if !svc.IPAssigned() {
1324 logger.Infow(ctx, "IP Not assigned, skipping general query", log.Fields{"Service": svc})
1325 return false
1326 }
1327
1328 //Send port up indication to igmp only for service with igmp enabled
1329 if svc.IgmpEnabled {
1330 if svc.VlanControl == ONUCVlan || svc.VlanControl == ONUCVlanOLTSVlan {
1331 vlan = svc.CVlan
1332 } else {
1333 vlan = svc.UniVlan
1334 }
1335 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
1336 GetApplication().ReceiverUpInd(device.Name, svc.Port, svc.MvlanProfileName, vlan, svc.Pbits)
1337 }
1338 return false
1339 }
1340 return true
1341}
1342
1343// PortDownInd : Port down indication is passed on to the services so that the services
1344// can make changes at this transition.
1345func (va *VoltApplication) PortDownInd(device string, port string) {
1346 logger.Infow(ctx, "Received SouthBound Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
1347 d := va.GetDevice(device)
1348
1349 if d == nil {
1350 logger.Warnw(ctx, "Device Not Found - Dropping Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
1351 return
1352 }
1353 //Fixme: If Port Update Comes in large numbers, this will result in slow update per device
1354 va.portLock.Lock()
1355 // Do not defer the port mutex unlock here
1356 // Some of the following func calls needs the port lock, so defering the lock here
1357 // may lead to dead-lock
1358 p := d.GetPort(port)
1359 if p == nil {
1360 logger.Infow(ctx, "Ignoring Port Ind: Down, Port doesnt exist", log.Fields{"Device": device, "PortName": port, "PortId": p})
1361 va.portLock.Unlock()
1362 return
1363 }
1364 p.State = PortStateDown
1365 va.portLock.Unlock()
1366
1367 if d.State == controller.DeviceStateREBOOTED {
1368 logger.Infow(ctx, "Ignoring Port Ind: Down, Device has been Rebooted", log.Fields{"Device": device, "PortName": port, "PortId": p})
1369 return
1370 }
1371
1372 if p.Type == VoltPortTypeNni {
1373 logger.Warnw(ctx, "Received NNI Port Ind: DOWN", log.Fields{"Device": device, "Port": port})
1374 va.DeleteDevFlowForDevice(d)
1375 va.NniDownInd(device, d.SerialNum)
1376 va.RemovePendingGroups(device, true)
1377 }
1378 vpvs, ok := va.VnetsByPort.Load(port)
1379 if !ok || nil == vpvs || len(vpvs.([]*VoltPortVnet)) == 0 {
1380 logger.Infow(ctx, "No VNETs on port", log.Fields{"Device": device, "Port": port})
1381 //msgbus.ProcessPortInd(msgbus.PortDown, d.SerialNum, p.Name, false, getServiceList(port))
1382 return
1383 }
1384/*
1385 if p.Type != VoltPortTypeNni {
1386 // Process port down indication
1387 indTask := cntlr.NewAddPortInd(p.Name, msgbus.PortDown, d.SerialNum, true, getServiceList(port))
1388 cntlr.GetController().PostIndication(device, indTask)
1389 }
1390*/
1391 for _, vpv := range vpvs.([]*VoltPortVnet) {
1392 vpv.VpvLock.Lock()
1393 vpv.PortDownInd(device, port)
1394 if vpv.IgmpEnabled {
1395 va.ReceiverDownInd(device, port)
1396 }
1397 vpv.VpvLock.Unlock()
1398 }
1399}
1400
1401// PacketInInd :
1402// -----------------------------------------------------------------------
1403// PacketIn Processing
1404// Packet In Indication processing. It arrives with the identities of
1405// the device and port on which the packet is received. At first, the
1406// packet is decoded and the right processor is called. Currently, we
1407// plan to support only DHCP and IGMP. In future, we can add more
1408// capabilities as needed
1409func (va *VoltApplication) PacketInInd(device string, port string, pkt []byte) {
1410 // Decode the incoming packet
1411 packetSide := US
1412 if strings.Contains(port, NNI) {
1413 packetSide = DS
1414 }
1415
1416 logger.Debugw(ctx, "Received a Packet-In Indication", log.Fields{"Device": device, "Port": port})
1417
1418 gopkt := gopacket.NewPacket(pkt, layers.LayerTypeEthernet, gopacket.Default)
1419
1420 var dot1qFound = false
1421 for _, l := range gopkt.Layers() {
1422 if l.LayerType() == layers.LayerTypeDot1Q {
1423 dot1qFound = true
1424 break
1425 }
1426 }
1427
1428 if !dot1qFound {
1429 logger.Debugw(ctx, "Ignoring Received Packet-In Indication without Dot1Q Header",
1430 log.Fields{"Device": device, "Port": port})
1431 return
1432 }
1433
1434 logger.Debugw(ctx, "Received Southbound Packet In", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1435
1436 // Classify the packet into packet types that we support
1437 // The supported types are DHCP and IGMP. The DHCP packet is
1438 // identified by matching the L4 protocol to UDP. The IGMP packet
1439 // is identified by matching L3 protocol to IGMP
1440 arpl := gopkt.Layer(layers.LayerTypeARP)
1441 if arpl != nil {
1442 if callBack, ok := PacketHandlers[ARP]; ok {
1443 callBack(device, port, gopkt)
1444 } else {
1445 logger.Debugw(ctx, "ARP handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1446 }
1447 return
1448 }
1449 ipv4l := gopkt.Layer(layers.LayerTypeIPv4)
1450 if ipv4l != nil {
1451 ip := ipv4l.(*layers.IPv4)
1452
1453 if ip.Protocol == layers.IPProtocolUDP {
1454 logger.Debugw(ctx, "Received Southbound UDP ipv4 packet in", log.Fields{"StreamSide": packetSide})
1455 dhcpl := gopkt.Layer(layers.LayerTypeDHCPv4)
1456 if dhcpl != nil {
1457 if callBack, ok := PacketHandlers[DHCPv4]; ok {
1458 callBack(device, port, gopkt)
1459 } else {
1460 logger.Debugw(ctx, "DHCPv4 handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1461 }
1462 }
1463 } else if ip.Protocol == layers.IPProtocolIGMP {
1464 logger.Debugw(ctx, "Received Southbound IGMP packet in", log.Fields{"StreamSide": packetSide})
1465 if callBack, ok := PacketHandlers[IGMP]; ok {
1466 callBack(device, port, gopkt)
1467 } else {
1468 logger.Debugw(ctx, "IGMP handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1469 }
1470 }
1471 return
1472 }
1473 ipv6l := gopkt.Layer(layers.LayerTypeIPv6)
1474 if ipv6l != nil {
1475 ip := ipv6l.(*layers.IPv6)
1476 if ip.NextHeader == layers.IPProtocolUDP {
1477 logger.Debug(ctx, "Received Southbound UDP ipv6 packet in")
1478 dhcpl := gopkt.Layer(layers.LayerTypeDHCPv6)
1479 if dhcpl != nil {
1480 if callBack, ok := PacketHandlers[DHCPv6]; ok {
1481 callBack(device, port, gopkt)
1482 } else {
1483 logger.Debugw(ctx, "DHCPv6 handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1484 }
1485 }
1486 }
1487 return
1488 }
1489
1490 pppoel := gopkt.Layer(layers.LayerTypePPPoE)
1491 if pppoel != nil {
1492 logger.Debugw(ctx, "Received Southbound PPPoE packet in", log.Fields{"StreamSide": packetSide})
1493 if callBack, ok := PacketHandlers[PPPOE]; ok {
1494 callBack(device, port, gopkt)
1495 } else {
1496 logger.Debugw(ctx, "PPPoE handler is not registered, dropping the packet", log.Fields{"Pkt": hex.EncodeToString(gopkt.Data())})
1497 }
1498 }
1499}
1500
1501// GetVlans : This utility gets the VLANs from the packet. The VLANs are
1502// used to identify the right service that must process the incoming
1503// packet
1504func GetVlans(pkt gopacket.Packet) []of.VlanType {
1505 var vlans []of.VlanType
1506 for _, l := range pkt.Layers() {
1507 if l.LayerType() == layers.LayerTypeDot1Q {
1508 q, ok := l.(*layers.Dot1Q)
1509 if ok {
1510 vlans = append(vlans, of.VlanType(q.VLANIdentifier))
1511 }
1512 }
1513 }
1514 return vlans
1515}
1516
1517// GetPriority to get priority
1518func GetPriority(pkt gopacket.Packet) uint8 {
1519 for _, l := range pkt.Layers() {
1520 if l.LayerType() == layers.LayerTypeDot1Q {
1521 q, ok := l.(*layers.Dot1Q)
1522 if ok {
1523 return q.Priority
1524 }
1525 }
1526 }
1527 return PriorityNone
1528}
1529
1530// HandleFlowClearFlag to handle flow clear flag during reboot
1531func (va *VoltApplication) HandleFlowClearFlag(deviceID string, serialNum, southBoundID string) {
1532 logger.Warnw(ctx, "Clear All flags for Device", log.Fields{"Device": deviceID, "SerialNum": serialNum, "SBID": southBoundID})
1533 dev, ok := va.DevicesDisc.Load(deviceID)
1534 if ok && dev != nil {
1535 logger.Infow(ctx, "Clear Flags for device", log.Fields{"voltDevice": dev.(*VoltDevice).Name})
1536 dev.(*VoltDevice).icmpv6GroupAdded = false
1537 logger.Infow(ctx, "Clearing DS Icmpv6 Map",
1538 log.Fields{"voltDevice": dev.(*VoltDevice).Name})
1539 dev.(*VoltDevice).ConfiguredVlanForDeviceFlows = util.NewConcurrentMap()
1540 logger.Infow(ctx, "Clearing DS IGMP Map",
1541 log.Fields{"voltDevice": dev.(*VoltDevice).Name})
1542 for k := range dev.(*VoltDevice).IgmpDsFlowAppliedForMvlan {
1543 delete(dev.(*VoltDevice).IgmpDsFlowAppliedForMvlan, k)
1544 }
1545 //Delete group 1 - ICMPv6/ARP group
1546 if err := ProcessIcmpv6McGroup(deviceID, true); err != nil {
1547 logger.Errorw(ctx, "ProcessIcmpv6McGroup failed", log.Fields{"Device": deviceID, "Error": err})
1548 }
1549 } else {
1550 logger.Warnw(ctx, "VoltDevice not found for device ", log.Fields{"deviceID": deviceID})
1551 }
1552
1553 getVpvs := func(key interface{}, value interface{}) bool {
1554 vpvs := value.([]*VoltPortVnet)
1555 for _, vpv := range vpvs {
1556 if vpv.Device == deviceID {
1557 logger.Infow(ctx, "Clear Flags for vpv",
1558 log.Fields{"device": vpv.Device, "port": vpv.Port,
1559 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
1560 vpv.ClearAllServiceFlags()
1561 vpv.ClearAllVpvFlags()
1562
1563 if vpv.IgmpEnabled {
1564 va.ReceiverDownInd(vpv.Device, vpv.Port)
1565 //Also clear service igmp stats
1566 vpv.ClearServiceCounters()
1567 }
1568 }
1569 }
1570 return true
1571 }
1572 va.VnetsByPort.Range(getVpvs)
1573
1574 //Clear Static Group
1575 va.ReceiverDownInd(deviceID, StaticPort)
1576
1577 logger.Warnw(ctx, "All flags cleared for device", log.Fields{"Device": deviceID})
1578
1579 //Reset pending group pool
1580 va.RemovePendingGroups(deviceID, true)
1581
1582 //Process all Migrate Service Request - force udpate all profiles since resources are already cleaned up
1583 if dev != nil {
1584 triggerForceUpdate := func(key, value interface{}) bool {
1585 msrList := value.(*util.ConcurrentMap)
1586 forceUpdateServices := func(key, value interface{}) bool {
1587 msr := value.(*MigrateServicesRequest)
1588 forceUpdateAllServices(msr)
1589 return true
1590 }
1591 msrList.Range(forceUpdateServices)
1592 return true
1593 }
1594 dev.(*VoltDevice).MigratingServices.Range(triggerForceUpdate)
1595 } else {
1596 va.FetchAndProcessAllMigrateServicesReq(deviceID, forceUpdateAllServices)
1597 }
1598}
1599
1600//GetPonPortIDFromUNIPort to get pon port id from uni port
1601func GetPonPortIDFromUNIPort(uniPortID uint32) uint32 {
1602 ponPortID := (uniPortID & 0x0FF00000) >> 20
1603 return ponPortID
1604}
1605
1606//ProcessFlowModResultIndication - Processes Flow mod operation indications from controller
1607func (va *VoltApplication) ProcessFlowModResultIndication(flowStatus intf.FlowStatus) {
1608
1609 d := va.GetDevice(flowStatus.Device)
1610 if d == nil {
1611 logger.Errorw(ctx, "Dropping Flow Mod Indication. Device not found", log.Fields{"Cookie": flowStatus.Cookie, "Device": flowStatus.Device})
1612 return
1613 }
1614
1615 cookieExists := ExecuteFlowEvent(d, flowStatus.Cookie, flowStatus)
1616
1617 if flowStatus.Flow != nil {
1618 flowAdd := (flowStatus.FlowModType == of.CommandAdd)
1619 if !cookieExists && !isFlowStatusSuccess(flowStatus.Status, flowAdd) {
1620 pushFlowFailureNotif(flowStatus)
1621 }
1622 }
1623}
1624
1625func pushFlowFailureNotif(flowStatus intf.FlowStatus) {
1626 subFlow := flowStatus.Flow
1627 cookie := subFlow.Cookie
1628 uniPort := cookie >> 16 & 0xFFFFFFFF
1629 logger.Errorw(ctx, "Flow Failure Notification", log.Fields{"uniPort": uniPort, "Cookie": cookie})
1630/*
1631 device := flowStatus.Device
1632 priority := subFlow.Priority
1633 isIgmp := false
1634 var devSerialNum string
1635 var service *VoltService
1636
1637 if subFlow.Match.L4Protocol == of.IPProtocolIgmp {
1638 isIgmp = true
1639 } else if priority != of.HsiaFlowPriority {
1640 logger.Info(ctx, "Not HSIA flow, ignoring the failure notification")
1641 return
1642 }
1643
1644 cookie := subFlow.Cookie
1645 pbit := subFlow.Pbits
1646 uniPort := cookie >> 16 & 0xFFFFFFFF
1647 portName, _ := GetApplication().GetPortName(uint32(uniPort))
1648 portState := msgbus.PortDown
1649 logger.Errorw(ctx, "Construct Flow Failure Notification", log.Fields{"uniPort": uniPort, "Cookie": cookie, "Pbit": pbit, "isIgmp": isIgmp})
1650
1651 if isIgmp {
1652 cvlan := subFlow.TableMetadata & 0xFFFF
1653 service = GetApplication().GetMatchingMcastService(portName, device, of.VlanType(cvlan))
1654 } else {
1655 service = GetApplication().GetServiceNameFromCookie(cookie, portName, uint8(pbit), device, subFlow.TableMetadata)
1656 }
1657 var trigger infra.Reason
1658 if nil != service {
1659 logger.Errorw(ctx, "Sending Flow Failure Notification", log.Fields{"uniPort": uniPort, "Cookie": cookie, "Pbit": pbit, "Service": service.Name, "ErrorCode": flowStatus.Status})
1660 if vd := GetApplication().GetDevice(device); vd != nil {
1661 devSerialNum = vd.SerialNum
1662 if portSt, _ := GetApplication().GetPortState(service.Port); portSt == PortStateUp {
1663 portState = msgbus.PortUp
1664 }
1665 trigger = service.getSrvDeactTrigger(vd, portState)
1666 }
1667 msgbus.PostAccessConfigInd(msgbus.Failed, devSerialNum, msgbus.HSIA, service.Name, int(flowStatus.Status), subFlow.ErrorReason, trigger, portState)
1668 }
1669*/
1670}
1671
1672//UpdateMvlanProfilesForDevice to update mvlan profile for device
1673func (va *VoltApplication) UpdateMvlanProfilesForDevice(device string) {
1674
1675 checkAndAddMvlanUpdateTask := func(key, value interface{}) bool {
1676 mvp := value.(*MvlanProfile)
1677 if mvp.IsUpdateInProgressForDevice(device) {
1678 mvp.UpdateProfile(device)
1679 }
1680 return true
1681 }
1682 va.MvlanProfilesByName.Range(checkAndAddMvlanUpdateTask)
1683}
1684
1685// TaskInfo structure that is used to store the task Info.
1686type TaskInfo struct {
1687 ID string
1688 Name string
1689 Timestamp string
1690}
1691
1692// GetTaskList to get task list information.
1693func (va *VoltApplication) GetTaskList(device string) map[int]*TaskInfo {
1694 taskList := cntlr.GetController().GetTaskList(device)
1695 taskMap := make(map[int]*TaskInfo)
1696 for i, task := range taskList {
1697 taskID := strconv.Itoa(int(task.TaskID()))
1698 name := task.Name()
1699 timestamp := task.Timestamp()
1700 taskInfo := &TaskInfo{ID: taskID, Name: name, Timestamp: timestamp}
1701 taskMap[i] = taskInfo
1702 }
1703 return taskMap
1704}
1705
1706// UpdateDeviceSerialNumberList to update the device serial number list after device serial number is updated for vnet and mvlan
1707func (va *VoltApplication) UpdateDeviceSerialNumberList(oldOltSlNo string, newOltSlNo string) {
1708
1709 voltDevice := va.GetDeviceBySerialNo(oldOltSlNo)
1710
1711 if voltDevice != nil {
1712 // Device is present with old serial number ID
1713 logger.Errorw(ctx, "OLT Migration cannot be completed as there are dangling devices", log.Fields{"Serial Number": oldOltSlNo})
1714
1715 } else {
1716 logger.Infow(ctx, "No device present with old serial number", log.Fields{"Serial Number": oldOltSlNo})
1717
1718 // Add Serial Number to Blocked Devices List.
1719 cntlr.GetController().AddBlockedDevices(oldOltSlNo)
1720 cntlr.GetController().AddBlockedDevices(newOltSlNo)
1721
1722 updateSlNoForVnet := func(key, value interface{}) bool {
1723 vnet := value.(*VoltVnet)
1724 for i, deviceSlNo := range vnet.VnetConfig.DevicesList {
1725 if deviceSlNo == oldOltSlNo {
1726 vnet.VnetConfig.DevicesList[i] = newOltSlNo
1727 logger.Infow(ctx, "device serial number updated for vnet profile", log.Fields{"Updated Serial Number": deviceSlNo, "Previous Serial Number": oldOltSlNo})
1728 break
1729 }
1730 }
1731 return true
1732 }
1733
1734 updateSlNoforMvlan := func(key interface{}, value interface{}) bool {
1735 mvProfile := value.(*MvlanProfile)
1736 for deviceSlNo := range mvProfile.DevicesList {
1737 if deviceSlNo == oldOltSlNo {
1738 mvProfile.DevicesList[newOltSlNo] = mvProfile.DevicesList[oldOltSlNo]
1739 delete(mvProfile.DevicesList, oldOltSlNo)
1740 logger.Infow(ctx, "device serial number updated for mvlan profile", log.Fields{"Updated Serial Number": deviceSlNo, "Previous Serial Number": oldOltSlNo})
1741 break
1742 }
1743 }
1744 return true
1745 }
1746
1747 va.VnetsByName.Range(updateSlNoForVnet)
1748 va.MvlanProfilesByName.Range(updateSlNoforMvlan)
1749
1750 // Clear the serial number from Blocked Devices List
1751 cntlr.GetController().DelBlockedDevices(oldOltSlNo)
1752 cntlr.GetController().DelBlockedDevices(newOltSlNo)
1753
1754 }
1755}
1756
1757// GetVpvsForDsPkt to get vpv for downstream packets
1758func (va *VoltApplication) GetVpvsForDsPkt(cvlan of.VlanType, svlan of.VlanType, clientMAC net.HardwareAddr,
1759 pbit uint8) ([]*VoltPortVnet, error) {
1760
1761 var matchVPVs []*VoltPortVnet
1762 findVpv := func(key, value interface{}) bool {
1763 vpvs := value.([]*VoltPortVnet)
1764 for _, vpv := range vpvs {
1765 if vpv.isVlanMatching(cvlan, svlan) && vpv.MatchesPriority(pbit) != nil {
1766 var subMac net.HardwareAddr
1767 if NonZeroMacAddress(vpv.MacAddr) {
1768 subMac = vpv.MacAddr
1769 } else if vpv.LearntMacAddr != nil && NonZeroMacAddress(vpv.LearntMacAddr) {
1770 subMac = vpv.LearntMacAddr
1771 } else {
1772 matchVPVs = append(matchVPVs, vpv)
1773 continue
1774 }
1775 if util.MacAddrsMatch(subMac, clientMAC) {
1776 matchVPVs = append([]*VoltPortVnet{}, vpv)
1777 logger.Infow(ctx, "Matching VPV found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "MAC": clientMAC})
1778 return false
1779 }
1780 }
1781 }
1782 return true
1783 }
1784 va.VnetsByPort.Range(findVpv)
1785
1786 if len(matchVPVs) != 1 {
1787 logger.Infow(ctx, "No matching VPV found or multiple vpvs found", log.Fields{"Match VPVs": matchVPVs, "MAC": clientMAC})
1788 return nil, errors.New("No matching VPV found or multiple vpvs found")
1789 }
1790 return matchVPVs, nil
1791}
1792
1793// GetMacInPortMap to get PORT value based on MAC key
1794func (va *VoltApplication) GetMacInPortMap(macAddr net.HardwareAddr) string {
1795 if NonZeroMacAddress(macAddr) {
1796 va.macPortLock.Lock()
1797 defer va.macPortLock.Unlock()
1798 if port, ok := va.macPortMap[macAddr.String()]; ok {
1799 logger.Debugw(ctx, "found-entry-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
1800 return port
1801 }
1802 }
1803 logger.Infow(ctx, "entry-not-found-macportmap", log.Fields{"MacAddr": macAddr.String()})
1804 return ""
1805}
1806
1807// UpdateMacInPortMap to update MAC PORT (key value) information in MacPortMap
1808func (va *VoltApplication) UpdateMacInPortMap(macAddr net.HardwareAddr, port string) {
1809 if NonZeroMacAddress(macAddr) {
1810 va.macPortLock.Lock()
1811 va.macPortMap[macAddr.String()] = port
1812 va.macPortLock.Unlock()
1813 logger.Debugw(ctx, "updated-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
1814 }
1815}
1816
1817// DeleteMacInPortMap to remove MAC key from MacPortMap
1818func (va *VoltApplication) DeleteMacInPortMap(macAddr net.HardwareAddr) {
1819 if NonZeroMacAddress(macAddr) {
1820 port := va.GetMacInPortMap(macAddr)
1821 va.macPortLock.Lock()
1822 delete(va.macPortMap, macAddr.String())
1823 va.macPortLock.Unlock()
1824 logger.Debugw(ctx, "deleted-from-macportmap", log.Fields{"MacAddr": macAddr.String(), "Port": port})
1825 }
1826}
1827
1828//AddGroupToPendingPool - adds the IgmpGroup with active group table entry to global pending pool
1829func (va *VoltApplication) AddGroupToPendingPool(ig *IgmpGroup) {
1830 var grpMap map[*IgmpGroup]bool
1831 var ok bool
1832
1833 va.PendingPoolLock.Lock()
1834 defer va.PendingPoolLock.Unlock()
1835
1836 logger.Infow(ctx, "Adding IgmpGroup to Global Pending Pool", log.Fields{"GroupID": ig.GroupID, "GroupName": ig.GroupName, "GroupAddr": ig.GroupAddr, "PendingDevices": len(ig.Devices)})
1837 // Do Not Reset any current profile info since group table entry tied to mvlan profile
1838 // The PonVlan is part of set field in group installed
1839 // Hence, Group created is always tied to the same mvlan profile until deleted
1840
1841 for device := range ig.Devices {
1842 key := getPendingPoolKey(ig.Mvlan, device)
1843
1844 if grpMap, ok = va.IgmpPendingPool[key]; !ok {
1845 grpMap = make(map[*IgmpGroup]bool)
1846 }
1847 grpMap[ig] = true
1848
1849 //Add grpObj reference to all associated devices
1850 va.IgmpPendingPool[key] = grpMap
1851 }
1852}
1853
1854//RemoveGroupFromPendingPool - removes the group from global pending group pool
1855func (va *VoltApplication) RemoveGroupFromPendingPool(device string, ig *IgmpGroup) bool {
1856 GetApplication().PendingPoolLock.Lock()
1857 defer GetApplication().PendingPoolLock.Unlock()
1858
1859 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)})
1860
1861 key := getPendingPoolKey(ig.Mvlan, device)
1862 if _, ok := va.IgmpPendingPool[key]; ok {
1863 delete(va.IgmpPendingPool[key], ig)
1864 return true
1865 }
1866 return false
1867}
1868
1869//RemoveGroupsFromPendingPool - removes the group from global pending group pool
1870func (va *VoltApplication) RemoveGroupsFromPendingPool(device string, mvlan of.VlanType) {
1871 GetApplication().PendingPoolLock.Lock()
1872 defer GetApplication().PendingPoolLock.Unlock()
1873
1874 logger.Infow(ctx, "Removing IgmpGroups from Global Pending Pool for given Deivce & Mvlan", log.Fields{"Device": device, "Mvlan": mvlan.String()})
1875
1876 key := getPendingPoolKey(mvlan, device)
1877 va.RemoveGroupListFromPendingPool(key)
1878}
1879
1880//RemoveGroupListFromPendingPool - removes the groups for provided key
1881// 1. Deletes the group from device
1882// 2. Delete the IgmpGroup obj and release the group ID to pool
1883// Note: Make sure to obtain PendingPoolLock lock before calling this func
1884func (va *VoltApplication) RemoveGroupListFromPendingPool(key string) {
1885 if grpMap, ok := va.IgmpPendingPool[key]; ok {
1886 delete(va.IgmpPendingPool, key)
1887 for ig := range grpMap {
1888 for device := range ig.Devices {
1889 ig.DeleteIgmpGroupDevice(device)
1890 }
1891 }
1892 }
1893}
1894
1895//RemoveGroupDevicesFromPendingPool - removes the group from global pending group pool
1896func (va *VoltApplication) RemoveGroupDevicesFromPendingPool(ig *IgmpGroup) {
1897
1898 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)})
1899 for device := range ig.PendingGroupForDevice {
1900 va.RemoveGroupFromPendingPool(device, ig)
1901 }
1902}
1903
1904//GetGroupFromPendingPool - Returns IgmpGroup obj from global pending pool
1905func (va *VoltApplication) GetGroupFromPendingPool(mvlan of.VlanType, device string) *IgmpGroup {
1906
1907 var ig *IgmpGroup
1908
1909 va.PendingPoolLock.Lock()
1910 defer va.PendingPoolLock.Unlock()
1911
1912 key := getPendingPoolKey(mvlan, device)
1913 logger.Infow(ctx, "Getting IgmpGroup from Global Pending Pool", log.Fields{"Device": device, "Mvlan": mvlan.String(), "Key": key})
1914
1915 //Gets all IgmpGrp Obj for the device
1916 grpMap, ok := va.IgmpPendingPool[key]
1917 if !ok || len(grpMap) == 0 {
1918 logger.Infow(ctx, "Matching IgmpGroup not found in Global Pending Pool", log.Fields{"Device": device, "Mvlan": mvlan.String()})
1919 return nil
1920 }
1921
1922 //Gets a random obj from available grps
1923 for ig = range grpMap {
1924
1925 //Remove grp obj reference from all devices associated in pending pool
1926 for dev := range ig.Devices {
1927 key := getPendingPoolKey(mvlan, dev)
1928 delete(va.IgmpPendingPool[key], ig)
1929 }
1930
1931 //Safety check to avoid re-allocating group already in use
1932 if ig.NumDevicesActive() == 0 {
1933 return ig
1934 }
1935
1936 //Iteration will continue only if IG is not allocated
1937 }
1938 return nil
1939}
1940
1941//RemovePendingGroups - removes all pending groups for provided reference from global pending pool
1942// reference - mvlan/device ID
1943// isRefDevice - true - Device as reference
1944// false - Mvlan as reference
1945func (va *VoltApplication) RemovePendingGroups(reference string, isRefDevice bool) {
1946 va.PendingPoolLock.Lock()
1947 defer va.PendingPoolLock.Unlock()
1948
1949 logger.Infow(ctx, "Removing IgmpGroups from Global Pending Pool", log.Fields{"Reference": reference, "isRefDevice": isRefDevice})
1950
1951 //Pending Pool key: "<mvlan>_<DeviceID>""
1952 paramPosition := 0
1953 if isRefDevice {
1954 paramPosition = 1
1955 }
1956
1957 // 1.Remove the Entry from pending pool
1958 // 2.Deletes the group from device
1959 // 3.Delete the IgmpGroup obj and release the group ID to pool
1960 for key := range va.IgmpPendingPool {
1961 keyParams := strings.Split(key, "_")
1962 if keyParams[paramPosition] == reference {
1963 va.RemoveGroupListFromPendingPool(key)
1964 }
1965 }
1966}
1967
1968func getPendingPoolKey(mvlan of.VlanType, device string) string {
1969 return mvlan.String() + "_" + device
1970}
1971
1972func (va *VoltApplication) removeExpiredGroups() {
1973 logger.Debug(ctx, "Check for expired Igmp Groups")
1974 removeExpiredGroups := func(key interface{}, value interface{}) bool {
1975 ig := value.(*IgmpGroup)
1976 ig.removeExpiredGroupFromDevice()
1977 return true
1978 }
1979 va.IgmpGroups.Range(removeExpiredGroups)
1980}
1981
1982//TriggerPendingProfileDeleteReq - trigger pending profile delete request
1983func (va *VoltApplication) TriggerPendingProfileDeleteReq(device string) {
1984 va.TriggerPendingServiceDeleteReq(device)
1985 va.TriggerPendingVpvDeleteReq(device)
1986 va.TriggerPendingVnetDeleteReq(device)
1987 logger.Warnw(ctx, "All Pending Profile Delete triggered for device", log.Fields{"Device": device})
1988}
1989
1990//TriggerPendingServiceDeleteReq - trigger pending service delete request
1991func (va *VoltApplication) TriggerPendingServiceDeleteReq(device string) {
1992
1993 logger.Warnw(ctx, "Pending Services to be deleted", log.Fields{"Count": len(va.ServicesToDelete)})
1994 for serviceName := range va.ServicesToDelete {
1995 logger.Debugw(ctx, "Trigger Service Delete", log.Fields{"Service": serviceName})
1996 if vs := va.GetService(serviceName); vs != nil {
1997 if vs.Device == device {
1998 logger.Warnw(ctx, "Triggering Pending Service delete", log.Fields{"Service": vs.Name})
1999 vs.DelHsiaFlows()
2000 if vs.ForceDelete {
2001 vs.DelFromDb()
2002 /*
2003 portState := msgbus.PortDown
2004 if d, err := va.GetDeviceFromPort(vs.Port); d != nil {
2005
2006 if portSt, _ := GetApplication().GetPortState(vs.Port); portSt == PortStateUp {
2007 portState = msgbus.PortUp
2008 }
2009 indTask := cntlr.NewAddServiceIndTask(vs.Name, d.SerialNum, msgbus.DelHSIA, msgbus.Success, "", portState, infra.DelHSIAFromNB)
2010 cntlr.GetController().PostIndication(d.Name, indTask)
2011 } else {
2012 // Port Not found can occur during ONU movement. However, port delete had already handled flow deletion,
2013 // hence indication can be sent immediately
2014 var devSrNo string
2015 logger.Errorw(ctx, "Device/Port not found. Send indication directly", log.Fields{"serviceName": vs.Name, "error": err})
2016 if vd := va.GetDevice(vs.Device); vd != nil {
2017 devSrNo = vd.SerialNum
2018 }
2019 msgbus.PostAccessConfigInd(msgbus.Success, devSrNo, msgbus.DelHSIA, vs.Name, 0, "", infra.DelHSIAFromNB, portState)
2020 }*/
2021 }
2022 }
2023 } else {
2024 logger.Errorw(ctx, "Pending Service Not found", log.Fields{"Service": serviceName})
2025 }
2026 }
2027}
2028
2029//TriggerPendingVpvDeleteReq - trigger pending VPV delete request
2030func (va *VoltApplication) TriggerPendingVpvDeleteReq(device string) {
2031
2032 logger.Warnw(ctx, "Pending VPVs to be deleted", log.Fields{"Count": len(va.VoltPortVnetsToDelete)})
2033 for vpv := range va.VoltPortVnetsToDelete {
2034 if vpv.Device == device {
2035 logger.Warnw(ctx, "Triggering Pending VPv flow delete", log.Fields{"Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
2036 va.DelVnetFromPort(vpv.Port, vpv)
2037 }
2038 }
2039}
2040
2041//TriggerPendingVnetDeleteReq - trigger pending vnet delete request
2042func (va *VoltApplication) TriggerPendingVnetDeleteReq(device string) {
2043
2044 logger.Warnw(ctx, "Pending Vnets to be deleted", log.Fields{"Count": len(va.VnetsToDelete)})
2045 for vnetName := range va.VnetsToDelete {
2046 if vnetIntf, _ := va.VnetsByName.Load(vnetName); vnetIntf != nil {
2047 vnet := vnetIntf.(*VoltVnet)
2048 logger.Warnw(ctx, "Triggering Pending Vnet flows delete", log.Fields{"Vnet": vnet.Name})
2049 if d := va.GetDeviceBySerialNo(vnet.PendingDeviceToDelete); d != nil && d.SerialNum == vnet.PendingDeviceToDelete {
2050 va.DeleteDevFlowForVlanFromDevice(vnet, vnet.PendingDeviceToDelete)
2051 va.deleteVnetConfig(vnet)
2052 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302053 logger.Warnw(ctx, "Vnet Delete Failed : Device Not Found", log.Fields{"Vnet": vnet.Name, "Device": vnet.PendingDeviceToDelete})
Naveen Sampath04696f72022-06-13 15:19:14 +05302054 }
2055 }
2056 }
2057}