blob: 1313490bcb5639805e350836f22c15a1ce61a089 [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"
Tinoj Joseph50d722c2022-12-06 22:53:22 +053047
48 // DPU_MGMT_TRAFFIC serviceType, vnetType constant
49 DPU_MGMT_TRAFFIC string = "DPU_MGMT_TRAFFIC"
50
51 // DPU_ANCP_TRAFFIC serviceType, vnetType constant
52 DPU_ANCP_TRAFFIC string = "DPU_ANCP_TRAFFIC"
53
54 // FTTB_SUBSCRIBER_TRAFFIC serviceType, vnetType constant
55 FTTB_SUBSCRIBER_TRAFFIC string = "FTTB_SUBSCRIBER_TRAFFIC"
Naveen Sampath04696f72022-06-13 15:19:14 +053056)
57
58var (
59 //BroadcastMAC - Broadcast MAC Address
60 BroadcastMAC, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")
61)
62
63// NonZeroMacAddress utility to identify if the MAC address is non-zero.
64// We use zero MAC address as an unset MAC address
65func NonZeroMacAddress(h net.HardwareAddr) bool {
66 for i := 0; i < 6; i++ {
67 if h[i] != 0 {
68 return true
69 }
70 }
71 return false
72}
73
74// VNET package manages the different virtual networks that are part of the
75// the network. In the case of VOLT, the networks can be single tagged or
76// double tagged networks. In addition, the networks may be used for unicast
77// and multicast traffic. The unicast traffic further has two models, the
78// 1:1 and N:1 model. In case of a 1:1 model, the outer tag is same for many
79// subscribers and the inner tag is unique to each subscriber for the same
80// outer tag. The N:1 uses the same inner and outer tags, or for that matter
81// a single tag that can also be shared by subscribers. The VNET implementation
82// manages all these possibilities and the associated configuration.
83
84const (
85 // PbitMatchNone constant
86 PbitMatchNone of.PbitType = 8
87 // PbitMatchAll constant
88 PbitMatchAll of.PbitType = 0xFF
89)
90
91// SVlan - Value of the outer tag if double tagged or the only tag if single
92// tagged
93// SVlanTpid - SVlan Tag Protocol Identifier
94// CVlan - Value of the inner tag. Set to VlanNone if single tagged
95// DhcpRelay - Set to true if the DHCP relay is enabled on the virtual network
96// MacLearning - Set to true if the flows should include MAC address
97// UsDhcpPbit - The pbit used for US DHCP packets
98// DsDhcpPbit - The pbit used for DS DHCP packets
99
100// VnetConfig structure
101type VnetConfig struct {
102 Name string
103 SVlan of.VlanType
104 CVlan of.VlanType
105 UniVlan of.VlanType
106 SVlanTpid layers.EthernetType
107 DhcpRelay bool
108 ArpLearning bool
109 MacLearning MacLearningType
110 PppoeIa bool
111 ONTEtherTypeClassification int
112 VlanControl VlanControl
113 Encapsulation string
114 UsDhcpPbit []of.PbitType
115 DsDhcpPbit []of.PbitType
116 UsIGMPPbit []of.PbitType
117 DsIGMPPbit []of.PbitType
118 DevicesList []string //List of serial number of devices on which this vnet is applied
119 AllowTransparent bool
120 CtrlPktPbitRemark map[of.PbitType]of.PbitType
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530121 UsPonCTagPriority of.PbitType
122 UsPonSTagPriority of.PbitType
123 DsPonCTagPriority of.PbitType
124 DsPonSTagPriority of.PbitType
125 VnetType string
Naveen Sampath04696f72022-06-13 15:19:14 +0530126}
127
128// VnetOper structure
129type VnetOper struct {
130 PendingDeleteFlow map[string]map[string]bool
131 DeleteInProgress bool
132 PendingDeviceToDelete string
133 VnetLock sync.RWMutex `json:"-"`
134 VnetPortLock sync.RWMutex `json:"-"`
135 AssociatedPorts map[string]bool `json:"-"`
136}
137
138// VoltVnet sructure
139type VoltVnet struct {
140 VnetConfig
141 VnetOper
142 Version string
143}
144
145const (
146 // EncapsulationPPPoEIA constant
147 EncapsulationPPPoEIA string = "PPPoE-IA"
148 // EncapsulationPPPoE constant
149 EncapsulationPPPoE string = "PPPoE"
150 // EncapsulationIPoE constant
151 EncapsulationIPoE string = "IPoE"
152)
153
154// NewVoltVnet is constructor for the VNET structure
155func NewVoltVnet(cfg VnetConfig) *VoltVnet {
156 var vv VoltVnet
157 vv.VnetConfig = cfg
158 if vv.PendingDeleteFlow == nil {
159 vv.PendingDeleteFlow = make(map[string]map[string]bool)
160 }
161 vv.DeleteInProgress = false
162 if cfg.Encapsulation == EncapsulationPPPoEIA {
163 vv.PppoeIa = true
164 }
165 vv.AssociatedPorts = make(map[string]bool)
166 return &vv
167}
168
169//associatePortToVnet - associate a port to Vnet
170func (vv *VoltVnet) associatePortToVnet(port string) {
171 vv.VnetPortLock.Lock()
172 if vv.AssociatedPorts == nil {
173 vv.AssociatedPorts = make(map[string]bool)
174 }
175 vv.AssociatedPorts[port] = true
176 vv.VnetPortLock.Unlock()
177}
178
179//disassociatePortFromVnet - disassociate a port from Vnet and return true if the association map is empty
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530180func (vv *VoltVnet) disassociatePortFromVnet(cntx context.Context, device string, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530181 vv.VnetPortLock.Lock()
182 delete(vv.AssociatedPorts, port)
183 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})
184 vv.VnetPortLock.Unlock()
185
186 if vv.DeleteInProgress {
187 if !vv.isAssociatedPortsPresent() {
188 if len(vv.PendingDeleteFlow[device]) == 0 {
189 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vv.Name})
190 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530191 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530192 } else {
193 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow})
194 }
195 } else {
196 vv.VnetPortLock.RLock()
197 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts})
198 vv.VnetPortLock.RUnlock()
199 }
200 }
201}
202
203func (vv *VoltVnet) isAssociatedPortsPresent() bool {
204 vv.VnetPortLock.RLock()
205 defer vv.VnetPortLock.RUnlock()
206 return len(vv.AssociatedPorts) != 0
207}
208
209// WriteToDb commit the VNET to the database
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530210func (vv *VoltVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530211
212 if vv.DeleteInProgress {
213 logger.Warnw(ctx, "Skipping Redis Update for Vnet, Vnet delete in progress", log.Fields{"Vnet": vv.Name})
214 return
215 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530216 vv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530217}
218
219//ForceWriteToDb force commit a vnet to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530220func (vv *VoltVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530221 vv.VnetPortLock.RLock()
222 defer vv.VnetPortLock.RUnlock()
223 vv.Version = database.PresentVersionMap[database.VnetPath]
224 logger.Debugw(ctx, "Updating VNET....", log.Fields{"vnet": vv})
225 if b, err := json.Marshal(vv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530226 if err:= db.PutVnet(cntx, vv.Name, string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530227 logger.Warnw(ctx, "Add Vnet to DB failed", log.Fields{"vnet name": vv.Name, "Error": err})
228 }
229 }
230}
231
232// VnetKey creates the key using the two VLAN tags
233// We append the two VLAN tags to create a single key
234func VnetKey(otag of.VlanType, itag of.VlanType, utag of.VlanType) string {
235 return strconv.Itoa(int(otag)) + "-" + strconv.Itoa(int(itag)) + "-" + strconv.Itoa(int(utag))
236}
237
238// GetVnet get VNET configuration related functionality associated with VOLT application
239func (va *VoltApplication) GetVnet(otag of.VlanType, itag of.VlanType, utag of.VlanType) *VoltVnet {
240 // When matching VNET, it is expected to match first just the outer
241 // tag, and then the combination to make sure there is no conflict
242 // for the new configuration.
243 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, of.VlanNone, utag)); ok {
244 return vnet.(*VoltVnet)
245 }
246 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, itag, utag)); ok {
247 return vnet.(*VoltVnet)
248 }
249 return nil
250}
251
252// The VNET may also be assigned name for easier references. For now,
253// the VNET is mainly identified by the two VLANs.
254
255// GetVnetByName to get vnet by name
256func (va *VoltApplication) GetVnetByName(name string) *VoltVnet {
257 if vnet, ok := va.VnetsByName.Load(name); ok {
258 return vnet.(*VoltVnet)
259 }
260 return nil
261}
262
263// storeVnetConfig to store vnet config
264func (va *VoltApplication) storeVnetConfig(cfg VnetConfig, vv *VoltVnet) {
265
266 var vnetMap *util.ConcurrentMap
267
268 va.VnetsByTag.Store(VnetKey(cfg.SVlan, cfg.CVlan, cfg.UniVlan), vv)
269 va.VnetsByName.Store(cfg.Name, vv)
270
271 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vv.SVlan); !ok {
272 vnetMap = util.NewConcurrentMap()
273 } else {
274 vnetMap = vnetMapIntf.(*util.ConcurrentMap)
275 }
276 vnetMap.Set(vv, true)
277 va.VnetsBySvlan.Set(vv.SVlan, vnetMap)
278}
279
280// deleteVnetConfig to delete vnet config
281func (va *VoltApplication) deleteVnetConfig(vnet *VoltVnet) {
282 va.VnetsByTag.Delete(VnetKey(vnet.SVlan, vnet.CVlan, vnet.UniVlan))
283 va.VnetsByName.Delete(vnet.Name)
284
285 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vnet.SVlan); ok {
286 vnetMap := vnetMapIntf.(*util.ConcurrentMap)
287 vnetMap.Remove(vnet)
288 va.VnetsBySvlan.Set(vnet.SVlan, vnetMap)
289 }
290}
291
292// AddVnet to add a VNET to the list of VNETs configured.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530293func (va *VoltApplication) AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530294
295 AppMutex.VnetMutex.Lock()
296 var vv *VoltVnet
297 devicesToHandle := []string{}
298 vv = va.GetVnetByName(cfg.Name)
299 if vv != nil {
300 //Could be for another OLT or could be case of backup-restore
301 for _, serialNum := range cfg.DevicesList {
302 if isDeviceInList(serialNum, vv.DevicesList) {
303 //This is backup restore scenario, just update the profile
304 logger.Info(ctx, "Add Vnet : Profile Name already exists with OLT, update-the-profile")
305 continue
306 }
307 devicesToHandle = append(devicesToHandle, serialNum)
308 }
309 if len(devicesToHandle) == 0 {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530310 logger.Debugw(ctx, "Ignoring Duplicate VNET by name ", log.Fields{"Vnet": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530311 AppMutex.VnetMutex.Unlock()
312 return nil
313 }
314 }
315
316 if vv == nil {
317 vv = NewVoltVnet(cfg)
318 if oper != nil {
319 vv.PendingDeleteFlow = oper.PendingDeleteFlow
320 vv.DeleteInProgress = oper.DeleteInProgress
321 vv.AssociatedPorts = oper.AssociatedPorts
322 vv.PendingDeviceToDelete = oper.PendingDeviceToDelete
323 }
324 devicesToHandle = append(devicesToHandle, cfg.DevicesList...)
325 } else {
326 vv.DevicesList = append(vv.DevicesList, devicesToHandle...)
327 }
328
329 va.storeVnetConfig(cfg, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530330 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530331
332 logger.Infow(ctx, "Added VNET TO DB", log.Fields{"cfg": cfg, "devicesToHandle": devicesToHandle})
333
334 //va.PushDevFlowForVlan(vv)
335 AppMutex.VnetMutex.Unlock()
336 return nil
337}
338
339// DelVnet to delete a VNET from the list of VNETs configured
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530340func (va *VoltApplication) DelVnet(cntx context.Context, name, deviceSerialNum string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530341 logger.Infow(ctx, "Deleting Vnet", log.Fields{"Vnet": name})
342 AppMutex.VnetMutex.Lock()
343 if vnetIntf, ok := va.VnetsByName.Load(name); ok {
344 vnet := vnetIntf.(*VoltVnet)
345 //Delete from mvp list
346 vnet.DevicesList = util.RemoveFromSlice(vnet.DevicesList, deviceSerialNum)
347
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530348 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, deviceSerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +0530349 if len(vnet.DevicesList) == 0 {
350 vnet.DeleteInProgress = true
351 vnet.PendingDeviceToDelete = deviceSerialNum
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530352 vnet.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530353 vnet.VnetPortLock.RLock()
354 if len(vnet.PendingDeleteFlow) == 0 && !vnet.isAssociatedPortsPresent() {
355 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
356 va.deleteVnetConfig(vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530357 _ = db.DelVnet(cntx, vnet.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530358 } else {
359 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
360 }
361 vnet.VnetPortLock.RUnlock()
362 } else {
363 //Update the devicelist in db
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530364 vnet.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530365 }
366 }
367 //TODO: if no vnets are present on device remove icmpv6 group from device
368 AppMutex.VnetMutex.Unlock()
369 return nil
370}
371
372// UpdateVnet to update the VNET with associated service count
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530373func (va *VoltApplication) UpdateVnet(cntx context.Context, vv *VoltVnet) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530374 va.storeVnetConfig(vv.VnetConfig, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530375 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530376 logger.Infow(ctx, "Updated VNET TO DB", log.Fields{"vv": vv.VnetConfig})
377 return nil
378}
379
380// ------------------------------------------------------------
381// Manifestation of a VNET on a port is handled below
382// ------------------------------------------------------------
383//
384// The VNET on a port handles everything that is done for a VNET
385// such as DHCP relay state machine, MAC addresses, IP addresses
386// learnt, so on.
387
388// DhcpStatus type
389type DhcpStatus uint8
390
391const (
392 // DhcpStatusNone constant
393 DhcpStatusNone DhcpStatus = 0
394 // DhcpStatusAcked constant
395 DhcpStatusAcked DhcpStatus = 1
396 // DhcpStatusNacked constant
397 DhcpStatusNacked DhcpStatus = 2
398 // EthTypeNone constant
399 EthTypeNone int = 0
400 // EthTypeIPoE constant
401 EthTypeIPoE int = 1
402 // EthTypePPPoE constant
403 EthTypePPPoE int = 2
404)
405
406// VoltPortVnet structure
407type VoltPortVnet struct {
408 Device string
409 Port string
410 PonPort uint32
411 VnetName string
412 SVlan of.VlanType
413 CVlan of.VlanType
414 UniVlan of.VlanType
415 SVlanTpid layers.EthernetType
416 DhcpRelay bool
417 ArpRelay bool
418 PppoeIa bool
419 MacLearning MacLearningType
420 DhcpStatus DhcpStatus
421 DhcpExpiryTime time.Time
422 Dhcp6ExpiryTime time.Time
423 FlowsApplied bool
424 services sync.Map
425 servicesCount *atomic.Uint64
426 Ipv4Addr net.IP
427 Ipv6Addr net.IP
428 MacAddr net.HardwareAddr
429 LearntMacAddr net.HardwareAddr
430 CircuitID []byte //Will not be used
431 RemoteID []byte //Will not be used
432 IsOption82Disabled bool //Will not be used
433 RelayState DhcpRelayState
434 PPPoeState PppoeIaState
435 RelayStatev6 Dhcpv6RelayState
436 IgmpEnabled bool
437 IgmpFlowsApplied bool
438 McastService bool
439 ONTEtherTypeClassification int
440 VlanControl VlanControl
441 MvlanProfileName string
442 Version string
443 McastTechProfileID uint16
444 McastPbit of.PbitType
445 McastUsMeterID uint32
446 AllowTransparent bool
447 VpvLock sync.Mutex `json:"-"`
448 SchedID int
449 DHCPv6DUID [MaxLenDhcpv6DUID]byte
450 PendingFlowLock sync.RWMutex `json:"-"`
451 PendingDeleteFlow map[string]bool
452 DeleteInProgress bool
453 Blocked bool
454 DhcpPbit of.PbitType
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530455 UsPonCTagPriority of.PbitType
456 UsPonSTagPriority of.PbitType
457 DsPonCTagPriority of.PbitType
458 DsPonSTagPriority of.PbitType
459 VnetType string
Naveen Sampath04696f72022-06-13 15:19:14 +0530460}
461
462//VlanControl vlan control type
463type VlanControl uint8
464
465const (
466 // None constant
467 // ONU and OLT will passthrough UNIVLAN as is to BNG
468 None VlanControl = iota
469
470 // ONUCVlanOLTSVlan constant
471 // Tagged traffic, ONU will replace UNIVLAN with CVLAN and OLT will add SVLAN
472 // Untagged traffic, ONU will add CVLAN and OLT will add SVLAN
473 ONUCVlanOLTSVlan
474
475 // OLTCVlanOLTSVlan constant
476 // Tagged traffic, ONU will passthrough UNIVLAN as is to OLT and
477 // OLT will replace UNIVLAN with CVLAN and add SVLAN
478 OLTCVlanOLTSVlan
479
480 // ONUCVlan constant
481 // Tagged traffic, ONU will replace UNIVLAN with CVLAN
482 // Untagged traffic, ONU will add CVLAN
483 ONUCVlan
484
485 // OLTSVlan constant
486 // UnTagged traffic, OLT will add the SVLAN
487 OLTSVlan
488)
489
490// NewVoltPortVnet is constructor for VoltPortVnet
491func NewVoltPortVnet(vnet *VoltVnet) *VoltPortVnet {
492 var vpv VoltPortVnet
493
494 vpv.VnetName = vnet.Name
495 vpv.SVlan = vnet.SVlan
496 vpv.CVlan = vnet.CVlan
497 vpv.UniVlan = vnet.UniVlan
498 vpv.SVlanTpid = vnet.SVlanTpid
499 vpv.DhcpRelay = vnet.DhcpRelay
500 vpv.DhcpStatus = DhcpStatusNone
501 vpv.PPPoeState = PppoeIaStateNone
502 vpv.ArpRelay = vnet.ArpLearning
503 vpv.PppoeIa = vnet.PppoeIa
504 vpv.VlanControl = vnet.VlanControl
505 vpv.ONTEtherTypeClassification = vnet.ONTEtherTypeClassification
506 vpv.AllowTransparent = vnet.AllowTransparent
507 vpv.FlowsApplied = false
508 vpv.IgmpEnabled = false
509 vpv.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
510 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
511 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530512 /*
Naveen Sampath04696f72022-06-13 15:19:14 +0530513 if vpv.VlanControl == ONUCVlan {
514 vpv.CVlan = vpv.SVlan
515 }
516 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
517 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
518 if vpv.VlanControl == OLTSVlan {
519 vpv.CVlan = vpv.UniVlan
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530520 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +0530521 vpv.servicesCount = atomic.NewUint64(0)
522 vpv.SchedID = 0
523 vpv.PendingDeleteFlow = make(map[string]bool)
524 vpv.DhcpPbit = vnet.UsDhcpPbit[0]
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530525 vpv.UsPonCTagPriority = vnet.UsPonCTagPriority
526 vpv.UsPonSTagPriority = vnet.UsPonSTagPriority
527 vpv.DsPonCTagPriority = vnet.UsPonCTagPriority
528 vpv.DsPonSTagPriority = vnet.UsPonSTagPriority
529
530 vpv.VnetType = vnet.VnetType
Naveen Sampath04696f72022-06-13 15:19:14 +0530531 return &vpv
532}
533
534func (vpv *VoltPortVnet) setDevice(device string) {
535
536 if vpv.Device != device && vpv.Device != "" {
537 GetApplication().DisassociateVpvsFromDevice(device, vpv)
538 //TEMP:
539 vpv.printAssociatedVPVs(false)
540 }
541
Tinoj Josephec742f62022-09-29 19:11:10 +0530542 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": device, "Port": vpv.Port, "SVlan": vpv.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530543
544 vpv.Device = device
545 GetApplication().AssociateVpvsToDevice(device, vpv)
546 //TEMP:
547 vpv.printAssociatedVPVs(true)
548}
549
550//TODO - Nav - Temp
551func (vpv *VoltPortVnet) printAssociatedVPVs(add bool) {
552 logger.Infow(ctx, "Start----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
553 if vMap := GetApplication().GetAssociatedVpvsForDevice(vpv.Device, vpv.SVlan); vMap != nil {
554 vMap.Range(func(key, value interface{}) bool {
555 vpvEntry := key.(*VoltPortVnet)
556 logger.Infow(ctx, "Associated VPVs", log.Fields{"SVlan": vpvEntry.SVlan, "CVlan": vpvEntry.CVlan, "UniVlan": vpvEntry.UniVlan})
557 return true
558 })
559 }
560 logger.Infow(ctx, "End----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
561
562}
563
564// GetCircuitID : The interface to be satisfied by the VoltPortVnet to be a DHCP relay
565// session is implemented below. The main functions still remain in
566// the service.go file.
567func (vpv *VoltPortVnet) GetCircuitID() []byte {
568 return []byte(vpv.CircuitID)
569}
570
571// GetRemoteID to get remote id
572func (vpv *VoltPortVnet) GetRemoteID() []byte {
573 return []byte(vpv.RemoteID)
574}
575
576// GetDhcpState to get dhcp state
577func (vpv *VoltPortVnet) GetDhcpState() DhcpRelayState {
578 return vpv.RelayState
579}
580
581// SetDhcpState to set the dhcp state
582func (vpv *VoltPortVnet) SetDhcpState(state DhcpRelayState) {
583 vpv.RelayState = state
584}
585
586// GetPppoeIaState to get pppoeia state
587func (vpv *VoltPortVnet) GetPppoeIaState() PppoeIaState {
588 return vpv.PPPoeState
589}
590
591// SetPppoeIaState to set pppoeia state
592func (vpv *VoltPortVnet) SetPppoeIaState(state PppoeIaState) {
593 vpv.PPPoeState = state
594}
595
596// GetDhcpv6State to get dhcpv6 state
597func (vpv *VoltPortVnet) GetDhcpv6State() Dhcpv6RelayState {
598 return vpv.RelayStatev6
599}
600
601// SetDhcpv6State to set dhcpv6 state
602func (vpv *VoltPortVnet) SetDhcpv6State(state Dhcpv6RelayState) {
603 vpv.RelayStatev6 = state
604}
605
606// DhcpResultInd for dhcp result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530607func (vpv *VoltPortVnet) DhcpResultInd(cntx context.Context, res *layers.DHCPv4) {
608 vpv.ProcessDhcpResult(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530609}
610
611// Dhcpv6ResultInd for dhcpv6 result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530612func (vpv *VoltPortVnet) Dhcpv6ResultInd(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
613 vpv.ProcessDhcpv6Result(cntx, ipv6Addr, leaseTime)
Naveen Sampath04696f72022-06-13 15:19:14 +0530614}
615
616// GetNniVlans to get nni vlans
617func (vpv *VoltPortVnet) GetNniVlans() (uint16, uint16) {
618 switch vpv.VlanControl {
619 case ONUCVlanOLTSVlan,
620 OLTCVlanOLTSVlan:
621 return uint16(vpv.SVlan), uint16(vpv.CVlan)
622 case ONUCVlan,
623 None:
624 return uint16(vpv.SVlan), uint16(of.VlanNone)
625 case OLTSVlan:
626 return uint16(vpv.SVlan), uint16(of.VlanNone)
627 }
628 return uint16(of.VlanNone), uint16(of.VlanNone)
629}
630
631// GetService to get service
632func (vpv *VoltPortVnet) GetService(name string) (*VoltService, bool) {
633 service, ok := vpv.services.Load(name)
634 if ok {
635 return service.(*VoltService), ok
636 }
637 return nil, ok
638}
639
640// AddService to add service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530641func (vpv *VoltPortVnet) AddService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530642 vpv.services.Store(service.Name, service)
643 vpv.servicesCount.Inc()
644 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()})
645}
646
647// DelService to delete service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530648func (vpv *VoltPortVnet) DelService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530649 vpv.services.Delete(service.Name)
650 vpv.servicesCount.Dec()
651
652 // If the only Igmp Enabled service is removed, remove the Igmp trap flow along with it
653 if service.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530654 if err := vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530655 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
656 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
657 }
658
659 vpv.IgmpEnabled = false
660 }
661 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()})
662}
663
664// ProcessDhcpResult to process dhcp results
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530665func (vpv *VoltPortVnet) ProcessDhcpResult(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530666 msgType := DhcpMsgType(res)
667 if msgType == layers.DHCPMsgTypeAck {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530668 vpv.ProcessDhcpSuccess(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530669 } else if msgType == layers.DHCPMsgTypeNak {
670 vpv.DhcpStatus = DhcpStatusNacked
671 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530672 vpv.WriteToDb(cntx)
673}
674
675// RangeOnServices to call a function on all services on the vpv
676func (vpv *VoltPortVnet) RangeOnServices(cntx context.Context, callback func(cntx context.Context, key, value interface{}) bool) {
677 vpv.services.Range(func(key, value interface{}) bool {
678 return callback(cntx, key, value)
679 })
Naveen Sampath04696f72022-06-13 15:19:14 +0530680}
681
682// ProcessDhcpSuccess : Learn the IPv4 address allocated to the services and update the
683// the services with the same. This also calls for adding flows
684// for the services as the DHCP procedure is completed
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530685func (vpv *VoltPortVnet) ProcessDhcpSuccess(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530686 vpv.DhcpStatus = DhcpStatusAcked
687 vpv.Ipv4Addr, _ = GetIpv4Addr(res)
688 logger.Infow(ctx, "Received IPv4 Address", log.Fields{"IP Address": vpv.Ipv4Addr.String()})
689 logger.Infow(ctx, "Services Configured", log.Fields{"Count": vpv.servicesCount.Load()})
690
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530691 vpv.RangeOnServices(cntx, vpv.updateIPv4AndProvisionFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530692 vpv.ProcessDhcpv4Options(res)
693}
694
695// ProcessDhcpv4Options : Currently we process lease time and store the validity of the
696// IP address allocated.
697func (vpv *VoltPortVnet) ProcessDhcpv4Options(res *layers.DHCPv4) {
698 for _, o := range res.Options {
699 switch o.Type {
700 case layers.DHCPOptLeaseTime:
701 leasetime := GetIPv4LeaseTime(o)
702 vpv.DhcpExpiryTime = time.Now().Add((time.Duration(leasetime) * time.Second))
703 logger.Infow(ctx, "Lease Expiry Set", log.Fields{"Time": vpv.DhcpExpiryTime})
704 }
705 }
706}
707
708// ProcessDhcpv6Result : Read the IPv6 address allocated to the device and store it on the
709// VNET. The same IPv6 address is also passed to the services. When a
710// service is fetched all the associated information such as MAC address,
711// IPv4 address and IPv6 addresses can be provided.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530712func (vpv *VoltPortVnet) ProcessDhcpv6Result(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530713 // TODO: Status based hanlding of flows
714 vpv.Dhcp6ExpiryTime = time.Now().Add((time.Duration(leaseTime) * time.Second))
715 vpv.Ipv6Addr = ipv6Addr
716
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530717 vpv.RangeOnServices(cntx, vpv.updateIPv6AndProvisionFlows)
718 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530719}
720
721// AddSvcUsMeterToDevice to add service upstream meter info to device
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530722func AddSvcUsMeterToDevice(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +0530723 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +0530724 logger.Infow(ctx, "Adding upstream meter profile to device", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530725 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
726 GetApplication().AddMeterToDevice(svc.Port, device.Name, svc.UsMeterID, 0)
727 return true
728 }
729 logger.Errorw(ctx, "Dropping US Meter request: Device not found", log.Fields{"Service": svc})
730 return false
731}
732
733// PushFlowsForPortVnet - triggers flow construction and push for provided VPV
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530734func (vpv *VoltPortVnet) PushFlowsForPortVnet(cntx context.Context, d *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530735
736 vp := d.GetPort(vpv.Port)
737
738 //Ignore if UNI port is not found or not UP
739 if vp == nil || vp.State != PortStateUp {
740 logger.Warnw(ctx, "Ignoring Vlan UP Ind for VPV: Port Not Found/Ready", log.Fields{"Port": vp})
741 return
742 }
743
744 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
745 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})
746 return
747 }
748
749 //Disable the flag so that flows can be pushed again
750 // vpv.IgmpFlowsApplied = false
751 // vpv.DsFlowsApplied = false
752 // vpv.UsFlowsApplied = false
753 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530754 vpv.PortUpInd(cntx, d, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530755 vpv.VpvLock.Unlock()
756}
757
758// PortUpInd : When a port transistions to UP state, the indication is passed
759// on to this module via the application. We read the VNET configuration
760// again here to apply the latest configuration if the configuration
761// changed. Thus, a reboot of ONT forces the new configuration to get
762// applied.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530763func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530764
765 if vpv.DeleteInProgress {
766 logger.Errorw(ctx, "Ignoring VPV Port UP Ind, VPV deleteion In-Progress", log.Fields{"Device": device, "Port": port, "Vnet": vpv.VnetName})
767 return
768 }
769 vpv.setDevice(device.Name)
770 logger.Infow(ctx, "Port UP Ind, pushing flows for the port", log.Fields{"Device": device, "Port": port, "VnetDhcp": vpv.DhcpRelay, "McastService": vpv.McastService})
771
772 nni, _ := GetApplication().GetNniPort(device.Name)
773 if nni == "" {
774 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name})
775 return
776 }
777
778 if vp := device.GetPort(port); vp != nil {
779
780 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
781 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})
782 return
783 }
784 }
785
786 if vpv.Blocked {
787 logger.Errorw(ctx, "VPV Bocked for Processing. Ignoring flow push request", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
788 return
789 }
790
791 if vpv.DhcpRelay || vpv.ArpRelay || vpv.PppoeIa {
792 // If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
793 // DS HSIA flows are installed after learning the MAC.
794 logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530795 // no HSIA flows for multicast service and DPU_MGMT Service
796 if !vpv.McastService && vpv.VnetType != DPU_MGMT_TRAFFIC {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530797 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530798 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530799 if vpv.VnetType == DPU_MGMT_TRAFFIC {
800 vpv.RangeOnServices(cntx, AddMeterToDevice)
801 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530802 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530803 if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
804 logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530805 /*In case of DPU_MGMT_TRAFFIC, need to install both US and DS traffic */
806 if vpv.VnetType == DPU_MGMT_TRAFFIC {
807 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
808 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530809 // US & DS DHCP, US HSIA flows are already installed
810 // install only DS HSIA flow here.
811 // no HSIA flows for multicast service
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530812 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530813 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530814 }
815 }
816
817 } else {
818 // DHCP relay is not configured. This implies that the service must use
819 // 1:1 and does not require MAC learning. In a completely uncommon but
820 // plausible case, the MAC address can be learnt from N:1 without DHCP
821 // relay by configuring any unknown MAC address to be reported. This
822 // however is not seen as a real use case.
823 logger.Infow(ctx, "Port Up - Service Flows", log.Fields{"Device": device.Name, "Port": port})
824 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530825 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530826 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530827 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530828 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530829 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530830 }
831 }
832
833 // Process IGMP proxy - install IGMP trap rules before DHCP trap rules
834 if vpv.IgmpEnabled {
835 logger.Infow(ctx, "Port Up - IGMP Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530836 vpv.RangeOnServices(cntx, AddSvcUsMeterToDevice)
837 if err := vpv.AddIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530838 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
839 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
840 }
841
842 if vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530843 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +0530844 }
845 }
846
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530847 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530848}
849
850// PortDownInd : When the port status changes to down, we delete all configured flows
851// The same indication is also passed to the services enqueued for them
852// to take appropriate actions
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530853func (vpv *VoltPortVnet) PortDownInd(cntx context.Context, device string, port string, nbRequest bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530854
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530855 if !nbRequest && !GetApplication().OltFlowServiceConfig.RemoveFlowsOnDisable {
856 logger.Info(ctx, "VPV Port DOWN Ind, Not deleting flows since RemoveOnDisable is disabled")
857 return
858 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530859 logger.Infow(ctx, "VPV Port DOWN Ind, deleting all flows for services",
860 log.Fields{"service count": vpv.servicesCount.Load()})
861
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530862 //vpv.RangeOnServices(cntx, DelAllFlows)
863 vpv.DelTrapFlows(cntx)
864 vpv.DelHsiaFlows(cntx)
865 vpv.WriteToDb(cntx)
866 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530867}
868
869// SetMacAddr : The MAC address is set when a MAC address is learnt through the
870// packets received from the network. Currently, DHCP packets are
871// only packets we learn the MAC address from
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530872func (vpv *VoltPortVnet) SetMacAddr(cntx context.Context, addr net.HardwareAddr) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530873
874 //Store Learnt MAC address and return if MACLearning is not enabled
875 vpv.LearntMacAddr = addr
876 if vpv.MacLearning == MacLearningNone || !NonZeroMacAddress(addr) ||
877 (NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn) {
878 return
879 }
880
881 // Compare the two MAC addresses to see if it is same
882 // If they are same, we just return. If not, we perform
883 // actions to address the change in MAC address
884 //if NonZeroMacAddress(vpv.MacAddr) && !util.MacAddrsMatch(vpv.MacAddr, addr) {
885 if !util.MacAddrsMatch(vpv.MacAddr, addr) {
886 expectedPort := GetApplication().GetMacInPortMap(addr)
887 if expectedPort != "" && expectedPort != vpv.Port {
888 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-setmacaddr",
889 log.Fields{"ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": addr.String()})
890 return
891 }
892 if NonZeroMacAddress(vpv.MacAddr) {
893 logger.Warnw(ctx, "MAC Address Changed. Remove old flows (if added) and re-add with updated MAC", log.Fields{"UpdatedMAC": addr})
894
895 // The newly learnt MAC address is different than earlier one.
896 // The existing MAC based HSIA flows need to be undone as the device
897 // may have been changed
898 // Atleast one HSIA flow should be present in adapter to retain the TP and GEM
899 // hence delete one after the other
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530900 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530901 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530902 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
903 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
904 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530905 GetApplication().DeleteMacInPortMap(vpv.MacAddr)
906 } else {
907 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530908 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530909 logger.Infow(ctx, "MAC Address learnt from DHCP or ARP", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
910 }
911 GetApplication().UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
912 } else {
913 logger.Infow(ctx, "Leant MAC Address is same", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
914 }
915
916 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
917 if err != nil {
918 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
919 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
920 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
921 return
922 }
923 // Ds Hsia flows has to be pushed
924 if vpv.FlowsApplied {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530925 // In case of DPU_MGMT_TRAFFIC install both US and DS Flows
926 if vpv.VnetType == DPU_MGMT_TRAFFIC {
927 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
928 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530929 // no HSIA flows for multicast service
930 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530931 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530932 }
933 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530934 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530935}
936
937// MatchesVlans : If the VNET matches both S and C VLANs, return true. Else, return false
938func (vpv *VoltPortVnet) MatchesVlans(svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) bool {
939 if vpv.SVlan != svlan || vpv.CVlan != cvlan || vpv.UniVlan != univlan {
940 return false
941 }
942 return true
943}
944
945// MatchesCvlan : If the VNET matches CVLAN, return true. Else, return false
946func (vpv *VoltPortVnet) MatchesCvlan(cvlan []of.VlanType) bool {
947 if len(cvlan) != 1 && !vpv.AllowTransparent {
948 return false
949 }
950 if vpv.CVlan != cvlan[0] {
951 return false
952 }
953 return true
954}
955
956// MatchesPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
957func (vpv *VoltPortVnet) MatchesPriority(priority uint8) *VoltService {
958
959 var service *VoltService
960 pbitFound := false
961 matchpbitsFunc := func(key, value interface{}) bool {
962 svc := value.(*VoltService)
963 for _, pbit := range svc.Pbits {
964 if uint8(pbit) == priority {
965 logger.Infow(ctx, "Pbit match found with service",
966 log.Fields{"Pbit": priority, "serviceName": svc.Name})
967 pbitFound = true
968 service = svc
969 return false //Returning false to stop the Range loop
970 }
971 }
972 return true
973 }
974 _ = pbitFound
975 vpv.services.Range(matchpbitsFunc)
976 return service
977}
978
979// GetRemarkedPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
980func (vpv *VoltPortVnet) GetRemarkedPriority(priority uint8) uint8 {
981
982 dsPbit := uint8(0)
983 matchpbitsFunc := func(key, value interface{}) bool {
984 svc := value.(*VoltService)
985 if remarkPbit, ok := svc.DsRemarkPbitsMap[int(priority)]; ok {
986 logger.Infow(ctx, "Pbit match found with service",
987 log.Fields{"Pbit": priority, "serviceName": svc.Name, "remarkPbit": remarkPbit})
988 dsPbit = uint8(remarkPbit)
989 return false //Returning false to stop the Range loop
990 }
991 // When no remarking info is available, remark the incoming pbit
992 // to highest pbit configured for the subscriber (across all subservices associated)
993 svcPbit := uint8(svc.Pbits[0])
994 if svcPbit > dsPbit {
995 dsPbit = svcPbit
996 }
997 return true
998 }
999 vpv.services.Range(matchpbitsFunc)
1000 logger.Debugw(ctx, "Remarked Pbit Value", log.Fields{"Incoming": priority, "Remarked": dsPbit})
1001 return dsPbit
1002}
1003
1004// AddSvc adds a service on the VNET on a port. The addition is
1005// triggered when NB requests for service addition
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301006func (vpv *VoltPortVnet) AddSvc(cntx context.Context, svc *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301007
1008 //vpv.services = append(vpv.services, svc)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301009 vpv.AddService(cntx, svc)
Naveen Sampath04696f72022-06-13 15:19:14 +05301010 logger.Debugw(ctx, "Added Service to VPV", log.Fields{"Num of SVCs": vpv.servicesCount.Load(), "SVC": svc})
1011
1012 // Learn the circuit-id and remote-id from the service
1013 // TODO: There must be a better way of doing this. This
1014 // may be explored
1015 if svc.IgmpEnabled {
1016 vpv.IgmpEnabled = true
1017 }
1018 // first time service activation MacLearning will have default value as None.
1019 // to handle reciliency if anythng other then None we should retain it .
1020 if svc.MacLearning == MacLearningNone {
1021 if !vpv.DhcpRelay && !vpv.ArpRelay {
1022 svc.MacLearning = MacLearningNone
1023 } else if vpv.MacLearning == Learn {
1024 svc.MacLearning = Learn
1025 } else if vpv.MacLearning == ReLearn {
1026 svc.MacLearning = ReLearn
1027 }
1028 }
1029
1030 //TODO: Temp Change - Need to address MAC Learning flow issues completely
1031 if (svc.MacLearning == Learn || svc.MacLearning == ReLearn) && NonZeroMacAddress(vpv.MacAddr) {
1032 svc.MacAddr = vpv.MacAddr
1033 } else if vpv.servicesCount.Load() == 1 {
1034 vpv.MacAddr = svc.MacAddr
1035 }
1036
1037 vpv.MacLearning = svc.MacLearning
1038 vpv.PonPort = svc.PonPort
1039 logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
1040 //Reconfigure Vlans based on Vlan Control type
1041 svc.VlanControl = vpv.VlanControl
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301042 //TODO Is it good to change NB config?? commenting for now
1043 /*
Naveen Sampath04696f72022-06-13 15:19:14 +05301044 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
1045 if vpv.VlanControl == ONUCVlan {
1046 svc.CVlan = svc.SVlan
1047 }
1048 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
1049 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
1050 if vpv.VlanControl == OLTSVlan {
1051 svc.CVlan = svc.UniVlan
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301052 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +05301053 if svc.McastService {
1054 vpv.McastService = true
1055 vpv.McastTechProfileID = svc.TechProfileID
1056 //Assumption: Only one Pbit for mcast service
1057 vpv.McastPbit = svc.Pbits[0]
1058 vpv.McastUsMeterID = svc.UsMeterID
1059 vpv.SchedID = svc.SchedID
1060 }
1061 svc.ONTEtherTypeClassification = vpv.ONTEtherTypeClassification
1062 svc.AllowTransparent = vpv.AllowTransparent
1063 svc.SVlanTpid = vpv.SVlanTpid
1064
1065 //Ensure configuring the mvlan profile only once
1066 //One subscriber cannot have multiple mvlan profiles. Only the first configuration is valid
1067 if svc.MvlanProfileName != "" {
1068 if vpv.MvlanProfileName == "" {
1069 vpv.MvlanProfileName = svc.MvlanProfileName
1070 } else {
1071 logger.Warnw(ctx, "Mvlan Profile already configured for subscriber. Ignoring new Mvlan", log.Fields{"Existing Mvlan": vpv.MvlanProfileName, "New Mvlan": svc.MvlanProfileName})
1072 }
1073 }
1074
1075 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
1076 if err != nil {
1077 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
1078 //statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1079 //TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1080 return
1081 }
Tinoj Josephec742f62022-09-29 19:11:10 +05301082 if !svc.IsActivated {
1083 logger.Warn(ctx, "Not pushing Service Flows: Service Not activated")
1084 return
1085 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301086 //Push Service Flows if DHCP relay is not configured
1087 //or already DHCP flows are configured for the VPV
1088 //to which the serivce is associated
1089 if vpv.FlowsApplied {
1090 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301091 svc.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301092 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301093 if err:= svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301094 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1095 }
1096 }
1097 }
1098
1099 //Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
1100 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1101 // service with Igmp Enabled needs to be installed
1102 if svc.IgmpEnabled && vpv.FlowsApplied {
1103 logger.Infow(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301104 if err := vpv.AddIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301105 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1106 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1107 }
1108
1109 if vpv.McastService {
1110 //For McastService, send Service Activated indication once IGMP US flow is pushed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301111 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +05301112 }
1113 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301114 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301115}
1116
1117// setLearntMAC to set learnt mac
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301118func (vpv *VoltPortVnet) setLearntMAC(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301119 svc := value.(*VoltService)
1120 svc.SetMacAddr(vpv.MacAddr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301121 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301122 return true
1123}
1124
1125// PostAccessConfigSuccessInd for posting access config success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301126func PostAccessConfigSuccessInd(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301127 return true
1128}
1129
1130// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301131func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301132 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301133 logger.Infow(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301134 svc.SetIpv4Addr(vpv.Ipv4Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301135 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301136
1137 return true
1138}
1139
1140// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301141func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301142 svc := value.(*VoltService)
1143 svc.SetIpv6Addr(vpv.Ipv6Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301144 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301145
1146 return true
1147}
1148
1149// AddUsHsiaFlows to add upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301150func AddUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301151 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301152 if err:= svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301153 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1154 }
1155 return true
1156}
1157
1158// AddDsHsiaFlows to add downstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301159func AddDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301160 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301161 if err:= svc.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301162 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1163 }
1164 return true
1165}
1166
1167// ClearFlagsInService to clear the flags used in service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301168func ClearFlagsInService(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301169 svc := value.(*VoltService)
1170 svc.ServiceLock.Lock()
1171 svc.IgmpFlowsApplied = false
1172 svc.DsDhcpFlowsApplied = false
1173 svc.DsHSIAFlowsApplied = false
1174 svc.Icmpv6FlowsApplied = false
1175 svc.UsHSIAFlowsApplied = false
1176 svc.UsDhcpFlowsApplied = false
1177 svc.PendingFlows = make(map[string]bool)
1178 svc.AssociatedFlows = make(map[string]bool)
1179 svc.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301180 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301181 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1182 return true
1183}
1184
1185// DelDsHsiaFlows to delete hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301186func DelDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301187 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301188 if err:= svc.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301189 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1190 }
1191 return true
1192}
1193
1194// DelUsHsiaFlows to delete upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301195func DelUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301196 svc := value.(*VoltService)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301197 if err:= svc.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301198 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1199 }
1200 return true
1201}
1202
1203// ClearServiceCounters to clear the service counters
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301204func ClearServiceCounters(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301205 svc := value.(*VoltService)
1206 //Delete the per service counter too
1207 GetApplication().ServiceCounters.Delete(svc.Name)
1208 if svc.IgmpEnabled && svc.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301209 _ = db.DelAllServiceChannelCounter(cntx, svc.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301210 }
1211 return true
1212}
1213
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301214// AddMeterToDevice to add meter config to device, used in FTTB case
1215func AddMeterToDevice(cntx context.Context, key, value interface{}) bool {
1216 svc := value.(*VoltService)
1217 if err:= svc.AddMeterToDevice(cntx); err != nil {
1218 logger.Warnw(ctx, "Add Meter failed", log.Fields{"service": svc.Name, "Error": err})
1219 }
1220 return true
1221}
1222
Naveen Sampath04696f72022-06-13 15:19:14 +05301223//AddTrapFlows - Adds US & DS Trap flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301224func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301225
1226 if !vpv.FlowsApplied || vgcRebooted {
1227 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301228 if err := vpv.AddUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301229 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1230 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1231 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301232 if err := vpv.AddDsDhcpFlows(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 }
1236 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1237 log.Fields{"port": vpv.Port})
1238 //vpv.updateICMPv6McGroup(true)
1239 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301240 if err := vpv.AddUsArpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301241 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1242 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1243 }
1244 logger.Info(ctx, "ARP trap rules not added in downstream direction")
1245
1246 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301247 if err := vpv.AddUsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301248 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1249 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1250 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301251 if err := vpv.AddDsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301252 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1253 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1254 }
1255 }
1256 vpv.FlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301257 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301258 }
1259}
1260
1261//DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301262func (vpv *VoltPortVnet) DelTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301263
1264 // Delete HSIA & DHCP flows before deleting IGMP flows
1265 if vpv.FlowsApplied || vgcRebooted {
1266 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301267 if err:= vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301268 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1269 "UniVlan": vpv.UniVlan, "Error": err})
1270 }
1271 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1272 log.Fields{"port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301273 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301274 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1275 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1276 }
1277 //vpv.updateICMPv6McGroup(false)
1278 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301279 if err := vpv.DelUsArpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301280 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1281 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1282 }
1283 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301284 if err := vpv.DelUsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301285 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1286 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1287 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301288 if err := vpv.DelDsPppoeFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301289 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1290 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1291 }
1292 }
1293 vpv.FlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301294 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301295 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301296 if err:= vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301297 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1298 "UniVlan": vpv.UniVlan, "Error": err})
1299 }
1300}
1301
1302// DelHsiaFlows deletes the service flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301303func (vpv *VoltPortVnet) DelHsiaFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301304 // no HSIA flows for multicast service
1305 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301306 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
1307 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301308 }
1309}
1310
1311//ClearServiceCounters - Removes all igmp counters for a service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301312func (vpv *VoltPortVnet) ClearServiceCounters(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301313 //send flows deleted indication to submgr
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301314 vpv.RangeOnServices(cntx, ClearServiceCounters)
Naveen Sampath04696f72022-06-13 15:19:14 +05301315}
1316
1317// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301318func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301319 var vd *VoltDevice
1320 device := vpv.Device
1321
1322 if vd = GetApplication().GetDevice(device); vd != nil {
1323 if vd.State != controller.DeviceStateUP {
1324 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})
1325 return nil
1326 }
1327 } else {
1328 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})
1329 return errorCodes.ErrDeviceNotFound
1330 }
1331
1332 flows, err := vpv.BuildUsDhcpFlows()
1333 if err == nil {
1334 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301335 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301336 //push ind here ABHI
1337 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1338 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1339 }
1340 } else {
1341 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1342 //push ind here ABHI
1343 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1344 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1345
1346 }
1347 /*
1348 flows, err = vpv.BuildUsDhcp6Flows()
1349 if err == nil {
1350 logger.Debugw(ctx, "Adding US DHCP6 flows", log.Fields{"Device": device})
1351 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1352 //pussh ind here ABHI
1353 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1354 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1355
1356 }
1357 } else {
1358 logger.Errorw(ctx, "US DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1359 //push ind here ABHI
1360 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1361 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1362
1363 }*/
1364 return nil
1365}
1366
1367// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301368func (vpv *VoltPortVnet) AddDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301369
1370 var vd *VoltDevice
1371 device := vpv.Device
1372
1373 if vd = GetApplication().GetDevice(device); vd != nil {
1374 if vd.State != controller.DeviceStateUP {
1375 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})
1376 return nil
1377 }
1378 } else {
1379 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})
1380 return errorCodes.ErrDeviceNotFound
1381 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301382 if vd.GlobalDhcpFlowAdded {
1383 logger.Info(ctx, "Global Dhcp flow already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301384 return nil
1385 }
1386
1387 flows, err := vpv.BuildDsDhcpFlows()
1388 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301389 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301390 //push ind here and procced
1391 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1392 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1393
1394 }
1395 } else {
1396 logger.Errorw(ctx, "DS DHCP Flow Add Failed", log.Fields{"Reason": err.Error()})
1397 //send ind here and proceed
1398 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1399 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1400
1401 }
1402 /*
1403 flows, err = vpv.BuildDsDhcp6Flows()
1404 if err == nil {
1405 if err1 := vpv.PushFlows(vd, flows); err1 != nil {
1406 //push ind and proceed
1407 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err1)
1408 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1409
1410 }
1411 } else {
1412 logger.Errorw(ctx, "DS DHCP6 Flow Add Failed", log.Fields{"Reason": err.Error()})
1413 //Send ind here and proceed
1414 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1415 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1416
1417 }*/
1418 if GetApplication().GetVendorID() != Radisys {
1419 vd.GlobalDhcpFlowAdded = true
1420 }
1421 return nil
1422}
1423
1424// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301425func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
1426 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301427 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1428 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1429 }
1430
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301431 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301432 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1433 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1434 }
1435}
1436
1437// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1438// Write the status of the VPV to the DB once the delete is scheduled
1439// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301440func (vpv *VoltPortVnet) DelUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301441 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1442 if err != nil {
1443 return err
1444 }
1445
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301446 err = vpv.delDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301447 if err != nil {
1448 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1449 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1450 }
1451 /*
1452 err = vpv.delDhcp6Flows(device)
1453 if err != nil {
1454 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1455 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1456 }*/
1457 return nil
1458}
1459
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301460func (vpv *VoltPortVnet) delDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301461 flows, err := vpv.BuildUsDhcpFlows()
1462 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301463 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301464 }
1465 logger.Errorw(ctx, "US DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1466 return err
1467}
1468/*
1469func (vpv *VoltPortVnet) delDhcp6Flows(device *VoltDevice) error {
1470 flows, err := vpv.BuildUsDhcp6Flows()
1471 if err == nil {
1472 return vpv.RemoveFlows(device, flows)
1473 }
1474 logger.Errorw(ctx, "US DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1475 return err
1476
1477}*/
1478
1479// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1480// Write the status of the VPV to the DB once the delete is scheduled
1481// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301482func (vpv *VoltPortVnet) DelDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301483 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1484 if err != nil {
1485 return err
1486 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301487 err = vpv.delDsDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301488 if err != nil {
1489 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1490 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1491 }
1492 /*
1493 err = vpv.delDsDhcp6Flows(device)
1494 if err != nil {
1495 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
1496 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1497 }*/
1498 return nil
1499}
1500
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301501func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301502 flows, err := vpv.BuildDsDhcpFlows()
1503 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301504 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301505 }
1506 logger.Errorw(ctx, "DS DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1507 return err
1508}
1509
1510/*
1511func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1512 flows, err := vpv.BuildDsDhcp6Flows()
1513 if err == nil {
1514 return vpv.RemoveFlows(device, flows)
1515 }
1516 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1517 return err
1518}*/
1519
1520// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301521func (vpv *VoltPortVnet) AddUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301522
1523 var vd *VoltDevice
1524 device := vpv.Device
1525 if vd = GetApplication().GetDevice(device); vd != nil {
1526 if vd.State != controller.DeviceStateUP {
1527 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})
1528 return nil
1529 }
1530 } else {
1531 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})
1532 return errorCodes.ErrDeviceNotFound
1533 }
1534
1535 flows, err := vpv.BuildUsArpFlows()
1536 if err == nil {
1537 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301538 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301539 return err1
1540 }
1541 } else {
1542 logger.Errorw(ctx, "US ARP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1543 return err
1544 }
1545 return nil
1546}
1547
1548// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1549// Write the status of the VPV to the DB once the delete is scheduled
1550// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301551func (vpv *VoltPortVnet) DelUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301552 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1553 if err != nil {
1554 return err
1555 }
1556 flows, err := vpv.BuildUsArpFlows()
1557 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301558 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301559 }
1560 logger.Errorw(ctx, "US ARP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1561 return err
1562}
1563
1564// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301565func (vpv *VoltPortVnet) AddUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301566 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1567
1568 var vd *VoltDevice
1569 device := vpv.Device
1570
1571 if vd = GetApplication().GetDevice(device); vd != nil {
1572 if vd.State != controller.DeviceStateUP {
1573 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})
1574 return nil
1575 }
1576 } else {
1577 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})
1578 return errorCodes.ErrDeviceNotFound
1579 }
1580
1581 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1582 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1583
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301584 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301585 return err1
1586 }
1587 } else {
1588 logger.Errorw(ctx, "US PPPoE Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1589 return err
1590 }
1591 return nil
1592}
1593
1594// AddDsPppoeFlows to add downstream pppoe flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301595func (vpv *VoltPortVnet) AddDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301596 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1597 var vd *VoltDevice
1598 device := vpv.Device
1599
1600 if vd = GetApplication().GetDevice(device); vd != nil {
1601 if vd.State != controller.DeviceStateUP {
1602 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})
1603 return nil
1604 }
1605 } else {
1606 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})
1607 return errorCodes.ErrDeviceNotFound
1608 }
1609
1610 flows, err := vpv.BuildDsPppoeFlows()
1611 if err == nil {
1612
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301613 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301614 return err1
1615 }
1616 } else {
1617 logger.Errorw(ctx, "DS PPPoE Flow Add Failed", log.Fields{"Reason": err.Error()})
1618 return err
1619 }
1620 return nil
1621}
1622
1623// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1624// Write the status of the VPV to the DB once the delete is scheduled
1625// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301626func (vpv *VoltPortVnet) DelUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301627 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1628 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1629 if err != nil {
1630 return err
1631 }
1632 flows, err := vpv.BuildUsPppoeFlows()
1633 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301634 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301635 }
1636 logger.Errorw(ctx, "US PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1637 return err
1638}
1639
1640// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1641// Write the status of the VPV to the DB once the delete is scheduled
1642// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301643func (vpv *VoltPortVnet) DelDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301644 logger.Debugw(ctx, "Deleting DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1645 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1646 if err != nil {
1647 return err
1648 }
1649 flows, err := vpv.BuildDsPppoeFlows()
1650 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301651 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301652 }
1653 logger.Errorw(ctx, "DS PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1654 return err
1655}
1656
1657// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301658func (vpv *VoltPortVnet) AddIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301659
1660 if !vpv.IgmpFlowsApplied || vgcRebooted {
1661 if vpv.MvlanProfileName == "" {
1662 logger.Info(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
1663 return nil
1664 }
1665 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1666 if err != nil {
1667 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1668 return err
1669 } else if device.State != controller.DeviceStateUP {
1670 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})
1671 return nil
1672 }
1673 flows, err := vpv.BuildIgmpFlows()
1674 if err == nil {
1675 for cookie := range flows.SubFlows {
1676 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1677 cookie := strconv.FormatUint(cookie, 10)
1678 fe := &FlowEvent{
1679 eType: EventTypeUsIgmpFlowAdded,
1680 cookie: cookie,
1681 eventData: vpv,
1682 }
1683 vd.RegisterFlowAddEvent(cookie, fe)
1684 }
1685 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301686 if err1 := cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301687 return err1
1688 }
1689 } else {
1690 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1691 return err
1692 }
1693 vpv.IgmpFlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301694 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301695 }
1696 return nil
1697}
1698
1699// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1700// Write the status of the VPV to the DB once the delete is scheduled
1701// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301702func (vpv *VoltPortVnet) DelIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301703
1704 if vpv.IgmpFlowsApplied || vgcRebooted {
1705 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1706 if err != nil {
1707 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1708 return err
1709 }
1710 flows, err := vpv.BuildIgmpFlows()
1711 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301712 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301713 return err1
1714 }
1715 } else {
1716 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1717 return err
1718 }
1719 vpv.IgmpFlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301720 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301721 }
1722 return nil
1723}
1724
1725// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1726// The flows included by this function cover US only as the DS is
1727// created either automatically by the VOLTHA or at the device level
1728// earlier
1729func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
1730 flow := &of.VoltFlow{}
1731 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1732
1733 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
1734 subFlow := of.NewVoltSubFlow()
1735 subFlow.SetTableID(0)
1736
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301737
1738 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1739 subFlow.SetMatchVlan(vpv.CVlan)
1740 subFlow.SetMatchPbit(vpv.UsPonCTagPriority)
1741 subFlow.SetPcp(vpv.UsPonSTagPriority)
1742 subFlow.SetSetVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301743 } else {
1744 subFlow.SetMatchVlan(vpv.UniVlan)
1745 subFlow.SetSetVlan(vpv.CVlan)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301746 subFlow.SetPcp(vpv.DhcpPbit)
Naveen Sampath04696f72022-06-13 15:19:14 +05301747 }
1748 subFlow.SetUdpv4Match()
Naveen Sampath04696f72022-06-13 15:19:14 +05301749 subFlow.DstPort = 67
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301750 subFlow.SrcPort = 68
Naveen Sampath04696f72022-06-13 15:19:14 +05301751 uniport, err := GetApplication().GetPortID(vpv.Port)
1752 if err != nil {
1753 logger.Errorw(ctx, "Failed to fetch uni port from vpv", log.Fields{"error": err, "port": vpv.Port})
1754 return nil, err
1755 }
1756 subFlow.SetInPort(uniport)
1757 // PortName and PortID to be used for validation of port before flow pushing
1758 flow.PortID = uniport
1759 flow.PortName = vpv.Port
1760 subFlow.SetReportToController()
1761
1762 // Set techprofile, meterid of first service
1763 vpv.services.Range(func(key, value interface{}) bool {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301764 vs := value.(*VoltService)
1765 var writemetadata uint64
1766 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1767 writemetadata = uint64(vs.SVlan)<<48 + uint64(vs.TechProfileID)<<32
1768 } else {
1769 writemetadata = uint64(vs.TechProfileID) << 32
1770 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301771 subFlow.SetWriteMetadata(writemetadata)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301772 subFlow.SetMeterID(vs.UsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301773 return false
1774 })
1775
Naveen Sampath04696f72022-06-13 15:19:14 +05301776 // metadata := uint64(uniport)
1777 // subFlow.SetWriteMetadata(metadata)
1778 allowTransparent := 0
1779 if vpv.AllowTransparent {
1780 allowTransparent = 1
1781 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301782 if vpv.VnetType != DPU_MGMT_TRAFFIC {
1783 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1784 subFlow.SetTableMetadata(metadata)
1785 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301786 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1787 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1788 subFlow.Priority = of.DhcpFlowPriority
1789
1790 flow.SubFlows[subFlow.Cookie] = subFlow
1791 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1792 return flow, nil
1793}
1794
1795// BuildDsDhcpFlows to build the downstream dhcp flows
1796func (vpv *VoltPortVnet) BuildDsDhcpFlows() (*of.VoltFlow, error) {
1797
1798 logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1799 flow := &of.VoltFlow{}
1800 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1801 subFlow := of.NewVoltSubFlow()
1802 subFlow.SetTableID(0)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301803 // match on vlan only for fttb case
1804 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1805 subFlow.SetMatchVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301806 }
1807 subFlow.SetUdpv4Match()
1808 subFlow.SrcPort = 67
1809 subFlow.DstPort = 68
1810 uniport, _ := GetApplication().GetPortID(vpv.Port)
1811 nni, err := GetApplication().GetNniPort(vpv.Device)
1812 if err != nil {
1813 return nil, err
1814 }
1815 nniport, err := GetApplication().GetPortID(nni)
1816 if err != nil {
1817 return nil, err
1818 }
1819 subFlow.SetInPort(nniport)
1820 // PortName and PortID to be used for validation of port before flow pushing
1821 flow.PortID = uniport
1822 flow.PortName = vpv.Port
1823 // metadata := uint64(uniport)
1824 // subFlow.SetWriteMetadata(metadata)
1825 allowTransparent := 0
1826 if vpv.AllowTransparent {
1827 allowTransparent = 1
1828 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301829 if vpv.VnetType != DPU_MGMT_TRAFFIC {
1830 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1831 subFlow.SetTableMetadata(metadata)
1832 subFlow.Priority = of.DhcpFlowPriority
1833 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301834 subFlow.SetReportToController()
1835 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1836 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
Naveen Sampath04696f72022-06-13 15:19:14 +05301837
1838 flow.SubFlows[subFlow.Cookie] = subFlow
1839 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1840
1841 return flow, nil
1842}
1843
1844// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1845// application.
1846func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
1847 flow := &of.VoltFlow{}
1848 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1849
1850 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
1851 subFlow := of.NewVoltSubFlow()
1852 subFlow.SetTableID(0)
1853
1854 subFlow.SetMatchVlan(vpv.UniVlan)
1855 subFlow.SetSetVlan(vpv.CVlan)
1856 subFlow.SetUdpv6Match()
1857 subFlow.SrcPort = 546
1858 subFlow.DstPort = 547
1859 uniport, err := GetApplication().GetPortID(vpv.Port)
1860 if err != nil {
1861 return nil, err
1862 }
1863 // Set techprofile, meterid of first service
1864 vpv.services.Range(func(key, value interface{}) bool {
1865 svc := value.(*VoltService)
1866 writemetadata := uint64(svc.TechProfileID) << 32
1867 subFlow.SetWriteMetadata(writemetadata)
1868 subFlow.SetMeterID(svc.UsMeterID)
1869 return false
1870 })
1871 subFlow.SetInPort(uniport)
1872 // PortName and PortID to be used for validation of port before flow pushing
1873 flow.PortID = uniport
1874 flow.PortName = vpv.Port
1875 //subFlow.SetMeterId(vpv.UsDhcpMeterId)
1876 // metadata := uint64(uniport)
1877 // subFlow.SetWriteMetadata(metadata)
1878 allowTransparent := 0
1879 if vpv.AllowTransparent {
1880 allowTransparent = 1
1881 }
1882 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1883 subFlow.SetTableMetadata(metadata)
1884 subFlow.SetReportToController()
1885 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1886 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
1887 subFlow.Priority = of.DhcpFlowPriority
1888
1889 flow.SubFlows[subFlow.Cookie] = subFlow
1890 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1891 return flow, nil
1892}
1893
1894// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1895// application.
1896func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
1897 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1898
1899 flow := &of.VoltFlow{}
1900 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1901 subFlow := of.NewVoltSubFlow()
1902 subFlow.SetTableID(0)
1903
1904 vpv.setDsMatchVlan(subFlow)
1905 subFlow.SetUdpv6Match()
1906 subFlow.SrcPort = 547
1907 subFlow.DstPort = 547
1908 uniport, _ := GetApplication().GetPortID(vpv.Port)
1909 nni, err := GetApplication().GetNniPort(vpv.Device)
1910 if err != nil {
1911 return nil, err
1912 }
1913 nniport, err := GetApplication().GetPortID(nni)
1914 if err != nil {
1915 return nil, err
1916 }
1917 subFlow.SetInPort(nniport)
1918 // PortName and PortID to be used for validation of port before flow pushing
1919 flow.PortID = uniport
1920 flow.PortName = vpv.Port
1921 // metadata := uint64(uniport)
1922 // subFlow.SetWriteMetadata(metadata)
1923 allowTransparent := 0
1924 if vpv.AllowTransparent {
1925 allowTransparent = 1
1926 }
1927 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1928 subFlow.SetTableMetadata(metadata)
1929 subFlow.SetReportToController()
1930 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1931 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
1932 subFlow.Priority = of.DhcpFlowPriority
1933
1934 flow.SubFlows[subFlow.Cookie] = subFlow
1935 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1936 return flow, nil
1937}
1938
1939// BuildUsArpFlows builds the US ARP relay flows for a subscriber
1940// The flows included by this function cover US only as the DS is
1941// created either automatically by the VOLTHA or at the device level
1942// earlier
1943func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
1944 flow := &of.VoltFlow{}
1945 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1946
1947 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
1948 subFlow := of.NewVoltSubFlow()
1949 subFlow.SetTableID(0)
1950
1951 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1952 subFlow.SetMatchSrcMac(vpv.MacAddr)
1953 }
1954
1955 subFlow.SetMatchDstMac(BroadcastMAC)
1956 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1957 return nil, err
1958 }
1959 subFlow.SetArpMatch()
1960 uniport, err := GetApplication().GetPortID(vpv.Port)
1961 if err != nil {
1962 return nil, err
1963 }
1964 subFlow.SetInPort(uniport)
1965 // PortName and PortID to be used for validation of port before flow pushing
1966 flow.PortID = uniport
1967 flow.PortName = vpv.Port
1968 subFlow.SetReportToController()
1969 allowTransparent := 0
1970 if vpv.AllowTransparent {
1971 allowTransparent = 1
1972 }
1973 metadata := uint64(uniport)
1974 subFlow.SetWriteMetadata(metadata)
1975 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1976 subFlow.SetTableMetadata(metadata)
1977 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
1978 subFlow.Priority = of.ArpFlowPriority
1979
1980 flow.SubFlows[subFlow.Cookie] = subFlow
1981 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1982 return flow, nil
1983}
1984
1985// setUsMatchVlan to set upstream match vlan
1986func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
1987 switch vpv.VlanControl {
1988 case None:
1989 flow.SetMatchVlan(vpv.SVlan)
1990 case ONUCVlanOLTSVlan:
1991 flow.SetMatchVlan(vpv.CVlan)
1992 case OLTCVlanOLTSVlan:
1993 flow.SetMatchVlan(vpv.UniVlan)
1994 //flow.SetSetVlan(vpv.CVlan)
1995 case ONUCVlan:
1996 flow.SetMatchVlan(vpv.SVlan)
1997 case OLTSVlan:
1998 flow.SetMatchVlan(vpv.UniVlan)
1999 //flow.SetSetVlan(vpv.SVlan)
2000 default:
2001 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2002 return errorCodes.ErrInvalidParamInRequest
2003 }
2004 return nil
2005}
2006
2007// BuildUsPppoeFlows to build upstream pppoe flows
2008func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
2009
2010 flow := &of.VoltFlow{}
2011 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2012 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
2013 subFlow := of.NewVoltSubFlow()
2014 subFlow.SetTableID(0)
2015
2016 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2017 subFlow.SetMatchSrcMac(vpv.MacAddr)
2018 }
2019
2020 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2021 return nil, err
2022 }
2023 subFlow.SetPppoeDiscoveryMatch()
2024 uniport, err := GetApplication().GetPortID(vpv.Port)
2025 if err != nil {
2026 return nil, err
2027 }
2028 subFlow.SetInPort(uniport)
2029 subFlow.SetReportToController()
2030 // PortName and PortID to be used for validation of port before flow pushing
2031 flow.PortID = uniport
2032 flow.PortName = vpv.Port
2033
2034 allowTransparent := 0
2035 if vpv.AllowTransparent {
2036 allowTransparent = 1
2037 }
2038 metadata := uint64(uniport)
2039 subFlow.SetWriteMetadata(metadata)
2040
2041 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2042 subFlow.SetTableMetadata(metadata)
2043
2044 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
2045 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
2046 subFlow.Priority = of.PppoeFlowPriority
2047
2048 flow.SubFlows[subFlow.Cookie] = subFlow
2049 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2050 return flow, nil
2051}
2052
2053// BuildDsPppoeFlows to build downstream pppoe flows
2054func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
2055
2056 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
2057 flow := &of.VoltFlow{}
2058 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2059 subFlow := of.NewVoltSubFlow()
2060 subFlow.SetTableID(0)
2061
2062 vpv.setDsMatchVlan(subFlow)
2063 subFlow.SetPppoeDiscoveryMatch()
2064
2065 if NonZeroMacAddress(vpv.MacAddr) {
2066 subFlow.SetMatchDstMac(vpv.MacAddr)
2067 }
2068
2069 uniport, _ := GetApplication().GetPortID(vpv.Port)
2070 nni, err := GetApplication().GetNniPort(vpv.Device)
2071 if err != nil {
2072 return nil, err
2073 }
2074 nniport, err := GetApplication().GetPortID(nni)
2075 if err != nil {
2076 return nil, err
2077 }
2078 subFlow.SetInPort(nniport)
2079 // PortName and PortID to be used for validation of port before flow pushing
2080 flow.PortID = uniport
2081 flow.PortName = vpv.Port
2082 metadata := uint64(uniport)
2083 subFlow.SetWriteMetadata(metadata)
2084 allowTransparent := 0
2085 if vpv.AllowTransparent {
2086 allowTransparent = 1
2087 }
2088 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2089 subFlow.SetTableMetadata(metadata)
2090 subFlow.SetReportToController()
2091 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
2092 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2093 subFlow.Priority = of.PppoeFlowPriority
2094
2095 flow.SubFlows[subFlow.Cookie] = subFlow
2096 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2097 return flow, nil
2098}
2099
2100// setDsMatchVlan to set downstream match vlan
2101func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
2102 switch vpv.VlanControl {
2103 case None:
2104 flow.SetMatchVlan(vpv.SVlan)
2105 case ONUCVlanOLTSVlan,
2106 OLTCVlanOLTSVlan,
2107 ONUCVlan,
2108 OLTSVlan:
2109 flow.SetMatchVlan(vpv.SVlan)
2110 default:
2111 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2112 }
2113}
2114
2115// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2116// in the US direction.
2117func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2118 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2119 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2120 if mvp == nil {
2121 return nil, errors.New("Mvlan Profile configured not found")
2122 }
2123 mvlan := mvp.GetUsMatchVlan()
2124 flow := &of.VoltFlow{}
2125 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2126 subFlow := of.NewVoltSubFlow()
2127 subFlow.SetTableID(0)
2128
2129 if GetApplication().GetVendorID() == Radisys {
2130 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2131 return nil, err
2132 }
2133 } else {
2134 subFlow.SetMatchVlan(vpv.UniVlan)
2135 subFlow.SetSetVlan(vpv.CVlan)
2136 }
2137
2138 uniport, err := GetApplication().GetPortID(vpv.Port)
2139 if err != nil {
2140 return nil, err
2141 }
2142 subFlow.SetInPort(uniport)
2143 // PortName and PortID to be used for validation of port before flow pushing
2144 flow.PortID = uniport
2145 flow.PortName = vpv.Port
2146
2147 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2148 subFlow.SetMatchSrcMac(vpv.MacAddr)
2149 }
2150 logger.Infow(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
2151 //metadata := uint64(mvlan)
2152
2153 if vpv.McastService {
2154 metadata := uint64(vpv.McastUsMeterID)
2155 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2156 subFlow.SetMatchPbit(vpv.McastPbit)
2157 subFlow.SetMeterID(vpv.McastUsMeterID)
2158 subFlow.SetWriteMetadata(metadata)
2159 } else {
2160 // Set techprofile, meterid of first service
2161 vpv.services.Range(func(key, value interface{}) bool {
2162 svc := value.(*VoltService)
2163 writemetadata := uint64(svc.TechProfileID) << 32
2164 subFlow.SetWriteMetadata(writemetadata)
2165 subFlow.SetMeterID(svc.UsMeterID)
2166 return false
2167 })
2168 }
2169
2170 allowTransparent := 0
2171 if vpv.AllowTransparent {
2172 allowTransparent = 1
2173 }
2174 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2175 subFlow.SetTableMetadata(metadata)
2176 subFlow.SetIgmpMatch()
2177 subFlow.SetReportToController()
2178 //| 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
2179 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2180 subFlow.Priority = of.IgmpFlowPriority
2181
2182 flow.SubFlows[subFlow.Cookie] = subFlow
2183 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2184 return flow, nil
2185}
2186
2187// WriteToDb for writing to database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302188func (vpv *VoltPortVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302189 if vpv.DeleteInProgress {
2190 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2191 return
2192 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302193 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302194}
2195
2196//ForceWriteToDb force commit a VPV to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302197func (vpv *VoltPortVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302198 vpv.PendingFlowLock.RLock()
2199 defer vpv.PendingFlowLock.RUnlock()
2200 vpv.Version = database.PresentVersionMap[database.VpvPath]
2201 if b, err := json.Marshal(vpv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302202 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 +05302203 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2204 "UniVlan": vpv.UniVlan, "Error": err})
2205 }
2206 }
2207}
2208
2209// DelFromDb for deleting from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302210func (vpv *VoltPortVnet) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302211 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 +05302212 _ = db.DelVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
Naveen Sampath04696f72022-06-13 15:19:14 +05302213}
2214
2215// ClearAllServiceFlags to clear all service flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302216func (vpv *VoltPortVnet) ClearAllServiceFlags(cntx context.Context) {
2217 vpv.RangeOnServices(cntx, ClearFlagsInService)
Naveen Sampath04696f72022-06-13 15:19:14 +05302218}
2219
2220// ClearAllVpvFlags to clear all vpv flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302221func (vpv *VoltPortVnet) ClearAllVpvFlags(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302222 vpv.PendingFlowLock.Lock()
2223 vpv.FlowsApplied = false
2224 vpv.IgmpFlowsApplied = false
2225 vpv.PendingDeleteFlow = make(map[string]bool)
2226 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302227 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302228 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2229 log.Fields{"device": vpv.Device, "port": vpv.Port,
2230 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2231}
2232
2233// CreateVpvFromString to create vpv from string
2234func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
2235 var vpv VoltPortVnet
2236 if err := json.Unmarshal(b, &vpv); err == nil {
2237 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2238 if !ok {
2239 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2240 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2241 }
2242 vpv.servicesCount = atomic.NewUint64(0)
2243 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2244 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2245 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2246 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2247 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2248 vnet.associatePortToVnet(vpv.Port)
2249 }
2250
2251 if vpv.DeleteInProgress {
2252 va.VoltPortVnetsToDelete[&vpv] = true
2253 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2254 }
2255 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2256 }
2257}
2258
2259// RestoreVpvsFromDb to restore vpvs from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302260func (va *VoltApplication) RestoreVpvsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302261 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302262 vpvs, _ := db.GetVpvs(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302263 for hash, vpv := range vpvs {
2264 b, ok := vpv.Value.([]byte)
2265 if !ok {
2266 logger.Warn(ctx, "The value type is not []byte")
2267 continue
2268 }
2269 va.CreateVpvFromString(b, hash)
2270 }
2271}
2272
2273// GetVnetByPort : VNET related functionality of VOLT Application here on.
2274// Get the VNET from a port. The port identity is passed as device and port identities in string.
2275// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2276// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2277func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
2278 if _, ok := va.VnetsByPort.Load(port); !ok {
2279 return nil
2280 }
2281 vpvs, _ := va.VnetsByPort.Load(port)
2282 for _, vpv := range vpvs.([]*VoltPortVnet) {
2283 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2284 return vpv
2285 }
2286 }
2287 return nil
2288}
2289
2290// AddVnetToPort to add vnet to port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302291func (va *VoltApplication) AddVnetToPort(cntx context.Context, port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
Naveen Sampath04696f72022-06-13 15:19:14 +05302292 // The VNET is not on the port and is to be added
2293 logger.Debugw(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
2294 vpv := NewVoltPortVnet(vvnet)
2295 vpv.MacLearning = vvnet.MacLearning
2296 vpv.Port = port
2297 vvnet.associatePortToVnet(port)
2298 if _, ok := va.VnetsByPort.Load(port); !ok {
2299 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2300 }
2301 vpvsIntf, _ := va.VnetsByPort.Load(port)
2302 vpvs := vpvsIntf.([]*VoltPortVnet)
2303 vpvs = append(vpvs, vpv)
2304 va.VnetsByPort.Store(port, vpvs)
2305 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2306
2307 vpv.VpvLock.Lock()
2308 defer vpv.VpvLock.Unlock()
2309
2310 // Add the service that is causing the VNET to be added to the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302311 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05302312
Tinoj Josephec742f62022-09-29 19:11:10 +05302313 if !vs.IsActivated {
2314 logger.Warn(ctx, "Not Checking port state: Service Not activated")
2315 // Process the PORT UP if the port is already up
2316 d, err := va.GetDeviceFromPort(port)
2317 if err == nil {
2318 vpv.setDevice(d.Name)
2319 }
2320 vpv.WriteToDb(cntx)
2321 return vpv
2322 }
2323
Naveen Sampath04696f72022-06-13 15:19:14 +05302324 // Process the PORT UP if the port is already up
2325 d, err := va.GetDeviceFromPort(port)
2326 if err == nil {
2327 vpv.setDevice(d.Name)
2328 p := d.GetPort(port)
2329 if p != nil {
2330
2331 if vs.PonPort != 0xFF && vs.PonPort != p.PonPort {
2332 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})
2333 } else {
2334 logger.Infow(ctx, "Checking UNI port state", log.Fields{"State": p.State})
2335 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302336 vpv.PortUpInd(cntx, d, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302337 }
2338 }
2339 }
2340 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302341 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302342 return vpv
2343}
2344
2345// DelVnetFromPort for deleting vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302346func (va *VoltApplication) DelVnetFromPort(cntx context.Context, port string, vpv *VoltPortVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302347
2348 //Delete DHCP Session
2349 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2350
2351 //Delete PPPoE session
2352 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2353
2354 //Delete Mac from MacPortMap
2355 va.DeleteMacInPortMap(vpv.MacAddr)
2356
2357 //Delete VPV
2358 vpvsIntf, ok := va.VnetsByPort.Load(port)
2359 if !ok {
2360 return
2361 }
2362 vpvs := vpvsIntf.([]*VoltPortVnet)
2363 for i, lvpv := range vpvs {
2364 if lvpv == vpv {
2365 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2366 "UNIVLAN": vpv.UniVlan})
2367
2368 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2369
2370 vpv.DeleteInProgress = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302371 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302372
2373 va.VnetsByPort.Store(port, vpvs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302374 vpv.DelTrapFlows(cntx)
2375 vpv.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302376 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2377 vpv.PendingFlowLock.RLock()
2378 if len(vpv.PendingDeleteFlow) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302379 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302380 }
2381 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302382 vnet.disassociatePortFromVnet(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302383 }
2384 vpv.PendingFlowLock.RUnlock()
2385 return
2386 }
2387 }
2388}
2389
2390// RestoreVnetsFromDb to restore vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302391func (va *VoltApplication) RestoreVnetsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302392 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302393 vnets, _ := db.GetVnets(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302394 for _, net := range vnets {
2395 b, ok := net.Value.([]byte)
2396 if !ok {
2397 logger.Warn(ctx, "The value type is not []byte")
2398 continue
2399 }
2400 var vnet VoltVnet
2401 err := json.Unmarshal(b, &vnet)
2402 if err != nil {
2403 logger.Warn(ctx, "Unmarshal of VNET failed")
2404 continue
2405 }
2406 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302407 if err := va.AddVnet(cntx, vnet.VnetConfig, &vnet.VnetOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302408 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2409 }
2410
2411 if vnet.DeleteInProgress {
2412 va.VnetsToDelete[vnet.Name] = true
2413 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2414 }
2415
2416 }
2417}
2418
2419// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2420// are used as the key to locate the service. If more than one service is on the
2421// same port (essentially a UNI of ONU), the services must be separated by different
2422// CVLANs
2423func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
2424 // Fetch the device first to make sure the device exists
2425 dIntf, ok := va.DevicesDisc.Load(device)
2426 if !ok {
2427 return nil
2428 }
2429 d := dIntf.(*VoltDevice)
2430
2431 // If the port is NNI port, the services dont exist on it. The svc then
2432 // must be obtained from a different context and is not included here
2433 if port == d.NniPort {
2434 return nil
2435 }
2436
2437 //To return the matched service
2438 var service *VoltService
2439
2440 // This is an access port and the port should have all the associated
2441 // services which can be uniquely identified by the VLANs in the packet
2442 vnets, ok := va.VnetsByPort.Load(port)
2443
2444 if !ok {
2445 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2446 return nil
2447 }
2448 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2449 for _, vnet := range vnets.([]*VoltPortVnet) {
2450 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2451 switch vnet.VlanControl {
2452 case ONUCVlanOLTSVlan:
2453 service = vnet.MatchesPriority(priority)
2454 if vnet.MatchesCvlan(vlans) && service != nil {
2455 return service
2456 }
2457 case ONUCVlan,
2458 None:
2459 service = vnet.MatchesPriority(priority)
2460 // In case of DHCP Flow - cvlan == VlanNone
2461 // In case of HSIA Flow - cvlan == Svlan
2462 if len(vlans) == 1 && (vlans[0] == vnet.SVlan || vlans[0] == of.VlanNone) && service != nil {
2463 return service
2464 }
2465 case OLTCVlanOLTSVlan,
2466 OLTSVlan:
2467 service = vnet.MatchesPriority(priority)
2468 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2469 return service
2470 }
2471 default:
2472 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2473 }
2474 }
2475 return nil
2476}
2477
2478// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2479// are used as the key to locate the service. If more than one service is on the
2480// same port (essentially a UNI of ONU), the services must be separated by different
2481// CVLANs
2482func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2483 // Fetch the device first to make sure the device exists
2484 dIntf, ok := va.DevicesDisc.Load(device)
2485 if !ok {
2486 return nil, nil
2487 }
2488 d := dIntf.(*VoltDevice)
2489
2490 // If the port is NNI port, the services dont exist on it. The svc then
2491 // must be obtained from a different context and is not included here
2492 if port == d.NniPort {
2493 return nil, nil
2494 }
2495
2496 //To return the matched service
2497 var service *VoltService
2498
2499 // This is an access port and the port should have all the associated
2500 // services which can be uniquely identified by the VLANs in the packet
2501 if vnets, ok := va.VnetsByPort.Load(port); ok {
2502 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2503 for _, vnet := range vnets.([]*VoltPortVnet) {
2504 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2505 switch vnet.VlanControl {
2506 case ONUCVlanOLTSVlan:
2507 service = vnet.MatchesPriority(priority)
2508 if vnet.MatchesCvlan(vlans) && service != nil {
2509 return vnet, service
2510 }
2511 case ONUCVlan,
2512 None:
2513 service = vnet.MatchesPriority(priority)
2514 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2515 return vnet, service
2516 }
2517 case OLTCVlanOLTSVlan,
2518 OLTSVlan:
2519 service = vnet.MatchesPriority(priority)
2520 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2521 return vnet, service
2522 }
2523 default:
2524 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2525 }
2526 }
2527 }
2528 return nil, nil
2529}
2530
2531// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2532// are used as the key to locate the service. If more than one service is on the
2533// same port (essentially a UNI of ONU), the services must be separated by different
2534// CVLANs
2535func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
2536 vlans := GetVlans(pkt)
2537 priority := GetPriority(pkt)
2538 return va.GetVnetFromFields(device, port, vlans, priority)
2539}
2540
2541// PushDevFlowForVlan to push icmpv6 flows for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302542func (va *VoltApplication) PushDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302543 logger.Infow(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2544 pushflow := func(key interface{}, value interface{}) bool {
2545 device := value.(*VoltDevice)
2546 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302547 logger.Infow(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +05302548 return true
2549 }
2550 if device.State != controller.DeviceStateUP {
2551 logger.Errorw(ctx, "Push Dev Flows Failed - Device state DOWN", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan, "device": device})
2552 return true
2553 }
2554 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2555 logger.Errorw(ctx, "Push Dev Flows Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2556 return true
2557 }
2558
2559 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2560 vnetList := vnetListIntf.(*util.ConcurrentMap)
2561 vnetList.Set(vnet.Name, true)
2562 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2563 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()})
2564 return true
2565 }
2566 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2567 err := ProcessIcmpv6McGroup(device.Name, false)
2568 if err != nil {
2569 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2570 return true
2571 }
2572 if portID, err := va.GetPortID(device.NniPort); err == nil {
2573 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2574 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2575 return true
2576 }
2577
2578 //Pushing ICMPv6 Flow
2579 flow := BuildICMPv6Flow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302580 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302581 if err != nil {
2582 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2583 return true
2584 }
2585 logger.Infow(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
2586
2587 // Pushing ARP Flow
2588 flow = BuildDSArpFlow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302589 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302590 if err != nil {
2591 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2592 return true
2593 }
2594 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2595
2596 vnetList := util.NewConcurrentMap()
2597 vnetList.Set(vnet.Name, true)
2598 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2599 }
2600 return true
2601 }
2602 va.DevicesDisc.Range(pushflow)
2603}
2604
2605// PushDevFlowForDevice to push icmpv6 flows for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302606func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302607 logger.Infow(ctx, "PushDevFlowForDevice", log.Fields{"device": device})
2608
2609 logger.Debugw(ctx, "Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2610 err := ProcessIcmpv6McGroup(device.Name, false)
2611 if err != nil {
2612 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2613 return
2614 }
2615 pushicmpv6 := func(key, value interface{}) bool {
2616 vnet := value.(*VoltVnet)
2617 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2618 vnetList := vnetListIntf.(*util.ConcurrentMap)
2619 vnetList.Set(vnet.Name, true)
2620 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2621 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()})
2622 return true
2623 }
2624 nniPortID, err := va.GetPortID(device.NniPort)
2625 if err != nil {
2626 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2627 }
2628 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2629 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2630 return true
2631 }
2632 flow := BuildICMPv6Flow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302633 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302634 if err != nil {
2635 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2636 return true
2637 }
2638 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2639
2640 flow = BuildDSArpFlow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302641 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302642 if err != nil {
2643 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2644 return true
2645 }
2646 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2647
2648 vnetList := util.NewConcurrentMap()
2649 vnetList.Set(vnet.Name, true)
2650 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2651 return true
2652 }
2653 va.VnetsByName.Range(pushicmpv6)
2654}
2655
2656// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302657func (va *VoltApplication) DeleteDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302658 logger.Infow(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2659 delflows := func(key interface{}, value interface{}) bool {
2660 device := value.(*VoltDevice)
2661
2662 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2663 vnetList := vnetListIntf.(*util.ConcurrentMap)
2664 vnetList.Remove(vnet.Name)
2665 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2666 if vnetList.Length() != 0 {
2667 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()})
2668 return true
2669 }
2670 }
2671 if portID, err := va.GetPortID(device.NniPort); err == nil {
2672 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2673 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2674 return true
2675 }
2676 //Pushing ICMPv6 Flow
2677 flow := BuildICMPv6Flow(portID, vnet)
2678 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302679 err := vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302680 if err != nil {
2681 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2682 return true
2683 }
2684 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2685
2686 //Pushing ARP Flow
2687 flow = BuildDSArpFlow(portID, vnet)
2688 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302689 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302690 if err != nil {
2691 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2692 return true
2693 }
2694 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2695
2696 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2697 }
2698 return true
2699 }
2700 va.DevicesDisc.Range(delflows)
2701}
2702
2703// DeleteDevFlowForDevice to delete icmpv6 flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302704func (va *VoltApplication) DeleteDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302705 logger.Infow(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
2706 delicmpv6 := func(key, value interface{}) bool {
2707 vnet := value.(*VoltVnet)
2708 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2709 vnetList := vnetListIntf.(*util.ConcurrentMap)
2710 vnetList.Remove(vnet.Name)
2711 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2712 if vnetList.Length() != 0 {
2713 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()})
2714 return true
2715 }
2716 } else {
2717 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2718 return true
2719 }
2720 nniPortID, err := va.GetPortID(device.NniPort)
2721 if err != nil {
2722 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2723 }
2724 flow := BuildICMPv6Flow(nniPortID, vnet)
2725 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302726 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302727 if err != nil {
2728 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2729 return true
2730 }
2731
2732 flow = BuildDSArpFlow(nniPortID, vnet)
2733 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302734 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302735 if err != nil {
2736 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2737 return true
2738 }
2739
2740 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2741 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2742 return true
2743 }
2744 va.VnetsByName.Range(delicmpv6)
2745 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2746 err := ProcessIcmpv6McGroup(device.Name, true)
2747 if err != nil {
2748 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2749 return
2750 }
2751}
2752
2753// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302754func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(cntx context.Context, vnet *VoltVnet, deviceSerialNum string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302755 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2756 delflows := func(key interface{}, value interface{}) bool {
2757 device := value.(*VoltDevice)
2758 if device.SerialNum != deviceSerialNum {
2759 return true
2760 }
2761 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2762 vnetList := vnetListIntf.(*util.ConcurrentMap)
2763 vnetList.Remove(vnet.Name)
2764 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2765 if vnetList.Length() != 0 {
2766 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()})
2767 return true
2768 }
2769 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2770 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2771 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2772 // The step will be as follow:
2773 // 1. Deact Service
2774 // 2. Pod Reboot
2775 // 3. Pending Delete Service triggered
2776 // 4. Del Service Ind followed by DelVnet req from NB
2777 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2778 // hence the flow will not be cleared
2779 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2780 return true
2781 }
2782 if portID, err := va.GetPortID(device.NniPort); err == nil {
2783 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2784 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2785 return false
2786 }
2787 flow := BuildICMPv6Flow(portID, vnet)
2788 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302789 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302790 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2791 }
2792 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2793
2794 flow = BuildDSArpFlow(portID, vnet)
2795 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302796 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302797 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2798 }
2799 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2800 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2801 }
2802 return false
2803 }
2804 va.DevicesDisc.Range(delflows)
2805}
2806
2807// BuildICMPv6Flow to Build DS flow for ICMPv6
2808func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302809 logger.Infow(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302810 flow := &of.VoltFlow{}
2811 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2812 subFlow := of.NewVoltSubFlow()
2813
2814 subFlow.SetICMPv6Match()
2815 subFlow.SetMatchVlan(vnet.SVlan)
2816 subFlow.SetInPort(inport)
2817 subFlow.SetPopVlan()
2818 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2819 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2820 subFlow.Priority = of.McFlowPriority
2821 var metadata uint64
2822 if vnet.VlanControl == None {
2823 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2824 } else {
2825 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2826 }
2827 subFlow.SetTableMetadata(metadata)
2828 metadata = uint64(vnet.setPbitRemarking())
2829
2830 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2831 subFlow.SetWriteMetadata(metadata)
2832 flow.SubFlows[subFlow.Cookie] = subFlow
2833 return flow
2834}
2835
2836//BuildDSArpFlow Builds DS flow for ARP
2837func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302838 logger.Infow(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302839
2840 flow := &of.VoltFlow{}
2841 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2842 subFlow := of.NewVoltSubFlow()
2843
2844 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
2845 subFlow.SetArpMatch()
2846 subFlow.SetMatchDstMac(BcastMAC)
2847 subFlow.SetMatchVlan(vnet.SVlan)
2848 subFlow.SetInPort(inport)
2849 subFlow.SetPopVlan()
2850 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2851
2852 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
2853 subFlow.Priority = of.McFlowPriority
2854
2855 var metadata uint64
2856 if vnet.VlanControl == None {
2857 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2858 } else {
2859 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2860 }
2861 subFlow.SetTableMetadata(metadata)
2862 metadata = uint64(vnet.setPbitRemarking())
2863 subFlow.SetWriteMetadata(metadata)
2864
2865 flow.SubFlows[subFlow.Cookie] = subFlow
2866 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2867 return flow
2868}
2869
2870// setPbitRemarking to set Pbit remarking
2871func (vv *VoltVnet) setPbitRemarking() uint32 {
2872
2873 // Remarkable
2874 // Remarked Pbit Pbit
2875 // |-----------------------------| |------|
2876 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
2877 // 000 000 000 000 000 000 000 000 00000000
2878
2879 // Eg:
2880 // For 6:3 & 7:1
2881 // 001 011 000 000 000 000 000 000 11000000
2882
2883 var remarkable uint8
2884 var remarked uint32
2885 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
2886 remarkable = remarkable | 1<<refPbit
2887 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
2888 }
2889 return remarked<<8 | uint32(remarkable)
2890}
2891
2892// ProcessIcmpv6McGroup to add icmpv6 multicast group
2893func ProcessIcmpv6McGroup(device string, delete bool) error {
2894
2895 logger.Info(ctx, "Creating ICMPv6 MC Group")
2896 va := GetApplication()
2897 vd := va.GetDevice(device)
2898 group := &of.Group{}
2899 group.GroupID = ICMPv6ArpGroupID
2900 group.Device = device
2901 if delete {
2902 if !vd.icmpv6GroupAdded {
2903 logger.Info(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
2904 return nil //TODO
2905 }
2906 vd.icmpv6GroupAdded = false
2907 group.Command = of.GroupCommandDel
2908 group.ForceAction = true
2909 } else {
2910 if vd.icmpv6GroupAdded {
2911 logger.Info(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
2912 return nil //TODO
2913 }
2914 vd.icmpv6GroupAdded = true
2915 group.Command = of.GroupCommandAdd
2916 receivers := GetApplication().GetIcmpv6Receivers(device)
2917 group.Buckets = append(group.Buckets, receivers...)
2918 }
2919 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
2920 port, _ := GetApplication().GetNniPort(device)
2921 err := cntlr.GetController().GroupUpdate(port, device, group)
2922 return err
2923}
2924
2925//isVlanMatching - checks is vlans matches with vpv based on vlan control
2926func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
2927
2928 switch vpv.VlanControl {
2929 case ONUCVlanOLTSVlan,
2930 OLTCVlanOLTSVlan:
2931 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
2932 return true
2933 }
2934 case ONUCVlan,
2935 OLTSVlan,
2936 None:
2937 if vpv.SVlan == svlan {
2938 return true
2939 }
2940 default:
2941 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2942 }
2943 return false
2944}
2945
2946//PushFlows - Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302947func (vpv *VoltPortVnet) PushFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302948
2949 for cookie := range flow.SubFlows {
2950 cookie := strconv.FormatUint(cookie, 10)
2951 fe := &FlowEvent{
2952 eType: EventTypeControlFlowAdded,
2953 cookie: cookie,
2954 eventData: vpv,
2955 }
2956 device.RegisterFlowAddEvent(cookie, fe)
2957 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302958 return cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302959}
2960
2961//FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
2962func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
2963
2964 sendFlowFailureInd := func(key, value interface{}) bool {
2965 //svc := value.(*VoltService)
2966 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
2967 return true
2968 }
2969 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2970 vpv.services.Range(sendFlowFailureInd)
2971}
2972
2973//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302974func (vpv *VoltPortVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302975
2976 vpv.PendingFlowLock.Lock()
2977 defer vpv.PendingFlowLock.Unlock()
2978
2979 for cookie := range flow.SubFlows {
2980 cookie := strconv.FormatUint(cookie, 10)
2981 fe := &FlowEvent{
2982 eType: EventTypeControlFlowRemoved,
2983 device: device.Name,
2984 cookie: cookie,
2985 eventData: vpv,
2986 }
2987 device.RegisterFlowDelEvent(cookie, fe)
2988 vpv.PendingDeleteFlow[cookie] = true
2989 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302990 return cntlr.GetController().DelFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302991}
2992
2993//CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302994func (vpv *VoltPortVnet) CheckAndDeleteVpv(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302995 vpv.PendingFlowLock.RLock()
2996 defer vpv.PendingFlowLock.RUnlock()
2997 if !vpv.DeleteInProgress {
2998 return
2999 }
3000 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
3001 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 +05303002 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303003 logger.Infow(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
3004 }
3005}
3006
3007//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303008func (vpv *VoltPortVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303009 vpv.PendingFlowLock.Lock()
3010 logger.Infow(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
3011
3012 delete(vpv.PendingDeleteFlow, cookie)
3013 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303014 vpv.CheckAndDeleteVpv(cntx)
3015 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303016}
3017
3018//FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303019func (vpv *VoltPortVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303020 vpv.PendingFlowLock.Lock()
3021
3022 logger.Errorw(ctx, "VPV Flow Remove Failure Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
3023
3024 sendFlowFailureInd := func(key, value interface{}) bool {
3025 svc := value.(*VoltService)
3026 svc.triggerServiceFailureInd(errorCode, errReason)
3027 return true
3028 }
3029 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3030 vpv.services.Range(sendFlowFailureInd)
3031
3032 if vpv.DeleteInProgress {
3033 delete(vpv.PendingDeleteFlow, cookie)
3034 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303035 vpv.CheckAndDeleteVpv(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303036 } else {
3037 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303038 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303039 }
3040}
3041
3042//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303043func (vv *VoltVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05303044
3045 vv.VnetLock.Lock()
3046 defer vv.VnetLock.Unlock()
3047
3048 var flowMap map[string]bool
3049 var ok bool
3050
3051 for cookie := range flow.SubFlows {
3052 cookie := strconv.FormatUint(cookie, 10)
3053 fe := &FlowEvent{
3054 eType: EventTypeDeviceFlowRemoved,
3055 device: device.Name,
3056 cookie: cookie,
3057 eventData: vv,
3058 }
3059 device.RegisterFlowDelEvent(cookie, fe)
3060 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
3061 flowMap = make(map[string]bool)
3062 }
3063 flowMap[cookie] = true
3064 vv.PendingDeleteFlow[device.Name] = flowMap
3065 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303066 vv.WriteToDb(cntx)
3067 return cntlr.GetController().DelFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05303068}
3069
3070//CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303071func (vv *VoltVnet) CheckAndDeleteVnet(cntx context.Context, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303072 if !vv.DeleteInProgress {
3073 return
3074 }
3075 vv.VnetPortLock.RLock()
3076 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
3077 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
3078 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303079 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05303080 logger.Infow(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
3081 } else {
3082 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
3083 }
3084 vv.VnetPortLock.RUnlock()
3085}
3086
3087//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303088func (vv *VoltVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303089 vv.VnetLock.Lock()
3090 defer vv.VnetLock.Unlock()
3091
3092 logger.Infow(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
3093
3094 if _, ok := vv.PendingDeleteFlow[device]; ok {
3095 delete(vv.PendingDeleteFlow[device], cookie)
3096 }
3097
3098 //Check and update success for pending disable request
3099 if d := GetApplication().GetDevice(device); d != nil {
3100 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3101 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303102 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303103 }
3104 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303105 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303106}
3107
3108//FlowRemoveFailure - Process flow failure indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303109func (vv *VoltVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303110
3111 vv.VnetLock.Lock()
3112 defer vv.VnetLock.Unlock()
3113
3114 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3115 if _, ok := flowMap[cookie]; ok {
3116 logger.Errorw(ctx, "Device Flow Remove Failure Notification", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
3117
3118 if vv.DeleteInProgress {
3119 delete(vv.PendingDeleteFlow[device], cookie)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303120 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303121 }
3122 return
3123 }
3124 }
3125 logger.Errorw(ctx, "Device Flow Remove Failure Notification for Unknown cookie", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3126}
3127
3128//IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
3129func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
3130
3131 //Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3132 //When multiple Igmp-suported service enabled, comment "return false"
3133
3134 sendFlowFailureInd := func(key, value interface{}) bool {
3135 svc := value.(*VoltService)
3136 if svc.IgmpEnabled {
3137 svc.triggerServiceFailureInd(errorCode, errReason)
3138 return false
3139 }
3140 return true
3141 }
3142 logger.Errorw(ctx, "US IGMP Flow Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3143 vpv.services.Range(sendFlowFailureInd)
3144}
3145
3146// GetMatchingMcastService to get matching multicast service
3147func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
3148
3149 var service *VoltService
3150 dIntf, ok := va.DevicesDisc.Load(device)
3151 if !ok {
3152 return nil
3153 }
3154 d := dIntf.(*VoltDevice)
3155
3156 // If the port is NNI port, the services dont exist on it. The svc then
3157 // must be obtained from a different context and is not included here
3158 if port == d.NniPort {
3159 return nil
3160 }
3161
3162 // This is an access port and the port should have all the associated
3163 // services which can be uniquely identified by the VLANs in the packet
3164 vnets, ok := va.VnetsByPort.Load(port)
3165
3166 if !ok {
3167 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3168 return nil
3169 }
3170 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3171 getMcastService := func(key, value interface{}) bool {
3172 srv := value.(*VoltService)
3173 if srv.IgmpEnabled {
3174 service = srv
3175
3176 //TODO: Current implementation supports only for single service with Igmp Enabled
3177 //FIX-ME: When multiple service suports Igmp, update of logic required
3178 return false
3179 }
3180 return true
3181 }
3182
3183 for _, vpv := range vnets.([]*VoltPortVnet) {
3184 if vpv.CVlan == cvlan {
3185 vpv.services.Range(getMcastService)
3186 if service != nil {
3187 break
3188 }
3189 }
3190 }
3191 return service
3192}
3193
3194//TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303195func (vv *VoltVnet) TriggerAssociatedFlowDelete(cntx context.Context, device string) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05303196 vv.VnetLock.Lock()
3197 cookieList := []uint64{}
3198 flowMap := vv.PendingDeleteFlow[device]
3199
3200 for cookie := range flowMap {
3201 cookieList = append(cookieList, convertToUInt64(cookie))
3202 }
3203 vv.VnetLock.Unlock()
3204
3205 if len(cookieList) == 0 {
3206 return false
3207 }
3208
3209 for _, cookie := range cookieList {
3210 if vd := GetApplication().GetDevice(device); vd != nil {
3211 flow := &of.VoltFlow{}
3212 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3213 subFlow := of.NewVoltSubFlow()
3214 subFlow.Cookie = cookie
3215 flow.SubFlows[cookie] = subFlow
3216 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303217 if err := vv.RemoveFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05303218 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3219 }
3220 }
3221 }
3222 return true
3223}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303224
3225// JsonMarshal wrapper function for json Marshal VoltVnet
3226func (vv *VoltVnet) JsonMarshal() ([]byte, error) {
3227 return json.Marshal(VoltVnet{
3228 VnetConfig: vv.VnetConfig,
3229 Version: vv.Version,
3230 VnetOper: VnetOper{
3231 PendingDeleteFlow: vv.VnetOper.PendingDeleteFlow,
3232 DeleteInProgress: vv.VnetOper.DeleteInProgress,
3233 PendingDeviceToDelete: vv.VnetOper.PendingDeviceToDelete,
3234 },
3235 })
3236}
3237
3238// JsonMarshal wrapper function for json Marshal VoltPortVnet
3239func (vpv *VoltPortVnet) JsonMarshal() ([]byte, error) {
3240 return json.Marshal(VoltPortVnet{
3241 Device: vpv.Device,
3242 Port: vpv.Port,
3243 PonPort: vpv.PonPort,
3244 VnetName: vpv.VnetName,
3245 SVlan: vpv.SVlan,
3246 CVlan: vpv.CVlan,
3247 UniVlan: vpv.UniVlan,
3248 SVlanTpid: vpv.SVlanTpid,
3249 DhcpRelay: vpv.DhcpRelay,
3250 ArpRelay: vpv.ArpRelay,
3251 PppoeIa: vpv.PppoeIa,
3252 MacLearning: vpv.MacLearning,
3253 DhcpStatus: vpv.DhcpStatus,
3254 DhcpExpiryTime: vpv.DhcpExpiryTime,
3255 Dhcp6ExpiryTime: vpv.Dhcp6ExpiryTime,
3256 FlowsApplied: vpv.FlowsApplied,
3257 Ipv4Addr: vpv.Ipv4Addr,
3258 Ipv6Addr: vpv.Ipv6Addr,
3259 MacAddr: vpv.MacAddr,
3260 LearntMacAddr: vpv.LearntMacAddr,
3261 CircuitID: vpv.CircuitID,
3262 RemoteID: vpv.RemoteID,
3263 IsOption82Disabled: vpv.IsOption82Disabled,
3264 RelayState: vpv.RelayState,
3265 PPPoeState: vpv.PPPoeState,
3266 RelayStatev6: vpv.RelayStatev6,
3267 IgmpEnabled: vpv.IgmpEnabled,
3268 IgmpFlowsApplied: vpv.IgmpFlowsApplied,
3269 McastService: vpv.McastService,
3270 ONTEtherTypeClassification: vpv.ONTEtherTypeClassification,
3271 VlanControl: vpv.VlanControl,
3272 MvlanProfileName: vpv.MvlanProfileName,
3273 Version: vpv.Version,
3274 McastTechProfileID: vpv.McastTechProfileID,
3275 McastPbit: vpv.McastPbit,
3276 McastUsMeterID: vpv.McastUsMeterID,
3277 AllowTransparent: vpv.AllowTransparent,
3278 SchedID: vpv.SchedID,
3279 DHCPv6DUID: vpv.DHCPv6DUID,
3280 PendingDeleteFlow: vpv.PendingDeleteFlow,
3281 DeleteInProgress: vpv.DeleteInProgress,
3282 Blocked: vpv.Blocked,
3283 DhcpPbit: vpv.DhcpPbit,
3284 })
3285}
Tinoj Josephec742f62022-09-29 19:11:10 +05303286
3287func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) bool {
3288 isActivated := false
3289 vpv.services.Range(func(key, value interface{}) bool {
3290 svc := value.(*VoltService)
3291 if svc.IsActivated {
3292 logger.Infow(ctx, "Found activated service on the vpv", log.Fields{"Name": svc.Name})
3293 isActivated = true
3294 return false //to exit loop
3295 }
3296 return true
3297 })
3298 return isActivated
3299}