blob: 85de6dc389c4416b5d2ee4e1344801c90dfe4097 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14 */
15
16package application
17
18import (
19 "encoding/json"
20 "errors"
Tinoj Joseph07cc5372022-07-18 22:53:51 +053021 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053022 "net"
23 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
24 "strconv"
25 "sync"
26 "time"
27
28 "github.com/google/gopacket"
29 "github.com/google/gopacket/layers"
30 "go.uber.org/atomic"
31
32 "voltha-go-controller/internal/pkg/controller"
33 cntlr "voltha-go-controller/internal/pkg/controller"
34 "voltha-go-controller/database"
35 "voltha-go-controller/internal/pkg/of"
36 "voltha-go-controller/internal/pkg/util"
37 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Tinoj Joseph1d108322022-07-13 10:07:39 +053038 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053039)
40
41const (
42 // ICMPv6ArpGroupID constant
43 ICMPv6ArpGroupID uint32 = 1
44
45 // Radisys vendor id constant
46 Radisys string = "Radisys"
47)
48
49var (
50 //BroadcastMAC - Broadcast MAC Address
51 BroadcastMAC, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")
52)
53
54// NonZeroMacAddress utility to identify if the MAC address is non-zero.
55// We use zero MAC address as an unset MAC address
56func NonZeroMacAddress(h net.HardwareAddr) bool {
57 for i := 0; i < 6; i++ {
58 if h[i] != 0 {
59 return true
60 }
61 }
62 return false
63}
64
65// VNET package manages the different virtual networks that are part of the
66// the network. In the case of VOLT, the networks can be single tagged or
67// double tagged networks. In addition, the networks may be used for unicast
68// and multicast traffic. The unicast traffic further has two models, the
69// 1:1 and N:1 model. In case of a 1:1 model, the outer tag is same for many
70// subscribers and the inner tag is unique to each subscriber for the same
71// outer tag. The N:1 uses the same inner and outer tags, or for that matter
72// a single tag that can also be shared by subscribers. The VNET implementation
73// manages all these possibilities and the associated configuration.
74
75const (
76 // PbitMatchNone constant
77 PbitMatchNone of.PbitType = 8
78 // PbitMatchAll constant
79 PbitMatchAll of.PbitType = 0xFF
80)
81
82// SVlan - Value of the outer tag if double tagged or the only tag if single
83// tagged
84// SVlanTpid - SVlan Tag Protocol Identifier
85// CVlan - Value of the inner tag. Set to VlanNone if single tagged
86// DhcpRelay - Set to true if the DHCP relay is enabled on the virtual network
87// MacLearning - Set to true if the flows should include MAC address
88// UsDhcpPbit - The pbit used for US DHCP packets
89// DsDhcpPbit - The pbit used for DS DHCP packets
90
91// VnetConfig structure
92type VnetConfig struct {
93 Name string
94 SVlan of.VlanType
95 CVlan of.VlanType
96 UniVlan of.VlanType
97 SVlanTpid layers.EthernetType
98 DhcpRelay bool
99 ArpLearning bool
100 MacLearning MacLearningType
101 PppoeIa bool
102 ONTEtherTypeClassification int
103 VlanControl VlanControl
104 Encapsulation string
105 UsDhcpPbit []of.PbitType
106 DsDhcpPbit []of.PbitType
107 UsIGMPPbit []of.PbitType
108 DsIGMPPbit []of.PbitType
109 DevicesList []string //List of serial number of devices on which this vnet is applied
110 AllowTransparent bool
111 CtrlPktPbitRemark map[of.PbitType]of.PbitType
112}
113
114// VnetOper structure
115type VnetOper struct {
116 PendingDeleteFlow map[string]map[string]bool
117 DeleteInProgress bool
118 PendingDeviceToDelete string
119 VnetLock sync.RWMutex `json:"-"`
120 VnetPortLock sync.RWMutex `json:"-"`
121 AssociatedPorts map[string]bool `json:"-"`
122}
123
124// VoltVnet sructure
125type VoltVnet struct {
126 VnetConfig
127 VnetOper
128 Version string
129}
130
131const (
132 // EncapsulationPPPoEIA constant
133 EncapsulationPPPoEIA string = "PPPoE-IA"
134 // EncapsulationPPPoE constant
135 EncapsulationPPPoE string = "PPPoE"
136 // EncapsulationIPoE constant
137 EncapsulationIPoE string = "IPoE"
138)
139
140// NewVoltVnet is constructor for the VNET structure
141func NewVoltVnet(cfg VnetConfig) *VoltVnet {
142 var vv VoltVnet
143 vv.VnetConfig = cfg
144 if vv.PendingDeleteFlow == nil {
145 vv.PendingDeleteFlow = make(map[string]map[string]bool)
146 }
147 vv.DeleteInProgress = false
148 if cfg.Encapsulation == EncapsulationPPPoEIA {
149 vv.PppoeIa = true
150 }
151 vv.AssociatedPorts = make(map[string]bool)
152 return &vv
153}
154
155//associatePortToVnet - associate a port to Vnet
156func (vv *VoltVnet) associatePortToVnet(port string) {
157 vv.VnetPortLock.Lock()
158 if vv.AssociatedPorts == nil {
159 vv.AssociatedPorts = make(map[string]bool)
160 }
161 vv.AssociatedPorts[port] = true
162 vv.VnetPortLock.Unlock()
163}
164
165//disassociatePortFromVnet - disassociate a port from Vnet and return true if the association map is empty
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530166func (vv *VoltVnet) disassociatePortFromVnet(cntx context.Context, device string, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530167 vv.VnetPortLock.Lock()
168 delete(vv.AssociatedPorts, port)
169 logger.Infow(ctx, "Disassociated Port from Vnet", log.Fields{"Device": device, "Port": port, "Vnet": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow, "AssociatedPorts": vv.AssociatedPorts, "DeleteFlag": vv.DeleteInProgress})
170 vv.VnetPortLock.Unlock()
171
172 if vv.DeleteInProgress {
173 if !vv.isAssociatedPortsPresent() {
174 if len(vv.PendingDeleteFlow[device]) == 0 {
175 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vv.Name})
176 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530177 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530178 } else {
179 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow})
180 }
181 } else {
182 vv.VnetPortLock.RLock()
183 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts})
184 vv.VnetPortLock.RUnlock()
185 }
186 }
187}
188
189func (vv *VoltVnet) isAssociatedPortsPresent() bool {
190 vv.VnetPortLock.RLock()
191 defer vv.VnetPortLock.RUnlock()
192 return len(vv.AssociatedPorts) != 0
193}
194
195// WriteToDb commit the VNET to the database
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530196func (vv *VoltVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530197
198 if vv.DeleteInProgress {
199 logger.Warnw(ctx, "Skipping Redis Update for Vnet, Vnet delete in progress", log.Fields{"Vnet": vv.Name})
200 return
201 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530202 vv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530203}
204
205//ForceWriteToDb force commit a vnet to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530206func (vv *VoltVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530207 vv.VnetPortLock.RLock()
208 defer vv.VnetPortLock.RUnlock()
209 vv.Version = database.PresentVersionMap[database.VnetPath]
210 logger.Debugw(ctx, "Updating VNET....", log.Fields{"vnet": vv})
211 if b, err := json.Marshal(vv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530212 if err:= db.PutVnet(cntx, vv.Name, string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530213 logger.Warnw(ctx, "Add Vnet to DB failed", log.Fields{"vnet name": vv.Name, "Error": err})
214 }
215 }
216}
217
218// VnetKey creates the key using the two VLAN tags
219// We append the two VLAN tags to create a single key
220func VnetKey(otag of.VlanType, itag of.VlanType, utag of.VlanType) string {
221 return strconv.Itoa(int(otag)) + "-" + strconv.Itoa(int(itag)) + "-" + strconv.Itoa(int(utag))
222}
223
224// GetVnet get VNET configuration related functionality associated with VOLT application
225func (va *VoltApplication) GetVnet(otag of.VlanType, itag of.VlanType, utag of.VlanType) *VoltVnet {
226 // When matching VNET, it is expected to match first just the outer
227 // tag, and then the combination to make sure there is no conflict
228 // for the new configuration.
229 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, of.VlanNone, utag)); ok {
230 return vnet.(*VoltVnet)
231 }
232 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, itag, utag)); ok {
233 return vnet.(*VoltVnet)
234 }
235 return nil
236}
237
238// The VNET may also be assigned name for easier references. For now,
239// the VNET is mainly identified by the two VLANs.
240
241// GetVnetByName to get vnet by name
242func (va *VoltApplication) GetVnetByName(name string) *VoltVnet {
243 if vnet, ok := va.VnetsByName.Load(name); ok {
244 return vnet.(*VoltVnet)
245 }
246 return nil
247}
248
249// storeVnetConfig to store vnet config
250func (va *VoltApplication) storeVnetConfig(cfg VnetConfig, vv *VoltVnet) {
251
252 var vnetMap *util.ConcurrentMap
253
254 va.VnetsByTag.Store(VnetKey(cfg.SVlan, cfg.CVlan, cfg.UniVlan), vv)
255 va.VnetsByName.Store(cfg.Name, vv)
256
257 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vv.SVlan); !ok {
258 vnetMap = util.NewConcurrentMap()
259 } else {
260 vnetMap = vnetMapIntf.(*util.ConcurrentMap)
261 }
262 vnetMap.Set(vv, true)
263 va.VnetsBySvlan.Set(vv.SVlan, vnetMap)
264}
265
266// deleteVnetConfig to delete vnet config
267func (va *VoltApplication) deleteVnetConfig(vnet *VoltVnet) {
268 va.VnetsByTag.Delete(VnetKey(vnet.SVlan, vnet.CVlan, vnet.UniVlan))
269 va.VnetsByName.Delete(vnet.Name)
270
271 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vnet.SVlan); ok {
272 vnetMap := vnetMapIntf.(*util.ConcurrentMap)
273 vnetMap.Remove(vnet)
274 va.VnetsBySvlan.Set(vnet.SVlan, vnetMap)
275 }
276}
277
278// AddVnet to add a VNET to the list of VNETs configured.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530279func (va *VoltApplication) AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530280
281 AppMutex.VnetMutex.Lock()
282 var vv *VoltVnet
283 devicesToHandle := []string{}
284 vv = va.GetVnetByName(cfg.Name)
285 if vv != nil {
286 //Could be for another OLT or could be case of backup-restore
287 for _, serialNum := range cfg.DevicesList {
288 if isDeviceInList(serialNum, vv.DevicesList) {
289 //This is backup restore scenario, just update the profile
290 logger.Info(ctx, "Add Vnet : Profile Name already exists with OLT, update-the-profile")
291 continue
292 }
293 devicesToHandle = append(devicesToHandle, serialNum)
294 }
295 if len(devicesToHandle) == 0 {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530296 logger.Debugw(ctx, "Ignoring Duplicate VNET by name ", log.Fields{"Vnet": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530297 AppMutex.VnetMutex.Unlock()
298 return nil
299 }
300 }
301
302 if vv == nil {
303 vv = NewVoltVnet(cfg)
304 if oper != nil {
305 vv.PendingDeleteFlow = oper.PendingDeleteFlow
306 vv.DeleteInProgress = oper.DeleteInProgress
307 vv.AssociatedPorts = oper.AssociatedPorts
308 vv.PendingDeviceToDelete = oper.PendingDeviceToDelete
309 }
310 devicesToHandle = append(devicesToHandle, cfg.DevicesList...)
311 } else {
312 vv.DevicesList = append(vv.DevicesList, devicesToHandle...)
313 }
314
315 va.storeVnetConfig(cfg, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530316 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530317
318 logger.Infow(ctx, "Added VNET TO DB", log.Fields{"cfg": cfg, "devicesToHandle": devicesToHandle})
319
320 //va.PushDevFlowForVlan(vv)
321 AppMutex.VnetMutex.Unlock()
322 return nil
323}
324
325// DelVnet to delete a VNET from the list of VNETs configured
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530326func (va *VoltApplication) DelVnet(cntx context.Context, name, deviceSerialNum string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530327 logger.Infow(ctx, "Deleting Vnet", log.Fields{"Vnet": name})
328 AppMutex.VnetMutex.Lock()
329 if vnetIntf, ok := va.VnetsByName.Load(name); ok {
330 vnet := vnetIntf.(*VoltVnet)
331 //Delete from mvp list
332 vnet.DevicesList = util.RemoveFromSlice(vnet.DevicesList, deviceSerialNum)
333
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530334 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, deviceSerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +0530335 if len(vnet.DevicesList) == 0 {
336 vnet.DeleteInProgress = true
337 vnet.PendingDeviceToDelete = deviceSerialNum
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530338 vnet.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530339 vnet.VnetPortLock.RLock()
340 if len(vnet.PendingDeleteFlow) == 0 && !vnet.isAssociatedPortsPresent() {
341 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
342 va.deleteVnetConfig(vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530343 _ = db.DelVnet(cntx, vnet.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530344 } else {
345 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
346 }
347 vnet.VnetPortLock.RUnlock()
348 } else {
349 //Update the devicelist in db
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530350 vnet.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530351 }
352 }
353 //TODO: if no vnets are present on device remove icmpv6 group from device
354 AppMutex.VnetMutex.Unlock()
355 return nil
356}
357
358// UpdateVnet to update the VNET with associated service count
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530359func (va *VoltApplication) UpdateVnet(cntx context.Context, vv *VoltVnet) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530360 va.storeVnetConfig(vv.VnetConfig, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530361 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530362 logger.Infow(ctx, "Updated VNET TO DB", log.Fields{"vv": vv.VnetConfig})
363 return nil
364}
365
366// ------------------------------------------------------------
367// Manifestation of a VNET on a port is handled below
368// ------------------------------------------------------------
369//
370// The VNET on a port handles everything that is done for a VNET
371// such as DHCP relay state machine, MAC addresses, IP addresses
372// learnt, so on.
373
374// DhcpStatus type
375type DhcpStatus uint8
376
377const (
378 // DhcpStatusNone constant
379 DhcpStatusNone DhcpStatus = 0
380 // DhcpStatusAcked constant
381 DhcpStatusAcked DhcpStatus = 1
382 // DhcpStatusNacked constant
383 DhcpStatusNacked DhcpStatus = 2
384 // EthTypeNone constant
385 EthTypeNone int = 0
386 // EthTypeIPoE constant
387 EthTypeIPoE int = 1
388 // EthTypePPPoE constant
389 EthTypePPPoE int = 2
390)
391
392// VoltPortVnet structure
393type VoltPortVnet struct {
394 Device string
395 Port string
396 PonPort uint32
397 VnetName string
398 SVlan of.VlanType
399 CVlan of.VlanType
400 UniVlan of.VlanType
401 SVlanTpid layers.EthernetType
402 DhcpRelay bool
403 ArpRelay bool
404 PppoeIa bool
405 MacLearning MacLearningType
406 DhcpStatus DhcpStatus
407 DhcpExpiryTime time.Time
408 Dhcp6ExpiryTime time.Time
409 FlowsApplied bool
410 services sync.Map
411 servicesCount *atomic.Uint64
412 Ipv4Addr net.IP
413 Ipv6Addr net.IP
414 MacAddr net.HardwareAddr
415 LearntMacAddr net.HardwareAddr
416 CircuitID []byte //Will not be used
417 RemoteID []byte //Will not be used
418 IsOption82Disabled bool //Will not be used
419 RelayState DhcpRelayState
420 PPPoeState PppoeIaState
421 RelayStatev6 Dhcpv6RelayState
422 IgmpEnabled bool
423 IgmpFlowsApplied bool
424 McastService bool
425 ONTEtherTypeClassification int
426 VlanControl VlanControl
427 MvlanProfileName string
428 Version string
429 McastTechProfileID uint16
430 McastPbit of.PbitType
431 McastUsMeterID uint32
432 AllowTransparent bool
433 VpvLock sync.Mutex `json:"-"`
434 SchedID int
435 DHCPv6DUID [MaxLenDhcpv6DUID]byte
436 PendingFlowLock sync.RWMutex `json:"-"`
437 PendingDeleteFlow map[string]bool
438 DeleteInProgress bool
439 Blocked bool
440 DhcpPbit of.PbitType
441}
442
443//VlanControl vlan control type
444type VlanControl uint8
445
446const (
447 // None constant
448 // ONU and OLT will passthrough UNIVLAN as is to BNG
449 None VlanControl = iota
450
451 // ONUCVlanOLTSVlan constant
452 // Tagged traffic, ONU will replace UNIVLAN with CVLAN and OLT will add SVLAN
453 // Untagged traffic, ONU will add CVLAN and OLT will add SVLAN
454 ONUCVlanOLTSVlan
455
456 // OLTCVlanOLTSVlan constant
457 // Tagged traffic, ONU will passthrough UNIVLAN as is to OLT and
458 // OLT will replace UNIVLAN with CVLAN and add SVLAN
459 OLTCVlanOLTSVlan
460
461 // ONUCVlan constant
462 // Tagged traffic, ONU will replace UNIVLAN with CVLAN
463 // Untagged traffic, ONU will add CVLAN
464 ONUCVlan
465
466 // OLTSVlan constant
467 // UnTagged traffic, OLT will add the SVLAN
468 OLTSVlan
469)
470
471// NewVoltPortVnet is constructor for VoltPortVnet
472func NewVoltPortVnet(vnet *VoltVnet) *VoltPortVnet {
473 var vpv VoltPortVnet
474
475 vpv.VnetName = vnet.Name
476 vpv.SVlan = vnet.SVlan
477 vpv.CVlan = vnet.CVlan
478 vpv.UniVlan = vnet.UniVlan
479 vpv.SVlanTpid = vnet.SVlanTpid
480 vpv.DhcpRelay = vnet.DhcpRelay
481 vpv.DhcpStatus = DhcpStatusNone
482 vpv.PPPoeState = PppoeIaStateNone
483 vpv.ArpRelay = vnet.ArpLearning
484 vpv.PppoeIa = vnet.PppoeIa
485 vpv.VlanControl = vnet.VlanControl
486 vpv.ONTEtherTypeClassification = vnet.ONTEtherTypeClassification
487 vpv.AllowTransparent = vnet.AllowTransparent
488 vpv.FlowsApplied = false
489 vpv.IgmpEnabled = false
490 vpv.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
491 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
492 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
493 if vpv.VlanControl == ONUCVlan {
494 vpv.CVlan = vpv.SVlan
495 }
496 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
497 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
498 if vpv.VlanControl == OLTSVlan {
499 vpv.CVlan = vpv.UniVlan
500 }
501 vpv.servicesCount = atomic.NewUint64(0)
502 vpv.SchedID = 0
503 vpv.PendingDeleteFlow = make(map[string]bool)
504 vpv.DhcpPbit = vnet.UsDhcpPbit[0]
505 return &vpv
506}
507
508func (vpv *VoltPortVnet) setDevice(device string) {
509
510 if vpv.Device != device && vpv.Device != "" {
511 GetApplication().DisassociateVpvsFromDevice(device, vpv)
512 //TEMP:
513 vpv.printAssociatedVPVs(false)
514 }
515
Tinoj Josephec742f62022-09-29 19:11:10 +0530516 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": device, "Port": vpv.Port, "SVlan": vpv.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530517
518 vpv.Device = device
519 GetApplication().AssociateVpvsToDevice(device, vpv)
520 //TEMP:
521 vpv.printAssociatedVPVs(true)
522}
523
524//TODO - Nav - Temp
525func (vpv *VoltPortVnet) printAssociatedVPVs(add bool) {
526 logger.Infow(ctx, "Start----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
527 if vMap := GetApplication().GetAssociatedVpvsForDevice(vpv.Device, vpv.SVlan); vMap != nil {
528 vMap.Range(func(key, value interface{}) bool {
529 vpvEntry := key.(*VoltPortVnet)
530 logger.Infow(ctx, "Associated VPVs", log.Fields{"SVlan": vpvEntry.SVlan, "CVlan": vpvEntry.CVlan, "UniVlan": vpvEntry.UniVlan})
531 return true
532 })
533 }
534 logger.Infow(ctx, "End----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
535
536}
537
538// GetCircuitID : The interface to be satisfied by the VoltPortVnet to be a DHCP relay
539// session is implemented below. The main functions still remain in
540// the service.go file.
541func (vpv *VoltPortVnet) GetCircuitID() []byte {
542 return []byte(vpv.CircuitID)
543}
544
545// GetRemoteID to get remote id
546func (vpv *VoltPortVnet) GetRemoteID() []byte {
547 return []byte(vpv.RemoteID)
548}
549
550// GetDhcpState to get dhcp state
551func (vpv *VoltPortVnet) GetDhcpState() DhcpRelayState {
552 return vpv.RelayState
553}
554
555// SetDhcpState to set the dhcp state
556func (vpv *VoltPortVnet) SetDhcpState(state DhcpRelayState) {
557 vpv.RelayState = state
558}
559
560// GetPppoeIaState to get pppoeia state
561func (vpv *VoltPortVnet) GetPppoeIaState() PppoeIaState {
562 return vpv.PPPoeState
563}
564
565// SetPppoeIaState to set pppoeia state
566func (vpv *VoltPortVnet) SetPppoeIaState(state PppoeIaState) {
567 vpv.PPPoeState = state
568}
569
570// GetDhcpv6State to get dhcpv6 state
571func (vpv *VoltPortVnet) GetDhcpv6State() Dhcpv6RelayState {
572 return vpv.RelayStatev6
573}
574
575// SetDhcpv6State to set dhcpv6 state
576func (vpv *VoltPortVnet) SetDhcpv6State(state Dhcpv6RelayState) {
577 vpv.RelayStatev6 = state
578}
579
580// DhcpResultInd for dhcp result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530581func (vpv *VoltPortVnet) DhcpResultInd(cntx context.Context, res *layers.DHCPv4) {
582 vpv.ProcessDhcpResult(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530583}
584
585// Dhcpv6ResultInd for dhcpv6 result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530586func (vpv *VoltPortVnet) Dhcpv6ResultInd(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
587 vpv.ProcessDhcpv6Result(cntx, ipv6Addr, leaseTime)
Naveen Sampath04696f72022-06-13 15:19:14 +0530588}
589
590// GetNniVlans to get nni vlans
591func (vpv *VoltPortVnet) GetNniVlans() (uint16, uint16) {
592 switch vpv.VlanControl {
593 case ONUCVlanOLTSVlan,
594 OLTCVlanOLTSVlan:
595 return uint16(vpv.SVlan), uint16(vpv.CVlan)
596 case ONUCVlan,
597 None:
598 return uint16(vpv.SVlan), uint16(of.VlanNone)
599 case OLTSVlan:
600 return uint16(vpv.SVlan), uint16(of.VlanNone)
601 }
602 return uint16(of.VlanNone), uint16(of.VlanNone)
603}
604
605// GetService to get service
606func (vpv *VoltPortVnet) GetService(name string) (*VoltService, bool) {
607 service, ok := vpv.services.Load(name)
608 if ok {
609 return service.(*VoltService), ok
610 }
611 return nil, ok
612}
613
614// AddService to add service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530615func (vpv *VoltPortVnet) AddService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530616 vpv.services.Store(service.Name, service)
617 vpv.servicesCount.Inc()
618 logger.Infow(ctx, "Service added/updated to VPV", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "Service": service.Name, "Count": vpv.servicesCount.Load()})
619}
620
621// DelService to delete service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530622func (vpv *VoltPortVnet) DelService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530623 vpv.services.Delete(service.Name)
624 vpv.servicesCount.Dec()
625
626 // If the only Igmp Enabled service is removed, remove the Igmp trap flow along with it
627 if service.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530628 if err := vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530629 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
630 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
631 }
632
633 vpv.IgmpEnabled = false
634 }
635 logger.Infow(ctx, "Service deleted from VPV", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "Service": service.Name, "Count": vpv.servicesCount.Load()})
636}
637
638// ProcessDhcpResult to process dhcp results
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530639func (vpv *VoltPortVnet) ProcessDhcpResult(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530640 msgType := DhcpMsgType(res)
641 if msgType == layers.DHCPMsgTypeAck {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530642 vpv.ProcessDhcpSuccess(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530643 } else if msgType == layers.DHCPMsgTypeNak {
644 vpv.DhcpStatus = DhcpStatusNacked
645 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530646 vpv.WriteToDb(cntx)
647}
648
649// RangeOnServices to call a function on all services on the vpv
650func (vpv *VoltPortVnet) RangeOnServices(cntx context.Context, callback func(cntx context.Context, key, value interface{}) bool) {
651 vpv.services.Range(func(key, value interface{}) bool {
652 return callback(cntx, key, value)
653 })
Naveen Sampath04696f72022-06-13 15:19:14 +0530654}
655
656// ProcessDhcpSuccess : Learn the IPv4 address allocated to the services and update the
657// the services with the same. This also calls for adding flows
658// for the services as the DHCP procedure is completed
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530659func (vpv *VoltPortVnet) ProcessDhcpSuccess(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530660 vpv.DhcpStatus = DhcpStatusAcked
661 vpv.Ipv4Addr, _ = GetIpv4Addr(res)
662 logger.Infow(ctx, "Received IPv4 Address", log.Fields{"IP Address": vpv.Ipv4Addr.String()})
663 logger.Infow(ctx, "Services Configured", log.Fields{"Count": vpv.servicesCount.Load()})
664
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530665 vpv.RangeOnServices(cntx, vpv.updateIPv4AndProvisionFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530666 vpv.ProcessDhcpv4Options(res)
667}
668
669// ProcessDhcpv4Options : Currently we process lease time and store the validity of the
670// IP address allocated.
671func (vpv *VoltPortVnet) ProcessDhcpv4Options(res *layers.DHCPv4) {
672 for _, o := range res.Options {
673 switch o.Type {
674 case layers.DHCPOptLeaseTime:
675 leasetime := GetIPv4LeaseTime(o)
676 vpv.DhcpExpiryTime = time.Now().Add((time.Duration(leasetime) * time.Second))
677 logger.Infow(ctx, "Lease Expiry Set", log.Fields{"Time": vpv.DhcpExpiryTime})
678 }
679 }
680}
681
682// ProcessDhcpv6Result : Read the IPv6 address allocated to the device and store it on the
683// VNET. The same IPv6 address is also passed to the services. When a
684// service is fetched all the associated information such as MAC address,
685// IPv4 address and IPv6 addresses can be provided.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530686func (vpv *VoltPortVnet) ProcessDhcpv6Result(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530687 // TODO: Status based hanlding of flows
688 vpv.Dhcp6ExpiryTime = time.Now().Add((time.Duration(leaseTime) * time.Second))
689 vpv.Ipv6Addr = ipv6Addr
690
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530691 vpv.RangeOnServices(cntx, vpv.updateIPv6AndProvisionFlows)
692 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530693}
694
695// AddSvcUsMeterToDevice to add service upstream meter info to device
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530696func AddSvcUsMeterToDevice(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +0530697 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +0530698 logger.Infow(ctx, "Adding upstream meter profile to device", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530699 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
700 GetApplication().AddMeterToDevice(svc.Port, device.Name, svc.UsMeterID, 0)
701 return true
702 }
703 logger.Errorw(ctx, "Dropping US Meter request: Device not found", log.Fields{"Service": svc})
704 return false
705}
706
707// PushFlowsForPortVnet - triggers flow construction and push for provided VPV
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530708func (vpv *VoltPortVnet) PushFlowsForPortVnet(cntx context.Context, d *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530709
710 vp := d.GetPort(vpv.Port)
711
712 //Ignore if UNI port is not found or not UP
713 if vp == nil || vp.State != PortStateUp {
714 logger.Warnw(ctx, "Ignoring Vlan UP Ind for VPV: Port Not Found/Ready", log.Fields{"Port": vp})
715 return
716 }
717
718 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
719 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Configuration for VPV", log.Fields{"Device": d.Name, "Port": vpv.Port, "DetectedPon": vp.PonPort, "ExpectedPon": vpv.PonPort, "Vnet": vpv.VnetName})
720 return
721 }
722
723 //Disable the flag so that flows can be pushed again
724 // vpv.IgmpFlowsApplied = false
725 // vpv.DsFlowsApplied = false
726 // vpv.UsFlowsApplied = false
727 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530728 vpv.PortUpInd(cntx, d, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530729 vpv.VpvLock.Unlock()
730}
731
732// PortUpInd : When a port transistions to UP state, the indication is passed
733// on to this module via the application. We read the VNET configuration
734// again here to apply the latest configuration if the configuration
735// changed. Thus, a reboot of ONT forces the new configuration to get
736// applied.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530737func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530738
739 if vpv.DeleteInProgress {
740 logger.Errorw(ctx, "Ignoring VPV Port UP Ind, VPV deleteion In-Progress", log.Fields{"Device": device, "Port": port, "Vnet": vpv.VnetName})
741 return
742 }
743 vpv.setDevice(device.Name)
744 logger.Infow(ctx, "Port UP Ind, pushing flows for the port", log.Fields{"Device": device, "Port": port, "VnetDhcp": vpv.DhcpRelay, "McastService": vpv.McastService})
745
746 nni, _ := GetApplication().GetNniPort(device.Name)
747 if nni == "" {
748 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name})
749 return
750 }
751
752 if vp := device.GetPort(port); vp != nil {
753
754 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
755 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Config for VPV", log.Fields{"Device": device.Name, "Port": port, "DetectedPon": vp.PonPort, "ExpectedPon": vpv.PonPort, "Vnet": vpv.VnetName})
756 return
757 }
758 }
759
760 if vpv.Blocked {
761 logger.Errorw(ctx, "VPV Bocked for Processing. Ignoring flow push request", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
762 return
763 }
764
765 if vpv.DhcpRelay || vpv.ArpRelay || vpv.PppoeIa {
766 // If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
767 // DS HSIA flows are installed after learning the MAC.
768 logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
769 // no HSIA flows for multicast service
770 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530771 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530772 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530773 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530774 if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
775 logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
776 // US & DS DHCP, US HSIA flows are already installed
777 // install only DS HSIA flow here.
778 // no HSIA flows for multicast service
779 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530780 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530781 }
782 }
783
784 } else {
785 // DHCP relay is not configured. This implies that the service must use
786 // 1:1 and does not require MAC learning. In a completely uncommon but
787 // plausible case, the MAC address can be learnt from N:1 without DHCP
788 // relay by configuring any unknown MAC address to be reported. This
789 // however is not seen as a real use case.
790 logger.Infow(ctx, "Port Up - Service Flows", log.Fields{"Device": device.Name, "Port": port})
791 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530792 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530793 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530794 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530795 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530796 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530797 }
798 }
799
800 // Process IGMP proxy - install IGMP trap rules before DHCP trap rules
801 if vpv.IgmpEnabled {
802 logger.Infow(ctx, "Port Up - IGMP Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530803 vpv.RangeOnServices(cntx, AddSvcUsMeterToDevice)
804 if err := vpv.AddIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530805 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
806 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
807 }
808
809 if vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530810 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +0530811 }
812 }
813
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530814 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530815}
816
817// PortDownInd : When the port status changes to down, we delete all configured flows
818// The same indication is also passed to the services enqueued for them
819// to take appropriate actions
Tinoj 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 }
Tinoj Josephec742f62022-09-29 19:11:10 +05301039 if !svc.IsActivated {
1040 logger.Warn(ctx, "Not pushing Service Flows: Service Not activated")
1041 return
1042 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301043 //Push Service Flows if DHCP relay is not configured
1044 //or already DHCP flows are configured for the VPV
1045 //to which the serivce is associated
1046 if vpv.FlowsApplied {
1047 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301048 svc.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301049 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301050 if err:= svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301051 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1052 }
1053 }
1054 }
1055
1056 //Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
1057 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1058 // service with Igmp Enabled needs to be installed
1059 if svc.IgmpEnabled && vpv.FlowsApplied {
1060 logger.Infow(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301061 if err := vpv.AddIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301062 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1063 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1064 }
1065
1066 if vpv.McastService {
1067 //For McastService, send Service Activated indication once IGMP US flow is pushed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301068 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +05301069 }
1070 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301071 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301072}
1073
1074// setLearntMAC to set learnt mac
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301075func (vpv *VoltPortVnet) setLearntMAC(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301076 svc := value.(*VoltService)
1077 svc.SetMacAddr(vpv.MacAddr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301078 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301079 return true
1080}
1081
1082// PostAccessConfigSuccessInd for posting access config success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301083func PostAccessConfigSuccessInd(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301084 return true
1085}
1086
1087// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301088func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301089 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301090 logger.Infow(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301091 svc.SetIpv4Addr(vpv.Ipv4Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301092 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301093
1094 return true
1095}
1096
1097// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301098func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301099 svc := value.(*VoltService)
1100 svc.SetIpv6Addr(vpv.Ipv6Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301101 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301102
1103 return true
1104}
1105
1106// AddUsHsiaFlows to add upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301107func AddUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301108 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301109 if err:= svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301110 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1111 }
1112 return true
1113}
1114
1115// AddDsHsiaFlows to add downstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301116func AddDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301117 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301118 if err:= svc.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301119 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1120 }
1121 return true
1122}
1123
1124// ClearFlagsInService to clear the flags used in service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301125func ClearFlagsInService(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301126 svc := value.(*VoltService)
1127 svc.ServiceLock.Lock()
1128 svc.IgmpFlowsApplied = false
1129 svc.DsDhcpFlowsApplied = false
1130 svc.DsHSIAFlowsApplied = false
1131 svc.Icmpv6FlowsApplied = false
1132 svc.UsHSIAFlowsApplied = false
1133 svc.UsDhcpFlowsApplied = false
1134 svc.PendingFlows = make(map[string]bool)
1135 svc.AssociatedFlows = make(map[string]bool)
1136 svc.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301137 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301138 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1139 return true
1140}
1141
1142// DelDsHsiaFlows to delete hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301143func DelDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301144 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301145 if err:= svc.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301146 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1147 }
1148 return true
1149}
1150
1151// DelUsHsiaFlows to delete upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301152func DelUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301153 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301154 if err:= svc.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301155 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1156 }
1157 return true
1158}
1159
1160// ClearServiceCounters to clear the service counters
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301161func ClearServiceCounters(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301162 svc := value.(*VoltService)
1163 //Delete the per service counter too
1164 GetApplication().ServiceCounters.Delete(svc.Name)
1165 if svc.IgmpEnabled && svc.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301166 _ = db.DelAllServiceChannelCounter(cntx, svc.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301167 }
1168 return true
1169}
1170
1171//AddTrapFlows - Adds US & DS Trap flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301172func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301173
1174 if !vpv.FlowsApplied || vgcRebooted {
1175 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301176 if err := vpv.AddUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301177 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1178 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1179 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301180 if err := vpv.AddDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301181 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1182 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1183 }
1184 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1185 log.Fields{"port": vpv.Port})
1186 //vpv.updateICMPv6McGroup(true)
1187 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301188 if err := vpv.AddUsArpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301189 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1190 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1191 }
1192 logger.Info(ctx, "ARP trap rules not added in downstream direction")
1193
1194 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301195 if err := vpv.AddUsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301196 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1197 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1198 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301199 if err := vpv.AddDsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301200 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1201 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1202 }
1203 }
1204 vpv.FlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301205 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301206 }
1207}
1208
1209//DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301210func (vpv *VoltPortVnet) DelTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301211
1212 // Delete HSIA & DHCP flows before deleting IGMP flows
1213 if vpv.FlowsApplied || vgcRebooted {
1214 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301215 if err:= vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301216 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1217 "UniVlan": vpv.UniVlan, "Error": err})
1218 }
1219 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1220 log.Fields{"port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301221 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301222 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1223 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1224 }
1225 //vpv.updateICMPv6McGroup(false)
1226 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301227 if err := vpv.DelUsArpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301228 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1229 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1230 }
1231 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301232 if err := vpv.DelUsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301233 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1234 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1235 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301236 if err := vpv.DelDsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301237 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1238 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1239 }
1240 }
1241 vpv.FlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301242 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301243 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301244 if err:= vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301245 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1246 "UniVlan": vpv.UniVlan, "Error": err})
1247 }
1248}
1249
1250// DelHsiaFlows deletes the service flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301251func (vpv *VoltPortVnet) DelHsiaFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301252 // no HSIA flows for multicast service
1253 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301254 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
1255 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301256 }
1257}
1258
1259//ClearServiceCounters - Removes all igmp counters for a service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301260func (vpv *VoltPortVnet) ClearServiceCounters(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301261 //send flows deleted indication to submgr
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301262 vpv.RangeOnServices(cntx, ClearServiceCounters)
Naveen Sampath04696f72022-06-13 15:19:14 +05301263}
1264
1265// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301266func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301267 var vd *VoltDevice
1268 device := vpv.Device
1269
1270 if vd = GetApplication().GetDevice(device); vd != nil {
1271 if vd.State != controller.DeviceStateUP {
1272 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})
1273 return nil
1274 }
1275 } else {
1276 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})
1277 return errorCodes.ErrDeviceNotFound
1278 }
1279
1280 flows, err := vpv.BuildUsDhcpFlows()
1281 if err == nil {
1282 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301283 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301284 //push ind here ABHI
1285 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1286 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1287 }
1288 } else {
1289 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1290 //push ind here ABHI
1291 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1292 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1293
1294 }
1295 /*
1296 flows, err = vpv.BuildUsDhcp6Flows()
1297 if err == nil {
1298 logger.Debugw(ctx, "Adding US DHCP6 flows", log.Fields{"Device": device})
1299 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1300 //pussh ind here ABHI
1301 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1302 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1303
1304 }
1305 } else {
1306 logger.Errorw(ctx, "US DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1307 //push ind here ABHI
1308 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1309 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1310
1311 }*/
1312 return nil
1313}
1314
1315// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301316func (vpv *VoltPortVnet) AddDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301317
1318 var vd *VoltDevice
1319 device := vpv.Device
1320
1321 if vd = GetApplication().GetDevice(device); vd != nil {
1322 if vd.State != controller.DeviceStateUP {
1323 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})
1324 return nil
1325 }
1326 } else {
1327 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})
1328 return errorCodes.ErrDeviceNotFound
1329 }
1330 if GetApplication().GetVendorID() != Radisys && vd.GlobalDhcpFlowAdded {
1331 return nil
1332 }
1333
1334 flows, err := vpv.BuildDsDhcpFlows()
1335 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301336 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301337 //push ind here and procced
1338 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1339 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1340
1341 }
1342 } else {
1343 logger.Errorw(ctx, "DS DHCP Flow Add Failed", log.Fields{"Reason": err.Error()})
1344 //send ind here and proceed
1345 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1346 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1347
1348 }
1349 /*
1350 flows, err = vpv.BuildDsDhcp6Flows()
1351 if err == nil {
1352 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1353 //push ind and proceed
1354 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1355 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1356
1357 }
1358 } else {
1359 logger.Errorw(ctx, "DS DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error()})
1360 //Send ind here and proceed
1361 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1362 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1363
1364 }*/
1365 if GetApplication().GetVendorID() != Radisys {
1366 vd.GlobalDhcpFlowAdded = true
1367 }
1368 return nil
1369}
1370
1371// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301372func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
1373 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301374 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1375 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1376 }
1377
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301378 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301379 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1380 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1381 }
1382}
1383
1384// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1385// Write the status of the VPV to the DB once the delete is scheduled
1386// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301387func (vpv *VoltPortVnet) DelUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301388 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1389 if err != nil {
1390 return err
1391 }
1392
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301393 err = vpv.delDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301394 if err != nil {
1395 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1396 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1397 }
1398 /*
1399 err = vpv.delDhcp6Flows(device)
1400 if err != nil {
1401 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1402 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1403 }*/
1404 return nil
1405}
1406
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301407func (vpv *VoltPortVnet) delDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301408 flows, err := vpv.BuildUsDhcpFlows()
1409 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301410 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301411 }
1412 logger.Errorw(ctx, "US DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1413 return err
1414}
1415/*
1416func (vpv *VoltPortVnet) delDhcp6Flows(device *VoltDevice) error {
1417 flows, err := vpv.BuildUsDhcp6Flows()
1418 if err == nil {
1419 return vpv.RemoveFlows(device, flows)
1420 }
1421 logger.Errorw(ctx, "US DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1422 return err
1423
1424}*/
1425
1426// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1427// Write the status of the VPV to the DB once the delete is scheduled
1428// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301429func (vpv *VoltPortVnet) DelDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301430 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1431 if err != nil {
1432 return err
1433 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301434 err = vpv.delDsDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301435 if err != nil {
1436 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1437 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1438 }
1439 /*
1440 err = vpv.delDsDhcp6Flows(device)
1441 if err != nil {
1442 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1443 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1444 }*/
1445 return nil
1446}
1447
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301448func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301449 flows, err := vpv.BuildDsDhcpFlows()
1450 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301451 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301452 }
1453 logger.Errorw(ctx, "DS DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1454 return err
1455}
1456
1457/*
1458func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1459 flows, err := vpv.BuildDsDhcp6Flows()
1460 if err == nil {
1461 return vpv.RemoveFlows(device, flows)
1462 }
1463 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1464 return err
1465}*/
1466
1467// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301468func (vpv *VoltPortVnet) AddUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301469
1470 var vd *VoltDevice
1471 device := vpv.Device
1472 if vd = GetApplication().GetDevice(device); vd != nil {
1473 if vd.State != controller.DeviceStateUP {
1474 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})
1475 return nil
1476 }
1477 } else {
1478 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})
1479 return errorCodes.ErrDeviceNotFound
1480 }
1481
1482 flows, err := vpv.BuildUsArpFlows()
1483 if err == nil {
1484 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301485 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301486 return err1
1487 }
1488 } else {
1489 logger.Errorw(ctx, "US ARP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1490 return err
1491 }
1492 return nil
1493}
1494
1495// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1496// Write the status of the VPV to the DB once the delete is scheduled
1497// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301498func (vpv *VoltPortVnet) DelUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301499 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1500 if err != nil {
1501 return err
1502 }
1503 flows, err := vpv.BuildUsArpFlows()
1504 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301505 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301506 }
1507 logger.Errorw(ctx, "US ARP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1508 return err
1509}
1510
1511// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301512func (vpv *VoltPortVnet) AddUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301513 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1514
1515 var vd *VoltDevice
1516 device := vpv.Device
1517
1518 if vd = GetApplication().GetDevice(device); vd != nil {
1519 if vd.State != controller.DeviceStateUP {
1520 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})
1521 return nil
1522 }
1523 } else {
1524 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})
1525 return errorCodes.ErrDeviceNotFound
1526 }
1527
1528 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1529 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1530
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301531 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301532 return err1
1533 }
1534 } else {
1535 logger.Errorw(ctx, "US PPPoE Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1536 return err
1537 }
1538 return nil
1539}
1540
1541// AddDsPppoeFlows to add downstream pppoe flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301542func (vpv *VoltPortVnet) AddDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301543 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1544 var vd *VoltDevice
1545 device := vpv.Device
1546
1547 if vd = GetApplication().GetDevice(device); vd != nil {
1548 if vd.State != controller.DeviceStateUP {
1549 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})
1550 return nil
1551 }
1552 } else {
1553 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})
1554 return errorCodes.ErrDeviceNotFound
1555 }
1556
1557 flows, err := vpv.BuildDsPppoeFlows()
1558 if err == nil {
1559
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301560 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301561 return err1
1562 }
1563 } else {
1564 logger.Errorw(ctx, "DS PPPoE Flow Add Failed", log.Fields{"Reason": err.Error()})
1565 return err
1566 }
1567 return nil
1568}
1569
1570// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1571// Write the status of the VPV to the DB once the delete is scheduled
1572// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301573func (vpv *VoltPortVnet) DelUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301574 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1575 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1576 if err != nil {
1577 return err
1578 }
1579 flows, err := vpv.BuildUsPppoeFlows()
1580 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301581 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301582 }
1583 logger.Errorw(ctx, "US PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1584 return err
1585}
1586
1587// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1588// Write the status of the VPV to the DB once the delete is scheduled
1589// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301590func (vpv *VoltPortVnet) DelDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301591 logger.Debugw(ctx, "Deleting DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1592 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1593 if err != nil {
1594 return err
1595 }
1596 flows, err := vpv.BuildDsPppoeFlows()
1597 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301598 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301599 }
1600 logger.Errorw(ctx, "DS PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1601 return err
1602}
1603
1604// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301605func (vpv *VoltPortVnet) AddIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301606
1607 if !vpv.IgmpFlowsApplied || vgcRebooted {
1608 if vpv.MvlanProfileName == "" {
1609 logger.Info(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
1610 return nil
1611 }
1612 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1613 if err != nil {
1614 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1615 return err
1616 } else if device.State != controller.DeviceStateUP {
1617 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})
1618 return nil
1619 }
1620 flows, err := vpv.BuildIgmpFlows()
1621 if err == nil {
1622 for cookie := range flows.SubFlows {
1623 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1624 cookie := strconv.FormatUint(cookie, 10)
1625 fe := &FlowEvent{
1626 eType: EventTypeUsIgmpFlowAdded,
1627 cookie: cookie,
1628 eventData: vpv,
1629 }
1630 vd.RegisterFlowAddEvent(cookie, fe)
1631 }
1632 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301633 if err1 := cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301634 return err1
1635 }
1636 } else {
1637 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1638 return err
1639 }
1640 vpv.IgmpFlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301641 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301642 }
1643 return nil
1644}
1645
1646// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1647// Write the status of the VPV to the DB once the delete is scheduled
1648// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301649func (vpv *VoltPortVnet) DelIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301650
1651 if vpv.IgmpFlowsApplied || vgcRebooted {
1652 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1653 if err != nil {
1654 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1655 return err
1656 }
1657 flows, err := vpv.BuildIgmpFlows()
1658 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301659 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301660 return err1
1661 }
1662 } else {
1663 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1664 return err
1665 }
1666 vpv.IgmpFlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301667 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301668 }
1669 return nil
1670}
1671
1672// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1673// The flows included by this function cover US only as the DS is
1674// created either automatically by the VOLTHA or at the device level
1675// earlier
1676func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
1677 flow := &of.VoltFlow{}
1678 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1679
1680 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
1681 subFlow := of.NewVoltSubFlow()
1682 subFlow.SetTableID(0)
1683
1684 if GetApplication().GetVendorID() == Radisys {
1685 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1686 return nil, err
1687 }
1688 } else {
1689 subFlow.SetMatchVlan(vpv.UniVlan)
1690 subFlow.SetSetVlan(vpv.CVlan)
1691 }
1692 subFlow.SetUdpv4Match()
1693 subFlow.SrcPort = 68
1694 subFlow.DstPort = 67
1695 uniport, err := GetApplication().GetPortID(vpv.Port)
1696 if err != nil {
1697 logger.Errorw(ctx, "Failed to fetch uni port from vpv", log.Fields{"error": err, "port": vpv.Port})
1698 return nil, err
1699 }
1700 subFlow.SetInPort(uniport)
1701 // PortName and PortID to be used for validation of port before flow pushing
1702 flow.PortID = uniport
1703 flow.PortName = vpv.Port
1704 subFlow.SetReportToController()
1705
1706 // Set techprofile, meterid of first service
1707 vpv.services.Range(func(key, value interface{}) bool {
1708 svc := value.(*VoltService)
1709 writemetadata := uint64(svc.TechProfileID) << 32
1710 subFlow.SetWriteMetadata(writemetadata)
1711 subFlow.SetMeterID(svc.UsMeterID)
1712 return false
1713 })
1714
1715 subFlow.SetPcp(vpv.DhcpPbit)
1716 // metadata := uint64(uniport)
1717 // subFlow.SetWriteMetadata(metadata)
1718 allowTransparent := 0
1719 if vpv.AllowTransparent {
1720 allowTransparent = 1
1721 }
1722 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1723 subFlow.SetTableMetadata(metadata)
1724
1725 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1726 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1727 subFlow.Priority = of.DhcpFlowPriority
1728
1729 flow.SubFlows[subFlow.Cookie] = subFlow
1730 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1731 return flow, nil
1732}
1733
1734// BuildDsDhcpFlows to build the downstream dhcp flows
1735func (vpv *VoltPortVnet) BuildDsDhcpFlows() (*of.VoltFlow, error) {
1736
1737 logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1738 flow := &of.VoltFlow{}
1739 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1740 subFlow := of.NewVoltSubFlow()
1741 subFlow.SetTableID(0)
1742 // If dhcp trap rule is global rule, No need to match on vlan
1743 if GetApplication().GetVendorID() == Radisys {
1744 vpv.setDsMatchVlan(subFlow)
1745 }
1746 subFlow.SetUdpv4Match()
1747 subFlow.SrcPort = 67
1748 subFlow.DstPort = 68
1749 uniport, _ := GetApplication().GetPortID(vpv.Port)
1750 nni, err := GetApplication().GetNniPort(vpv.Device)
1751 if err != nil {
1752 return nil, err
1753 }
1754 nniport, err := GetApplication().GetPortID(nni)
1755 if err != nil {
1756 return nil, err
1757 }
1758 subFlow.SetInPort(nniport)
1759 // PortName and PortID to be used for validation of port before flow pushing
1760 flow.PortID = uniport
1761 flow.PortName = vpv.Port
1762 // metadata := uint64(uniport)
1763 // subFlow.SetWriteMetadata(metadata)
1764 allowTransparent := 0
1765 if vpv.AllowTransparent {
1766 allowTransparent = 1
1767 }
1768 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1769 subFlow.SetTableMetadata(metadata)
1770 subFlow.SetReportToController()
1771 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1772 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
1773 subFlow.Priority = of.DhcpFlowPriority
1774
1775 flow.SubFlows[subFlow.Cookie] = subFlow
1776 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1777
1778 return flow, nil
1779}
1780
1781// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1782// application.
1783func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
1784 flow := &of.VoltFlow{}
1785 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1786
1787 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
1788 subFlow := of.NewVoltSubFlow()
1789 subFlow.SetTableID(0)
1790
1791 subFlow.SetMatchVlan(vpv.UniVlan)
1792 subFlow.SetSetVlan(vpv.CVlan)
1793 subFlow.SetUdpv6Match()
1794 subFlow.SrcPort = 546
1795 subFlow.DstPort = 547
1796 uniport, err := GetApplication().GetPortID(vpv.Port)
1797 if err != nil {
1798 return nil, err
1799 }
1800 // Set techprofile, meterid of first service
1801 vpv.services.Range(func(key, value interface{}) bool {
1802 svc := value.(*VoltService)
1803 writemetadata := uint64(svc.TechProfileID) << 32
1804 subFlow.SetWriteMetadata(writemetadata)
1805 subFlow.SetMeterID(svc.UsMeterID)
1806 return false
1807 })
1808 subFlow.SetInPort(uniport)
1809 // PortName and PortID to be used for validation of port before flow pushing
1810 flow.PortID = uniport
1811 flow.PortName = vpv.Port
1812 //subFlow.SetMeterId(vpv.UsDhcpMeterId)
1813 // metadata := uint64(uniport)
1814 // subFlow.SetWriteMetadata(metadata)
1815 allowTransparent := 0
1816 if vpv.AllowTransparent {
1817 allowTransparent = 1
1818 }
1819 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1820 subFlow.SetTableMetadata(metadata)
1821 subFlow.SetReportToController()
1822 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1823 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
1824 subFlow.Priority = of.DhcpFlowPriority
1825
1826 flow.SubFlows[subFlow.Cookie] = subFlow
1827 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1828 return flow, nil
1829}
1830
1831// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1832// application.
1833func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
1834 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1835
1836 flow := &of.VoltFlow{}
1837 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1838 subFlow := of.NewVoltSubFlow()
1839 subFlow.SetTableID(0)
1840
1841 vpv.setDsMatchVlan(subFlow)
1842 subFlow.SetUdpv6Match()
1843 subFlow.SrcPort = 547
1844 subFlow.DstPort = 547
1845 uniport, _ := GetApplication().GetPortID(vpv.Port)
1846 nni, err := GetApplication().GetNniPort(vpv.Device)
1847 if err != nil {
1848 return nil, err
1849 }
1850 nniport, err := GetApplication().GetPortID(nni)
1851 if err != nil {
1852 return nil, err
1853 }
1854 subFlow.SetInPort(nniport)
1855 // PortName and PortID to be used for validation of port before flow pushing
1856 flow.PortID = uniport
1857 flow.PortName = vpv.Port
1858 // metadata := uint64(uniport)
1859 // subFlow.SetWriteMetadata(metadata)
1860 allowTransparent := 0
1861 if vpv.AllowTransparent {
1862 allowTransparent = 1
1863 }
1864 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1865 subFlow.SetTableMetadata(metadata)
1866 subFlow.SetReportToController()
1867 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1868 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
1869 subFlow.Priority = of.DhcpFlowPriority
1870
1871 flow.SubFlows[subFlow.Cookie] = subFlow
1872 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1873 return flow, nil
1874}
1875
1876// BuildUsArpFlows builds the US ARP relay flows for a subscriber
1877// The flows included by this function cover US only as the DS is
1878// created either automatically by the VOLTHA or at the device level
1879// earlier
1880func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
1881 flow := &of.VoltFlow{}
1882 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1883
1884 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
1885 subFlow := of.NewVoltSubFlow()
1886 subFlow.SetTableID(0)
1887
1888 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1889 subFlow.SetMatchSrcMac(vpv.MacAddr)
1890 }
1891
1892 subFlow.SetMatchDstMac(BroadcastMAC)
1893 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1894 return nil, err
1895 }
1896 subFlow.SetArpMatch()
1897 uniport, err := GetApplication().GetPortID(vpv.Port)
1898 if err != nil {
1899 return nil, err
1900 }
1901 subFlow.SetInPort(uniport)
1902 // PortName and PortID to be used for validation of port before flow pushing
1903 flow.PortID = uniport
1904 flow.PortName = vpv.Port
1905 subFlow.SetReportToController()
1906 allowTransparent := 0
1907 if vpv.AllowTransparent {
1908 allowTransparent = 1
1909 }
1910 metadata := uint64(uniport)
1911 subFlow.SetWriteMetadata(metadata)
1912 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1913 subFlow.SetTableMetadata(metadata)
1914 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
1915 subFlow.Priority = of.ArpFlowPriority
1916
1917 flow.SubFlows[subFlow.Cookie] = subFlow
1918 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1919 return flow, nil
1920}
1921
1922// setUsMatchVlan to set upstream match vlan
1923func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
1924 switch vpv.VlanControl {
1925 case None:
1926 flow.SetMatchVlan(vpv.SVlan)
1927 case ONUCVlanOLTSVlan:
1928 flow.SetMatchVlan(vpv.CVlan)
1929 case OLTCVlanOLTSVlan:
1930 flow.SetMatchVlan(vpv.UniVlan)
1931 //flow.SetSetVlan(vpv.CVlan)
1932 case ONUCVlan:
1933 flow.SetMatchVlan(vpv.SVlan)
1934 case OLTSVlan:
1935 flow.SetMatchVlan(vpv.UniVlan)
1936 //flow.SetSetVlan(vpv.SVlan)
1937 default:
1938 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
1939 return errorCodes.ErrInvalidParamInRequest
1940 }
1941 return nil
1942}
1943
1944// BuildUsPppoeFlows to build upstream pppoe flows
1945func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
1946
1947 flow := &of.VoltFlow{}
1948 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1949 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
1950 subFlow := of.NewVoltSubFlow()
1951 subFlow.SetTableID(0)
1952
1953 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1954 subFlow.SetMatchSrcMac(vpv.MacAddr)
1955 }
1956
1957 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1958 return nil, err
1959 }
1960 subFlow.SetPppoeDiscoveryMatch()
1961 uniport, err := GetApplication().GetPortID(vpv.Port)
1962 if err != nil {
1963 return nil, err
1964 }
1965 subFlow.SetInPort(uniport)
1966 subFlow.SetReportToController()
1967 // PortName and PortID to be used for validation of port before flow pushing
1968 flow.PortID = uniport
1969 flow.PortName = vpv.Port
1970
1971 allowTransparent := 0
1972 if vpv.AllowTransparent {
1973 allowTransparent = 1
1974 }
1975 metadata := uint64(uniport)
1976 subFlow.SetWriteMetadata(metadata)
1977
1978 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1979 subFlow.SetTableMetadata(metadata)
1980
1981 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
1982 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
1983 subFlow.Priority = of.PppoeFlowPriority
1984
1985 flow.SubFlows[subFlow.Cookie] = subFlow
1986 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1987 return flow, nil
1988}
1989
1990// BuildDsPppoeFlows to build downstream pppoe flows
1991func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
1992
1993 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1994 flow := &of.VoltFlow{}
1995 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1996 subFlow := of.NewVoltSubFlow()
1997 subFlow.SetTableID(0)
1998
1999 vpv.setDsMatchVlan(subFlow)
2000 subFlow.SetPppoeDiscoveryMatch()
2001
2002 if NonZeroMacAddress(vpv.MacAddr) {
2003 subFlow.SetMatchDstMac(vpv.MacAddr)
2004 }
2005
2006 uniport, _ := GetApplication().GetPortID(vpv.Port)
2007 nni, err := GetApplication().GetNniPort(vpv.Device)
2008 if err != nil {
2009 return nil, err
2010 }
2011 nniport, err := GetApplication().GetPortID(nni)
2012 if err != nil {
2013 return nil, err
2014 }
2015 subFlow.SetInPort(nniport)
2016 // PortName and PortID to be used for validation of port before flow pushing
2017 flow.PortID = uniport
2018 flow.PortName = vpv.Port
2019 metadata := uint64(uniport)
2020 subFlow.SetWriteMetadata(metadata)
2021 allowTransparent := 0
2022 if vpv.AllowTransparent {
2023 allowTransparent = 1
2024 }
2025 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2026 subFlow.SetTableMetadata(metadata)
2027 subFlow.SetReportToController()
2028 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
2029 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2030 subFlow.Priority = of.PppoeFlowPriority
2031
2032 flow.SubFlows[subFlow.Cookie] = subFlow
2033 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2034 return flow, nil
2035}
2036
2037// setDsMatchVlan to set downstream match vlan
2038func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
2039 switch vpv.VlanControl {
2040 case None:
2041 flow.SetMatchVlan(vpv.SVlan)
2042 case ONUCVlanOLTSVlan,
2043 OLTCVlanOLTSVlan,
2044 ONUCVlan,
2045 OLTSVlan:
2046 flow.SetMatchVlan(vpv.SVlan)
2047 default:
2048 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2049 }
2050}
2051
2052// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2053// in the US direction.
2054func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2055 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2056 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2057 if mvp == nil {
2058 return nil, errors.New("Mvlan Profile configured not found")
2059 }
2060 mvlan := mvp.GetUsMatchVlan()
2061 flow := &of.VoltFlow{}
2062 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2063 subFlow := of.NewVoltSubFlow()
2064 subFlow.SetTableID(0)
2065
2066 if GetApplication().GetVendorID() == Radisys {
2067 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2068 return nil, err
2069 }
2070 } else {
2071 subFlow.SetMatchVlan(vpv.UniVlan)
2072 subFlow.SetSetVlan(vpv.CVlan)
2073 }
2074
2075 uniport, err := GetApplication().GetPortID(vpv.Port)
2076 if err != nil {
2077 return nil, err
2078 }
2079 subFlow.SetInPort(uniport)
2080 // PortName and PortID to be used for validation of port before flow pushing
2081 flow.PortID = uniport
2082 flow.PortName = vpv.Port
2083
2084 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2085 subFlow.SetMatchSrcMac(vpv.MacAddr)
2086 }
2087 logger.Infow(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
2088 //metadata := uint64(mvlan)
2089
2090 if vpv.McastService {
2091 metadata := uint64(vpv.McastUsMeterID)
2092 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2093 subFlow.SetMatchPbit(vpv.McastPbit)
2094 subFlow.SetMeterID(vpv.McastUsMeterID)
2095 subFlow.SetWriteMetadata(metadata)
2096 } else {
2097 // Set techprofile, meterid of first service
2098 vpv.services.Range(func(key, value interface{}) bool {
2099 svc := value.(*VoltService)
2100 writemetadata := uint64(svc.TechProfileID) << 32
2101 subFlow.SetWriteMetadata(writemetadata)
2102 subFlow.SetMeterID(svc.UsMeterID)
2103 return false
2104 })
2105 }
2106
2107 allowTransparent := 0
2108 if vpv.AllowTransparent {
2109 allowTransparent = 1
2110 }
2111 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2112 subFlow.SetTableMetadata(metadata)
2113 subFlow.SetIgmpMatch()
2114 subFlow.SetReportToController()
2115 //| 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
2116 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2117 subFlow.Priority = of.IgmpFlowPriority
2118
2119 flow.SubFlows[subFlow.Cookie] = subFlow
2120 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2121 return flow, nil
2122}
2123
2124// WriteToDb for writing to database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302125func (vpv *VoltPortVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302126 if vpv.DeleteInProgress {
2127 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2128 return
2129 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302130 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302131}
2132
2133//ForceWriteToDb force commit a VPV to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302134func (vpv *VoltPortVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302135 vpv.PendingFlowLock.RLock()
2136 defer vpv.PendingFlowLock.RUnlock()
2137 vpv.Version = database.PresentVersionMap[database.VpvPath]
2138 if b, err := json.Marshal(vpv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302139 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 +05302140 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2141 "UniVlan": vpv.UniVlan, "Error": err})
2142 }
2143 }
2144}
2145
2146// DelFromDb for deleting from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302147func (vpv *VoltPortVnet) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302148 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 +05302149 _ = db.DelVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
Naveen Sampath04696f72022-06-13 15:19:14 +05302150}
2151
2152// ClearAllServiceFlags to clear all service flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302153func (vpv *VoltPortVnet) ClearAllServiceFlags(cntx context.Context) {
2154 vpv.RangeOnServices(cntx, ClearFlagsInService)
Naveen Sampath04696f72022-06-13 15:19:14 +05302155}
2156
2157// ClearAllVpvFlags to clear all vpv flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302158func (vpv *VoltPortVnet) ClearAllVpvFlags(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302159 vpv.PendingFlowLock.Lock()
2160 vpv.FlowsApplied = false
2161 vpv.IgmpFlowsApplied = false
2162 vpv.PendingDeleteFlow = make(map[string]bool)
2163 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302164 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302165 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2166 log.Fields{"device": vpv.Device, "port": vpv.Port,
2167 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2168}
2169
2170// CreateVpvFromString to create vpv from string
2171func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
2172 var vpv VoltPortVnet
2173 if err := json.Unmarshal(b, &vpv); err == nil {
2174 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2175 if !ok {
2176 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2177 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2178 }
2179 vpv.servicesCount = atomic.NewUint64(0)
2180 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2181 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2182 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2183 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2184 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2185 vnet.associatePortToVnet(vpv.Port)
2186 }
2187
2188 if vpv.DeleteInProgress {
2189 va.VoltPortVnetsToDelete[&vpv] = true
2190 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2191 }
2192 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2193 }
2194}
2195
2196// RestoreVpvsFromDb to restore vpvs from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302197func (va *VoltApplication) RestoreVpvsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302198 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302199 vpvs, _ := db.GetVpvs(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302200 for hash, vpv := range vpvs {
2201 b, ok := vpv.Value.([]byte)
2202 if !ok {
2203 logger.Warn(ctx, "The value type is not []byte")
2204 continue
2205 }
2206 va.CreateVpvFromString(b, hash)
2207 }
2208}
2209
2210// GetVnetByPort : VNET related functionality of VOLT Application here on.
2211// Get the VNET from a port. The port identity is passed as device and port identities in string.
2212// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2213// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2214func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
2215 if _, ok := va.VnetsByPort.Load(port); !ok {
2216 return nil
2217 }
2218 vpvs, _ := va.VnetsByPort.Load(port)
2219 for _, vpv := range vpvs.([]*VoltPortVnet) {
2220 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2221 return vpv
2222 }
2223 }
2224 return nil
2225}
2226
2227// AddVnetToPort to add vnet to port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302228func (va *VoltApplication) AddVnetToPort(cntx context.Context, port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
Naveen Sampath04696f72022-06-13 15:19:14 +05302229 // The VNET is not on the port and is to be added
2230 logger.Debugw(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
2231 vpv := NewVoltPortVnet(vvnet)
2232 vpv.MacLearning = vvnet.MacLearning
2233 vpv.Port = port
2234 vvnet.associatePortToVnet(port)
2235 if _, ok := va.VnetsByPort.Load(port); !ok {
2236 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2237 }
2238 vpvsIntf, _ := va.VnetsByPort.Load(port)
2239 vpvs := vpvsIntf.([]*VoltPortVnet)
2240 vpvs = append(vpvs, vpv)
2241 va.VnetsByPort.Store(port, vpvs)
2242 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2243
2244 vpv.VpvLock.Lock()
2245 defer vpv.VpvLock.Unlock()
2246
2247 // Add the service that is causing the VNET to be added to the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302248 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05302249
Tinoj Josephec742f62022-09-29 19:11:10 +05302250 if !vs.IsActivated {
2251 logger.Warn(ctx, "Not Checking port state: Service Not activated")
2252 // Process the PORT UP if the port is already up
2253 d, err := va.GetDeviceFromPort(port)
2254 if err == nil {
2255 vpv.setDevice(d.Name)
2256 }
2257 vpv.WriteToDb(cntx)
2258 return vpv
2259 }
2260
Naveen Sampath04696f72022-06-13 15:19:14 +05302261 // Process the PORT UP if the port is already up
2262 d, err := va.GetDeviceFromPort(port)
2263 if err == nil {
2264 vpv.setDevice(d.Name)
2265 p := d.GetPort(port)
2266 if p != nil {
2267
2268 if vs.PonPort != 0xFF && vs.PonPort != p.PonPort {
2269 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})
2270 } else {
2271 logger.Infow(ctx, "Checking UNI port state", log.Fields{"State": p.State})
2272 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302273 vpv.PortUpInd(cntx, d, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302274 }
2275 }
2276 }
2277 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302278 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302279 return vpv
2280}
2281
2282// DelVnetFromPort for deleting vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302283func (va *VoltApplication) DelVnetFromPort(cntx context.Context, port string, vpv *VoltPortVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302284
2285 //Delete DHCP Session
2286 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2287
2288 //Delete PPPoE session
2289 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2290
2291 //Delete Mac from MacPortMap
2292 va.DeleteMacInPortMap(vpv.MacAddr)
2293
2294 //Delete VPV
2295 vpvsIntf, ok := va.VnetsByPort.Load(port)
2296 if !ok {
2297 return
2298 }
2299 vpvs := vpvsIntf.([]*VoltPortVnet)
2300 for i, lvpv := range vpvs {
2301 if lvpv == vpv {
2302 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2303 "UNIVLAN": vpv.UniVlan})
2304
2305 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2306
2307 vpv.DeleteInProgress = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302308 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302309
2310 va.VnetsByPort.Store(port, vpvs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302311 vpv.DelTrapFlows(cntx)
2312 vpv.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302313 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2314 vpv.PendingFlowLock.RLock()
2315 if len(vpv.PendingDeleteFlow) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302316 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302317 }
2318 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302319 vnet.disassociatePortFromVnet(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302320 }
2321 vpv.PendingFlowLock.RUnlock()
2322 return
2323 }
2324 }
2325}
2326
2327// RestoreVnetsFromDb to restore vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302328func (va *VoltApplication) RestoreVnetsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302329 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302330 vnets, _ := db.GetVnets(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302331 for _, net := range vnets {
2332 b, ok := net.Value.([]byte)
2333 if !ok {
2334 logger.Warn(ctx, "The value type is not []byte")
2335 continue
2336 }
2337 var vnet VoltVnet
2338 err := json.Unmarshal(b, &vnet)
2339 if err != nil {
2340 logger.Warn(ctx, "Unmarshal of VNET failed")
2341 continue
2342 }
2343 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302344 if err := va.AddVnet(cntx, vnet.VnetConfig, &vnet.VnetOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302345 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2346 }
2347
2348 if vnet.DeleteInProgress {
2349 va.VnetsToDelete[vnet.Name] = true
2350 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2351 }
2352
2353 }
2354}
2355
2356// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2357// are used as the key to locate the service. If more than one service is on the
2358// same port (essentially a UNI of ONU), the services must be separated by different
2359// CVLANs
2360func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
2361 // Fetch the device first to make sure the device exists
2362 dIntf, ok := va.DevicesDisc.Load(device)
2363 if !ok {
2364 return nil
2365 }
2366 d := dIntf.(*VoltDevice)
2367
2368 // If the port is NNI port, the services dont exist on it. The svc then
2369 // must be obtained from a different context and is not included here
2370 if port == d.NniPort {
2371 return nil
2372 }
2373
2374 //To return the matched service
2375 var service *VoltService
2376
2377 // This is an access port and the port should have all the associated
2378 // services which can be uniquely identified by the VLANs in the packet
2379 vnets, ok := va.VnetsByPort.Load(port)
2380
2381 if !ok {
2382 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2383 return nil
2384 }
2385 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2386 for _, vnet := range vnets.([]*VoltPortVnet) {
2387 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2388 switch vnet.VlanControl {
2389 case ONUCVlanOLTSVlan:
2390 service = vnet.MatchesPriority(priority)
2391 if vnet.MatchesCvlan(vlans) && service != nil {
2392 return service
2393 }
2394 case ONUCVlan,
2395 None:
2396 service = vnet.MatchesPriority(priority)
2397 // In case of DHCP Flow - cvlan == VlanNone
2398 // In case of HSIA Flow - cvlan == Svlan
2399 if len(vlans) == 1 && (vlans[0] == vnet.SVlan || vlans[0] == of.VlanNone) && service != nil {
2400 return service
2401 }
2402 case OLTCVlanOLTSVlan,
2403 OLTSVlan:
2404 service = vnet.MatchesPriority(priority)
2405 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2406 return service
2407 }
2408 default:
2409 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2410 }
2411 }
2412 return nil
2413}
2414
2415// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2416// are used as the key to locate the service. If more than one service is on the
2417// same port (essentially a UNI of ONU), the services must be separated by different
2418// CVLANs
2419func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2420 // Fetch the device first to make sure the device exists
2421 dIntf, ok := va.DevicesDisc.Load(device)
2422 if !ok {
2423 return nil, nil
2424 }
2425 d := dIntf.(*VoltDevice)
2426
2427 // If the port is NNI port, the services dont exist on it. The svc then
2428 // must be obtained from a different context and is not included here
2429 if port == d.NniPort {
2430 return nil, nil
2431 }
2432
2433 //To return the matched service
2434 var service *VoltService
2435
2436 // This is an access port and the port should have all the associated
2437 // services which can be uniquely identified by the VLANs in the packet
2438 if vnets, ok := va.VnetsByPort.Load(port); ok {
2439 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2440 for _, vnet := range vnets.([]*VoltPortVnet) {
2441 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2442 switch vnet.VlanControl {
2443 case ONUCVlanOLTSVlan:
2444 service = vnet.MatchesPriority(priority)
2445 if vnet.MatchesCvlan(vlans) && service != nil {
2446 return vnet, service
2447 }
2448 case ONUCVlan,
2449 None:
2450 service = vnet.MatchesPriority(priority)
2451 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2452 return vnet, service
2453 }
2454 case OLTCVlanOLTSVlan,
2455 OLTSVlan:
2456 service = vnet.MatchesPriority(priority)
2457 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2458 return vnet, service
2459 }
2460 default:
2461 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2462 }
2463 }
2464 }
2465 return nil, nil
2466}
2467
2468// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2469// are used as the key to locate the service. If more than one service is on the
2470// same port (essentially a UNI of ONU), the services must be separated by different
2471// CVLANs
2472func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
2473 vlans := GetVlans(pkt)
2474 priority := GetPriority(pkt)
2475 return va.GetVnetFromFields(device, port, vlans, priority)
2476}
2477
2478// PushDevFlowForVlan to push icmpv6 flows for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302479func (va *VoltApplication) PushDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302480 logger.Infow(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2481 pushflow := func(key interface{}, value interface{}) bool {
2482 device := value.(*VoltDevice)
2483 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302484 logger.Infow(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +05302485 return true
2486 }
2487 if device.State != controller.DeviceStateUP {
2488 logger.Errorw(ctx, "Push Dev Flows Failed - Device state DOWN", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan, "device": device})
2489 return true
2490 }
2491 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2492 logger.Errorw(ctx, "Push Dev Flows Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2493 return true
2494 }
2495
2496 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2497 vnetList := vnetListIntf.(*util.ConcurrentMap)
2498 vnetList.Set(vnet.Name, true)
2499 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2500 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()})
2501 return true
2502 }
2503 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2504 err := ProcessIcmpv6McGroup(device.Name, false)
2505 if err != nil {
2506 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2507 return true
2508 }
2509 if portID, err := va.GetPortID(device.NniPort); err == nil {
2510 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2511 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2512 return true
2513 }
2514
2515 //Pushing ICMPv6 Flow
2516 flow := BuildICMPv6Flow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302517 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302518 if err != nil {
2519 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2520 return true
2521 }
2522 logger.Infow(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
2523
2524 // Pushing ARP Flow
2525 flow = BuildDSArpFlow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302526 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302527 if err != nil {
2528 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2529 return true
2530 }
2531 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2532
2533 vnetList := util.NewConcurrentMap()
2534 vnetList.Set(vnet.Name, true)
2535 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2536 }
2537 return true
2538 }
2539 va.DevicesDisc.Range(pushflow)
2540}
2541
2542// PushDevFlowForDevice to push icmpv6 flows for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302543func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302544 logger.Infow(ctx, "PushDevFlowForDevice", log.Fields{"device": device})
2545
2546 logger.Debugw(ctx, "Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2547 err := ProcessIcmpv6McGroup(device.Name, false)
2548 if err != nil {
2549 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2550 return
2551 }
2552 pushicmpv6 := func(key, value interface{}) bool {
2553 vnet := value.(*VoltVnet)
2554 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2555 vnetList := vnetListIntf.(*util.ConcurrentMap)
2556 vnetList.Set(vnet.Name, true)
2557 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2558 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()})
2559 return true
2560 }
2561 nniPortID, err := va.GetPortID(device.NniPort)
2562 if err != nil {
2563 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2564 }
2565 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2566 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2567 return true
2568 }
2569 flow := BuildICMPv6Flow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302570 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302571 if err != nil {
2572 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2573 return true
2574 }
2575 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2576
2577 flow = BuildDSArpFlow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302578 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302579 if err != nil {
2580 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2581 return true
2582 }
2583 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2584
2585 vnetList := util.NewConcurrentMap()
2586 vnetList.Set(vnet.Name, true)
2587 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2588 return true
2589 }
2590 va.VnetsByName.Range(pushicmpv6)
2591}
2592
2593// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302594func (va *VoltApplication) DeleteDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302595 logger.Infow(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2596 delflows := func(key interface{}, value interface{}) bool {
2597 device := value.(*VoltDevice)
2598
2599 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2600 vnetList := vnetListIntf.(*util.ConcurrentMap)
2601 vnetList.Remove(vnet.Name)
2602 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2603 if vnetList.Length() != 0 {
2604 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()})
2605 return true
2606 }
2607 }
2608 if portID, err := va.GetPortID(device.NniPort); err == nil {
2609 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2610 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2611 return true
2612 }
2613 //Pushing ICMPv6 Flow
2614 flow := BuildICMPv6Flow(portID, vnet)
2615 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302616 err := vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302617 if err != nil {
2618 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2619 return true
2620 }
2621 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2622
2623 //Pushing ARP Flow
2624 flow = BuildDSArpFlow(portID, vnet)
2625 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302626 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302627 if err != nil {
2628 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2629 return true
2630 }
2631 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2632
2633 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2634 }
2635 return true
2636 }
2637 va.DevicesDisc.Range(delflows)
2638}
2639
2640// DeleteDevFlowForDevice to delete icmpv6 flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302641func (va *VoltApplication) DeleteDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302642 logger.Infow(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
2643 delicmpv6 := func(key, value interface{}) bool {
2644 vnet := value.(*VoltVnet)
2645 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2646 vnetList := vnetListIntf.(*util.ConcurrentMap)
2647 vnetList.Remove(vnet.Name)
2648 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2649 if vnetList.Length() != 0 {
2650 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()})
2651 return true
2652 }
2653 } else {
2654 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2655 return true
2656 }
2657 nniPortID, err := va.GetPortID(device.NniPort)
2658 if err != nil {
2659 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2660 }
2661 flow := BuildICMPv6Flow(nniPortID, vnet)
2662 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302663 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302664 if err != nil {
2665 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2666 return true
2667 }
2668
2669 flow = BuildDSArpFlow(nniPortID, vnet)
2670 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302671 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302672 if err != nil {
2673 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2674 return true
2675 }
2676
2677 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2678 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2679 return true
2680 }
2681 va.VnetsByName.Range(delicmpv6)
2682 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2683 err := ProcessIcmpv6McGroup(device.Name, true)
2684 if err != nil {
2685 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2686 return
2687 }
2688}
2689
2690// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302691func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(cntx context.Context, vnet *VoltVnet, deviceSerialNum string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302692 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2693 delflows := func(key interface{}, value interface{}) bool {
2694 device := value.(*VoltDevice)
2695 if device.SerialNum != deviceSerialNum {
2696 return true
2697 }
2698 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2699 vnetList := vnetListIntf.(*util.ConcurrentMap)
2700 vnetList.Remove(vnet.Name)
2701 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2702 if vnetList.Length() != 0 {
2703 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()})
2704 return true
2705 }
2706 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2707 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2708 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2709 // The step will be as follow:
2710 // 1. Deact Service
2711 // 2. Pod Reboot
2712 // 3. Pending Delete Service triggered
2713 // 4. Del Service Ind followed by DelVnet req from NB
2714 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2715 // hence the flow will not be cleared
2716 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2717 return true
2718 }
2719 if portID, err := va.GetPortID(device.NniPort); err == nil {
2720 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2721 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2722 return false
2723 }
2724 flow := BuildICMPv6Flow(portID, vnet)
2725 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302726 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302727 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2728 }
2729 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2730
2731 flow = BuildDSArpFlow(portID, vnet)
2732 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302733 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302734 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2735 }
2736 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2737 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2738 }
2739 return false
2740 }
2741 va.DevicesDisc.Range(delflows)
2742}
2743
2744// BuildICMPv6Flow to Build DS flow for ICMPv6
2745func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302746 logger.Infow(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302747 flow := &of.VoltFlow{}
2748 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2749 subFlow := of.NewVoltSubFlow()
2750
2751 subFlow.SetICMPv6Match()
2752 subFlow.SetMatchVlan(vnet.SVlan)
2753 subFlow.SetInPort(inport)
2754 subFlow.SetPopVlan()
2755 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2756 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2757 subFlow.Priority = of.McFlowPriority
2758 var metadata uint64
2759 if vnet.VlanControl == None {
2760 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2761 } else {
2762 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2763 }
2764 subFlow.SetTableMetadata(metadata)
2765 metadata = uint64(vnet.setPbitRemarking())
2766
2767 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2768 subFlow.SetWriteMetadata(metadata)
2769 flow.SubFlows[subFlow.Cookie] = subFlow
2770 return flow
2771}
2772
2773//BuildDSArpFlow Builds DS flow for ARP
2774func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302775 logger.Infow(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302776
2777 flow := &of.VoltFlow{}
2778 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2779 subFlow := of.NewVoltSubFlow()
2780
2781 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
2782 subFlow.SetArpMatch()
2783 subFlow.SetMatchDstMac(BcastMAC)
2784 subFlow.SetMatchVlan(vnet.SVlan)
2785 subFlow.SetInPort(inport)
2786 subFlow.SetPopVlan()
2787 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2788
2789 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
2790 subFlow.Priority = of.McFlowPriority
2791
2792 var metadata uint64
2793 if vnet.VlanControl == None {
2794 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2795 } else {
2796 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2797 }
2798 subFlow.SetTableMetadata(metadata)
2799 metadata = uint64(vnet.setPbitRemarking())
2800 subFlow.SetWriteMetadata(metadata)
2801
2802 flow.SubFlows[subFlow.Cookie] = subFlow
2803 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2804 return flow
2805}
2806
2807// setPbitRemarking to set Pbit remarking
2808func (vv *VoltVnet) setPbitRemarking() uint32 {
2809
2810 // Remarkable
2811 // Remarked Pbit Pbit
2812 // |-----------------------------| |------|
2813 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
2814 // 000 000 000 000 000 000 000 000 00000000
2815
2816 // Eg:
2817 // For 6:3 & 7:1
2818 // 001 011 000 000 000 000 000 000 11000000
2819
2820 var remarkable uint8
2821 var remarked uint32
2822 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
2823 remarkable = remarkable | 1<<refPbit
2824 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
2825 }
2826 return remarked<<8 | uint32(remarkable)
2827}
2828
2829// ProcessIcmpv6McGroup to add icmpv6 multicast group
2830func ProcessIcmpv6McGroup(device string, delete bool) error {
2831
2832 logger.Info(ctx, "Creating ICMPv6 MC Group")
2833 va := GetApplication()
2834 vd := va.GetDevice(device)
2835 group := &of.Group{}
2836 group.GroupID = ICMPv6ArpGroupID
2837 group.Device = device
2838 if delete {
2839 if !vd.icmpv6GroupAdded {
2840 logger.Info(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
2841 return nil //TODO
2842 }
2843 vd.icmpv6GroupAdded = false
2844 group.Command = of.GroupCommandDel
2845 group.ForceAction = true
2846 } else {
2847 if vd.icmpv6GroupAdded {
2848 logger.Info(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
2849 return nil //TODO
2850 }
2851 vd.icmpv6GroupAdded = true
2852 group.Command = of.GroupCommandAdd
2853 receivers := GetApplication().GetIcmpv6Receivers(device)
2854 group.Buckets = append(group.Buckets, receivers...)
2855 }
2856 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
2857 port, _ := GetApplication().GetNniPort(device)
2858 err := cntlr.GetController().GroupUpdate(port, device, group)
2859 return err
2860}
2861
2862//isVlanMatching - checks is vlans matches with vpv based on vlan control
2863func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
2864
2865 switch vpv.VlanControl {
2866 case ONUCVlanOLTSVlan,
2867 OLTCVlanOLTSVlan:
2868 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
2869 return true
2870 }
2871 case ONUCVlan,
2872 OLTSVlan,
2873 None:
2874 if vpv.SVlan == svlan {
2875 return true
2876 }
2877 default:
2878 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2879 }
2880 return false
2881}
2882
2883//PushFlows - Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302884func (vpv *VoltPortVnet) PushFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302885
2886 for cookie := range flow.SubFlows {
2887 cookie := strconv.FormatUint(cookie, 10)
2888 fe := &FlowEvent{
2889 eType: EventTypeControlFlowAdded,
2890 cookie: cookie,
2891 eventData: vpv,
2892 }
2893 device.RegisterFlowAddEvent(cookie, fe)
2894 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302895 return cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302896}
2897
2898//FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
2899func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
2900
2901 sendFlowFailureInd := func(key, value interface{}) bool {
2902 //svc := value.(*VoltService)
2903 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
2904 return true
2905 }
2906 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2907 vpv.services.Range(sendFlowFailureInd)
2908}
2909
2910//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302911func (vpv *VoltPortVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302912
2913 vpv.PendingFlowLock.Lock()
2914 defer vpv.PendingFlowLock.Unlock()
2915
2916 for cookie := range flow.SubFlows {
2917 cookie := strconv.FormatUint(cookie, 10)
2918 fe := &FlowEvent{
2919 eType: EventTypeControlFlowRemoved,
2920 device: device.Name,
2921 cookie: cookie,
2922 eventData: vpv,
2923 }
2924 device.RegisterFlowDelEvent(cookie, fe)
2925 vpv.PendingDeleteFlow[cookie] = true
2926 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302927 return cntlr.GetController().DelFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302928}
2929
2930//CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302931func (vpv *VoltPortVnet) CheckAndDeleteVpv(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302932 vpv.PendingFlowLock.RLock()
2933 defer vpv.PendingFlowLock.RUnlock()
2934 if !vpv.DeleteInProgress {
2935 return
2936 }
2937 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
2938 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 +05302939 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302940 logger.Infow(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
2941 }
2942}
2943
2944//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302945func (vpv *VoltPortVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302946 vpv.PendingFlowLock.Lock()
2947 logger.Infow(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
2948
2949 delete(vpv.PendingDeleteFlow, cookie)
2950 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302951 vpv.CheckAndDeleteVpv(cntx)
2952 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302953}
2954
2955//FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302956func (vpv *VoltPortVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302957 vpv.PendingFlowLock.Lock()
2958
2959 logger.Errorw(ctx, "VPV Flow Remove Failure Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
2960
2961 sendFlowFailureInd := func(key, value interface{}) bool {
2962 svc := value.(*VoltService)
2963 svc.triggerServiceFailureInd(errorCode, errReason)
2964 return true
2965 }
2966 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2967 vpv.services.Range(sendFlowFailureInd)
2968
2969 if vpv.DeleteInProgress {
2970 delete(vpv.PendingDeleteFlow, cookie)
2971 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302972 vpv.CheckAndDeleteVpv(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302973 } else {
2974 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302975 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302976 }
2977}
2978
2979//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302980func (vv *VoltVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302981
2982 vv.VnetLock.Lock()
2983 defer vv.VnetLock.Unlock()
2984
2985 var flowMap map[string]bool
2986 var ok bool
2987
2988 for cookie := range flow.SubFlows {
2989 cookie := strconv.FormatUint(cookie, 10)
2990 fe := &FlowEvent{
2991 eType: EventTypeDeviceFlowRemoved,
2992 device: device.Name,
2993 cookie: cookie,
2994 eventData: vv,
2995 }
2996 device.RegisterFlowDelEvent(cookie, fe)
2997 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
2998 flowMap = make(map[string]bool)
2999 }
3000 flowMap[cookie] = true
3001 vv.PendingDeleteFlow[device.Name] = flowMap
3002 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303003 vv.WriteToDb(cntx)
3004 return cntlr.GetController().DelFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05303005}
3006
3007//CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303008func (vv *VoltVnet) CheckAndDeleteVnet(cntx context.Context, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303009 if !vv.DeleteInProgress {
3010 return
3011 }
3012 vv.VnetPortLock.RLock()
3013 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
3014 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
3015 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303016 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05303017 logger.Infow(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
3018 } else {
3019 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
3020 }
3021 vv.VnetPortLock.RUnlock()
3022}
3023
3024//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303025func (vv *VoltVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303026 vv.VnetLock.Lock()
3027 defer vv.VnetLock.Unlock()
3028
3029 logger.Infow(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
3030
3031 if _, ok := vv.PendingDeleteFlow[device]; ok {
3032 delete(vv.PendingDeleteFlow[device], cookie)
3033 }
3034
3035 //Check and update success for pending disable request
3036 if d := GetApplication().GetDevice(device); d != nil {
3037 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3038 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303039 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303040 }
3041 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303042 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303043}
3044
3045//FlowRemoveFailure - Process flow failure indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303046func (vv *VoltVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303047
3048 vv.VnetLock.Lock()
3049 defer vv.VnetLock.Unlock()
3050
3051 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3052 if _, ok := flowMap[cookie]; ok {
3053 logger.Errorw(ctx, "Device Flow Remove Failure Notification", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
3054
3055 if vv.DeleteInProgress {
3056 delete(vv.PendingDeleteFlow[device], cookie)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303057 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303058 }
3059 return
3060 }
3061 }
3062 logger.Errorw(ctx, "Device Flow Remove Failure Notification for Unknown cookie", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3063}
3064
3065//IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
3066func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
3067
3068 //Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3069 //When multiple Igmp-suported service enabled, comment "return false"
3070
3071 sendFlowFailureInd := func(key, value interface{}) bool {
3072 svc := value.(*VoltService)
3073 if svc.IgmpEnabled {
3074 svc.triggerServiceFailureInd(errorCode, errReason)
3075 return false
3076 }
3077 return true
3078 }
3079 logger.Errorw(ctx, "US IGMP Flow Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3080 vpv.services.Range(sendFlowFailureInd)
3081}
3082
3083// GetMatchingMcastService to get matching multicast service
3084func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
3085
3086 var service *VoltService
3087 dIntf, ok := va.DevicesDisc.Load(device)
3088 if !ok {
3089 return nil
3090 }
3091 d := dIntf.(*VoltDevice)
3092
3093 // If the port is NNI port, the services dont exist on it. The svc then
3094 // must be obtained from a different context and is not included here
3095 if port == d.NniPort {
3096 return nil
3097 }
3098
3099 // This is an access port and the port should have all the associated
3100 // services which can be uniquely identified by the VLANs in the packet
3101 vnets, ok := va.VnetsByPort.Load(port)
3102
3103 if !ok {
3104 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3105 return nil
3106 }
3107 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3108 getMcastService := func(key, value interface{}) bool {
3109 srv := value.(*VoltService)
3110 if srv.IgmpEnabled {
3111 service = srv
3112
3113 //TODO: Current implementation supports only for single service with Igmp Enabled
3114 //FIX-ME: When multiple service suports Igmp, update of logic required
3115 return false
3116 }
3117 return true
3118 }
3119
3120 for _, vpv := range vnets.([]*VoltPortVnet) {
3121 if vpv.CVlan == cvlan {
3122 vpv.services.Range(getMcastService)
3123 if service != nil {
3124 break
3125 }
3126 }
3127 }
3128 return service
3129}
3130
3131//TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303132func (vv *VoltVnet) TriggerAssociatedFlowDelete(cntx context.Context, device string) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05303133 vv.VnetLock.Lock()
3134 cookieList := []uint64{}
3135 flowMap := vv.PendingDeleteFlow[device]
3136
3137 for cookie := range flowMap {
3138 cookieList = append(cookieList, convertToUInt64(cookie))
3139 }
3140 vv.VnetLock.Unlock()
3141
3142 if len(cookieList) == 0 {
3143 return false
3144 }
3145
3146 for _, cookie := range cookieList {
3147 if vd := GetApplication().GetDevice(device); vd != nil {
3148 flow := &of.VoltFlow{}
3149 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3150 subFlow := of.NewVoltSubFlow()
3151 subFlow.Cookie = cookie
3152 flow.SubFlows[cookie] = subFlow
3153 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303154 if err := vv.RemoveFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05303155 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3156 }
3157 }
3158 }
3159 return true
3160}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303161
3162// JsonMarshal wrapper function for json Marshal VoltVnet
3163func (vv *VoltVnet) JsonMarshal() ([]byte, error) {
3164 return json.Marshal(VoltVnet{
3165 VnetConfig: vv.VnetConfig,
3166 Version: vv.Version,
3167 VnetOper: VnetOper{
3168 PendingDeleteFlow: vv.VnetOper.PendingDeleteFlow,
3169 DeleteInProgress: vv.VnetOper.DeleteInProgress,
3170 PendingDeviceToDelete: vv.VnetOper.PendingDeviceToDelete,
3171 },
3172 })
3173}
3174
3175// JsonMarshal wrapper function for json Marshal VoltPortVnet
3176func (vpv *VoltPortVnet) JsonMarshal() ([]byte, error) {
3177 return json.Marshal(VoltPortVnet{
3178 Device: vpv.Device,
3179 Port: vpv.Port,
3180 PonPort: vpv.PonPort,
3181 VnetName: vpv.VnetName,
3182 SVlan: vpv.SVlan,
3183 CVlan: vpv.CVlan,
3184 UniVlan: vpv.UniVlan,
3185 SVlanTpid: vpv.SVlanTpid,
3186 DhcpRelay: vpv.DhcpRelay,
3187 ArpRelay: vpv.ArpRelay,
3188 PppoeIa: vpv.PppoeIa,
3189 MacLearning: vpv.MacLearning,
3190 DhcpStatus: vpv.DhcpStatus,
3191 DhcpExpiryTime: vpv.DhcpExpiryTime,
3192 Dhcp6ExpiryTime: vpv.Dhcp6ExpiryTime,
3193 FlowsApplied: vpv.FlowsApplied,
3194 Ipv4Addr: vpv.Ipv4Addr,
3195 Ipv6Addr: vpv.Ipv6Addr,
3196 MacAddr: vpv.MacAddr,
3197 LearntMacAddr: vpv.LearntMacAddr,
3198 CircuitID: vpv.CircuitID,
3199 RemoteID: vpv.RemoteID,
3200 IsOption82Disabled: vpv.IsOption82Disabled,
3201 RelayState: vpv.RelayState,
3202 PPPoeState: vpv.PPPoeState,
3203 RelayStatev6: vpv.RelayStatev6,
3204 IgmpEnabled: vpv.IgmpEnabled,
3205 IgmpFlowsApplied: vpv.IgmpFlowsApplied,
3206 McastService: vpv.McastService,
3207 ONTEtherTypeClassification: vpv.ONTEtherTypeClassification,
3208 VlanControl: vpv.VlanControl,
3209 MvlanProfileName: vpv.MvlanProfileName,
3210 Version: vpv.Version,
3211 McastTechProfileID: vpv.McastTechProfileID,
3212 McastPbit: vpv.McastPbit,
3213 McastUsMeterID: vpv.McastUsMeterID,
3214 AllowTransparent: vpv.AllowTransparent,
3215 SchedID: vpv.SchedID,
3216 DHCPv6DUID: vpv.DHCPv6DUID,
3217 PendingDeleteFlow: vpv.PendingDeleteFlow,
3218 DeleteInProgress: vpv.DeleteInProgress,
3219 Blocked: vpv.Blocked,
3220 DhcpPbit: vpv.DhcpPbit,
3221 })
3222}
Tinoj Josephec742f62022-09-29 19:11:10 +05303223
3224func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) bool {
3225 isActivated := false
3226 vpv.services.Range(func(key, value interface{}) bool {
3227 svc := value.(*VoltService)
3228 if svc.IsActivated {
3229 logger.Infow(ctx, "Found activated service on the vpv", log.Fields{"Name": svc.Name})
3230 isActivated = true
3231 return false //to exit loop
3232 }
3233 return true
3234 })
3235 return isActivated
3236}