blob: dffbb008dbbaa2318a14836ba4b1a0226d3289da [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 "encoding/json"
20 "errors"
Tinoj Joseph07cc5372022-07-18 22:53:51 +053021 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053022 "net"
23 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
24 "strconv"
25 "sync"
26 "time"
27
28 "github.com/google/gopacket"
29 "github.com/google/gopacket/layers"
30 "go.uber.org/atomic"
31
32 "voltha-go-controller/internal/pkg/controller"
33 cntlr "voltha-go-controller/internal/pkg/controller"
34 "voltha-go-controller/database"
35 "voltha-go-controller/internal/pkg/of"
36 "voltha-go-controller/internal/pkg/util"
37 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Tinoj Joseph1d108322022-07-13 10:07:39 +053038 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053039)
40
41const (
42 // ICMPv6ArpGroupID constant
43 ICMPv6ArpGroupID uint32 = 1
44
45 // Radisys vendor id constant
46 Radisys string = "Radisys"
47)
48
49var (
50 //BroadcastMAC - Broadcast MAC Address
51 BroadcastMAC, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")
52)
53
54// NonZeroMacAddress utility to identify if the MAC address is non-zero.
55// We use zero MAC address as an unset MAC address
56func NonZeroMacAddress(h net.HardwareAddr) bool {
57 for i := 0; i < 6; i++ {
58 if h[i] != 0 {
59 return true
60 }
61 }
62 return false
63}
64
65// VNET package manages the different virtual networks that are part of the
66// the network. In the case of VOLT, the networks can be single tagged or
67// double tagged networks. In addition, the networks may be used for unicast
68// and multicast traffic. The unicast traffic further has two models, the
69// 1:1 and N:1 model. In case of a 1:1 model, the outer tag is same for many
70// subscribers and the inner tag is unique to each subscriber for the same
71// outer tag. The N:1 uses the same inner and outer tags, or for that matter
72// a single tag that can also be shared by subscribers. The VNET implementation
73// manages all these possibilities and the associated configuration.
74
75const (
76 // PbitMatchNone constant
77 PbitMatchNone of.PbitType = 8
78 // PbitMatchAll constant
79 PbitMatchAll of.PbitType = 0xFF
80)
81
82// SVlan - Value of the outer tag if double tagged or the only tag if single
83// tagged
84// SVlanTpid - SVlan Tag Protocol Identifier
85// CVlan - Value of the inner tag. Set to VlanNone if single tagged
86// DhcpRelay - Set to true if the DHCP relay is enabled on the virtual network
87// MacLearning - Set to true if the flows should include MAC address
88// UsDhcpPbit - The pbit used for US DHCP packets
89// DsDhcpPbit - The pbit used for DS DHCP packets
90
91// VnetConfig structure
92type VnetConfig struct {
93 Name string
94 SVlan of.VlanType
95 CVlan of.VlanType
96 UniVlan of.VlanType
97 SVlanTpid layers.EthernetType
98 DhcpRelay bool
99 ArpLearning bool
100 MacLearning MacLearningType
101 PppoeIa bool
102 ONTEtherTypeClassification int
103 VlanControl VlanControl
104 Encapsulation string
105 UsDhcpPbit []of.PbitType
106 DsDhcpPbit []of.PbitType
107 UsIGMPPbit []of.PbitType
108 DsIGMPPbit []of.PbitType
109 DevicesList []string //List of serial number of devices on which this vnet is applied
110 AllowTransparent bool
111 CtrlPktPbitRemark map[of.PbitType]of.PbitType
112}
113
114// VnetOper structure
115type VnetOper struct {
116 PendingDeleteFlow map[string]map[string]bool
117 DeleteInProgress bool
118 PendingDeviceToDelete string
119 VnetLock sync.RWMutex `json:"-"`
120 VnetPortLock sync.RWMutex `json:"-"`
121 AssociatedPorts map[string]bool `json:"-"`
122}
123
124// VoltVnet sructure
125type VoltVnet struct {
126 VnetConfig
127 VnetOper
128 Version string
129}
130
131const (
132 // EncapsulationPPPoEIA constant
133 EncapsulationPPPoEIA string = "PPPoE-IA"
134 // EncapsulationPPPoE constant
135 EncapsulationPPPoE string = "PPPoE"
136 // EncapsulationIPoE constant
137 EncapsulationIPoE string = "IPoE"
138)
139
140// NewVoltVnet is constructor for the VNET structure
141func NewVoltVnet(cfg VnetConfig) *VoltVnet {
142 var vv VoltVnet
143 vv.VnetConfig = cfg
144 if vv.PendingDeleteFlow == nil {
145 vv.PendingDeleteFlow = make(map[string]map[string]bool)
146 }
147 vv.DeleteInProgress = false
148 if cfg.Encapsulation == EncapsulationPPPoEIA {
149 vv.PppoeIa = true
150 }
151 vv.AssociatedPorts = make(map[string]bool)
152 return &vv
153}
154
155//associatePortToVnet - associate a port to Vnet
156func (vv *VoltVnet) associatePortToVnet(port string) {
157 vv.VnetPortLock.Lock()
158 if vv.AssociatedPorts == nil {
159 vv.AssociatedPorts = make(map[string]bool)
160 }
161 vv.AssociatedPorts[port] = true
162 vv.VnetPortLock.Unlock()
163}
164
165//disassociatePortFromVnet - disassociate a port from Vnet and return true if the association map is empty
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530166func (vv *VoltVnet) disassociatePortFromVnet(cntx context.Context, device string, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530167 vv.VnetPortLock.Lock()
168 delete(vv.AssociatedPorts, port)
169 logger.Infow(ctx, "Disassociated Port from Vnet", log.Fields{"Device": device, "Port": port, "Vnet": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow, "AssociatedPorts": vv.AssociatedPorts, "DeleteFlag": vv.DeleteInProgress})
170 vv.VnetPortLock.Unlock()
171
172 if vv.DeleteInProgress {
173 if !vv.isAssociatedPortsPresent() {
174 if len(vv.PendingDeleteFlow[device]) == 0 {
175 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vv.Name})
176 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530177 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530178 } else {
179 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow})
180 }
181 } else {
182 vv.VnetPortLock.RLock()
183 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts})
184 vv.VnetPortLock.RUnlock()
185 }
186 }
187}
188
189func (vv *VoltVnet) isAssociatedPortsPresent() bool {
190 vv.VnetPortLock.RLock()
191 defer vv.VnetPortLock.RUnlock()
192 return len(vv.AssociatedPorts) != 0
193}
194
195// WriteToDb commit the VNET to the database
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530196func (vv *VoltVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530197
198 if vv.DeleteInProgress {
199 logger.Warnw(ctx, "Skipping Redis Update for Vnet, Vnet delete in progress", log.Fields{"Vnet": vv.Name})
200 return
201 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530202 vv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530203}
204
205//ForceWriteToDb force commit a vnet to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530206func (vv *VoltVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530207 vv.VnetPortLock.RLock()
208 defer vv.VnetPortLock.RUnlock()
209 vv.Version = database.PresentVersionMap[database.VnetPath]
210 logger.Debugw(ctx, "Updating VNET....", log.Fields{"vnet": vv})
211 if b, err := json.Marshal(vv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530212 if err:= db.PutVnet(cntx, vv.Name, string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530213 logger.Warnw(ctx, "Add Vnet to DB failed", log.Fields{"vnet name": vv.Name, "Error": err})
214 }
215 }
216}
217
218// VnetKey creates the key using the two VLAN tags
219// We append the two VLAN tags to create a single key
220func VnetKey(otag of.VlanType, itag of.VlanType, utag of.VlanType) string {
221 return strconv.Itoa(int(otag)) + "-" + strconv.Itoa(int(itag)) + "-" + strconv.Itoa(int(utag))
222}
223
224// GetVnet get VNET configuration related functionality associated with VOLT application
225func (va *VoltApplication) GetVnet(otag of.VlanType, itag of.VlanType, utag of.VlanType) *VoltVnet {
226 // When matching VNET, it is expected to match first just the outer
227 // tag, and then the combination to make sure there is no conflict
228 // for the new configuration.
229 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, of.VlanNone, utag)); ok {
230 return vnet.(*VoltVnet)
231 }
232 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, itag, utag)); ok {
233 return vnet.(*VoltVnet)
234 }
235 return nil
236}
237
238// The VNET may also be assigned name for easier references. For now,
239// the VNET is mainly identified by the two VLANs.
240
241// GetVnetByName to get vnet by name
242func (va *VoltApplication) GetVnetByName(name string) *VoltVnet {
243 if vnet, ok := va.VnetsByName.Load(name); ok {
244 return vnet.(*VoltVnet)
245 }
246 return nil
247}
248
249// storeVnetConfig to store vnet config
250func (va *VoltApplication) storeVnetConfig(cfg VnetConfig, vv *VoltVnet) {
251
252 var vnetMap *util.ConcurrentMap
253
254 va.VnetsByTag.Store(VnetKey(cfg.SVlan, cfg.CVlan, cfg.UniVlan), vv)
255 va.VnetsByName.Store(cfg.Name, vv)
256
257 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vv.SVlan); !ok {
258 vnetMap = util.NewConcurrentMap()
259 } else {
260 vnetMap = vnetMapIntf.(*util.ConcurrentMap)
261 }
262 vnetMap.Set(vv, true)
263 va.VnetsBySvlan.Set(vv.SVlan, vnetMap)
264}
265
266// deleteVnetConfig to delete vnet config
267func (va *VoltApplication) deleteVnetConfig(vnet *VoltVnet) {
268 va.VnetsByTag.Delete(VnetKey(vnet.SVlan, vnet.CVlan, vnet.UniVlan))
269 va.VnetsByName.Delete(vnet.Name)
270
271 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vnet.SVlan); ok {
272 vnetMap := vnetMapIntf.(*util.ConcurrentMap)
273 vnetMap.Remove(vnet)
274 va.VnetsBySvlan.Set(vnet.SVlan, vnetMap)
275 }
276}
277
278// AddVnet to add a VNET to the list of VNETs configured.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530279func (va *VoltApplication) AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530280
281 AppMutex.VnetMutex.Lock()
282 var vv *VoltVnet
283 devicesToHandle := []string{}
284 vv = va.GetVnetByName(cfg.Name)
285 if vv != nil {
286 //Could be for another OLT or could be case of backup-restore
287 for _, serialNum := range cfg.DevicesList {
288 if isDeviceInList(serialNum, vv.DevicesList) {
289 //This is backup restore scenario, just update the profile
290 logger.Info(ctx, "Add Vnet : Profile Name already exists with OLT, update-the-profile")
291 continue
292 }
293 devicesToHandle = append(devicesToHandle, serialNum)
294 }
295 if len(devicesToHandle) == 0 {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530296 logger.Debugw(ctx, "Ignoring Duplicate VNET by name ", log.Fields{"Vnet": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530297 AppMutex.VnetMutex.Unlock()
298 return nil
299 }
300 }
301
302 if vv == nil {
303 vv = NewVoltVnet(cfg)
304 if oper != nil {
305 vv.PendingDeleteFlow = oper.PendingDeleteFlow
306 vv.DeleteInProgress = oper.DeleteInProgress
307 vv.AssociatedPorts = oper.AssociatedPorts
308 vv.PendingDeviceToDelete = oper.PendingDeviceToDelete
309 }
310 devicesToHandle = append(devicesToHandle, cfg.DevicesList...)
311 } else {
312 vv.DevicesList = append(vv.DevicesList, devicesToHandle...)
313 }
314
315 va.storeVnetConfig(cfg, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530316 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530317
318 logger.Infow(ctx, "Added VNET TO DB", log.Fields{"cfg": cfg, "devicesToHandle": devicesToHandle})
319
320 //va.PushDevFlowForVlan(vv)
321 AppMutex.VnetMutex.Unlock()
322 return nil
323}
324
325// DelVnet to delete a VNET from the list of VNETs configured
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530326func (va *VoltApplication) DelVnet(cntx context.Context, name, deviceSerialNum string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530327 logger.Infow(ctx, "Deleting Vnet", log.Fields{"Vnet": name})
328 AppMutex.VnetMutex.Lock()
329 if vnetIntf, ok := va.VnetsByName.Load(name); ok {
330 vnet := vnetIntf.(*VoltVnet)
331 //Delete from mvp list
332 vnet.DevicesList = util.RemoveFromSlice(vnet.DevicesList, deviceSerialNum)
333
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530334 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, deviceSerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +0530335 if len(vnet.DevicesList) == 0 {
336 vnet.DeleteInProgress = true
337 vnet.PendingDeviceToDelete = deviceSerialNum
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530338 vnet.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530339 vnet.VnetPortLock.RLock()
340 if len(vnet.PendingDeleteFlow) == 0 && !vnet.isAssociatedPortsPresent() {
341 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
342 va.deleteVnetConfig(vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530343 _ = db.DelVnet(cntx, vnet.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530344 } else {
345 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
346 }
347 vnet.VnetPortLock.RUnlock()
348 } else {
349 //Update the devicelist in db
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530350 vnet.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530351 }
352 }
353 //TODO: if no vnets are present on device remove icmpv6 group from device
354 AppMutex.VnetMutex.Unlock()
355 return nil
356}
357
358// UpdateVnet to update the VNET with associated service count
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530359func (va *VoltApplication) UpdateVnet(cntx context.Context, vv *VoltVnet) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530360 va.storeVnetConfig(vv.VnetConfig, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530361 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530362 logger.Infow(ctx, "Updated VNET TO DB", log.Fields{"vv": vv.VnetConfig})
363 return nil
364}
365
366// ------------------------------------------------------------
367// Manifestation of a VNET on a port is handled below
368// ------------------------------------------------------------
369//
370// The VNET on a port handles everything that is done for a VNET
371// such as DHCP relay state machine, MAC addresses, IP addresses
372// learnt, so on.
373
374// DhcpStatus type
375type DhcpStatus uint8
376
377const (
378 // DhcpStatusNone constant
379 DhcpStatusNone DhcpStatus = 0
380 // DhcpStatusAcked constant
381 DhcpStatusAcked DhcpStatus = 1
382 // DhcpStatusNacked constant
383 DhcpStatusNacked DhcpStatus = 2
384 // EthTypeNone constant
385 EthTypeNone int = 0
386 // EthTypeIPoE constant
387 EthTypeIPoE int = 1
388 // EthTypePPPoE constant
389 EthTypePPPoE int = 2
390)
391
392// VoltPortVnet structure
393type VoltPortVnet struct {
394 Device string
395 Port string
396 PonPort uint32
397 VnetName string
398 SVlan of.VlanType
399 CVlan of.VlanType
400 UniVlan of.VlanType
401 SVlanTpid layers.EthernetType
402 DhcpRelay bool
403 ArpRelay bool
404 PppoeIa bool
405 MacLearning MacLearningType
406 DhcpStatus DhcpStatus
407 DhcpExpiryTime time.Time
408 Dhcp6ExpiryTime time.Time
409 FlowsApplied bool
410 services sync.Map
411 servicesCount *atomic.Uint64
412 Ipv4Addr net.IP
413 Ipv6Addr net.IP
414 MacAddr net.HardwareAddr
415 LearntMacAddr net.HardwareAddr
416 CircuitID []byte //Will not be used
417 RemoteID []byte //Will not be used
418 IsOption82Disabled bool //Will not be used
419 RelayState DhcpRelayState
420 PPPoeState PppoeIaState
421 RelayStatev6 Dhcpv6RelayState
422 IgmpEnabled bool
423 IgmpFlowsApplied bool
424 McastService bool
425 ONTEtherTypeClassification int
426 VlanControl VlanControl
427 MvlanProfileName string
428 Version string
429 McastTechProfileID uint16
430 McastPbit of.PbitType
431 McastUsMeterID uint32
432 AllowTransparent bool
433 VpvLock sync.Mutex `json:"-"`
434 SchedID int
435 DHCPv6DUID [MaxLenDhcpv6DUID]byte
436 PendingFlowLock sync.RWMutex `json:"-"`
437 PendingDeleteFlow map[string]bool
438 DeleteInProgress bool
439 Blocked bool
440 DhcpPbit of.PbitType
441}
442
443//VlanControl vlan control type
444type VlanControl uint8
445
446const (
447 // None constant
448 // ONU and OLT will passthrough UNIVLAN as is to BNG
449 None VlanControl = iota
450
451 // ONUCVlanOLTSVlan constant
452 // Tagged traffic, ONU will replace UNIVLAN with CVLAN and OLT will add SVLAN
453 // Untagged traffic, ONU will add CVLAN and OLT will add SVLAN
454 ONUCVlanOLTSVlan
455
456 // OLTCVlanOLTSVlan constant
457 // Tagged traffic, ONU will passthrough UNIVLAN as is to OLT and
458 // OLT will replace UNIVLAN with CVLAN and add SVLAN
459 OLTCVlanOLTSVlan
460
461 // ONUCVlan constant
462 // Tagged traffic, ONU will replace UNIVLAN with CVLAN
463 // Untagged traffic, ONU will add CVLAN
464 ONUCVlan
465
466 // OLTSVlan constant
467 // UnTagged traffic, OLT will add the SVLAN
468 OLTSVlan
469)
470
471// NewVoltPortVnet is constructor for VoltPortVnet
472func NewVoltPortVnet(vnet *VoltVnet) *VoltPortVnet {
473 var vpv VoltPortVnet
474
475 vpv.VnetName = vnet.Name
476 vpv.SVlan = vnet.SVlan
477 vpv.CVlan = vnet.CVlan
478 vpv.UniVlan = vnet.UniVlan
479 vpv.SVlanTpid = vnet.SVlanTpid
480 vpv.DhcpRelay = vnet.DhcpRelay
481 vpv.DhcpStatus = DhcpStatusNone
482 vpv.PPPoeState = PppoeIaStateNone
483 vpv.ArpRelay = vnet.ArpLearning
484 vpv.PppoeIa = vnet.PppoeIa
485 vpv.VlanControl = vnet.VlanControl
486 vpv.ONTEtherTypeClassification = vnet.ONTEtherTypeClassification
487 vpv.AllowTransparent = vnet.AllowTransparent
488 vpv.FlowsApplied = false
489 vpv.IgmpEnabled = false
490 vpv.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
491 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
492 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
493 if vpv.VlanControl == ONUCVlan {
494 vpv.CVlan = vpv.SVlan
495 }
496 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
497 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
498 if vpv.VlanControl == OLTSVlan {
499 vpv.CVlan = vpv.UniVlan
500 }
501 vpv.servicesCount = atomic.NewUint64(0)
502 vpv.SchedID = 0
503 vpv.PendingDeleteFlow = make(map[string]bool)
504 vpv.DhcpPbit = vnet.UsDhcpPbit[0]
505 return &vpv
506}
507
508func (vpv *VoltPortVnet) setDevice(device string) {
509
510 if vpv.Device != device && vpv.Device != "" {
511 GetApplication().DisassociateVpvsFromDevice(device, vpv)
512 //TEMP:
513 vpv.printAssociatedVPVs(false)
514 }
515
Tinoj Josephec742f62022-09-29 19:11:10 +0530516 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": device, "Port": vpv.Port, "SVlan": vpv.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530517
518 vpv.Device = device
519 GetApplication().AssociateVpvsToDevice(device, vpv)
520 //TEMP:
521 vpv.printAssociatedVPVs(true)
522}
523
524//TODO - Nav - Temp
525func (vpv *VoltPortVnet) printAssociatedVPVs(add bool) {
526 logger.Infow(ctx, "Start----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
527 if vMap := GetApplication().GetAssociatedVpvsForDevice(vpv.Device, vpv.SVlan); vMap != nil {
528 vMap.Range(func(key, value interface{}) bool {
529 vpvEntry := key.(*VoltPortVnet)
530 logger.Infow(ctx, "Associated VPVs", log.Fields{"SVlan": vpvEntry.SVlan, "CVlan": vpvEntry.CVlan, "UniVlan": vpvEntry.UniVlan})
531 return true
532 })
533 }
534 logger.Infow(ctx, "End----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
535
536}
537
538// GetCircuitID : The interface to be satisfied by the VoltPortVnet to be a DHCP relay
539// session is implemented below. The main functions still remain in
540// the service.go file.
541func (vpv *VoltPortVnet) GetCircuitID() []byte {
542 return []byte(vpv.CircuitID)
543}
544
545// GetRemoteID to get remote id
546func (vpv *VoltPortVnet) GetRemoteID() []byte {
547 return []byte(vpv.RemoteID)
548}
549
550// GetDhcpState to get dhcp state
551func (vpv *VoltPortVnet) GetDhcpState() DhcpRelayState {
552 return vpv.RelayState
553}
554
555// SetDhcpState to set the dhcp state
556func (vpv *VoltPortVnet) SetDhcpState(state DhcpRelayState) {
557 vpv.RelayState = state
558}
559
560// GetPppoeIaState to get pppoeia state
561func (vpv *VoltPortVnet) GetPppoeIaState() PppoeIaState {
562 return vpv.PPPoeState
563}
564
565// SetPppoeIaState to set pppoeia state
566func (vpv *VoltPortVnet) SetPppoeIaState(state PppoeIaState) {
567 vpv.PPPoeState = state
568}
569
570// GetDhcpv6State to get dhcpv6 state
571func (vpv *VoltPortVnet) GetDhcpv6State() Dhcpv6RelayState {
572 return vpv.RelayStatev6
573}
574
575// SetDhcpv6State to set dhcpv6 state
576func (vpv *VoltPortVnet) SetDhcpv6State(state Dhcpv6RelayState) {
577 vpv.RelayStatev6 = state
578}
579
580// DhcpResultInd for dhcp result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530581func (vpv *VoltPortVnet) DhcpResultInd(cntx context.Context, res *layers.DHCPv4) {
582 vpv.ProcessDhcpResult(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530583}
584
585// Dhcpv6ResultInd for dhcpv6 result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530586func (vpv *VoltPortVnet) Dhcpv6ResultInd(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
587 vpv.ProcessDhcpv6Result(cntx, ipv6Addr, leaseTime)
Naveen Sampath04696f72022-06-13 15:19:14 +0530588}
589
590// GetNniVlans to get nni vlans
591func (vpv *VoltPortVnet) GetNniVlans() (uint16, uint16) {
592 switch vpv.VlanControl {
593 case ONUCVlanOLTSVlan,
594 OLTCVlanOLTSVlan:
595 return uint16(vpv.SVlan), uint16(vpv.CVlan)
596 case ONUCVlan,
597 None:
598 return uint16(vpv.SVlan), uint16(of.VlanNone)
599 case OLTSVlan:
600 return uint16(vpv.SVlan), uint16(of.VlanNone)
601 }
602 return uint16(of.VlanNone), uint16(of.VlanNone)
603}
604
605// GetService to get service
606func (vpv *VoltPortVnet) GetService(name string) (*VoltService, bool) {
607 service, ok := vpv.services.Load(name)
608 if ok {
609 return service.(*VoltService), ok
610 }
611 return nil, ok
612}
613
614// AddService to add service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530615func (vpv *VoltPortVnet) AddService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530616 vpv.services.Store(service.Name, service)
617 vpv.servicesCount.Inc()
618 logger.Infow(ctx, "Service added/updated to VPV", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "Service": service.Name, "Count": vpv.servicesCount.Load()})
619}
620
621// DelService to delete service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530622func (vpv *VoltPortVnet) DelService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530623 vpv.services.Delete(service.Name)
624 vpv.servicesCount.Dec()
625
626 // If the only Igmp Enabled service is removed, remove the Igmp trap flow along with it
627 if service.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530628 if err := vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530629 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
630 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
631 }
632
633 vpv.IgmpEnabled = false
634 }
635 logger.Infow(ctx, "Service deleted from VPV", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "Service": service.Name, "Count": vpv.servicesCount.Load()})
636}
637
638// ProcessDhcpResult to process dhcp results
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530639func (vpv *VoltPortVnet) ProcessDhcpResult(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530640 msgType := DhcpMsgType(res)
641 if msgType == layers.DHCPMsgTypeAck {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530642 vpv.ProcessDhcpSuccess(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530643 } else if msgType == layers.DHCPMsgTypeNak {
644 vpv.DhcpStatus = DhcpStatusNacked
645 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530646 vpv.WriteToDb(cntx)
647}
648
649// RangeOnServices to call a function on all services on the vpv
650func (vpv *VoltPortVnet) RangeOnServices(cntx context.Context, callback func(cntx context.Context, key, value interface{}) bool) {
651 vpv.services.Range(func(key, value interface{}) bool {
652 return callback(cntx, key, value)
653 })
Naveen Sampath04696f72022-06-13 15:19:14 +0530654}
655
656// ProcessDhcpSuccess : Learn the IPv4 address allocated to the services and update the
657// the services with the same. This also calls for adding flows
658// for the services as the DHCP procedure is completed
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530659func (vpv *VoltPortVnet) ProcessDhcpSuccess(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530660 vpv.DhcpStatus = DhcpStatusAcked
661 vpv.Ipv4Addr, _ = GetIpv4Addr(res)
662 logger.Infow(ctx, "Received IPv4 Address", log.Fields{"IP Address": vpv.Ipv4Addr.String()})
663 logger.Infow(ctx, "Services Configured", log.Fields{"Count": vpv.servicesCount.Load()})
664
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530665 vpv.RangeOnServices(cntx, vpv.updateIPv4AndProvisionFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530666 vpv.ProcessDhcpv4Options(res)
667}
668
669// ProcessDhcpv4Options : Currently we process lease time and store the validity of the
670// IP address allocated.
671func (vpv *VoltPortVnet) ProcessDhcpv4Options(res *layers.DHCPv4) {
672 for _, o := range res.Options {
673 switch o.Type {
674 case layers.DHCPOptLeaseTime:
675 leasetime := GetIPv4LeaseTime(o)
676 vpv.DhcpExpiryTime = time.Now().Add((time.Duration(leasetime) * time.Second))
677 logger.Infow(ctx, "Lease Expiry Set", log.Fields{"Time": vpv.DhcpExpiryTime})
678 }
679 }
680}
681
682// ProcessDhcpv6Result : Read the IPv6 address allocated to the device and store it on the
683// VNET. The same IPv6 address is also passed to the services. When a
684// service is fetched all the associated information such as MAC address,
685// IPv4 address and IPv6 addresses can be provided.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530686func (vpv *VoltPortVnet) ProcessDhcpv6Result(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530687 // TODO: Status based hanlding of flows
688 vpv.Dhcp6ExpiryTime = time.Now().Add((time.Duration(leaseTime) * time.Second))
689 vpv.Ipv6Addr = ipv6Addr
690
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530691 vpv.RangeOnServices(cntx, vpv.updateIPv6AndProvisionFlows)
692 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530693}
694
695// AddSvcUsMeterToDevice to add service upstream meter info to device
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530696func AddSvcUsMeterToDevice(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +0530697 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +0530698 logger.Infow(ctx, "Adding upstream meter profile to device", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530699 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
700 GetApplication().AddMeterToDevice(svc.Port, device.Name, svc.UsMeterID, 0)
701 return true
702 }
703 logger.Errorw(ctx, "Dropping US Meter request: Device not found", log.Fields{"Service": svc})
704 return false
705}
706
707// PushFlowsForPortVnet - triggers flow construction and push for provided VPV
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530708func (vpv *VoltPortVnet) PushFlowsForPortVnet(cntx context.Context, d *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530709
710 vp := d.GetPort(vpv.Port)
711
712 //Ignore if UNI port is not found or not UP
713 if vp == nil || vp.State != PortStateUp {
714 logger.Warnw(ctx, "Ignoring Vlan UP Ind for VPV: Port Not Found/Ready", log.Fields{"Port": vp})
715 return
716 }
717
718 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
719 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Configuration for VPV", log.Fields{"Device": d.Name, "Port": vpv.Port, "DetectedPon": vp.PonPort, "ExpectedPon": vpv.PonPort, "Vnet": vpv.VnetName})
720 return
721 }
722
723 //Disable the flag so that flows can be pushed again
724 // vpv.IgmpFlowsApplied = false
725 // vpv.DsFlowsApplied = false
726 // vpv.UsFlowsApplied = false
727 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530728 vpv.PortUpInd(cntx, d, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530729 vpv.VpvLock.Unlock()
730}
731
732// PortUpInd : When a port transistions to UP state, the indication is passed
733// on to this module via the application. We read the VNET configuration
734// again here to apply the latest configuration if the configuration
735// changed. Thus, a reboot of ONT forces the new configuration to get
736// applied.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530737func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530738
739 if vpv.DeleteInProgress {
740 logger.Errorw(ctx, "Ignoring VPV Port UP Ind, VPV deleteion In-Progress", log.Fields{"Device": device, "Port": port, "Vnet": vpv.VnetName})
741 return
742 }
743 vpv.setDevice(device.Name)
744 logger.Infow(ctx, "Port UP Ind, pushing flows for the port", log.Fields{"Device": device, "Port": port, "VnetDhcp": vpv.DhcpRelay, "McastService": vpv.McastService})
745
746 nni, _ := GetApplication().GetNniPort(device.Name)
747 if nni == "" {
748 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name})
749 return
750 }
751
752 if vp := device.GetPort(port); vp != nil {
753
754 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
755 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Config for VPV", log.Fields{"Device": device.Name, "Port": port, "DetectedPon": vp.PonPort, "ExpectedPon": vpv.PonPort, "Vnet": vpv.VnetName})
756 return
757 }
758 }
759
760 if vpv.Blocked {
761 logger.Errorw(ctx, "VPV Bocked for Processing. Ignoring flow push request", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
762 return
763 }
764
765 if vpv.DhcpRelay || vpv.ArpRelay || vpv.PppoeIa {
766 // If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
767 // DS HSIA flows are installed after learning the MAC.
768 logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
769 // no HSIA flows for multicast service
770 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530771 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530772 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530773 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530774 if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
775 logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
776 // US & DS DHCP, US HSIA flows are already installed
777 // install only DS HSIA flow here.
778 // no HSIA flows for multicast service
779 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530780 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530781 }
782 }
783
784 } else {
785 // DHCP relay is not configured. This implies that the service must use
786 // 1:1 and does not require MAC learning. In a completely uncommon but
787 // plausible case, the MAC address can be learnt from N:1 without DHCP
788 // relay by configuring any unknown MAC address to be reported. This
789 // however is not seen as a real use case.
790 logger.Infow(ctx, "Port Up - Service Flows", log.Fields{"Device": device.Name, "Port": port})
791 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530792 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530793 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530794 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530795 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530796 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530797 }
798 }
799
800 // Process IGMP proxy - install IGMP trap rules before DHCP trap rules
801 if vpv.IgmpEnabled {
802 logger.Infow(ctx, "Port Up - IGMP Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530803 vpv.RangeOnServices(cntx, AddSvcUsMeterToDevice)
804 if err := vpv.AddIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530805 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
806 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
807 }
808
809 if vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530810 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +0530811 }
812 }
813
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530814 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530815}
816
817// PortDownInd : When the port status changes to down, we delete all configured flows
818// The same indication is also passed to the services enqueued for them
819// to take appropriate actions
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530820func (vpv *VoltPortVnet) PortDownInd(cntx context.Context, device string, port string, nbRequest bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530821
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530822 if !nbRequest && !GetApplication().OltFlowServiceConfig.RemoveFlowsOnDisable {
823 logger.Info(ctx, "VPV Port DOWN Ind, Not deleting flows since RemoveOnDisable is disabled")
824 return
825 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530826 logger.Infow(ctx, "VPV Port DOWN Ind, deleting all flows for services",
827 log.Fields{"service count": vpv.servicesCount.Load()})
828
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530829 //vpv.RangeOnServices(cntx, DelAllFlows)
830 vpv.DelTrapFlows(cntx)
831 vpv.DelHsiaFlows(cntx)
832 vpv.WriteToDb(cntx)
833 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530834}
835
836// SetMacAddr : The MAC address is set when a MAC address is learnt through the
837// packets received from the network. Currently, DHCP packets are
838// only packets we learn the MAC address from
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530839func (vpv *VoltPortVnet) SetMacAddr(cntx context.Context, addr net.HardwareAddr) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530840
841 //Store Learnt MAC address and return if MACLearning is not enabled
842 vpv.LearntMacAddr = addr
843 if vpv.MacLearning == MacLearningNone || !NonZeroMacAddress(addr) ||
844 (NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn) {
845 return
846 }
847
848 // Compare the two MAC addresses to see if it is same
849 // If they are same, we just return. If not, we perform
850 // actions to address the change in MAC address
851 //if NonZeroMacAddress(vpv.MacAddr) && !util.MacAddrsMatch(vpv.MacAddr, addr) {
852 if !util.MacAddrsMatch(vpv.MacAddr, addr) {
853 expectedPort := GetApplication().GetMacInPortMap(addr)
854 if expectedPort != "" && expectedPort != vpv.Port {
855 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-setmacaddr",
856 log.Fields{"ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": addr.String()})
857 return
858 }
859 if NonZeroMacAddress(vpv.MacAddr) {
860 logger.Warnw(ctx, "MAC Address Changed. Remove old flows (if added) and re-add with updated MAC", log.Fields{"UpdatedMAC": addr})
861
862 // The newly learnt MAC address is different than earlier one.
863 // The existing MAC based HSIA flows need to be undone as the device
864 // may have been changed
865 // Atleast one HSIA flow should be present in adapter to retain the TP and GEM
866 // hence delete one after the other
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530867 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530868 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530869 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
870 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
871 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530872 GetApplication().DeleteMacInPortMap(vpv.MacAddr)
873 } else {
874 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530875 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530876 logger.Infow(ctx, "MAC Address learnt from DHCP or ARP", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
877 }
878 GetApplication().UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
879 } else {
880 logger.Infow(ctx, "Leant MAC Address is same", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
881 }
882
883 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
884 if err != nil {
885 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
886 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
887 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
888 return
889 }
890 // Ds Hsia flows has to be pushed
891 if vpv.FlowsApplied {
892 // no HSIA flows for multicast service
893 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530894 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530895 }
896 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530897 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530898}
899
900// MatchesVlans : If the VNET matches both S and C VLANs, return true. Else, return false
901func (vpv *VoltPortVnet) MatchesVlans(svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) bool {
902 if vpv.SVlan != svlan || vpv.CVlan != cvlan || vpv.UniVlan != univlan {
903 return false
904 }
905 return true
906}
907
908// MatchesCvlan : If the VNET matches CVLAN, return true. Else, return false
909func (vpv *VoltPortVnet) MatchesCvlan(cvlan []of.VlanType) bool {
910 if len(cvlan) != 1 && !vpv.AllowTransparent {
911 return false
912 }
913 if vpv.CVlan != cvlan[0] {
914 return false
915 }
916 return true
917}
918
919// MatchesPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
920func (vpv *VoltPortVnet) MatchesPriority(priority uint8) *VoltService {
921
922 var service *VoltService
923 pbitFound := false
924 matchpbitsFunc := func(key, value interface{}) bool {
925 svc := value.(*VoltService)
926 for _, pbit := range svc.Pbits {
927 if uint8(pbit) == priority {
928 logger.Infow(ctx, "Pbit match found with service",
929 log.Fields{"Pbit": priority, "serviceName": svc.Name})
930 pbitFound = true
931 service = svc
932 return false //Returning false to stop the Range loop
933 }
934 }
935 return true
936 }
937 _ = pbitFound
938 vpv.services.Range(matchpbitsFunc)
939 return service
940}
941
942// GetRemarkedPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
943func (vpv *VoltPortVnet) GetRemarkedPriority(priority uint8) uint8 {
944
945 dsPbit := uint8(0)
946 matchpbitsFunc := func(key, value interface{}) bool {
947 svc := value.(*VoltService)
948 if remarkPbit, ok := svc.DsRemarkPbitsMap[int(priority)]; ok {
949 logger.Infow(ctx, "Pbit match found with service",
950 log.Fields{"Pbit": priority, "serviceName": svc.Name, "remarkPbit": remarkPbit})
951 dsPbit = uint8(remarkPbit)
952 return false //Returning false to stop the Range loop
953 }
954 // When no remarking info is available, remark the incoming pbit
955 // to highest pbit configured for the subscriber (across all subservices associated)
956 svcPbit := uint8(svc.Pbits[0])
957 if svcPbit > dsPbit {
958 dsPbit = svcPbit
959 }
960 return true
961 }
962 vpv.services.Range(matchpbitsFunc)
963 logger.Debugw(ctx, "Remarked Pbit Value", log.Fields{"Incoming": priority, "Remarked": dsPbit})
964 return dsPbit
965}
966
967// AddSvc adds a service on the VNET on a port. The addition is
968// triggered when NB requests for service addition
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530969func (vpv *VoltPortVnet) AddSvc(cntx context.Context, svc *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530970
971 //vpv.services = append(vpv.services, svc)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530972 vpv.AddService(cntx, svc)
Naveen Sampath04696f72022-06-13 15:19:14 +0530973 logger.Debugw(ctx, "Added Service to VPV", log.Fields{"Num of SVCs": vpv.servicesCount.Load(), "SVC": svc})
974
975 // Learn the circuit-id and remote-id from the service
976 // TODO: There must be a better way of doing this. This
977 // may be explored
978 if svc.IgmpEnabled {
979 vpv.IgmpEnabled = true
980 }
981 // first time service activation MacLearning will have default value as None.
982 // to handle reciliency if anythng other then None we should retain it .
983 if svc.MacLearning == MacLearningNone {
984 if !vpv.DhcpRelay && !vpv.ArpRelay {
985 svc.MacLearning = MacLearningNone
986 } else if vpv.MacLearning == Learn {
987 svc.MacLearning = Learn
988 } else if vpv.MacLearning == ReLearn {
989 svc.MacLearning = ReLearn
990 }
991 }
992
993 //TODO: Temp Change - Need to address MAC Learning flow issues completely
994 if (svc.MacLearning == Learn || svc.MacLearning == ReLearn) && NonZeroMacAddress(vpv.MacAddr) {
995 svc.MacAddr = vpv.MacAddr
996 } else if vpv.servicesCount.Load() == 1 {
997 vpv.MacAddr = svc.MacAddr
998 }
999
1000 vpv.MacLearning = svc.MacLearning
1001 vpv.PonPort = svc.PonPort
1002 logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
1003 //Reconfigure Vlans based on Vlan Control type
1004 svc.VlanControl = vpv.VlanControl
1005 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
1006 if vpv.VlanControl == ONUCVlan {
1007 svc.CVlan = svc.SVlan
1008 }
1009 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
1010 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
1011 if vpv.VlanControl == OLTSVlan {
1012 svc.CVlan = svc.UniVlan
1013 }
1014 if svc.McastService {
1015 vpv.McastService = true
1016 vpv.McastTechProfileID = svc.TechProfileID
1017 //Assumption: Only one Pbit for mcast service
1018 vpv.McastPbit = svc.Pbits[0]
1019 vpv.McastUsMeterID = svc.UsMeterID
1020 vpv.SchedID = svc.SchedID
1021 }
1022 svc.ONTEtherTypeClassification = vpv.ONTEtherTypeClassification
1023 svc.AllowTransparent = vpv.AllowTransparent
1024 svc.SVlanTpid = vpv.SVlanTpid
1025
1026 //Ensure configuring the mvlan profile only once
1027 //One subscriber cannot have multiple mvlan profiles. Only the first configuration is valid
1028 if svc.MvlanProfileName != "" {
1029 if vpv.MvlanProfileName == "" {
1030 vpv.MvlanProfileName = svc.MvlanProfileName
1031 } else {
1032 logger.Warnw(ctx, "Mvlan Profile already configured for subscriber. Ignoring new Mvlan", log.Fields{"Existing Mvlan": vpv.MvlanProfileName, "New Mvlan": svc.MvlanProfileName})
1033 }
1034 }
1035
1036 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
1037 if err != nil {
1038 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
1039 //statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1040 //TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1041 return
1042 }
Tinoj Josephec742f62022-09-29 19:11:10 +05301043 if !svc.IsActivated {
1044 logger.Warn(ctx, "Not pushing Service Flows: Service Not activated")
1045 return
1046 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301047 //Push Service Flows if DHCP relay is not configured
1048 //or already DHCP flows are configured for the VPV
1049 //to which the serivce is associated
1050 if vpv.FlowsApplied {
1051 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301052 svc.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301053 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301054 if err:= svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301055 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1056 }
1057 }
1058 }
1059
1060 //Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
1061 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1062 // service with Igmp Enabled needs to be installed
1063 if svc.IgmpEnabled && vpv.FlowsApplied {
1064 logger.Infow(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301065 if err := vpv.AddIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301066 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1067 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1068 }
1069
1070 if vpv.McastService {
1071 //For McastService, send Service Activated indication once IGMP US flow is pushed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301072 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +05301073 }
1074 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301075 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301076}
1077
1078// setLearntMAC to set learnt mac
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301079func (vpv *VoltPortVnet) setLearntMAC(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301080 svc := value.(*VoltService)
1081 svc.SetMacAddr(vpv.MacAddr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301082 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301083 return true
1084}
1085
1086// PostAccessConfigSuccessInd for posting access config success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301087func PostAccessConfigSuccessInd(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301088 return true
1089}
1090
1091// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301092func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301093 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301094 logger.Infow(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301095 svc.SetIpv4Addr(vpv.Ipv4Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301096 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301097
1098 return true
1099}
1100
1101// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301102func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301103 svc := value.(*VoltService)
1104 svc.SetIpv6Addr(vpv.Ipv6Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301105 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301106
1107 return true
1108}
1109
1110// AddUsHsiaFlows to add upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301111func AddUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301112 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301113 if err:= svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301114 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1115 }
1116 return true
1117}
1118
1119// AddDsHsiaFlows to add downstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301120func AddDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301121 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301122 if err:= svc.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301123 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1124 }
1125 return true
1126}
1127
1128// ClearFlagsInService to clear the flags used in service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301129func ClearFlagsInService(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301130 svc := value.(*VoltService)
1131 svc.ServiceLock.Lock()
1132 svc.IgmpFlowsApplied = false
1133 svc.DsDhcpFlowsApplied = false
1134 svc.DsHSIAFlowsApplied = false
1135 svc.Icmpv6FlowsApplied = false
1136 svc.UsHSIAFlowsApplied = false
1137 svc.UsDhcpFlowsApplied = false
1138 svc.PendingFlows = make(map[string]bool)
1139 svc.AssociatedFlows = make(map[string]bool)
1140 svc.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301141 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301142 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1143 return true
1144}
1145
1146// DelDsHsiaFlows to delete hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301147func DelDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301148 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301149 if err:= svc.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301150 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1151 }
1152 return true
1153}
1154
1155// DelUsHsiaFlows to delete upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301156func DelUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301157 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301158 if err:= svc.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301159 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1160 }
1161 return true
1162}
1163
1164// ClearServiceCounters to clear the service counters
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301165func ClearServiceCounters(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301166 svc := value.(*VoltService)
1167 //Delete the per service counter too
1168 GetApplication().ServiceCounters.Delete(svc.Name)
1169 if svc.IgmpEnabled && svc.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301170 _ = db.DelAllServiceChannelCounter(cntx, svc.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301171 }
1172 return true
1173}
1174
1175//AddTrapFlows - Adds US & DS Trap flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301176func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301177
1178 if !vpv.FlowsApplied || vgcRebooted {
1179 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301180 if err := vpv.AddUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301181 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1182 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1183 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301184 if err := vpv.AddDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301185 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1186 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1187 }
1188 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1189 log.Fields{"port": vpv.Port})
1190 //vpv.updateICMPv6McGroup(true)
1191 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301192 if err := vpv.AddUsArpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301193 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1194 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1195 }
1196 logger.Info(ctx, "ARP trap rules not added in downstream direction")
1197
1198 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301199 if err := vpv.AddUsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301200 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1201 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1202 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301203 if err := vpv.AddDsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301204 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1205 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1206 }
1207 }
1208 vpv.FlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301209 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301210 }
1211}
1212
1213//DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301214func (vpv *VoltPortVnet) DelTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301215
1216 // Delete HSIA & DHCP flows before deleting IGMP flows
1217 if vpv.FlowsApplied || vgcRebooted {
1218 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301219 if err:= vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301220 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1221 "UniVlan": vpv.UniVlan, "Error": err})
1222 }
1223 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1224 log.Fields{"port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301225 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301226 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1227 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1228 }
1229 //vpv.updateICMPv6McGroup(false)
1230 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301231 if err := vpv.DelUsArpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301232 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1233 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1234 }
1235 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301236 if err := vpv.DelUsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301237 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1238 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1239 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301240 if err := vpv.DelDsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301241 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1242 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1243 }
1244 }
1245 vpv.FlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301246 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301247 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301248 if err:= vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301249 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1250 "UniVlan": vpv.UniVlan, "Error": err})
1251 }
1252}
1253
1254// DelHsiaFlows deletes the service flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301255func (vpv *VoltPortVnet) DelHsiaFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301256 // no HSIA flows for multicast service
1257 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301258 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
1259 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301260 }
1261}
1262
1263//ClearServiceCounters - Removes all igmp counters for a service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301264func (vpv *VoltPortVnet) ClearServiceCounters(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301265 //send flows deleted indication to submgr
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301266 vpv.RangeOnServices(cntx, ClearServiceCounters)
Naveen Sampath04696f72022-06-13 15:19:14 +05301267}
1268
1269// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301270func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301271 var vd *VoltDevice
1272 device := vpv.Device
1273
1274 if vd = GetApplication().GetDevice(device); vd != nil {
1275 if vd.State != controller.DeviceStateUP {
1276 logger.Errorw(ctx, "Skipping US DHCP Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1277 return nil
1278 }
1279 } else {
1280 logger.Errorw(ctx, "US DHCP Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1281 return errorCodes.ErrDeviceNotFound
1282 }
1283
1284 flows, err := vpv.BuildUsDhcpFlows()
1285 if err == nil {
1286 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301287 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301288 //push ind here ABHI
1289 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1290 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1291 }
1292 } else {
1293 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1294 //push ind here ABHI
1295 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1296 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1297
1298 }
1299 /*
1300 flows, err = vpv.BuildUsDhcp6Flows()
1301 if err == nil {
1302 logger.Debugw(ctx, "Adding US DHCP6 flows", log.Fields{"Device": device})
1303 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1304 //pussh ind here ABHI
1305 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1306 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1307
1308 }
1309 } else {
1310 logger.Errorw(ctx, "US DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1311 //push ind here ABHI
1312 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1313 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1314
1315 }*/
1316 return nil
1317}
1318
1319// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301320func (vpv *VoltPortVnet) AddDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301321
1322 var vd *VoltDevice
1323 device := vpv.Device
1324
1325 if vd = GetApplication().GetDevice(device); vd != nil {
1326 if vd.State != controller.DeviceStateUP {
1327 logger.Errorw(ctx, "Skipping DS DHCP Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1328 return nil
1329 }
1330 } else {
1331 logger.Errorw(ctx, "DS DHCP Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1332 return errorCodes.ErrDeviceNotFound
1333 }
1334 if GetApplication().GetVendorID() != Radisys && vd.GlobalDhcpFlowAdded {
1335 return nil
1336 }
1337
1338 flows, err := vpv.BuildDsDhcpFlows()
1339 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301340 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301341 //push ind here and procced
1342 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1343 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1344
1345 }
1346 } else {
1347 logger.Errorw(ctx, "DS DHCP Flow Add Failed", log.Fields{"Reason": err.Error()})
1348 //send ind here and proceed
1349 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1350 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1351
1352 }
1353 /*
1354 flows, err = vpv.BuildDsDhcp6Flows()
1355 if err == nil {
1356 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1357 //push ind and proceed
1358 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1359 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1360
1361 }
1362 } else {
1363 logger.Errorw(ctx, "DS DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error()})
1364 //Send ind here and proceed
1365 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1366 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1367
1368 }*/
1369 if GetApplication().GetVendorID() != Radisys {
1370 vd.GlobalDhcpFlowAdded = true
1371 }
1372 return nil
1373}
1374
1375// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301376func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
1377 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301378 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1379 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1380 }
1381
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301382 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301383 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1384 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1385 }
1386}
1387
1388// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1389// Write the status of the VPV to the DB once the delete is scheduled
1390// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301391func (vpv *VoltPortVnet) DelUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301392 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1393 if err != nil {
1394 return err
1395 }
1396
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301397 err = vpv.delDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301398 if err != nil {
1399 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1400 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1401 }
1402 /*
1403 err = vpv.delDhcp6Flows(device)
1404 if err != nil {
1405 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1406 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1407 }*/
1408 return nil
1409}
1410
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301411func (vpv *VoltPortVnet) delDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301412 flows, err := vpv.BuildUsDhcpFlows()
1413 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301414 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301415 }
1416 logger.Errorw(ctx, "US DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1417 return err
1418}
1419/*
1420func (vpv *VoltPortVnet) delDhcp6Flows(device *VoltDevice) error {
1421 flows, err := vpv.BuildUsDhcp6Flows()
1422 if err == nil {
1423 return vpv.RemoveFlows(device, flows)
1424 }
1425 logger.Errorw(ctx, "US DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1426 return err
1427
1428}*/
1429
1430// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1431// Write the status of the VPV to the DB once the delete is scheduled
1432// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301433func (vpv *VoltPortVnet) DelDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301434 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1435 if err != nil {
1436 return err
1437 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301438 err = vpv.delDsDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301439 if err != nil {
1440 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1441 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1442 }
1443 /*
1444 err = vpv.delDsDhcp6Flows(device)
1445 if err != nil {
1446 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1447 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1448 }*/
1449 return nil
1450}
1451
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301452func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301453 flows, err := vpv.BuildDsDhcpFlows()
1454 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301455 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301456 }
1457 logger.Errorw(ctx, "DS DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1458 return err
1459}
1460
1461/*
1462func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1463 flows, err := vpv.BuildDsDhcp6Flows()
1464 if err == nil {
1465 return vpv.RemoveFlows(device, flows)
1466 }
1467 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1468 return err
1469}*/
1470
1471// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301472func (vpv *VoltPortVnet) AddUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301473
1474 var vd *VoltDevice
1475 device := vpv.Device
1476 if vd = GetApplication().GetDevice(device); vd != nil {
1477 if vd.State != controller.DeviceStateUP {
1478 logger.Errorw(ctx, "Skipping US ARP Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1479 return nil
1480 }
1481 } else {
1482 logger.Errorw(ctx, "US ARP Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1483 return errorCodes.ErrDeviceNotFound
1484 }
1485
1486 flows, err := vpv.BuildUsArpFlows()
1487 if err == nil {
1488 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301489 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301490 return err1
1491 }
1492 } else {
1493 logger.Errorw(ctx, "US ARP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1494 return err
1495 }
1496 return nil
1497}
1498
1499// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1500// Write the status of the VPV to the DB once the delete is scheduled
1501// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301502func (vpv *VoltPortVnet) DelUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301503 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1504 if err != nil {
1505 return err
1506 }
1507 flows, err := vpv.BuildUsArpFlows()
1508 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301509 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301510 }
1511 logger.Errorw(ctx, "US ARP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1512 return err
1513}
1514
1515// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301516func (vpv *VoltPortVnet) AddUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301517 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1518
1519 var vd *VoltDevice
1520 device := vpv.Device
1521
1522 if vd = GetApplication().GetDevice(device); vd != nil {
1523 if vd.State != controller.DeviceStateUP {
1524 logger.Errorw(ctx, "Skipping US PPPoE Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1525 return nil
1526 }
1527 } else {
1528 logger.Errorw(ctx, "US PPPoE Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1529 return errorCodes.ErrDeviceNotFound
1530 }
1531
1532 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1533 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1534
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301535 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301536 return err1
1537 }
1538 } else {
1539 logger.Errorw(ctx, "US PPPoE Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1540 return err
1541 }
1542 return nil
1543}
1544
1545// AddDsPppoeFlows to add downstream pppoe flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301546func (vpv *VoltPortVnet) AddDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301547 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1548 var vd *VoltDevice
1549 device := vpv.Device
1550
1551 if vd = GetApplication().GetDevice(device); vd != nil {
1552 if vd.State != controller.DeviceStateUP {
1553 logger.Errorw(ctx, "Skipping DS PPPoE Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1554 return nil
1555 }
1556 } else {
1557 logger.Errorw(ctx, "DS PPPoE Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1558 return errorCodes.ErrDeviceNotFound
1559 }
1560
1561 flows, err := vpv.BuildDsPppoeFlows()
1562 if err == nil {
1563
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301564 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301565 return err1
1566 }
1567 } else {
1568 logger.Errorw(ctx, "DS PPPoE Flow Add Failed", log.Fields{"Reason": err.Error()})
1569 return err
1570 }
1571 return nil
1572}
1573
1574// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1575// Write the status of the VPV to the DB once the delete is scheduled
1576// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301577func (vpv *VoltPortVnet) DelUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301578 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1579 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1580 if err != nil {
1581 return err
1582 }
1583 flows, err := vpv.BuildUsPppoeFlows()
1584 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301585 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301586 }
1587 logger.Errorw(ctx, "US PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1588 return err
1589}
1590
1591// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1592// Write the status of the VPV to the DB once the delete is scheduled
1593// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301594func (vpv *VoltPortVnet) DelDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301595 logger.Debugw(ctx, "Deleting DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1596 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1597 if err != nil {
1598 return err
1599 }
1600 flows, err := vpv.BuildDsPppoeFlows()
1601 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301602 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301603 }
1604 logger.Errorw(ctx, "DS PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1605 return err
1606}
1607
1608// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301609func (vpv *VoltPortVnet) AddIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301610
1611 if !vpv.IgmpFlowsApplied || vgcRebooted {
1612 if vpv.MvlanProfileName == "" {
1613 logger.Info(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
1614 return nil
1615 }
1616 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1617 if err != nil {
1618 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1619 return err
1620 } else if device.State != controller.DeviceStateUP {
1621 logger.Warnw(ctx, "Device state Down. Ignoring US IGMP Flow Push", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan})
1622 return nil
1623 }
1624 flows, err := vpv.BuildIgmpFlows()
1625 if err == nil {
1626 for cookie := range flows.SubFlows {
1627 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1628 cookie := strconv.FormatUint(cookie, 10)
1629 fe := &FlowEvent{
1630 eType: EventTypeUsIgmpFlowAdded,
1631 cookie: cookie,
1632 eventData: vpv,
1633 }
1634 vd.RegisterFlowAddEvent(cookie, fe)
1635 }
1636 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301637 if err1 := cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301638 return err1
1639 }
1640 } else {
1641 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1642 return err
1643 }
1644 vpv.IgmpFlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301645 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301646 }
1647 return nil
1648}
1649
1650// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1651// Write the status of the VPV to the DB once the delete is scheduled
1652// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301653func (vpv *VoltPortVnet) DelIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301654
1655 if vpv.IgmpFlowsApplied || vgcRebooted {
1656 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1657 if err != nil {
1658 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1659 return err
1660 }
1661 flows, err := vpv.BuildIgmpFlows()
1662 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301663 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301664 return err1
1665 }
1666 } else {
1667 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1668 return err
1669 }
1670 vpv.IgmpFlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301671 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301672 }
1673 return nil
1674}
1675
1676// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1677// The flows included by this function cover US only as the DS is
1678// created either automatically by the VOLTHA or at the device level
1679// earlier
1680func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
1681 flow := &of.VoltFlow{}
1682 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1683
1684 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
1685 subFlow := of.NewVoltSubFlow()
1686 subFlow.SetTableID(0)
1687
1688 if GetApplication().GetVendorID() == Radisys {
1689 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1690 return nil, err
1691 }
1692 } else {
1693 subFlow.SetMatchVlan(vpv.UniVlan)
1694 subFlow.SetSetVlan(vpv.CVlan)
1695 }
1696 subFlow.SetUdpv4Match()
1697 subFlow.SrcPort = 68
1698 subFlow.DstPort = 67
1699 uniport, err := GetApplication().GetPortID(vpv.Port)
1700 if err != nil {
1701 logger.Errorw(ctx, "Failed to fetch uni port from vpv", log.Fields{"error": err, "port": vpv.Port})
1702 return nil, err
1703 }
1704 subFlow.SetInPort(uniport)
1705 // PortName and PortID to be used for validation of port before flow pushing
1706 flow.PortID = uniport
1707 flow.PortName = vpv.Port
1708 subFlow.SetReportToController()
1709
1710 // Set techprofile, meterid of first service
1711 vpv.services.Range(func(key, value interface{}) bool {
1712 svc := value.(*VoltService)
1713 writemetadata := uint64(svc.TechProfileID) << 32
1714 subFlow.SetWriteMetadata(writemetadata)
1715 subFlow.SetMeterID(svc.UsMeterID)
1716 return false
1717 })
1718
1719 subFlow.SetPcp(vpv.DhcpPbit)
1720 // metadata := uint64(uniport)
1721 // subFlow.SetWriteMetadata(metadata)
1722 allowTransparent := 0
1723 if vpv.AllowTransparent {
1724 allowTransparent = 1
1725 }
1726 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1727 subFlow.SetTableMetadata(metadata)
1728
1729 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1730 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1731 subFlow.Priority = of.DhcpFlowPriority
1732
1733 flow.SubFlows[subFlow.Cookie] = subFlow
1734 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1735 return flow, nil
1736}
1737
1738// BuildDsDhcpFlows to build the downstream dhcp flows
1739func (vpv *VoltPortVnet) BuildDsDhcpFlows() (*of.VoltFlow, error) {
1740
1741 logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1742 flow := &of.VoltFlow{}
1743 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1744 subFlow := of.NewVoltSubFlow()
1745 subFlow.SetTableID(0)
1746 // If dhcp trap rule is global rule, No need to match on vlan
1747 if GetApplication().GetVendorID() == Radisys {
1748 vpv.setDsMatchVlan(subFlow)
1749 }
1750 subFlow.SetUdpv4Match()
1751 subFlow.SrcPort = 67
1752 subFlow.DstPort = 68
1753 uniport, _ := GetApplication().GetPortID(vpv.Port)
1754 nni, err := GetApplication().GetNniPort(vpv.Device)
1755 if err != nil {
1756 return nil, err
1757 }
1758 nniport, err := GetApplication().GetPortID(nni)
1759 if err != nil {
1760 return nil, err
1761 }
1762 subFlow.SetInPort(nniport)
1763 // PortName and PortID to be used for validation of port before flow pushing
1764 flow.PortID = uniport
1765 flow.PortName = vpv.Port
1766 // metadata := uint64(uniport)
1767 // subFlow.SetWriteMetadata(metadata)
1768 allowTransparent := 0
1769 if vpv.AllowTransparent {
1770 allowTransparent = 1
1771 }
1772 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1773 subFlow.SetTableMetadata(metadata)
1774 subFlow.SetReportToController()
1775 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1776 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
1777 subFlow.Priority = of.DhcpFlowPriority
1778
1779 flow.SubFlows[subFlow.Cookie] = subFlow
1780 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1781
1782 return flow, nil
1783}
1784
1785// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1786// application.
1787func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
1788 flow := &of.VoltFlow{}
1789 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1790
1791 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
1792 subFlow := of.NewVoltSubFlow()
1793 subFlow.SetTableID(0)
1794
1795 subFlow.SetMatchVlan(vpv.UniVlan)
1796 subFlow.SetSetVlan(vpv.CVlan)
1797 subFlow.SetUdpv6Match()
1798 subFlow.SrcPort = 546
1799 subFlow.DstPort = 547
1800 uniport, err := GetApplication().GetPortID(vpv.Port)
1801 if err != nil {
1802 return nil, err
1803 }
1804 // Set techprofile, meterid of first service
1805 vpv.services.Range(func(key, value interface{}) bool {
1806 svc := value.(*VoltService)
1807 writemetadata := uint64(svc.TechProfileID) << 32
1808 subFlow.SetWriteMetadata(writemetadata)
1809 subFlow.SetMeterID(svc.UsMeterID)
1810 return false
1811 })
1812 subFlow.SetInPort(uniport)
1813 // PortName and PortID to be used for validation of port before flow pushing
1814 flow.PortID = uniport
1815 flow.PortName = vpv.Port
1816 //subFlow.SetMeterId(vpv.UsDhcpMeterId)
1817 // metadata := uint64(uniport)
1818 // subFlow.SetWriteMetadata(metadata)
1819 allowTransparent := 0
1820 if vpv.AllowTransparent {
1821 allowTransparent = 1
1822 }
1823 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1824 subFlow.SetTableMetadata(metadata)
1825 subFlow.SetReportToController()
1826 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1827 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
1828 subFlow.Priority = of.DhcpFlowPriority
1829
1830 flow.SubFlows[subFlow.Cookie] = subFlow
1831 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1832 return flow, nil
1833}
1834
1835// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1836// application.
1837func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
1838 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1839
1840 flow := &of.VoltFlow{}
1841 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1842 subFlow := of.NewVoltSubFlow()
1843 subFlow.SetTableID(0)
1844
1845 vpv.setDsMatchVlan(subFlow)
1846 subFlow.SetUdpv6Match()
1847 subFlow.SrcPort = 547
1848 subFlow.DstPort = 547
1849 uniport, _ := GetApplication().GetPortID(vpv.Port)
1850 nni, err := GetApplication().GetNniPort(vpv.Device)
1851 if err != nil {
1852 return nil, err
1853 }
1854 nniport, err := GetApplication().GetPortID(nni)
1855 if err != nil {
1856 return nil, err
1857 }
1858 subFlow.SetInPort(nniport)
1859 // PortName and PortID to be used for validation of port before flow pushing
1860 flow.PortID = uniport
1861 flow.PortName = vpv.Port
1862 // metadata := uint64(uniport)
1863 // subFlow.SetWriteMetadata(metadata)
1864 allowTransparent := 0
1865 if vpv.AllowTransparent {
1866 allowTransparent = 1
1867 }
1868 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1869 subFlow.SetTableMetadata(metadata)
1870 subFlow.SetReportToController()
1871 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1872 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
1873 subFlow.Priority = of.DhcpFlowPriority
1874
1875 flow.SubFlows[subFlow.Cookie] = subFlow
1876 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1877 return flow, nil
1878}
1879
1880// BuildUsArpFlows builds the US ARP relay flows for a subscriber
1881// The flows included by this function cover US only as the DS is
1882// created either automatically by the VOLTHA or at the device level
1883// earlier
1884func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
1885 flow := &of.VoltFlow{}
1886 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1887
1888 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
1889 subFlow := of.NewVoltSubFlow()
1890 subFlow.SetTableID(0)
1891
1892 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1893 subFlow.SetMatchSrcMac(vpv.MacAddr)
1894 }
1895
1896 subFlow.SetMatchDstMac(BroadcastMAC)
1897 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1898 return nil, err
1899 }
1900 subFlow.SetArpMatch()
1901 uniport, err := GetApplication().GetPortID(vpv.Port)
1902 if err != nil {
1903 return nil, err
1904 }
1905 subFlow.SetInPort(uniport)
1906 // PortName and PortID to be used for validation of port before flow pushing
1907 flow.PortID = uniport
1908 flow.PortName = vpv.Port
1909 subFlow.SetReportToController()
1910 allowTransparent := 0
1911 if vpv.AllowTransparent {
1912 allowTransparent = 1
1913 }
1914 metadata := uint64(uniport)
1915 subFlow.SetWriteMetadata(metadata)
1916 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1917 subFlow.SetTableMetadata(metadata)
1918 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
1919 subFlow.Priority = of.ArpFlowPriority
1920
1921 flow.SubFlows[subFlow.Cookie] = subFlow
1922 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1923 return flow, nil
1924}
1925
1926// setUsMatchVlan to set upstream match vlan
1927func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
1928 switch vpv.VlanControl {
1929 case None:
1930 flow.SetMatchVlan(vpv.SVlan)
1931 case ONUCVlanOLTSVlan:
1932 flow.SetMatchVlan(vpv.CVlan)
1933 case OLTCVlanOLTSVlan:
1934 flow.SetMatchVlan(vpv.UniVlan)
1935 //flow.SetSetVlan(vpv.CVlan)
1936 case ONUCVlan:
1937 flow.SetMatchVlan(vpv.SVlan)
1938 case OLTSVlan:
1939 flow.SetMatchVlan(vpv.UniVlan)
1940 //flow.SetSetVlan(vpv.SVlan)
1941 default:
1942 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
1943 return errorCodes.ErrInvalidParamInRequest
1944 }
1945 return nil
1946}
1947
1948// BuildUsPppoeFlows to build upstream pppoe flows
1949func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
1950
1951 flow := &of.VoltFlow{}
1952 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1953 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
1954 subFlow := of.NewVoltSubFlow()
1955 subFlow.SetTableID(0)
1956
1957 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1958 subFlow.SetMatchSrcMac(vpv.MacAddr)
1959 }
1960
1961 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1962 return nil, err
1963 }
1964 subFlow.SetPppoeDiscoveryMatch()
1965 uniport, err := GetApplication().GetPortID(vpv.Port)
1966 if err != nil {
1967 return nil, err
1968 }
1969 subFlow.SetInPort(uniport)
1970 subFlow.SetReportToController()
1971 // PortName and PortID to be used for validation of port before flow pushing
1972 flow.PortID = uniport
1973 flow.PortName = vpv.Port
1974
1975 allowTransparent := 0
1976 if vpv.AllowTransparent {
1977 allowTransparent = 1
1978 }
1979 metadata := uint64(uniport)
1980 subFlow.SetWriteMetadata(metadata)
1981
1982 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1983 subFlow.SetTableMetadata(metadata)
1984
1985 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
1986 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
1987 subFlow.Priority = of.PppoeFlowPriority
1988
1989 flow.SubFlows[subFlow.Cookie] = subFlow
1990 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1991 return flow, nil
1992}
1993
1994// BuildDsPppoeFlows to build downstream pppoe flows
1995func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
1996
1997 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1998 flow := &of.VoltFlow{}
1999 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2000 subFlow := of.NewVoltSubFlow()
2001 subFlow.SetTableID(0)
2002
2003 vpv.setDsMatchVlan(subFlow)
2004 subFlow.SetPppoeDiscoveryMatch()
2005
2006 if NonZeroMacAddress(vpv.MacAddr) {
2007 subFlow.SetMatchDstMac(vpv.MacAddr)
2008 }
2009
2010 uniport, _ := GetApplication().GetPortID(vpv.Port)
2011 nni, err := GetApplication().GetNniPort(vpv.Device)
2012 if err != nil {
2013 return nil, err
2014 }
2015 nniport, err := GetApplication().GetPortID(nni)
2016 if err != nil {
2017 return nil, err
2018 }
2019 subFlow.SetInPort(nniport)
2020 // PortName and PortID to be used for validation of port before flow pushing
2021 flow.PortID = uniport
2022 flow.PortName = vpv.Port
2023 metadata := uint64(uniport)
2024 subFlow.SetWriteMetadata(metadata)
2025 allowTransparent := 0
2026 if vpv.AllowTransparent {
2027 allowTransparent = 1
2028 }
2029 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2030 subFlow.SetTableMetadata(metadata)
2031 subFlow.SetReportToController()
2032 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
2033 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2034 subFlow.Priority = of.PppoeFlowPriority
2035
2036 flow.SubFlows[subFlow.Cookie] = subFlow
2037 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2038 return flow, nil
2039}
2040
2041// setDsMatchVlan to set downstream match vlan
2042func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
2043 switch vpv.VlanControl {
2044 case None:
2045 flow.SetMatchVlan(vpv.SVlan)
2046 case ONUCVlanOLTSVlan,
2047 OLTCVlanOLTSVlan,
2048 ONUCVlan,
2049 OLTSVlan:
2050 flow.SetMatchVlan(vpv.SVlan)
2051 default:
2052 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2053 }
2054}
2055
2056// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2057// in the US direction.
2058func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2059 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2060 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2061 if mvp == nil {
2062 return nil, errors.New("Mvlan Profile configured not found")
2063 }
2064 mvlan := mvp.GetUsMatchVlan()
2065 flow := &of.VoltFlow{}
2066 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2067 subFlow := of.NewVoltSubFlow()
2068 subFlow.SetTableID(0)
2069
2070 if GetApplication().GetVendorID() == Radisys {
2071 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2072 return nil, err
2073 }
2074 } else {
2075 subFlow.SetMatchVlan(vpv.UniVlan)
2076 subFlow.SetSetVlan(vpv.CVlan)
2077 }
2078
2079 uniport, err := GetApplication().GetPortID(vpv.Port)
2080 if err != nil {
2081 return nil, err
2082 }
2083 subFlow.SetInPort(uniport)
2084 // PortName and PortID to be used for validation of port before flow pushing
2085 flow.PortID = uniport
2086 flow.PortName = vpv.Port
2087
2088 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2089 subFlow.SetMatchSrcMac(vpv.MacAddr)
2090 }
2091 logger.Infow(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
2092 //metadata := uint64(mvlan)
2093
2094 if vpv.McastService {
2095 metadata := uint64(vpv.McastUsMeterID)
2096 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2097 subFlow.SetMatchPbit(vpv.McastPbit)
2098 subFlow.SetMeterID(vpv.McastUsMeterID)
2099 subFlow.SetWriteMetadata(metadata)
2100 } else {
2101 // Set techprofile, meterid of first service
2102 vpv.services.Range(func(key, value interface{}) bool {
2103 svc := value.(*VoltService)
2104 writemetadata := uint64(svc.TechProfileID) << 32
2105 subFlow.SetWriteMetadata(writemetadata)
2106 subFlow.SetMeterID(svc.UsMeterID)
2107 return false
2108 })
2109 }
2110
2111 allowTransparent := 0
2112 if vpv.AllowTransparent {
2113 allowTransparent = 1
2114 }
2115 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2116 subFlow.SetTableMetadata(metadata)
2117 subFlow.SetIgmpMatch()
2118 subFlow.SetReportToController()
2119 //| 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
2120 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2121 subFlow.Priority = of.IgmpFlowPriority
2122
2123 flow.SubFlows[subFlow.Cookie] = subFlow
2124 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2125 return flow, nil
2126}
2127
2128// WriteToDb for writing to database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302129func (vpv *VoltPortVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302130 if vpv.DeleteInProgress {
2131 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2132 return
2133 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302134 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302135}
2136
2137//ForceWriteToDb force commit a VPV to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302138func (vpv *VoltPortVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302139 vpv.PendingFlowLock.RLock()
2140 defer vpv.PendingFlowLock.RUnlock()
2141 vpv.Version = database.PresentVersionMap[database.VpvPath]
2142 if b, err := json.Marshal(vpv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302143 if err := db.PutVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302144 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2145 "UniVlan": vpv.UniVlan, "Error": err})
2146 }
2147 }
2148}
2149
2150// DelFromDb for deleting from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302151func (vpv *VoltPortVnet) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302152 logger.Debugw(ctx, "Deleting VPV from DB", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302153 _ = db.DelVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
Naveen Sampath04696f72022-06-13 15:19:14 +05302154}
2155
2156// ClearAllServiceFlags to clear all service flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302157func (vpv *VoltPortVnet) ClearAllServiceFlags(cntx context.Context) {
2158 vpv.RangeOnServices(cntx, ClearFlagsInService)
Naveen Sampath04696f72022-06-13 15:19:14 +05302159}
2160
2161// ClearAllVpvFlags to clear all vpv flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302162func (vpv *VoltPortVnet) ClearAllVpvFlags(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302163 vpv.PendingFlowLock.Lock()
2164 vpv.FlowsApplied = false
2165 vpv.IgmpFlowsApplied = false
2166 vpv.PendingDeleteFlow = make(map[string]bool)
2167 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302168 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302169 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2170 log.Fields{"device": vpv.Device, "port": vpv.Port,
2171 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2172}
2173
2174// CreateVpvFromString to create vpv from string
2175func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
2176 var vpv VoltPortVnet
2177 if err := json.Unmarshal(b, &vpv); err == nil {
2178 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2179 if !ok {
2180 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2181 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2182 }
2183 vpv.servicesCount = atomic.NewUint64(0)
2184 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2185 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2186 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2187 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2188 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2189 vnet.associatePortToVnet(vpv.Port)
2190 }
2191
2192 if vpv.DeleteInProgress {
2193 va.VoltPortVnetsToDelete[&vpv] = true
2194 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2195 }
2196 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2197 }
2198}
2199
2200// RestoreVpvsFromDb to restore vpvs from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302201func (va *VoltApplication) RestoreVpvsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302202 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302203 vpvs, _ := db.GetVpvs(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302204 for hash, vpv := range vpvs {
2205 b, ok := vpv.Value.([]byte)
2206 if !ok {
2207 logger.Warn(ctx, "The value type is not []byte")
2208 continue
2209 }
2210 va.CreateVpvFromString(b, hash)
2211 }
2212}
2213
2214// GetVnetByPort : VNET related functionality of VOLT Application here on.
2215// Get the VNET from a port. The port identity is passed as device and port identities in string.
2216// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2217// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2218func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
2219 if _, ok := va.VnetsByPort.Load(port); !ok {
2220 return nil
2221 }
2222 vpvs, _ := va.VnetsByPort.Load(port)
2223 for _, vpv := range vpvs.([]*VoltPortVnet) {
2224 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2225 return vpv
2226 }
2227 }
2228 return nil
2229}
2230
2231// AddVnetToPort to add vnet to port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302232func (va *VoltApplication) AddVnetToPort(cntx context.Context, port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
Naveen Sampath04696f72022-06-13 15:19:14 +05302233 // The VNET is not on the port and is to be added
2234 logger.Debugw(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
2235 vpv := NewVoltPortVnet(vvnet)
2236 vpv.MacLearning = vvnet.MacLearning
2237 vpv.Port = port
2238 vvnet.associatePortToVnet(port)
2239 if _, ok := va.VnetsByPort.Load(port); !ok {
2240 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2241 }
2242 vpvsIntf, _ := va.VnetsByPort.Load(port)
2243 vpvs := vpvsIntf.([]*VoltPortVnet)
2244 vpvs = append(vpvs, vpv)
2245 va.VnetsByPort.Store(port, vpvs)
2246 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2247
2248 vpv.VpvLock.Lock()
2249 defer vpv.VpvLock.Unlock()
2250
2251 // Add the service that is causing the VNET to be added to the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302252 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05302253
Tinoj Josephec742f62022-09-29 19:11:10 +05302254 if !vs.IsActivated {
2255 logger.Warn(ctx, "Not Checking port state: Service Not activated")
2256 // Process the PORT UP if the port is already up
2257 d, err := va.GetDeviceFromPort(port)
2258 if err == nil {
2259 vpv.setDevice(d.Name)
2260 }
2261 vpv.WriteToDb(cntx)
2262 return vpv
2263 }
2264
Naveen Sampath04696f72022-06-13 15:19:14 +05302265 // Process the PORT UP if the port is already up
2266 d, err := va.GetDeviceFromPort(port)
2267 if err == nil {
2268 vpv.setDevice(d.Name)
2269 p := d.GetPort(port)
2270 if p != nil {
2271
2272 if vs.PonPort != 0xFF && vs.PonPort != p.PonPort {
2273 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Push for VPV", log.Fields{"Device": d.Name, "Port": port, "DetectedPon": p.PonPort, "ExpectedPon": vs.PonPort, "Vnet": vpv.VnetName})
2274 } else {
2275 logger.Infow(ctx, "Checking UNI port state", log.Fields{"State": p.State})
2276 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302277 vpv.PortUpInd(cntx, d, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302278 }
2279 }
2280 }
2281 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302282 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302283 return vpv
2284}
2285
2286// DelVnetFromPort for deleting vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302287func (va *VoltApplication) DelVnetFromPort(cntx context.Context, port string, vpv *VoltPortVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302288
2289 //Delete DHCP Session
2290 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2291
2292 //Delete PPPoE session
2293 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2294
2295 //Delete Mac from MacPortMap
2296 va.DeleteMacInPortMap(vpv.MacAddr)
2297
2298 //Delete VPV
2299 vpvsIntf, ok := va.VnetsByPort.Load(port)
2300 if !ok {
2301 return
2302 }
2303 vpvs := vpvsIntf.([]*VoltPortVnet)
2304 for i, lvpv := range vpvs {
2305 if lvpv == vpv {
2306 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2307 "UNIVLAN": vpv.UniVlan})
2308
2309 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2310
2311 vpv.DeleteInProgress = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302312 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302313
2314 va.VnetsByPort.Store(port, vpvs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302315 vpv.DelTrapFlows(cntx)
2316 vpv.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302317 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2318 vpv.PendingFlowLock.RLock()
2319 if len(vpv.PendingDeleteFlow) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302320 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302321 }
2322 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302323 vnet.disassociatePortFromVnet(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302324 }
2325 vpv.PendingFlowLock.RUnlock()
2326 return
2327 }
2328 }
2329}
2330
2331// RestoreVnetsFromDb to restore vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302332func (va *VoltApplication) RestoreVnetsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302333 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302334 vnets, _ := db.GetVnets(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302335 for _, net := range vnets {
2336 b, ok := net.Value.([]byte)
2337 if !ok {
2338 logger.Warn(ctx, "The value type is not []byte")
2339 continue
2340 }
2341 var vnet VoltVnet
2342 err := json.Unmarshal(b, &vnet)
2343 if err != nil {
2344 logger.Warn(ctx, "Unmarshal of VNET failed")
2345 continue
2346 }
2347 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302348 if err := va.AddVnet(cntx, vnet.VnetConfig, &vnet.VnetOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302349 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2350 }
2351
2352 if vnet.DeleteInProgress {
2353 va.VnetsToDelete[vnet.Name] = true
2354 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2355 }
2356
2357 }
2358}
2359
2360// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2361// are used as the key to locate the service. If more than one service is on the
2362// same port (essentially a UNI of ONU), the services must be separated by different
2363// CVLANs
2364func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
2365 // Fetch the device first to make sure the device exists
2366 dIntf, ok := va.DevicesDisc.Load(device)
2367 if !ok {
2368 return nil
2369 }
2370 d := dIntf.(*VoltDevice)
2371
2372 // If the port is NNI port, the services dont exist on it. The svc then
2373 // must be obtained from a different context and is not included here
2374 if port == d.NniPort {
2375 return nil
2376 }
2377
2378 //To return the matched service
2379 var service *VoltService
2380
2381 // This is an access port and the port should have all the associated
2382 // services which can be uniquely identified by the VLANs in the packet
2383 vnets, ok := va.VnetsByPort.Load(port)
2384
2385 if !ok {
2386 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2387 return nil
2388 }
2389 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2390 for _, vnet := range vnets.([]*VoltPortVnet) {
2391 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2392 switch vnet.VlanControl {
2393 case ONUCVlanOLTSVlan:
2394 service = vnet.MatchesPriority(priority)
2395 if vnet.MatchesCvlan(vlans) && service != nil {
2396 return service
2397 }
2398 case ONUCVlan,
2399 None:
2400 service = vnet.MatchesPriority(priority)
2401 // In case of DHCP Flow - cvlan == VlanNone
2402 // In case of HSIA Flow - cvlan == Svlan
2403 if len(vlans) == 1 && (vlans[0] == vnet.SVlan || vlans[0] == of.VlanNone) && service != nil {
2404 return service
2405 }
2406 case OLTCVlanOLTSVlan,
2407 OLTSVlan:
2408 service = vnet.MatchesPriority(priority)
2409 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2410 return service
2411 }
2412 default:
2413 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2414 }
2415 }
2416 return nil
2417}
2418
2419// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2420// are used as the key to locate the service. If more than one service is on the
2421// same port (essentially a UNI of ONU), the services must be separated by different
2422// CVLANs
2423func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2424 // Fetch the device first to make sure the device exists
2425 dIntf, ok := va.DevicesDisc.Load(device)
2426 if !ok {
2427 return nil, nil
2428 }
2429 d := dIntf.(*VoltDevice)
2430
2431 // If the port is NNI port, the services dont exist on it. The svc then
2432 // must be obtained from a different context and is not included here
2433 if port == d.NniPort {
2434 return nil, nil
2435 }
2436
2437 //To return the matched service
2438 var service *VoltService
2439
2440 // This is an access port and the port should have all the associated
2441 // services which can be uniquely identified by the VLANs in the packet
2442 if vnets, ok := va.VnetsByPort.Load(port); ok {
2443 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2444 for _, vnet := range vnets.([]*VoltPortVnet) {
2445 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2446 switch vnet.VlanControl {
2447 case ONUCVlanOLTSVlan:
2448 service = vnet.MatchesPriority(priority)
2449 if vnet.MatchesCvlan(vlans) && service != nil {
2450 return vnet, service
2451 }
2452 case ONUCVlan,
2453 None:
2454 service = vnet.MatchesPriority(priority)
2455 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2456 return vnet, service
2457 }
2458 case OLTCVlanOLTSVlan,
2459 OLTSVlan:
2460 service = vnet.MatchesPriority(priority)
2461 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2462 return vnet, service
2463 }
2464 default:
2465 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2466 }
2467 }
2468 }
2469 return nil, nil
2470}
2471
2472// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2473// are used as the key to locate the service. If more than one service is on the
2474// same port (essentially a UNI of ONU), the services must be separated by different
2475// CVLANs
2476func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
2477 vlans := GetVlans(pkt)
2478 priority := GetPriority(pkt)
2479 return va.GetVnetFromFields(device, port, vlans, priority)
2480}
2481
2482// PushDevFlowForVlan to push icmpv6 flows for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302483func (va *VoltApplication) PushDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302484 logger.Infow(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2485 pushflow := func(key interface{}, value interface{}) bool {
2486 device := value.(*VoltDevice)
2487 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302488 logger.Infow(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +05302489 return true
2490 }
2491 if device.State != controller.DeviceStateUP {
2492 logger.Errorw(ctx, "Push Dev Flows Failed - Device state DOWN", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan, "device": device})
2493 return true
2494 }
2495 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2496 logger.Errorw(ctx, "Push Dev Flows Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2497 return true
2498 }
2499
2500 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2501 vnetList := vnetListIntf.(*util.ConcurrentMap)
2502 vnetList.Set(vnet.Name, true)
2503 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2504 logger.Infow(ctx, "Flow already pushed for these Vlans. Adding profile to list", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2505 return true
2506 }
2507 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2508 err := ProcessIcmpv6McGroup(device.Name, false)
2509 if err != nil {
2510 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2511 return true
2512 }
2513 if portID, err := va.GetPortID(device.NniPort); err == nil {
2514 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2515 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2516 return true
2517 }
2518
2519 //Pushing ICMPv6 Flow
2520 flow := BuildICMPv6Flow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302521 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302522 if err != nil {
2523 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2524 return true
2525 }
2526 logger.Infow(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
2527
2528 // Pushing ARP Flow
2529 flow = BuildDSArpFlow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302530 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302531 if err != nil {
2532 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2533 return true
2534 }
2535 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2536
2537 vnetList := util.NewConcurrentMap()
2538 vnetList.Set(vnet.Name, true)
2539 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2540 }
2541 return true
2542 }
2543 va.DevicesDisc.Range(pushflow)
2544}
2545
2546// PushDevFlowForDevice to push icmpv6 flows for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302547func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302548 logger.Infow(ctx, "PushDevFlowForDevice", log.Fields{"device": device})
2549
2550 logger.Debugw(ctx, "Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2551 err := ProcessIcmpv6McGroup(device.Name, false)
2552 if err != nil {
2553 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2554 return
2555 }
2556 pushicmpv6 := func(key, value interface{}) bool {
2557 vnet := value.(*VoltVnet)
2558 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2559 vnetList := vnetListIntf.(*util.ConcurrentMap)
2560 vnetList.Set(vnet.Name, true)
2561 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2562 logger.Infow(ctx, "Flow already pushed for these Vlans. Adding profile to list", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2563 return true
2564 }
2565 nniPortID, err := va.GetPortID(device.NniPort)
2566 if err != nil {
2567 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2568 }
2569 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2570 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2571 return true
2572 }
2573 flow := BuildICMPv6Flow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302574 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302575 if err != nil {
2576 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2577 return true
2578 }
2579 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2580
2581 flow = BuildDSArpFlow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302582 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302583 if err != nil {
2584 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2585 return true
2586 }
2587 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2588
2589 vnetList := util.NewConcurrentMap()
2590 vnetList.Set(vnet.Name, true)
2591 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2592 return true
2593 }
2594 va.VnetsByName.Range(pushicmpv6)
2595}
2596
2597// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302598func (va *VoltApplication) DeleteDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302599 logger.Infow(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2600 delflows := func(key interface{}, value interface{}) bool {
2601 device := value.(*VoltDevice)
2602
2603 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2604 vnetList := vnetListIntf.(*util.ConcurrentMap)
2605 vnetList.Remove(vnet.Name)
2606 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2607 if vnetList.Length() != 0 {
2608 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2609 return true
2610 }
2611 }
2612 if portID, err := va.GetPortID(device.NniPort); err == nil {
2613 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2614 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2615 return true
2616 }
2617 //Pushing ICMPv6 Flow
2618 flow := BuildICMPv6Flow(portID, vnet)
2619 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302620 err := vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302621 if err != nil {
2622 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2623 return true
2624 }
2625 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2626
2627 //Pushing ARP Flow
2628 flow = BuildDSArpFlow(portID, vnet)
2629 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302630 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302631 if err != nil {
2632 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2633 return true
2634 }
2635 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2636
2637 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2638 }
2639 return true
2640 }
2641 va.DevicesDisc.Range(delflows)
2642}
2643
2644// DeleteDevFlowForDevice to delete icmpv6 flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302645func (va *VoltApplication) DeleteDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302646 logger.Infow(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
2647 delicmpv6 := func(key, value interface{}) bool {
2648 vnet := value.(*VoltVnet)
2649 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2650 vnetList := vnetListIntf.(*util.ConcurrentMap)
2651 vnetList.Remove(vnet.Name)
2652 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2653 if vnetList.Length() != 0 {
2654 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2655 return true
2656 }
2657 } else {
2658 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2659 return true
2660 }
2661 nniPortID, err := va.GetPortID(device.NniPort)
2662 if err != nil {
2663 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2664 }
2665 flow := BuildICMPv6Flow(nniPortID, vnet)
2666 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302667 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302668 if err != nil {
2669 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2670 return true
2671 }
2672
2673 flow = BuildDSArpFlow(nniPortID, vnet)
2674 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302675 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302676 if err != nil {
2677 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2678 return true
2679 }
2680
2681 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2682 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2683 return true
2684 }
2685 va.VnetsByName.Range(delicmpv6)
2686 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2687 err := ProcessIcmpv6McGroup(device.Name, true)
2688 if err != nil {
2689 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2690 return
2691 }
2692}
2693
2694// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302695func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(cntx context.Context, vnet *VoltVnet, deviceSerialNum string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302696 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2697 delflows := func(key interface{}, value interface{}) bool {
2698 device := value.(*VoltDevice)
2699 if device.SerialNum != deviceSerialNum {
2700 return true
2701 }
2702 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2703 vnetList := vnetListIntf.(*util.ConcurrentMap)
2704 vnetList.Remove(vnet.Name)
2705 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2706 if vnetList.Length() != 0 {
2707 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2708 return true
2709 }
2710 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2711 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2712 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2713 // The step will be as follow:
2714 // 1. Deact Service
2715 // 2. Pod Reboot
2716 // 3. Pending Delete Service triggered
2717 // 4. Del Service Ind followed by DelVnet req from NB
2718 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2719 // hence the flow will not be cleared
2720 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2721 return true
2722 }
2723 if portID, err := va.GetPortID(device.NniPort); err == nil {
2724 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2725 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2726 return false
2727 }
2728 flow := BuildICMPv6Flow(portID, vnet)
2729 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302730 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302731 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2732 }
2733 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2734
2735 flow = BuildDSArpFlow(portID, vnet)
2736 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302737 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302738 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2739 }
2740 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2741 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2742 }
2743 return false
2744 }
2745 va.DevicesDisc.Range(delflows)
2746}
2747
2748// BuildICMPv6Flow to Build DS flow for ICMPv6
2749func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302750 logger.Infow(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302751 flow := &of.VoltFlow{}
2752 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2753 subFlow := of.NewVoltSubFlow()
2754
2755 subFlow.SetICMPv6Match()
2756 subFlow.SetMatchVlan(vnet.SVlan)
2757 subFlow.SetInPort(inport)
2758 subFlow.SetPopVlan()
2759 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2760 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2761 subFlow.Priority = of.McFlowPriority
2762 var metadata uint64
2763 if vnet.VlanControl == None {
2764 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2765 } else {
2766 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2767 }
2768 subFlow.SetTableMetadata(metadata)
2769 metadata = uint64(vnet.setPbitRemarking())
2770
2771 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2772 subFlow.SetWriteMetadata(metadata)
2773 flow.SubFlows[subFlow.Cookie] = subFlow
2774 return flow
2775}
2776
2777//BuildDSArpFlow Builds DS flow for ARP
2778func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302779 logger.Infow(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302780
2781 flow := &of.VoltFlow{}
2782 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2783 subFlow := of.NewVoltSubFlow()
2784
2785 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
2786 subFlow.SetArpMatch()
2787 subFlow.SetMatchDstMac(BcastMAC)
2788 subFlow.SetMatchVlan(vnet.SVlan)
2789 subFlow.SetInPort(inport)
2790 subFlow.SetPopVlan()
2791 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2792
2793 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
2794 subFlow.Priority = of.McFlowPriority
2795
2796 var metadata uint64
2797 if vnet.VlanControl == None {
2798 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2799 } else {
2800 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2801 }
2802 subFlow.SetTableMetadata(metadata)
2803 metadata = uint64(vnet.setPbitRemarking())
2804 subFlow.SetWriteMetadata(metadata)
2805
2806 flow.SubFlows[subFlow.Cookie] = subFlow
2807 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2808 return flow
2809}
2810
2811// setPbitRemarking to set Pbit remarking
2812func (vv *VoltVnet) setPbitRemarking() uint32 {
2813
2814 // Remarkable
2815 // Remarked Pbit Pbit
2816 // |-----------------------------| |------|
2817 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
2818 // 000 000 000 000 000 000 000 000 00000000
2819
2820 // Eg:
2821 // For 6:3 & 7:1
2822 // 001 011 000 000 000 000 000 000 11000000
2823
2824 var remarkable uint8
2825 var remarked uint32
2826 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
2827 remarkable = remarkable | 1<<refPbit
2828 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
2829 }
2830 return remarked<<8 | uint32(remarkable)
2831}
2832
2833// ProcessIcmpv6McGroup to add icmpv6 multicast group
2834func ProcessIcmpv6McGroup(device string, delete bool) error {
2835
2836 logger.Info(ctx, "Creating ICMPv6 MC Group")
2837 va := GetApplication()
2838 vd := va.GetDevice(device)
2839 group := &of.Group{}
2840 group.GroupID = ICMPv6ArpGroupID
2841 group.Device = device
2842 if delete {
2843 if !vd.icmpv6GroupAdded {
2844 logger.Info(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
2845 return nil //TODO
2846 }
2847 vd.icmpv6GroupAdded = false
2848 group.Command = of.GroupCommandDel
2849 group.ForceAction = true
2850 } else {
2851 if vd.icmpv6GroupAdded {
2852 logger.Info(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
2853 return nil //TODO
2854 }
2855 vd.icmpv6GroupAdded = true
2856 group.Command = of.GroupCommandAdd
2857 receivers := GetApplication().GetIcmpv6Receivers(device)
2858 group.Buckets = append(group.Buckets, receivers...)
2859 }
2860 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
2861 port, _ := GetApplication().GetNniPort(device)
2862 err := cntlr.GetController().GroupUpdate(port, device, group)
2863 return err
2864}
2865
2866//isVlanMatching - checks is vlans matches with vpv based on vlan control
2867func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
2868
2869 switch vpv.VlanControl {
2870 case ONUCVlanOLTSVlan,
2871 OLTCVlanOLTSVlan:
2872 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
2873 return true
2874 }
2875 case ONUCVlan,
2876 OLTSVlan,
2877 None:
2878 if vpv.SVlan == svlan {
2879 return true
2880 }
2881 default:
2882 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2883 }
2884 return false
2885}
2886
2887//PushFlows - Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302888func (vpv *VoltPortVnet) PushFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302889
2890 for cookie := range flow.SubFlows {
2891 cookie := strconv.FormatUint(cookie, 10)
2892 fe := &FlowEvent{
2893 eType: EventTypeControlFlowAdded,
2894 cookie: cookie,
2895 eventData: vpv,
2896 }
2897 device.RegisterFlowAddEvent(cookie, fe)
2898 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302899 return cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302900}
2901
2902//FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
2903func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
2904
2905 sendFlowFailureInd := func(key, value interface{}) bool {
2906 //svc := value.(*VoltService)
2907 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
2908 return true
2909 }
2910 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2911 vpv.services.Range(sendFlowFailureInd)
2912}
2913
2914//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302915func (vpv *VoltPortVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302916
2917 vpv.PendingFlowLock.Lock()
2918 defer vpv.PendingFlowLock.Unlock()
2919
2920 for cookie := range flow.SubFlows {
2921 cookie := strconv.FormatUint(cookie, 10)
2922 fe := &FlowEvent{
2923 eType: EventTypeControlFlowRemoved,
2924 device: device.Name,
2925 cookie: cookie,
2926 eventData: vpv,
2927 }
2928 device.RegisterFlowDelEvent(cookie, fe)
2929 vpv.PendingDeleteFlow[cookie] = true
2930 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302931 return cntlr.GetController().DelFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302932}
2933
2934//CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302935func (vpv *VoltPortVnet) CheckAndDeleteVpv(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302936 vpv.PendingFlowLock.RLock()
2937 defer vpv.PendingFlowLock.RUnlock()
2938 if !vpv.DeleteInProgress {
2939 return
2940 }
2941 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
2942 logger.Infow(ctx, "All Flows removed for VPV. Triggering VPV Deletion from DB", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302943 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302944 logger.Infow(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
2945 }
2946}
2947
2948//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302949func (vpv *VoltPortVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302950 vpv.PendingFlowLock.Lock()
2951 logger.Infow(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
2952
2953 delete(vpv.PendingDeleteFlow, cookie)
2954 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302955 vpv.CheckAndDeleteVpv(cntx)
2956 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302957}
2958
2959//FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302960func (vpv *VoltPortVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302961 vpv.PendingFlowLock.Lock()
2962
2963 logger.Errorw(ctx, "VPV Flow Remove Failure Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
2964
2965 sendFlowFailureInd := func(key, value interface{}) bool {
2966 svc := value.(*VoltService)
2967 svc.triggerServiceFailureInd(errorCode, errReason)
2968 return true
2969 }
2970 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2971 vpv.services.Range(sendFlowFailureInd)
2972
2973 if vpv.DeleteInProgress {
2974 delete(vpv.PendingDeleteFlow, cookie)
2975 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302976 vpv.CheckAndDeleteVpv(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302977 } else {
2978 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302979 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302980 }
2981}
2982
2983//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302984func (vv *VoltVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302985
2986 vv.VnetLock.Lock()
2987 defer vv.VnetLock.Unlock()
2988
2989 var flowMap map[string]bool
2990 var ok bool
2991
2992 for cookie := range flow.SubFlows {
2993 cookie := strconv.FormatUint(cookie, 10)
2994 fe := &FlowEvent{
2995 eType: EventTypeDeviceFlowRemoved,
2996 device: device.Name,
2997 cookie: cookie,
2998 eventData: vv,
2999 }
3000 device.RegisterFlowDelEvent(cookie, fe)
3001 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
3002 flowMap = make(map[string]bool)
3003 }
3004 flowMap[cookie] = true
3005 vv.PendingDeleteFlow[device.Name] = flowMap
3006 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303007 vv.WriteToDb(cntx)
3008 return cntlr.GetController().DelFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05303009}
3010
3011//CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303012func (vv *VoltVnet) CheckAndDeleteVnet(cntx context.Context, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303013 if !vv.DeleteInProgress {
3014 return
3015 }
3016 vv.VnetPortLock.RLock()
3017 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
3018 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
3019 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303020 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05303021 logger.Infow(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
3022 } else {
3023 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
3024 }
3025 vv.VnetPortLock.RUnlock()
3026}
3027
3028//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303029func (vv *VoltVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303030 vv.VnetLock.Lock()
3031 defer vv.VnetLock.Unlock()
3032
3033 logger.Infow(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
3034
3035 if _, ok := vv.PendingDeleteFlow[device]; ok {
3036 delete(vv.PendingDeleteFlow[device], cookie)
3037 }
3038
3039 //Check and update success for pending disable request
3040 if d := GetApplication().GetDevice(device); d != nil {
3041 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3042 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303043 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303044 }
3045 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303046 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303047}
3048
3049//FlowRemoveFailure - Process flow failure indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303050func (vv *VoltVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303051
3052 vv.VnetLock.Lock()
3053 defer vv.VnetLock.Unlock()
3054
3055 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3056 if _, ok := flowMap[cookie]; ok {
3057 logger.Errorw(ctx, "Device Flow Remove Failure Notification", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
3058
3059 if vv.DeleteInProgress {
3060 delete(vv.PendingDeleteFlow[device], cookie)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303061 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303062 }
3063 return
3064 }
3065 }
3066 logger.Errorw(ctx, "Device Flow Remove Failure Notification for Unknown cookie", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3067}
3068
3069//IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
3070func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
3071
3072 //Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3073 //When multiple Igmp-suported service enabled, comment "return false"
3074
3075 sendFlowFailureInd := func(key, value interface{}) bool {
3076 svc := value.(*VoltService)
3077 if svc.IgmpEnabled {
3078 svc.triggerServiceFailureInd(errorCode, errReason)
3079 return false
3080 }
3081 return true
3082 }
3083 logger.Errorw(ctx, "US IGMP Flow Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3084 vpv.services.Range(sendFlowFailureInd)
3085}
3086
3087// GetMatchingMcastService to get matching multicast service
3088func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
3089
3090 var service *VoltService
3091 dIntf, ok := va.DevicesDisc.Load(device)
3092 if !ok {
3093 return nil
3094 }
3095 d := dIntf.(*VoltDevice)
3096
3097 // If the port is NNI port, the services dont exist on it. The svc then
3098 // must be obtained from a different context and is not included here
3099 if port == d.NniPort {
3100 return nil
3101 }
3102
3103 // This is an access port and the port should have all the associated
3104 // services which can be uniquely identified by the VLANs in the packet
3105 vnets, ok := va.VnetsByPort.Load(port)
3106
3107 if !ok {
3108 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3109 return nil
3110 }
3111 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3112 getMcastService := func(key, value interface{}) bool {
3113 srv := value.(*VoltService)
3114 if srv.IgmpEnabled {
3115 service = srv
3116
3117 //TODO: Current implementation supports only for single service with Igmp Enabled
3118 //FIX-ME: When multiple service suports Igmp, update of logic required
3119 return false
3120 }
3121 return true
3122 }
3123
3124 for _, vpv := range vnets.([]*VoltPortVnet) {
3125 if vpv.CVlan == cvlan {
3126 vpv.services.Range(getMcastService)
3127 if service != nil {
3128 break
3129 }
3130 }
3131 }
3132 return service
3133}
3134
3135//TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303136func (vv *VoltVnet) TriggerAssociatedFlowDelete(cntx context.Context, device string) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05303137 vv.VnetLock.Lock()
3138 cookieList := []uint64{}
3139 flowMap := vv.PendingDeleteFlow[device]
3140
3141 for cookie := range flowMap {
3142 cookieList = append(cookieList, convertToUInt64(cookie))
3143 }
3144 vv.VnetLock.Unlock()
3145
3146 if len(cookieList) == 0 {
3147 return false
3148 }
3149
3150 for _, cookie := range cookieList {
3151 if vd := GetApplication().GetDevice(device); vd != nil {
3152 flow := &of.VoltFlow{}
3153 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3154 subFlow := of.NewVoltSubFlow()
3155 subFlow.Cookie = cookie
3156 flow.SubFlows[cookie] = subFlow
3157 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303158 if err := vv.RemoveFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05303159 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3160 }
3161 }
3162 }
3163 return true
3164}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303165
3166// JsonMarshal wrapper function for json Marshal VoltVnet
3167func (vv *VoltVnet) JsonMarshal() ([]byte, error) {
3168 return json.Marshal(VoltVnet{
3169 VnetConfig: vv.VnetConfig,
3170 Version: vv.Version,
3171 VnetOper: VnetOper{
3172 PendingDeleteFlow: vv.VnetOper.PendingDeleteFlow,
3173 DeleteInProgress: vv.VnetOper.DeleteInProgress,
3174 PendingDeviceToDelete: vv.VnetOper.PendingDeviceToDelete,
3175 },
3176 })
3177}
3178
3179// JsonMarshal wrapper function for json Marshal VoltPortVnet
3180func (vpv *VoltPortVnet) JsonMarshal() ([]byte, error) {
3181 return json.Marshal(VoltPortVnet{
3182 Device: vpv.Device,
3183 Port: vpv.Port,
3184 PonPort: vpv.PonPort,
3185 VnetName: vpv.VnetName,
3186 SVlan: vpv.SVlan,
3187 CVlan: vpv.CVlan,
3188 UniVlan: vpv.UniVlan,
3189 SVlanTpid: vpv.SVlanTpid,
3190 DhcpRelay: vpv.DhcpRelay,
3191 ArpRelay: vpv.ArpRelay,
3192 PppoeIa: vpv.PppoeIa,
3193 MacLearning: vpv.MacLearning,
3194 DhcpStatus: vpv.DhcpStatus,
3195 DhcpExpiryTime: vpv.DhcpExpiryTime,
3196 Dhcp6ExpiryTime: vpv.Dhcp6ExpiryTime,
3197 FlowsApplied: vpv.FlowsApplied,
3198 Ipv4Addr: vpv.Ipv4Addr,
3199 Ipv6Addr: vpv.Ipv6Addr,
3200 MacAddr: vpv.MacAddr,
3201 LearntMacAddr: vpv.LearntMacAddr,
3202 CircuitID: vpv.CircuitID,
3203 RemoteID: vpv.RemoteID,
3204 IsOption82Disabled: vpv.IsOption82Disabled,
3205 RelayState: vpv.RelayState,
3206 PPPoeState: vpv.PPPoeState,
3207 RelayStatev6: vpv.RelayStatev6,
3208 IgmpEnabled: vpv.IgmpEnabled,
3209 IgmpFlowsApplied: vpv.IgmpFlowsApplied,
3210 McastService: vpv.McastService,
3211 ONTEtherTypeClassification: vpv.ONTEtherTypeClassification,
3212 VlanControl: vpv.VlanControl,
3213 MvlanProfileName: vpv.MvlanProfileName,
3214 Version: vpv.Version,
3215 McastTechProfileID: vpv.McastTechProfileID,
3216 McastPbit: vpv.McastPbit,
3217 McastUsMeterID: vpv.McastUsMeterID,
3218 AllowTransparent: vpv.AllowTransparent,
3219 SchedID: vpv.SchedID,
3220 DHCPv6DUID: vpv.DHCPv6DUID,
3221 PendingDeleteFlow: vpv.PendingDeleteFlow,
3222 DeleteInProgress: vpv.DeleteInProgress,
3223 Blocked: vpv.Blocked,
3224 DhcpPbit: vpv.DhcpPbit,
3225 })
3226}
Tinoj Josephec742f62022-09-29 19:11:10 +05303227
3228func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) bool {
3229 isActivated := false
3230 vpv.services.Range(func(key, value interface{}) bool {
3231 svc := value.(*VoltService)
3232 if svc.IsActivated {
3233 logger.Infow(ctx, "Found activated service on the vpv", log.Fields{"Name": svc.Name})
3234 isActivated = true
3235 return false //to exit loop
3236 }
3237 return true
3238 })
3239 return isActivated
3240}