blob: e11960c358f0e34360f3935ca2f2088d523bacd6 [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
516 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": vpv.Device, "Port": vpv.Port, "SVlan": vpv.SVlan})
517
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 Joseph07cc5372022-07-18 22:53:51 +0530820func (vpv *VoltPortVnet) PortDownInd(cntx context.Context, device string, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530821
822 logger.Infow(ctx, "VPV Port DOWN Ind, deleting all flows for services",
823 log.Fields{"service count": vpv.servicesCount.Load()})
824
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530825 //vpv.RangeOnServices(cntx, DelAllFlows)
826 vpv.DelTrapFlows(cntx)
827 vpv.DelHsiaFlows(cntx)
828 vpv.WriteToDb(cntx)
829 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530830}
831
832// SetMacAddr : The MAC address is set when a MAC address is learnt through the
833// packets received from the network. Currently, DHCP packets are
834// only packets we learn the MAC address from
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530835func (vpv *VoltPortVnet) SetMacAddr(cntx context.Context, addr net.HardwareAddr) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530836
837 //Store Learnt MAC address and return if MACLearning is not enabled
838 vpv.LearntMacAddr = addr
839 if vpv.MacLearning == MacLearningNone || !NonZeroMacAddress(addr) ||
840 (NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn) {
841 return
842 }
843
844 // Compare the two MAC addresses to see if it is same
845 // If they are same, we just return. If not, we perform
846 // actions to address the change in MAC address
847 //if NonZeroMacAddress(vpv.MacAddr) && !util.MacAddrsMatch(vpv.MacAddr, addr) {
848 if !util.MacAddrsMatch(vpv.MacAddr, addr) {
849 expectedPort := GetApplication().GetMacInPortMap(addr)
850 if expectedPort != "" && expectedPort != vpv.Port {
851 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-setmacaddr",
852 log.Fields{"ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": addr.String()})
853 return
854 }
855 if NonZeroMacAddress(vpv.MacAddr) {
856 logger.Warnw(ctx, "MAC Address Changed. Remove old flows (if added) and re-add with updated MAC", log.Fields{"UpdatedMAC": addr})
857
858 // The newly learnt MAC address is different than earlier one.
859 // The existing MAC based HSIA flows need to be undone as the device
860 // may have been changed
861 // Atleast one HSIA flow should be present in adapter to retain the TP and GEM
862 // hence delete one after the other
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530863 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530864 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530865 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
866 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
867 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530868 GetApplication().DeleteMacInPortMap(vpv.MacAddr)
869 } else {
870 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530871 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530872 logger.Infow(ctx, "MAC Address learnt from DHCP or ARP", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
873 }
874 GetApplication().UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
875 } else {
876 logger.Infow(ctx, "Leant MAC Address is same", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
877 }
878
879 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
880 if err != nil {
881 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
882 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
883 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
884 return
885 }
886 // Ds Hsia flows has to be pushed
887 if vpv.FlowsApplied {
888 // no HSIA flows for multicast service
889 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530890 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530891 }
892 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530893 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530894}
895
896// MatchesVlans : If the VNET matches both S and C VLANs, return true. Else, return false
897func (vpv *VoltPortVnet) MatchesVlans(svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) bool {
898 if vpv.SVlan != svlan || vpv.CVlan != cvlan || vpv.UniVlan != univlan {
899 return false
900 }
901 return true
902}
903
904// MatchesCvlan : If the VNET matches CVLAN, return true. Else, return false
905func (vpv *VoltPortVnet) MatchesCvlan(cvlan []of.VlanType) bool {
906 if len(cvlan) != 1 && !vpv.AllowTransparent {
907 return false
908 }
909 if vpv.CVlan != cvlan[0] {
910 return false
911 }
912 return true
913}
914
915// MatchesPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
916func (vpv *VoltPortVnet) MatchesPriority(priority uint8) *VoltService {
917
918 var service *VoltService
919 pbitFound := false
920 matchpbitsFunc := func(key, value interface{}) bool {
921 svc := value.(*VoltService)
922 for _, pbit := range svc.Pbits {
923 if uint8(pbit) == priority {
924 logger.Infow(ctx, "Pbit match found with service",
925 log.Fields{"Pbit": priority, "serviceName": svc.Name})
926 pbitFound = true
927 service = svc
928 return false //Returning false to stop the Range loop
929 }
930 }
931 return true
932 }
933 _ = pbitFound
934 vpv.services.Range(matchpbitsFunc)
935 return service
936}
937
938// GetRemarkedPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
939func (vpv *VoltPortVnet) GetRemarkedPriority(priority uint8) uint8 {
940
941 dsPbit := uint8(0)
942 matchpbitsFunc := func(key, value interface{}) bool {
943 svc := value.(*VoltService)
944 if remarkPbit, ok := svc.DsRemarkPbitsMap[int(priority)]; ok {
945 logger.Infow(ctx, "Pbit match found with service",
946 log.Fields{"Pbit": priority, "serviceName": svc.Name, "remarkPbit": remarkPbit})
947 dsPbit = uint8(remarkPbit)
948 return false //Returning false to stop the Range loop
949 }
950 // When no remarking info is available, remark the incoming pbit
951 // to highest pbit configured for the subscriber (across all subservices associated)
952 svcPbit := uint8(svc.Pbits[0])
953 if svcPbit > dsPbit {
954 dsPbit = svcPbit
955 }
956 return true
957 }
958 vpv.services.Range(matchpbitsFunc)
959 logger.Debugw(ctx, "Remarked Pbit Value", log.Fields{"Incoming": priority, "Remarked": dsPbit})
960 return dsPbit
961}
962
963// AddSvc adds a service on the VNET on a port. The addition is
964// triggered when NB requests for service addition
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530965func (vpv *VoltPortVnet) AddSvc(cntx context.Context, svc *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530966
967 //vpv.services = append(vpv.services, svc)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530968 vpv.AddService(cntx, svc)
Naveen Sampath04696f72022-06-13 15:19:14 +0530969 logger.Debugw(ctx, "Added Service to VPV", log.Fields{"Num of SVCs": vpv.servicesCount.Load(), "SVC": svc})
970
971 // Learn the circuit-id and remote-id from the service
972 // TODO: There must be a better way of doing this. This
973 // may be explored
974 if svc.IgmpEnabled {
975 vpv.IgmpEnabled = true
976 }
977 // first time service activation MacLearning will have default value as None.
978 // to handle reciliency if anythng other then None we should retain it .
979 if svc.MacLearning == MacLearningNone {
980 if !vpv.DhcpRelay && !vpv.ArpRelay {
981 svc.MacLearning = MacLearningNone
982 } else if vpv.MacLearning == Learn {
983 svc.MacLearning = Learn
984 } else if vpv.MacLearning == ReLearn {
985 svc.MacLearning = ReLearn
986 }
987 }
988
989 //TODO: Temp Change - Need to address MAC Learning flow issues completely
990 if (svc.MacLearning == Learn || svc.MacLearning == ReLearn) && NonZeroMacAddress(vpv.MacAddr) {
991 svc.MacAddr = vpv.MacAddr
992 } else if vpv.servicesCount.Load() == 1 {
993 vpv.MacAddr = svc.MacAddr
994 }
995
996 vpv.MacLearning = svc.MacLearning
997 vpv.PonPort = svc.PonPort
998 logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
999 //Reconfigure Vlans based on Vlan Control type
1000 svc.VlanControl = vpv.VlanControl
1001 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
1002 if vpv.VlanControl == ONUCVlan {
1003 svc.CVlan = svc.SVlan
1004 }
1005 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
1006 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
1007 if vpv.VlanControl == OLTSVlan {
1008 svc.CVlan = svc.UniVlan
1009 }
1010 if svc.McastService {
1011 vpv.McastService = true
1012 vpv.McastTechProfileID = svc.TechProfileID
1013 //Assumption: Only one Pbit for mcast service
1014 vpv.McastPbit = svc.Pbits[0]
1015 vpv.McastUsMeterID = svc.UsMeterID
1016 vpv.SchedID = svc.SchedID
1017 }
1018 svc.ONTEtherTypeClassification = vpv.ONTEtherTypeClassification
1019 svc.AllowTransparent = vpv.AllowTransparent
1020 svc.SVlanTpid = vpv.SVlanTpid
1021
1022 //Ensure configuring the mvlan profile only once
1023 //One subscriber cannot have multiple mvlan profiles. Only the first configuration is valid
1024 if svc.MvlanProfileName != "" {
1025 if vpv.MvlanProfileName == "" {
1026 vpv.MvlanProfileName = svc.MvlanProfileName
1027 } else {
1028 logger.Warnw(ctx, "Mvlan Profile already configured for subscriber. Ignoring new Mvlan", log.Fields{"Existing Mvlan": vpv.MvlanProfileName, "New Mvlan": svc.MvlanProfileName})
1029 }
1030 }
1031
1032 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
1033 if err != nil {
1034 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
1035 //statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1036 //TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1037 return
1038 }
1039
1040 //Push Service Flows if DHCP relay is not configured
1041 //or already DHCP flows are configured for the VPV
1042 //to which the serivce is associated
1043 if vpv.FlowsApplied {
1044 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301045 svc.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301046 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301047 if err:= svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301048 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1049 }
1050 }
1051 }
1052
1053 //Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
1054 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1055 // service with Igmp Enabled needs to be installed
1056 if svc.IgmpEnabled && vpv.FlowsApplied {
1057 logger.Infow(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301058 if err := vpv.AddIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301059 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1060 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1061 }
1062
1063 if vpv.McastService {
1064 //For McastService, send Service Activated indication once IGMP US flow is pushed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301065 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +05301066 }
1067 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301068 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301069}
1070
1071// setLearntMAC to set learnt mac
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301072func (vpv *VoltPortVnet) setLearntMAC(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301073 svc := value.(*VoltService)
1074 svc.SetMacAddr(vpv.MacAddr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301075 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301076 return true
1077}
1078
1079// PostAccessConfigSuccessInd for posting access config success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301080func PostAccessConfigSuccessInd(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301081 return true
1082}
1083
1084// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301085func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301086 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301087 logger.Infow(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301088 svc.SetIpv4Addr(vpv.Ipv4Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301089 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301090
1091 return true
1092}
1093
1094// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301095func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301096 svc := value.(*VoltService)
1097 svc.SetIpv6Addr(vpv.Ipv6Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301098 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301099
1100 return true
1101}
1102
1103// AddUsHsiaFlows to add upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301104func AddUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301105 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301106 if err:= svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301107 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1108 }
1109 return true
1110}
1111
1112// AddDsHsiaFlows to add downstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301113func AddDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301114 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301115 if err:= svc.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301116 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1117 }
1118 return true
1119}
1120
1121// ClearFlagsInService to clear the flags used in service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301122func ClearFlagsInService(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301123 svc := value.(*VoltService)
1124 svc.ServiceLock.Lock()
1125 svc.IgmpFlowsApplied = false
1126 svc.DsDhcpFlowsApplied = false
1127 svc.DsHSIAFlowsApplied = false
1128 svc.Icmpv6FlowsApplied = false
1129 svc.UsHSIAFlowsApplied = false
1130 svc.UsDhcpFlowsApplied = false
1131 svc.PendingFlows = make(map[string]bool)
1132 svc.AssociatedFlows = make(map[string]bool)
1133 svc.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301134 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301135 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1136 return true
1137}
1138
1139// DelDsHsiaFlows to delete hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301140func DelDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301141 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301142 if err:= svc.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301143 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1144 }
1145 return true
1146}
1147
1148// DelUsHsiaFlows to delete upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301149func DelUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301150 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301151 if err:= svc.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301152 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1153 }
1154 return true
1155}
1156
1157// ClearServiceCounters to clear the service counters
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301158func ClearServiceCounters(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301159 svc := value.(*VoltService)
1160 //Delete the per service counter too
1161 GetApplication().ServiceCounters.Delete(svc.Name)
1162 if svc.IgmpEnabled && svc.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301163 _ = db.DelAllServiceChannelCounter(cntx, svc.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301164 }
1165 return true
1166}
1167
1168//AddTrapFlows - Adds US & DS Trap flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301169func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301170
1171 if !vpv.FlowsApplied || vgcRebooted {
1172 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301173 if err := vpv.AddUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301174 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1175 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1176 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301177 if err := vpv.AddDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301178 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1179 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1180 }
1181 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1182 log.Fields{"port": vpv.Port})
1183 //vpv.updateICMPv6McGroup(true)
1184 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301185 if err := vpv.AddUsArpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301186 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1187 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1188 }
1189 logger.Info(ctx, "ARP trap rules not added in downstream direction")
1190
1191 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301192 if err := vpv.AddUsPppoeFlows(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 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301196 if err := vpv.AddDsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301197 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1198 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1199 }
1200 }
1201 vpv.FlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301202 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301203 }
1204}
1205
1206//DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301207func (vpv *VoltPortVnet) DelTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301208
1209 // Delete HSIA & DHCP flows before deleting IGMP flows
1210 if vpv.FlowsApplied || vgcRebooted {
1211 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301212 if err:= vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301213 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1214 "UniVlan": vpv.UniVlan, "Error": err})
1215 }
1216 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1217 log.Fields{"port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301218 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301219 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1220 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1221 }
1222 //vpv.updateICMPv6McGroup(false)
1223 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301224 if err := vpv.DelUsArpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301225 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1226 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1227 }
1228 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301229 if err := vpv.DelUsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301230 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1231 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1232 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301233 if err := vpv.DelDsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301234 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1235 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1236 }
1237 }
1238 vpv.FlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301239 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301240 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301241 if err:= vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301242 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1243 "UniVlan": vpv.UniVlan, "Error": err})
1244 }
1245}
1246
1247// DelHsiaFlows deletes the service flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301248func (vpv *VoltPortVnet) DelHsiaFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301249 // no HSIA flows for multicast service
1250 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301251 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
1252 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301253 }
1254}
1255
1256//ClearServiceCounters - Removes all igmp counters for a service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301257func (vpv *VoltPortVnet) ClearServiceCounters(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301258 //send flows deleted indication to submgr
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301259 vpv.RangeOnServices(cntx, ClearServiceCounters)
Naveen Sampath04696f72022-06-13 15:19:14 +05301260}
1261
1262// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301263func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301264 var vd *VoltDevice
1265 device := vpv.Device
1266
1267 if vd = GetApplication().GetDevice(device); vd != nil {
1268 if vd.State != controller.DeviceStateUP {
1269 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})
1270 return nil
1271 }
1272 } else {
1273 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})
1274 return errorCodes.ErrDeviceNotFound
1275 }
1276
1277 flows, err := vpv.BuildUsDhcpFlows()
1278 if err == nil {
1279 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301280 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301281 //push ind here ABHI
1282 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1283 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1284 }
1285 } else {
1286 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1287 //push ind here ABHI
1288 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1289 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1290
1291 }
1292 /*
1293 flows, err = vpv.BuildUsDhcp6Flows()
1294 if err == nil {
1295 logger.Debugw(ctx, "Adding US DHCP6 flows", log.Fields{"Device": device})
1296 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1297 //pussh ind here ABHI
1298 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1299 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1300
1301 }
1302 } else {
1303 logger.Errorw(ctx, "US DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1304 //push ind here ABHI
1305 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1306 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1307
1308 }*/
1309 return nil
1310}
1311
1312// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301313func (vpv *VoltPortVnet) AddDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301314
1315 var vd *VoltDevice
1316 device := vpv.Device
1317
1318 if vd = GetApplication().GetDevice(device); vd != nil {
1319 if vd.State != controller.DeviceStateUP {
1320 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})
1321 return nil
1322 }
1323 } else {
1324 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})
1325 return errorCodes.ErrDeviceNotFound
1326 }
1327 if GetApplication().GetVendorID() != Radisys && vd.GlobalDhcpFlowAdded {
1328 return nil
1329 }
1330
1331 flows, err := vpv.BuildDsDhcpFlows()
1332 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301333 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301334 //push ind here and procced
1335 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1336 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1337
1338 }
1339 } else {
1340 logger.Errorw(ctx, "DS DHCP Flow Add Failed", log.Fields{"Reason": err.Error()})
1341 //send ind here and proceed
1342 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1343 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1344
1345 }
1346 /*
1347 flows, err = vpv.BuildDsDhcp6Flows()
1348 if err == nil {
1349 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1350 //push ind and proceed
1351 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1352 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1353
1354 }
1355 } else {
1356 logger.Errorw(ctx, "DS DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error()})
1357 //Send ind here and proceed
1358 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1359 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1360
1361 }*/
1362 if GetApplication().GetVendorID() != Radisys {
1363 vd.GlobalDhcpFlowAdded = true
1364 }
1365 return nil
1366}
1367
1368// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301369func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
1370 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301371 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1372 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1373 }
1374
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301375 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301376 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1377 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1378 }
1379}
1380
1381// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1382// Write the status of the VPV to the DB once the delete is scheduled
1383// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301384func (vpv *VoltPortVnet) DelUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301385 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1386 if err != nil {
1387 return err
1388 }
1389
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301390 err = vpv.delDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301391 if err != nil {
1392 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1393 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1394 }
1395 /*
1396 err = vpv.delDhcp6Flows(device)
1397 if err != nil {
1398 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1399 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1400 }*/
1401 return nil
1402}
1403
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301404func (vpv *VoltPortVnet) delDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301405 flows, err := vpv.BuildUsDhcpFlows()
1406 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301407 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301408 }
1409 logger.Errorw(ctx, "US DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1410 return err
1411}
1412/*
1413func (vpv *VoltPortVnet) delDhcp6Flows(device *VoltDevice) error {
1414 flows, err := vpv.BuildUsDhcp6Flows()
1415 if err == nil {
1416 return vpv.RemoveFlows(device, flows)
1417 }
1418 logger.Errorw(ctx, "US DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1419 return err
1420
1421}*/
1422
1423// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1424// Write the status of the VPV to the DB once the delete is scheduled
1425// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301426func (vpv *VoltPortVnet) DelDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301427 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1428 if err != nil {
1429 return err
1430 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301431 err = vpv.delDsDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301432 if err != nil {
1433 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1434 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1435 }
1436 /*
1437 err = vpv.delDsDhcp6Flows(device)
1438 if err != nil {
1439 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1440 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1441 }*/
1442 return nil
1443}
1444
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301445func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301446 flows, err := vpv.BuildDsDhcpFlows()
1447 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301448 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301449 }
1450 logger.Errorw(ctx, "DS DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1451 return err
1452}
1453
1454/*
1455func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1456 flows, err := vpv.BuildDsDhcp6Flows()
1457 if err == nil {
1458 return vpv.RemoveFlows(device, flows)
1459 }
1460 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1461 return err
1462}*/
1463
1464// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301465func (vpv *VoltPortVnet) AddUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301466
1467 var vd *VoltDevice
1468 device := vpv.Device
1469 if vd = GetApplication().GetDevice(device); vd != nil {
1470 if vd.State != controller.DeviceStateUP {
1471 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})
1472 return nil
1473 }
1474 } else {
1475 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})
1476 return errorCodes.ErrDeviceNotFound
1477 }
1478
1479 flows, err := vpv.BuildUsArpFlows()
1480 if err == nil {
1481 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301482 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301483 return err1
1484 }
1485 } else {
1486 logger.Errorw(ctx, "US ARP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1487 return err
1488 }
1489 return nil
1490}
1491
1492// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1493// Write the status of the VPV to the DB once the delete is scheduled
1494// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301495func (vpv *VoltPortVnet) DelUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301496 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1497 if err != nil {
1498 return err
1499 }
1500 flows, err := vpv.BuildUsArpFlows()
1501 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301502 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301503 }
1504 logger.Errorw(ctx, "US ARP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1505 return err
1506}
1507
1508// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301509func (vpv *VoltPortVnet) AddUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301510 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1511
1512 var vd *VoltDevice
1513 device := vpv.Device
1514
1515 if vd = GetApplication().GetDevice(device); vd != nil {
1516 if vd.State != controller.DeviceStateUP {
1517 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})
1518 return nil
1519 }
1520 } else {
1521 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})
1522 return errorCodes.ErrDeviceNotFound
1523 }
1524
1525 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1526 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1527
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301528 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301529 return err1
1530 }
1531 } else {
1532 logger.Errorw(ctx, "US PPPoE Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1533 return err
1534 }
1535 return nil
1536}
1537
1538// AddDsPppoeFlows to add downstream pppoe flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301539func (vpv *VoltPortVnet) AddDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301540 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1541 var vd *VoltDevice
1542 device := vpv.Device
1543
1544 if vd = GetApplication().GetDevice(device); vd != nil {
1545 if vd.State != controller.DeviceStateUP {
1546 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})
1547 return nil
1548 }
1549 } else {
1550 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})
1551 return errorCodes.ErrDeviceNotFound
1552 }
1553
1554 flows, err := vpv.BuildDsPppoeFlows()
1555 if err == nil {
1556
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301557 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301558 return err1
1559 }
1560 } else {
1561 logger.Errorw(ctx, "DS PPPoE Flow Add Failed", log.Fields{"Reason": err.Error()})
1562 return err
1563 }
1564 return nil
1565}
1566
1567// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1568// Write the status of the VPV to the DB once the delete is scheduled
1569// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301570func (vpv *VoltPortVnet) DelUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301571 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1572 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1573 if err != nil {
1574 return err
1575 }
1576 flows, err := vpv.BuildUsPppoeFlows()
1577 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301578 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301579 }
1580 logger.Errorw(ctx, "US PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1581 return err
1582}
1583
1584// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1585// Write the status of the VPV to the DB once the delete is scheduled
1586// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301587func (vpv *VoltPortVnet) DelDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301588 logger.Debugw(ctx, "Deleting DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1589 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1590 if err != nil {
1591 return err
1592 }
1593 flows, err := vpv.BuildDsPppoeFlows()
1594 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301595 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301596 }
1597 logger.Errorw(ctx, "DS PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1598 return err
1599}
1600
1601// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301602func (vpv *VoltPortVnet) AddIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301603
1604 if !vpv.IgmpFlowsApplied || vgcRebooted {
1605 if vpv.MvlanProfileName == "" {
1606 logger.Info(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
1607 return nil
1608 }
1609 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1610 if err != nil {
1611 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1612 return err
1613 } else if device.State != controller.DeviceStateUP {
1614 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})
1615 return nil
1616 }
1617 flows, err := vpv.BuildIgmpFlows()
1618 if err == nil {
1619 for cookie := range flows.SubFlows {
1620 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1621 cookie := strconv.FormatUint(cookie, 10)
1622 fe := &FlowEvent{
1623 eType: EventTypeUsIgmpFlowAdded,
1624 cookie: cookie,
1625 eventData: vpv,
1626 }
1627 vd.RegisterFlowAddEvent(cookie, fe)
1628 }
1629 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301630 if err1 := cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301631 return err1
1632 }
1633 } else {
1634 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1635 return err
1636 }
1637 vpv.IgmpFlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301638 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301639 }
1640 return nil
1641}
1642
1643// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1644// Write the status of the VPV to the DB once the delete is scheduled
1645// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301646func (vpv *VoltPortVnet) DelIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301647
1648 if vpv.IgmpFlowsApplied || vgcRebooted {
1649 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1650 if err != nil {
1651 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1652 return err
1653 }
1654 flows, err := vpv.BuildIgmpFlows()
1655 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301656 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301657 return err1
1658 }
1659 } else {
1660 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1661 return err
1662 }
1663 vpv.IgmpFlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301664 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301665 }
1666 return nil
1667}
1668
1669// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1670// The flows included by this function cover US only as the DS is
1671// created either automatically by the VOLTHA or at the device level
1672// earlier
1673func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
1674 flow := &of.VoltFlow{}
1675 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1676
1677 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
1678 subFlow := of.NewVoltSubFlow()
1679 subFlow.SetTableID(0)
1680
1681 if GetApplication().GetVendorID() == Radisys {
1682 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1683 return nil, err
1684 }
1685 } else {
1686 subFlow.SetMatchVlan(vpv.UniVlan)
1687 subFlow.SetSetVlan(vpv.CVlan)
1688 }
1689 subFlow.SetUdpv4Match()
1690 subFlow.SrcPort = 68
1691 subFlow.DstPort = 67
1692 uniport, err := GetApplication().GetPortID(vpv.Port)
1693 if err != nil {
1694 logger.Errorw(ctx, "Failed to fetch uni port from vpv", log.Fields{"error": err, "port": vpv.Port})
1695 return nil, err
1696 }
1697 subFlow.SetInPort(uniport)
1698 // PortName and PortID to be used for validation of port before flow pushing
1699 flow.PortID = uniport
1700 flow.PortName = vpv.Port
1701 subFlow.SetReportToController()
1702
1703 // Set techprofile, meterid of first service
1704 vpv.services.Range(func(key, value interface{}) bool {
1705 svc := value.(*VoltService)
1706 writemetadata := uint64(svc.TechProfileID) << 32
1707 subFlow.SetWriteMetadata(writemetadata)
1708 subFlow.SetMeterID(svc.UsMeterID)
1709 return false
1710 })
1711
1712 subFlow.SetPcp(vpv.DhcpPbit)
1713 // metadata := uint64(uniport)
1714 // subFlow.SetWriteMetadata(metadata)
1715 allowTransparent := 0
1716 if vpv.AllowTransparent {
1717 allowTransparent = 1
1718 }
1719 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1720 subFlow.SetTableMetadata(metadata)
1721
1722 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1723 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1724 subFlow.Priority = of.DhcpFlowPriority
1725
1726 flow.SubFlows[subFlow.Cookie] = subFlow
1727 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1728 return flow, nil
1729}
1730
1731// BuildDsDhcpFlows to build the downstream dhcp flows
1732func (vpv *VoltPortVnet) BuildDsDhcpFlows() (*of.VoltFlow, error) {
1733
1734 logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1735 flow := &of.VoltFlow{}
1736 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1737 subFlow := of.NewVoltSubFlow()
1738 subFlow.SetTableID(0)
1739 // If dhcp trap rule is global rule, No need to match on vlan
1740 if GetApplication().GetVendorID() == Radisys {
1741 vpv.setDsMatchVlan(subFlow)
1742 }
1743 subFlow.SetUdpv4Match()
1744 subFlow.SrcPort = 67
1745 subFlow.DstPort = 68
1746 uniport, _ := GetApplication().GetPortID(vpv.Port)
1747 nni, err := GetApplication().GetNniPort(vpv.Device)
1748 if err != nil {
1749 return nil, err
1750 }
1751 nniport, err := GetApplication().GetPortID(nni)
1752 if err != nil {
1753 return nil, err
1754 }
1755 subFlow.SetInPort(nniport)
1756 // PortName and PortID to be used for validation of port before flow pushing
1757 flow.PortID = uniport
1758 flow.PortName = vpv.Port
1759 // metadata := uint64(uniport)
1760 // subFlow.SetWriteMetadata(metadata)
1761 allowTransparent := 0
1762 if vpv.AllowTransparent {
1763 allowTransparent = 1
1764 }
1765 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1766 subFlow.SetTableMetadata(metadata)
1767 subFlow.SetReportToController()
1768 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1769 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
1770 subFlow.Priority = of.DhcpFlowPriority
1771
1772 flow.SubFlows[subFlow.Cookie] = subFlow
1773 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1774
1775 return flow, nil
1776}
1777
1778// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1779// application.
1780func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
1781 flow := &of.VoltFlow{}
1782 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1783
1784 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
1785 subFlow := of.NewVoltSubFlow()
1786 subFlow.SetTableID(0)
1787
1788 subFlow.SetMatchVlan(vpv.UniVlan)
1789 subFlow.SetSetVlan(vpv.CVlan)
1790 subFlow.SetUdpv6Match()
1791 subFlow.SrcPort = 546
1792 subFlow.DstPort = 547
1793 uniport, err := GetApplication().GetPortID(vpv.Port)
1794 if err != nil {
1795 return nil, err
1796 }
1797 // Set techprofile, meterid of first service
1798 vpv.services.Range(func(key, value interface{}) bool {
1799 svc := value.(*VoltService)
1800 writemetadata := uint64(svc.TechProfileID) << 32
1801 subFlow.SetWriteMetadata(writemetadata)
1802 subFlow.SetMeterID(svc.UsMeterID)
1803 return false
1804 })
1805 subFlow.SetInPort(uniport)
1806 // PortName and PortID to be used for validation of port before flow pushing
1807 flow.PortID = uniport
1808 flow.PortName = vpv.Port
1809 //subFlow.SetMeterId(vpv.UsDhcpMeterId)
1810 // metadata := uint64(uniport)
1811 // subFlow.SetWriteMetadata(metadata)
1812 allowTransparent := 0
1813 if vpv.AllowTransparent {
1814 allowTransparent = 1
1815 }
1816 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1817 subFlow.SetTableMetadata(metadata)
1818 subFlow.SetReportToController()
1819 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1820 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
1821 subFlow.Priority = of.DhcpFlowPriority
1822
1823 flow.SubFlows[subFlow.Cookie] = subFlow
1824 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1825 return flow, nil
1826}
1827
1828// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1829// application.
1830func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
1831 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1832
1833 flow := &of.VoltFlow{}
1834 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1835 subFlow := of.NewVoltSubFlow()
1836 subFlow.SetTableID(0)
1837
1838 vpv.setDsMatchVlan(subFlow)
1839 subFlow.SetUdpv6Match()
1840 subFlow.SrcPort = 547
1841 subFlow.DstPort = 547
1842 uniport, _ := GetApplication().GetPortID(vpv.Port)
1843 nni, err := GetApplication().GetNniPort(vpv.Device)
1844 if err != nil {
1845 return nil, err
1846 }
1847 nniport, err := GetApplication().GetPortID(nni)
1848 if err != nil {
1849 return nil, err
1850 }
1851 subFlow.SetInPort(nniport)
1852 // PortName and PortID to be used for validation of port before flow pushing
1853 flow.PortID = uniport
1854 flow.PortName = vpv.Port
1855 // metadata := uint64(uniport)
1856 // subFlow.SetWriteMetadata(metadata)
1857 allowTransparent := 0
1858 if vpv.AllowTransparent {
1859 allowTransparent = 1
1860 }
1861 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1862 subFlow.SetTableMetadata(metadata)
1863 subFlow.SetReportToController()
1864 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1865 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
1866 subFlow.Priority = of.DhcpFlowPriority
1867
1868 flow.SubFlows[subFlow.Cookie] = subFlow
1869 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1870 return flow, nil
1871}
1872
1873// BuildUsArpFlows builds the US ARP relay flows for a subscriber
1874// The flows included by this function cover US only as the DS is
1875// created either automatically by the VOLTHA or at the device level
1876// earlier
1877func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
1878 flow := &of.VoltFlow{}
1879 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1880
1881 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
1882 subFlow := of.NewVoltSubFlow()
1883 subFlow.SetTableID(0)
1884
1885 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1886 subFlow.SetMatchSrcMac(vpv.MacAddr)
1887 }
1888
1889 subFlow.SetMatchDstMac(BroadcastMAC)
1890 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1891 return nil, err
1892 }
1893 subFlow.SetArpMatch()
1894 uniport, err := GetApplication().GetPortID(vpv.Port)
1895 if err != nil {
1896 return nil, err
1897 }
1898 subFlow.SetInPort(uniport)
1899 // PortName and PortID to be used for validation of port before flow pushing
1900 flow.PortID = uniport
1901 flow.PortName = vpv.Port
1902 subFlow.SetReportToController()
1903 allowTransparent := 0
1904 if vpv.AllowTransparent {
1905 allowTransparent = 1
1906 }
1907 metadata := uint64(uniport)
1908 subFlow.SetWriteMetadata(metadata)
1909 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1910 subFlow.SetTableMetadata(metadata)
1911 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
1912 subFlow.Priority = of.ArpFlowPriority
1913
1914 flow.SubFlows[subFlow.Cookie] = subFlow
1915 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1916 return flow, nil
1917}
1918
1919// setUsMatchVlan to set upstream match vlan
1920func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
1921 switch vpv.VlanControl {
1922 case None:
1923 flow.SetMatchVlan(vpv.SVlan)
1924 case ONUCVlanOLTSVlan:
1925 flow.SetMatchVlan(vpv.CVlan)
1926 case OLTCVlanOLTSVlan:
1927 flow.SetMatchVlan(vpv.UniVlan)
1928 //flow.SetSetVlan(vpv.CVlan)
1929 case ONUCVlan:
1930 flow.SetMatchVlan(vpv.SVlan)
1931 case OLTSVlan:
1932 flow.SetMatchVlan(vpv.UniVlan)
1933 //flow.SetSetVlan(vpv.SVlan)
1934 default:
1935 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
1936 return errorCodes.ErrInvalidParamInRequest
1937 }
1938 return nil
1939}
1940
1941// BuildUsPppoeFlows to build upstream pppoe flows
1942func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
1943
1944 flow := &of.VoltFlow{}
1945 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1946 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
1947 subFlow := of.NewVoltSubFlow()
1948 subFlow.SetTableID(0)
1949
1950 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1951 subFlow.SetMatchSrcMac(vpv.MacAddr)
1952 }
1953
1954 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1955 return nil, err
1956 }
1957 subFlow.SetPppoeDiscoveryMatch()
1958 uniport, err := GetApplication().GetPortID(vpv.Port)
1959 if err != nil {
1960 return nil, err
1961 }
1962 subFlow.SetInPort(uniport)
1963 subFlow.SetReportToController()
1964 // PortName and PortID to be used for validation of port before flow pushing
1965 flow.PortID = uniport
1966 flow.PortName = vpv.Port
1967
1968 allowTransparent := 0
1969 if vpv.AllowTransparent {
1970 allowTransparent = 1
1971 }
1972 metadata := uint64(uniport)
1973 subFlow.SetWriteMetadata(metadata)
1974
1975 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1976 subFlow.SetTableMetadata(metadata)
1977
1978 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
1979 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
1980 subFlow.Priority = of.PppoeFlowPriority
1981
1982 flow.SubFlows[subFlow.Cookie] = subFlow
1983 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1984 return flow, nil
1985}
1986
1987// BuildDsPppoeFlows to build downstream pppoe flows
1988func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
1989
1990 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1991 flow := &of.VoltFlow{}
1992 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1993 subFlow := of.NewVoltSubFlow()
1994 subFlow.SetTableID(0)
1995
1996 vpv.setDsMatchVlan(subFlow)
1997 subFlow.SetPppoeDiscoveryMatch()
1998
1999 if NonZeroMacAddress(vpv.MacAddr) {
2000 subFlow.SetMatchDstMac(vpv.MacAddr)
2001 }
2002
2003 uniport, _ := GetApplication().GetPortID(vpv.Port)
2004 nni, err := GetApplication().GetNniPort(vpv.Device)
2005 if err != nil {
2006 return nil, err
2007 }
2008 nniport, err := GetApplication().GetPortID(nni)
2009 if err != nil {
2010 return nil, err
2011 }
2012 subFlow.SetInPort(nniport)
2013 // PortName and PortID to be used for validation of port before flow pushing
2014 flow.PortID = uniport
2015 flow.PortName = vpv.Port
2016 metadata := uint64(uniport)
2017 subFlow.SetWriteMetadata(metadata)
2018 allowTransparent := 0
2019 if vpv.AllowTransparent {
2020 allowTransparent = 1
2021 }
2022 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2023 subFlow.SetTableMetadata(metadata)
2024 subFlow.SetReportToController()
2025 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
2026 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2027 subFlow.Priority = of.PppoeFlowPriority
2028
2029 flow.SubFlows[subFlow.Cookie] = subFlow
2030 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2031 return flow, nil
2032}
2033
2034// setDsMatchVlan to set downstream match vlan
2035func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
2036 switch vpv.VlanControl {
2037 case None:
2038 flow.SetMatchVlan(vpv.SVlan)
2039 case ONUCVlanOLTSVlan,
2040 OLTCVlanOLTSVlan,
2041 ONUCVlan,
2042 OLTSVlan:
2043 flow.SetMatchVlan(vpv.SVlan)
2044 default:
2045 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2046 }
2047}
2048
2049// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2050// in the US direction.
2051func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2052 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2053 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2054 if mvp == nil {
2055 return nil, errors.New("Mvlan Profile configured not found")
2056 }
2057 mvlan := mvp.GetUsMatchVlan()
2058 flow := &of.VoltFlow{}
2059 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2060 subFlow := of.NewVoltSubFlow()
2061 subFlow.SetTableID(0)
2062
2063 if GetApplication().GetVendorID() == Radisys {
2064 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2065 return nil, err
2066 }
2067 } else {
2068 subFlow.SetMatchVlan(vpv.UniVlan)
2069 subFlow.SetSetVlan(vpv.CVlan)
2070 }
2071
2072 uniport, err := GetApplication().GetPortID(vpv.Port)
2073 if err != nil {
2074 return nil, err
2075 }
2076 subFlow.SetInPort(uniport)
2077 // PortName and PortID to be used for validation of port before flow pushing
2078 flow.PortID = uniport
2079 flow.PortName = vpv.Port
2080
2081 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2082 subFlow.SetMatchSrcMac(vpv.MacAddr)
2083 }
2084 logger.Infow(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
2085 //metadata := uint64(mvlan)
2086
2087 if vpv.McastService {
2088 metadata := uint64(vpv.McastUsMeterID)
2089 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2090 subFlow.SetMatchPbit(vpv.McastPbit)
2091 subFlow.SetMeterID(vpv.McastUsMeterID)
2092 subFlow.SetWriteMetadata(metadata)
2093 } else {
2094 // Set techprofile, meterid of first service
2095 vpv.services.Range(func(key, value interface{}) bool {
2096 svc := value.(*VoltService)
2097 writemetadata := uint64(svc.TechProfileID) << 32
2098 subFlow.SetWriteMetadata(writemetadata)
2099 subFlow.SetMeterID(svc.UsMeterID)
2100 return false
2101 })
2102 }
2103
2104 allowTransparent := 0
2105 if vpv.AllowTransparent {
2106 allowTransparent = 1
2107 }
2108 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2109 subFlow.SetTableMetadata(metadata)
2110 subFlow.SetIgmpMatch()
2111 subFlow.SetReportToController()
2112 //| 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
2113 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2114 subFlow.Priority = of.IgmpFlowPriority
2115
2116 flow.SubFlows[subFlow.Cookie] = subFlow
2117 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2118 return flow, nil
2119}
2120
2121// WriteToDb for writing to database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302122func (vpv *VoltPortVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302123 if vpv.DeleteInProgress {
2124 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2125 return
2126 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302127 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302128}
2129
2130//ForceWriteToDb force commit a VPV to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302131func (vpv *VoltPortVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302132 vpv.PendingFlowLock.RLock()
2133 defer vpv.PendingFlowLock.RUnlock()
2134 vpv.Version = database.PresentVersionMap[database.VpvPath]
2135 if b, err := json.Marshal(vpv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302136 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 +05302137 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2138 "UniVlan": vpv.UniVlan, "Error": err})
2139 }
2140 }
2141}
2142
2143// DelFromDb for deleting from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302144func (vpv *VoltPortVnet) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302145 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 +05302146 _ = db.DelVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
Naveen Sampath04696f72022-06-13 15:19:14 +05302147}
2148
2149// ClearAllServiceFlags to clear all service flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302150func (vpv *VoltPortVnet) ClearAllServiceFlags(cntx context.Context) {
2151 vpv.RangeOnServices(cntx, ClearFlagsInService)
Naveen Sampath04696f72022-06-13 15:19:14 +05302152}
2153
2154// ClearAllVpvFlags to clear all vpv flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302155func (vpv *VoltPortVnet) ClearAllVpvFlags(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302156 vpv.PendingFlowLock.Lock()
2157 vpv.FlowsApplied = false
2158 vpv.IgmpFlowsApplied = false
2159 vpv.PendingDeleteFlow = make(map[string]bool)
2160 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302161 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302162 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2163 log.Fields{"device": vpv.Device, "port": vpv.Port,
2164 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2165}
2166
2167// CreateVpvFromString to create vpv from string
2168func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
2169 var vpv VoltPortVnet
2170 if err := json.Unmarshal(b, &vpv); err == nil {
2171 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2172 if !ok {
2173 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2174 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2175 }
2176 vpv.servicesCount = atomic.NewUint64(0)
2177 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2178 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2179 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2180 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2181 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2182 vnet.associatePortToVnet(vpv.Port)
2183 }
2184
2185 if vpv.DeleteInProgress {
2186 va.VoltPortVnetsToDelete[&vpv] = true
2187 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2188 }
2189 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2190 }
2191}
2192
2193// RestoreVpvsFromDb to restore vpvs from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302194func (va *VoltApplication) RestoreVpvsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302195 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302196 vpvs, _ := db.GetVpvs(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302197 for hash, vpv := range vpvs {
2198 b, ok := vpv.Value.([]byte)
2199 if !ok {
2200 logger.Warn(ctx, "The value type is not []byte")
2201 continue
2202 }
2203 va.CreateVpvFromString(b, hash)
2204 }
2205}
2206
2207// GetVnetByPort : VNET related functionality of VOLT Application here on.
2208// Get the VNET from a port. The port identity is passed as device and port identities in string.
2209// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2210// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2211func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
2212 if _, ok := va.VnetsByPort.Load(port); !ok {
2213 return nil
2214 }
2215 vpvs, _ := va.VnetsByPort.Load(port)
2216 for _, vpv := range vpvs.([]*VoltPortVnet) {
2217 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2218 return vpv
2219 }
2220 }
2221 return nil
2222}
2223
2224// AddVnetToPort to add vnet to port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302225func (va *VoltApplication) AddVnetToPort(cntx context.Context, port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
Naveen Sampath04696f72022-06-13 15:19:14 +05302226 // The VNET is not on the port and is to be added
2227 logger.Debugw(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
2228 vpv := NewVoltPortVnet(vvnet)
2229 vpv.MacLearning = vvnet.MacLearning
2230 vpv.Port = port
2231 vvnet.associatePortToVnet(port)
2232 if _, ok := va.VnetsByPort.Load(port); !ok {
2233 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2234 }
2235 vpvsIntf, _ := va.VnetsByPort.Load(port)
2236 vpvs := vpvsIntf.([]*VoltPortVnet)
2237 vpvs = append(vpvs, vpv)
2238 va.VnetsByPort.Store(port, vpvs)
2239 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2240
2241 vpv.VpvLock.Lock()
2242 defer vpv.VpvLock.Unlock()
2243
2244 // Add the service that is causing the VNET to be added to the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302245 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05302246
2247 // Process the PORT UP if the port is already up
2248 d, err := va.GetDeviceFromPort(port)
2249 if err == nil {
2250 vpv.setDevice(d.Name)
2251 p := d.GetPort(port)
2252 if p != nil {
2253
2254 if vs.PonPort != 0xFF && vs.PonPort != p.PonPort {
2255 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})
2256 } else {
2257 logger.Infow(ctx, "Checking UNI port state", log.Fields{"State": p.State})
2258 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302259 vpv.PortUpInd(cntx, d, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302260 }
2261 }
2262 }
2263 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302264 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302265 return vpv
2266}
2267
2268// DelVnetFromPort for deleting vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302269func (va *VoltApplication) DelVnetFromPort(cntx context.Context, port string, vpv *VoltPortVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302270
2271 //Delete DHCP Session
2272 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2273
2274 //Delete PPPoE session
2275 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2276
2277 //Delete Mac from MacPortMap
2278 va.DeleteMacInPortMap(vpv.MacAddr)
2279
2280 //Delete VPV
2281 vpvsIntf, ok := va.VnetsByPort.Load(port)
2282 if !ok {
2283 return
2284 }
2285 vpvs := vpvsIntf.([]*VoltPortVnet)
2286 for i, lvpv := range vpvs {
2287 if lvpv == vpv {
2288 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2289 "UNIVLAN": vpv.UniVlan})
2290
2291 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2292
2293 vpv.DeleteInProgress = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302294 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302295
2296 va.VnetsByPort.Store(port, vpvs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302297 vpv.DelTrapFlows(cntx)
2298 vpv.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302299 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2300 vpv.PendingFlowLock.RLock()
2301 if len(vpv.PendingDeleteFlow) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302302 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302303 }
2304 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302305 vnet.disassociatePortFromVnet(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302306 }
2307 vpv.PendingFlowLock.RUnlock()
2308 return
2309 }
2310 }
2311}
2312
2313// RestoreVnetsFromDb to restore vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302314func (va *VoltApplication) RestoreVnetsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302315 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302316 vnets, _ := db.GetVnets(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302317 for _, net := range vnets {
2318 b, ok := net.Value.([]byte)
2319 if !ok {
2320 logger.Warn(ctx, "The value type is not []byte")
2321 continue
2322 }
2323 var vnet VoltVnet
2324 err := json.Unmarshal(b, &vnet)
2325 if err != nil {
2326 logger.Warn(ctx, "Unmarshal of VNET failed")
2327 continue
2328 }
2329 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302330 if err := va.AddVnet(cntx, vnet.VnetConfig, &vnet.VnetOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302331 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2332 }
2333
2334 if vnet.DeleteInProgress {
2335 va.VnetsToDelete[vnet.Name] = true
2336 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2337 }
2338
2339 }
2340}
2341
2342// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2343// are used as the key to locate the service. If more than one service is on the
2344// same port (essentially a UNI of ONU), the services must be separated by different
2345// CVLANs
2346func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
2347 // Fetch the device first to make sure the device exists
2348 dIntf, ok := va.DevicesDisc.Load(device)
2349 if !ok {
2350 return nil
2351 }
2352 d := dIntf.(*VoltDevice)
2353
2354 // If the port is NNI port, the services dont exist on it. The svc then
2355 // must be obtained from a different context and is not included here
2356 if port == d.NniPort {
2357 return nil
2358 }
2359
2360 //To return the matched service
2361 var service *VoltService
2362
2363 // This is an access port and the port should have all the associated
2364 // services which can be uniquely identified by the VLANs in the packet
2365 vnets, ok := va.VnetsByPort.Load(port)
2366
2367 if !ok {
2368 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2369 return nil
2370 }
2371 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2372 for _, vnet := range vnets.([]*VoltPortVnet) {
2373 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2374 switch vnet.VlanControl {
2375 case ONUCVlanOLTSVlan:
2376 service = vnet.MatchesPriority(priority)
2377 if vnet.MatchesCvlan(vlans) && service != nil {
2378 return service
2379 }
2380 case ONUCVlan,
2381 None:
2382 service = vnet.MatchesPriority(priority)
2383 // In case of DHCP Flow - cvlan == VlanNone
2384 // In case of HSIA Flow - cvlan == Svlan
2385 if len(vlans) == 1 && (vlans[0] == vnet.SVlan || vlans[0] == of.VlanNone) && service != nil {
2386 return service
2387 }
2388 case OLTCVlanOLTSVlan,
2389 OLTSVlan:
2390 service = vnet.MatchesPriority(priority)
2391 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2392 return service
2393 }
2394 default:
2395 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2396 }
2397 }
2398 return nil
2399}
2400
2401// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2402// are used as the key to locate the service. If more than one service is on the
2403// same port (essentially a UNI of ONU), the services must be separated by different
2404// CVLANs
2405func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2406 // Fetch the device first to make sure the device exists
2407 dIntf, ok := va.DevicesDisc.Load(device)
2408 if !ok {
2409 return nil, nil
2410 }
2411 d := dIntf.(*VoltDevice)
2412
2413 // If the port is NNI port, the services dont exist on it. The svc then
2414 // must be obtained from a different context and is not included here
2415 if port == d.NniPort {
2416 return nil, nil
2417 }
2418
2419 //To return the matched service
2420 var service *VoltService
2421
2422 // This is an access port and the port should have all the associated
2423 // services which can be uniquely identified by the VLANs in the packet
2424 if vnets, ok := va.VnetsByPort.Load(port); ok {
2425 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2426 for _, vnet := range vnets.([]*VoltPortVnet) {
2427 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2428 switch vnet.VlanControl {
2429 case ONUCVlanOLTSVlan:
2430 service = vnet.MatchesPriority(priority)
2431 if vnet.MatchesCvlan(vlans) && service != nil {
2432 return vnet, service
2433 }
2434 case ONUCVlan,
2435 None:
2436 service = vnet.MatchesPriority(priority)
2437 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2438 return vnet, service
2439 }
2440 case OLTCVlanOLTSVlan,
2441 OLTSVlan:
2442 service = vnet.MatchesPriority(priority)
2443 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2444 return vnet, service
2445 }
2446 default:
2447 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2448 }
2449 }
2450 }
2451 return nil, nil
2452}
2453
2454// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2455// are used as the key to locate the service. If more than one service is on the
2456// same port (essentially a UNI of ONU), the services must be separated by different
2457// CVLANs
2458func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
2459 vlans := GetVlans(pkt)
2460 priority := GetPriority(pkt)
2461 return va.GetVnetFromFields(device, port, vlans, priority)
2462}
2463
2464// PushDevFlowForVlan to push icmpv6 flows for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302465func (va *VoltApplication) PushDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302466 logger.Infow(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2467 pushflow := func(key interface{}, value interface{}) bool {
2468 device := value.(*VoltDevice)
2469 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302470 logger.Infow(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +05302471 return true
2472 }
2473 if device.State != controller.DeviceStateUP {
2474 logger.Errorw(ctx, "Push Dev Flows Failed - Device state DOWN", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan, "device": device})
2475 return true
2476 }
2477 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2478 logger.Errorw(ctx, "Push Dev Flows Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2479 return true
2480 }
2481
2482 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2483 vnetList := vnetListIntf.(*util.ConcurrentMap)
2484 vnetList.Set(vnet.Name, true)
2485 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2486 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()})
2487 return true
2488 }
2489 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2490 err := ProcessIcmpv6McGroup(device.Name, false)
2491 if err != nil {
2492 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2493 return true
2494 }
2495 if portID, err := va.GetPortID(device.NniPort); err == nil {
2496 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2497 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2498 return true
2499 }
2500
2501 //Pushing ICMPv6 Flow
2502 flow := BuildICMPv6Flow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302503 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302504 if err != nil {
2505 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2506 return true
2507 }
2508 logger.Infow(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
2509
2510 // Pushing ARP Flow
2511 flow = BuildDSArpFlow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302512 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302513 if err != nil {
2514 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2515 return true
2516 }
2517 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2518
2519 vnetList := util.NewConcurrentMap()
2520 vnetList.Set(vnet.Name, true)
2521 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2522 }
2523 return true
2524 }
2525 va.DevicesDisc.Range(pushflow)
2526}
2527
2528// PushDevFlowForDevice to push icmpv6 flows for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302529func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302530 logger.Infow(ctx, "PushDevFlowForDevice", log.Fields{"device": device})
2531
2532 logger.Debugw(ctx, "Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2533 err := ProcessIcmpv6McGroup(device.Name, false)
2534 if err != nil {
2535 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2536 return
2537 }
2538 pushicmpv6 := func(key, value interface{}) bool {
2539 vnet := value.(*VoltVnet)
2540 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2541 vnetList := vnetListIntf.(*util.ConcurrentMap)
2542 vnetList.Set(vnet.Name, true)
2543 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2544 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()})
2545 return true
2546 }
2547 nniPortID, err := va.GetPortID(device.NniPort)
2548 if err != nil {
2549 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2550 }
2551 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2552 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2553 return true
2554 }
2555 flow := BuildICMPv6Flow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302556 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302557 if err != nil {
2558 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2559 return true
2560 }
2561 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2562
2563 flow = BuildDSArpFlow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302564 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302565 if err != nil {
2566 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2567 return true
2568 }
2569 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2570
2571 vnetList := util.NewConcurrentMap()
2572 vnetList.Set(vnet.Name, true)
2573 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2574 return true
2575 }
2576 va.VnetsByName.Range(pushicmpv6)
2577}
2578
2579// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302580func (va *VoltApplication) DeleteDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302581 logger.Infow(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2582 delflows := func(key interface{}, value interface{}) bool {
2583 device := value.(*VoltDevice)
2584
2585 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2586 vnetList := vnetListIntf.(*util.ConcurrentMap)
2587 vnetList.Remove(vnet.Name)
2588 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2589 if vnetList.Length() != 0 {
2590 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()})
2591 return true
2592 }
2593 }
2594 if portID, err := va.GetPortID(device.NniPort); err == nil {
2595 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2596 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2597 return true
2598 }
2599 //Pushing ICMPv6 Flow
2600 flow := BuildICMPv6Flow(portID, vnet)
2601 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302602 err := vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302603 if err != nil {
2604 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2605 return true
2606 }
2607 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2608
2609 //Pushing ARP Flow
2610 flow = BuildDSArpFlow(portID, vnet)
2611 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302612 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302613 if err != nil {
2614 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2615 return true
2616 }
2617 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2618
2619 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2620 }
2621 return true
2622 }
2623 va.DevicesDisc.Range(delflows)
2624}
2625
2626// DeleteDevFlowForDevice to delete icmpv6 flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302627func (va *VoltApplication) DeleteDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302628 logger.Infow(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
2629 delicmpv6 := func(key, value interface{}) bool {
2630 vnet := value.(*VoltVnet)
2631 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2632 vnetList := vnetListIntf.(*util.ConcurrentMap)
2633 vnetList.Remove(vnet.Name)
2634 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2635 if vnetList.Length() != 0 {
2636 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()})
2637 return true
2638 }
2639 } else {
2640 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2641 return true
2642 }
2643 nniPortID, err := va.GetPortID(device.NniPort)
2644 if err != nil {
2645 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2646 }
2647 flow := BuildICMPv6Flow(nniPortID, vnet)
2648 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302649 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302650 if err != nil {
2651 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2652 return true
2653 }
2654
2655 flow = BuildDSArpFlow(nniPortID, vnet)
2656 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302657 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302658 if err != nil {
2659 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2660 return true
2661 }
2662
2663 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2664 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2665 return true
2666 }
2667 va.VnetsByName.Range(delicmpv6)
2668 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2669 err := ProcessIcmpv6McGroup(device.Name, true)
2670 if err != nil {
2671 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2672 return
2673 }
2674}
2675
2676// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302677func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(cntx context.Context, vnet *VoltVnet, deviceSerialNum string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302678 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2679 delflows := func(key interface{}, value interface{}) bool {
2680 device := value.(*VoltDevice)
2681 if device.SerialNum != deviceSerialNum {
2682 return true
2683 }
2684 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2685 vnetList := vnetListIntf.(*util.ConcurrentMap)
2686 vnetList.Remove(vnet.Name)
2687 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2688 if vnetList.Length() != 0 {
2689 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()})
2690 return true
2691 }
2692 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2693 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2694 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2695 // The step will be as follow:
2696 // 1. Deact Service
2697 // 2. Pod Reboot
2698 // 3. Pending Delete Service triggered
2699 // 4. Del Service Ind followed by DelVnet req from NB
2700 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2701 // hence the flow will not be cleared
2702 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2703 return true
2704 }
2705 if portID, err := va.GetPortID(device.NniPort); err == nil {
2706 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2707 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2708 return false
2709 }
2710 flow := BuildICMPv6Flow(portID, vnet)
2711 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302712 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302713 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2714 }
2715 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2716
2717 flow = BuildDSArpFlow(portID, vnet)
2718 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302719 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302720 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2721 }
2722 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2723 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2724 }
2725 return false
2726 }
2727 va.DevicesDisc.Range(delflows)
2728}
2729
2730// BuildICMPv6Flow to Build DS flow for ICMPv6
2731func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302732 logger.Infow(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302733 flow := &of.VoltFlow{}
2734 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2735 subFlow := of.NewVoltSubFlow()
2736
2737 subFlow.SetICMPv6Match()
2738 subFlow.SetMatchVlan(vnet.SVlan)
2739 subFlow.SetInPort(inport)
2740 subFlow.SetPopVlan()
2741 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2742 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2743 subFlow.Priority = of.McFlowPriority
2744 var metadata uint64
2745 if vnet.VlanControl == None {
2746 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2747 } else {
2748 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2749 }
2750 subFlow.SetTableMetadata(metadata)
2751 metadata = uint64(vnet.setPbitRemarking())
2752
2753 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2754 subFlow.SetWriteMetadata(metadata)
2755 flow.SubFlows[subFlow.Cookie] = subFlow
2756 return flow
2757}
2758
2759//BuildDSArpFlow Builds DS flow for ARP
2760func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302761 logger.Infow(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302762
2763 flow := &of.VoltFlow{}
2764 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2765 subFlow := of.NewVoltSubFlow()
2766
2767 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
2768 subFlow.SetArpMatch()
2769 subFlow.SetMatchDstMac(BcastMAC)
2770 subFlow.SetMatchVlan(vnet.SVlan)
2771 subFlow.SetInPort(inport)
2772 subFlow.SetPopVlan()
2773 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2774
2775 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
2776 subFlow.Priority = of.McFlowPriority
2777
2778 var metadata uint64
2779 if vnet.VlanControl == None {
2780 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2781 } else {
2782 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2783 }
2784 subFlow.SetTableMetadata(metadata)
2785 metadata = uint64(vnet.setPbitRemarking())
2786 subFlow.SetWriteMetadata(metadata)
2787
2788 flow.SubFlows[subFlow.Cookie] = subFlow
2789 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2790 return flow
2791}
2792
2793// setPbitRemarking to set Pbit remarking
2794func (vv *VoltVnet) setPbitRemarking() uint32 {
2795
2796 // Remarkable
2797 // Remarked Pbit Pbit
2798 // |-----------------------------| |------|
2799 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
2800 // 000 000 000 000 000 000 000 000 00000000
2801
2802 // Eg:
2803 // For 6:3 & 7:1
2804 // 001 011 000 000 000 000 000 000 11000000
2805
2806 var remarkable uint8
2807 var remarked uint32
2808 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
2809 remarkable = remarkable | 1<<refPbit
2810 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
2811 }
2812 return remarked<<8 | uint32(remarkable)
2813}
2814
2815// ProcessIcmpv6McGroup to add icmpv6 multicast group
2816func ProcessIcmpv6McGroup(device string, delete bool) error {
2817
2818 logger.Info(ctx, "Creating ICMPv6 MC Group")
2819 va := GetApplication()
2820 vd := va.GetDevice(device)
2821 group := &of.Group{}
2822 group.GroupID = ICMPv6ArpGroupID
2823 group.Device = device
2824 if delete {
2825 if !vd.icmpv6GroupAdded {
2826 logger.Info(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
2827 return nil //TODO
2828 }
2829 vd.icmpv6GroupAdded = false
2830 group.Command = of.GroupCommandDel
2831 group.ForceAction = true
2832 } else {
2833 if vd.icmpv6GroupAdded {
2834 logger.Info(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
2835 return nil //TODO
2836 }
2837 vd.icmpv6GroupAdded = true
2838 group.Command = of.GroupCommandAdd
2839 receivers := GetApplication().GetIcmpv6Receivers(device)
2840 group.Buckets = append(group.Buckets, receivers...)
2841 }
2842 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
2843 port, _ := GetApplication().GetNniPort(device)
2844 err := cntlr.GetController().GroupUpdate(port, device, group)
2845 return err
2846}
2847
2848//isVlanMatching - checks is vlans matches with vpv based on vlan control
2849func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
2850
2851 switch vpv.VlanControl {
2852 case ONUCVlanOLTSVlan,
2853 OLTCVlanOLTSVlan:
2854 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
2855 return true
2856 }
2857 case ONUCVlan,
2858 OLTSVlan,
2859 None:
2860 if vpv.SVlan == svlan {
2861 return true
2862 }
2863 default:
2864 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2865 }
2866 return false
2867}
2868
2869//PushFlows - Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302870func (vpv *VoltPortVnet) PushFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302871
2872 for cookie := range flow.SubFlows {
2873 cookie := strconv.FormatUint(cookie, 10)
2874 fe := &FlowEvent{
2875 eType: EventTypeControlFlowAdded,
2876 cookie: cookie,
2877 eventData: vpv,
2878 }
2879 device.RegisterFlowAddEvent(cookie, fe)
2880 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302881 return cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302882}
2883
2884//FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
2885func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
2886
2887 sendFlowFailureInd := func(key, value interface{}) bool {
2888 //svc := value.(*VoltService)
2889 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
2890 return true
2891 }
2892 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2893 vpv.services.Range(sendFlowFailureInd)
2894}
2895
2896//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302897func (vpv *VoltPortVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302898
2899 vpv.PendingFlowLock.Lock()
2900 defer vpv.PendingFlowLock.Unlock()
2901
2902 for cookie := range flow.SubFlows {
2903 cookie := strconv.FormatUint(cookie, 10)
2904 fe := &FlowEvent{
2905 eType: EventTypeControlFlowRemoved,
2906 device: device.Name,
2907 cookie: cookie,
2908 eventData: vpv,
2909 }
2910 device.RegisterFlowDelEvent(cookie, fe)
2911 vpv.PendingDeleteFlow[cookie] = true
2912 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302913 return cntlr.GetController().DelFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302914}
2915
2916//CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302917func (vpv *VoltPortVnet) CheckAndDeleteVpv(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302918 vpv.PendingFlowLock.RLock()
2919 defer vpv.PendingFlowLock.RUnlock()
2920 if !vpv.DeleteInProgress {
2921 return
2922 }
2923 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
2924 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 +05302925 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302926 logger.Infow(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
2927 }
2928}
2929
2930//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302931func (vpv *VoltPortVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302932 vpv.PendingFlowLock.Lock()
2933 logger.Infow(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
2934
2935 delete(vpv.PendingDeleteFlow, cookie)
2936 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302937 vpv.CheckAndDeleteVpv(cntx)
2938 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302939}
2940
2941//FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302942func (vpv *VoltPortVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302943 vpv.PendingFlowLock.Lock()
2944
2945 logger.Errorw(ctx, "VPV Flow Remove Failure Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
2946
2947 sendFlowFailureInd := func(key, value interface{}) bool {
2948 svc := value.(*VoltService)
2949 svc.triggerServiceFailureInd(errorCode, errReason)
2950 return true
2951 }
2952 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2953 vpv.services.Range(sendFlowFailureInd)
2954
2955 if vpv.DeleteInProgress {
2956 delete(vpv.PendingDeleteFlow, cookie)
2957 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302958 vpv.CheckAndDeleteVpv(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302959 } else {
2960 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302961 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302962 }
2963}
2964
2965//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302966func (vv *VoltVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302967
2968 vv.VnetLock.Lock()
2969 defer vv.VnetLock.Unlock()
2970
2971 var flowMap map[string]bool
2972 var ok bool
2973
2974 for cookie := range flow.SubFlows {
2975 cookie := strconv.FormatUint(cookie, 10)
2976 fe := &FlowEvent{
2977 eType: EventTypeDeviceFlowRemoved,
2978 device: device.Name,
2979 cookie: cookie,
2980 eventData: vv,
2981 }
2982 device.RegisterFlowDelEvent(cookie, fe)
2983 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
2984 flowMap = make(map[string]bool)
2985 }
2986 flowMap[cookie] = true
2987 vv.PendingDeleteFlow[device.Name] = flowMap
2988 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302989 vv.WriteToDb(cntx)
2990 return cntlr.GetController().DelFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302991}
2992
2993//CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302994func (vv *VoltVnet) CheckAndDeleteVnet(cntx context.Context, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302995 if !vv.DeleteInProgress {
2996 return
2997 }
2998 vv.VnetPortLock.RLock()
2999 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
3000 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
3001 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303002 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05303003 logger.Infow(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
3004 } else {
3005 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
3006 }
3007 vv.VnetPortLock.RUnlock()
3008}
3009
3010//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303011func (vv *VoltVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303012 vv.VnetLock.Lock()
3013 defer vv.VnetLock.Unlock()
3014
3015 logger.Infow(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
3016
3017 if _, ok := vv.PendingDeleteFlow[device]; ok {
3018 delete(vv.PendingDeleteFlow[device], cookie)
3019 }
3020
3021 //Check and update success for pending disable request
3022 if d := GetApplication().GetDevice(device); d != nil {
3023 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3024 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303025 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303026 }
3027 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303028 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303029}
3030
3031//FlowRemoveFailure - Process flow failure indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303032func (vv *VoltVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303033
3034 vv.VnetLock.Lock()
3035 defer vv.VnetLock.Unlock()
3036
3037 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3038 if _, ok := flowMap[cookie]; ok {
3039 logger.Errorw(ctx, "Device Flow Remove Failure Notification", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
3040
3041 if vv.DeleteInProgress {
3042 delete(vv.PendingDeleteFlow[device], cookie)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303043 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303044 }
3045 return
3046 }
3047 }
3048 logger.Errorw(ctx, "Device Flow Remove Failure Notification for Unknown cookie", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3049}
3050
3051//IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
3052func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
3053
3054 //Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3055 //When multiple Igmp-suported service enabled, comment "return false"
3056
3057 sendFlowFailureInd := func(key, value interface{}) bool {
3058 svc := value.(*VoltService)
3059 if svc.IgmpEnabled {
3060 svc.triggerServiceFailureInd(errorCode, errReason)
3061 return false
3062 }
3063 return true
3064 }
3065 logger.Errorw(ctx, "US IGMP Flow Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3066 vpv.services.Range(sendFlowFailureInd)
3067}
3068
3069// GetMatchingMcastService to get matching multicast service
3070func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
3071
3072 var service *VoltService
3073 dIntf, ok := va.DevicesDisc.Load(device)
3074 if !ok {
3075 return nil
3076 }
3077 d := dIntf.(*VoltDevice)
3078
3079 // If the port is NNI port, the services dont exist on it. The svc then
3080 // must be obtained from a different context and is not included here
3081 if port == d.NniPort {
3082 return nil
3083 }
3084
3085 // This is an access port and the port should have all the associated
3086 // services which can be uniquely identified by the VLANs in the packet
3087 vnets, ok := va.VnetsByPort.Load(port)
3088
3089 if !ok {
3090 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3091 return nil
3092 }
3093 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3094 getMcastService := func(key, value interface{}) bool {
3095 srv := value.(*VoltService)
3096 if srv.IgmpEnabled {
3097 service = srv
3098
3099 //TODO: Current implementation supports only for single service with Igmp Enabled
3100 //FIX-ME: When multiple service suports Igmp, update of logic required
3101 return false
3102 }
3103 return true
3104 }
3105
3106 for _, vpv := range vnets.([]*VoltPortVnet) {
3107 if vpv.CVlan == cvlan {
3108 vpv.services.Range(getMcastService)
3109 if service != nil {
3110 break
3111 }
3112 }
3113 }
3114 return service
3115}
3116
3117//TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303118func (vv *VoltVnet) TriggerAssociatedFlowDelete(cntx context.Context, device string) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05303119 vv.VnetLock.Lock()
3120 cookieList := []uint64{}
3121 flowMap := vv.PendingDeleteFlow[device]
3122
3123 for cookie := range flowMap {
3124 cookieList = append(cookieList, convertToUInt64(cookie))
3125 }
3126 vv.VnetLock.Unlock()
3127
3128 if len(cookieList) == 0 {
3129 return false
3130 }
3131
3132 for _, cookie := range cookieList {
3133 if vd := GetApplication().GetDevice(device); vd != nil {
3134 flow := &of.VoltFlow{}
3135 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3136 subFlow := of.NewVoltSubFlow()
3137 subFlow.Cookie = cookie
3138 flow.SubFlows[cookie] = subFlow
3139 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303140 if err := vv.RemoveFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05303141 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3142 }
3143 }
3144 }
3145 return true
3146}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303147
3148// JsonMarshal wrapper function for json Marshal VoltVnet
3149func (vv *VoltVnet) JsonMarshal() ([]byte, error) {
3150 return json.Marshal(VoltVnet{
3151 VnetConfig: vv.VnetConfig,
3152 Version: vv.Version,
3153 VnetOper: VnetOper{
3154 PendingDeleteFlow: vv.VnetOper.PendingDeleteFlow,
3155 DeleteInProgress: vv.VnetOper.DeleteInProgress,
3156 PendingDeviceToDelete: vv.VnetOper.PendingDeviceToDelete,
3157 },
3158 })
3159}
3160
3161// JsonMarshal wrapper function for json Marshal VoltPortVnet
3162func (vpv *VoltPortVnet) JsonMarshal() ([]byte, error) {
3163 return json.Marshal(VoltPortVnet{
3164 Device: vpv.Device,
3165 Port: vpv.Port,
3166 PonPort: vpv.PonPort,
3167 VnetName: vpv.VnetName,
3168 SVlan: vpv.SVlan,
3169 CVlan: vpv.CVlan,
3170 UniVlan: vpv.UniVlan,
3171 SVlanTpid: vpv.SVlanTpid,
3172 DhcpRelay: vpv.DhcpRelay,
3173 ArpRelay: vpv.ArpRelay,
3174 PppoeIa: vpv.PppoeIa,
3175 MacLearning: vpv.MacLearning,
3176 DhcpStatus: vpv.DhcpStatus,
3177 DhcpExpiryTime: vpv.DhcpExpiryTime,
3178 Dhcp6ExpiryTime: vpv.Dhcp6ExpiryTime,
3179 FlowsApplied: vpv.FlowsApplied,
3180 Ipv4Addr: vpv.Ipv4Addr,
3181 Ipv6Addr: vpv.Ipv6Addr,
3182 MacAddr: vpv.MacAddr,
3183 LearntMacAddr: vpv.LearntMacAddr,
3184 CircuitID: vpv.CircuitID,
3185 RemoteID: vpv.RemoteID,
3186 IsOption82Disabled: vpv.IsOption82Disabled,
3187 RelayState: vpv.RelayState,
3188 PPPoeState: vpv.PPPoeState,
3189 RelayStatev6: vpv.RelayStatev6,
3190 IgmpEnabled: vpv.IgmpEnabled,
3191 IgmpFlowsApplied: vpv.IgmpFlowsApplied,
3192 McastService: vpv.McastService,
3193 ONTEtherTypeClassification: vpv.ONTEtherTypeClassification,
3194 VlanControl: vpv.VlanControl,
3195 MvlanProfileName: vpv.MvlanProfileName,
3196 Version: vpv.Version,
3197 McastTechProfileID: vpv.McastTechProfileID,
3198 McastPbit: vpv.McastPbit,
3199 McastUsMeterID: vpv.McastUsMeterID,
3200 AllowTransparent: vpv.AllowTransparent,
3201 SchedID: vpv.SchedID,
3202 DHCPv6DUID: vpv.DHCPv6DUID,
3203 PendingDeleteFlow: vpv.PendingDeleteFlow,
3204 DeleteInProgress: vpv.DeleteInProgress,
3205 Blocked: vpv.Blocked,
3206 DhcpPbit: vpv.DhcpPbit,
3207 })
3208}