blob: 548879ff54c37a9dccce6e32037670fddaa258a6 [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 (
Akash Sonia8246972023-01-03 10:37:08 +053019 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053020 "encoding/json"
21 "errors"
22 "net"
Naveen Sampath04696f72022-06-13 15:19:14 +053023 "strconv"
24 "sync"
25 "time"
26
Akash Sonia8246972023-01-03 10:37:08 +053027 //errorCodes "voltha-go-controller/internal/pkg/errorcodes"
28
Naveen Sampath04696f72022-06-13 15:19:14 +053029 "github.com/google/gopacket"
30 "github.com/google/gopacket/layers"
31 "go.uber.org/atomic"
32
Akash Sonia8246972023-01-03 10:37:08 +053033 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053034 "voltha-go-controller/internal/pkg/controller"
35 cntlr "voltha-go-controller/internal/pkg/controller"
Akash Sonia8246972023-01-03 10:37:08 +053036
37 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053038 "voltha-go-controller/internal/pkg/of"
39 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053040 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053041)
42
43const (
44 // ICMPv6ArpGroupID constant
45 ICMPv6ArpGroupID uint32 = 1
46
47 // Radisys vendor id constant
48 Radisys string = "Radisys"
Tinoj Joseph50d722c2022-12-06 22:53:22 +053049
50 // DPU_MGMT_TRAFFIC serviceType, vnetType constant
51 DPU_MGMT_TRAFFIC string = "DPU_MGMT_TRAFFIC"
52
53 // DPU_ANCP_TRAFFIC serviceType, vnetType constant
54 DPU_ANCP_TRAFFIC string = "DPU_ANCP_TRAFFIC"
55
56 // FTTB_SUBSCRIBER_TRAFFIC serviceType, vnetType constant
57 FTTB_SUBSCRIBER_TRAFFIC string = "FTTB_SUBSCRIBER_TRAFFIC"
Naveen Sampath04696f72022-06-13 15:19:14 +053058)
59
60var (
61 //BroadcastMAC - Broadcast MAC Address
62 BroadcastMAC, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")
63)
64
65// NonZeroMacAddress utility to identify if the MAC address is non-zero.
66// We use zero MAC address as an unset MAC address
67func NonZeroMacAddress(h net.HardwareAddr) bool {
68 for i := 0; i < 6; i++ {
69 if h[i] != 0 {
70 return true
71 }
72 }
73 return false
74}
75
76// VNET package manages the different virtual networks that are part of the
77// the network. In the case of VOLT, the networks can be single tagged or
78// double tagged networks. In addition, the networks may be used for unicast
79// and multicast traffic. The unicast traffic further has two models, the
80// 1:1 and N:1 model. In case of a 1:1 model, the outer tag is same for many
81// subscribers and the inner tag is unique to each subscriber for the same
82// outer tag. The N:1 uses the same inner and outer tags, or for that matter
83// a single tag that can also be shared by subscribers. The VNET implementation
84// manages all these possibilities and the associated configuration.
85
86const (
87 // PbitMatchNone constant
88 PbitMatchNone of.PbitType = 8
89 // PbitMatchAll constant
90 PbitMatchAll of.PbitType = 0xFF
91)
92
93// SVlan - Value of the outer tag if double tagged or the only tag if single
94// tagged
95// SVlanTpid - SVlan Tag Protocol Identifier
96// CVlan - Value of the inner tag. Set to VlanNone if single tagged
97// DhcpRelay - Set to true if the DHCP relay is enabled on the virtual network
98// MacLearning - Set to true if the flows should include MAC address
99// UsDhcpPbit - The pbit used for US DHCP packets
100// DsDhcpPbit - The pbit used for DS DHCP packets
101
102// VnetConfig structure
103type VnetConfig struct {
104 Name string
105 SVlan of.VlanType
106 CVlan of.VlanType
107 UniVlan of.VlanType
108 SVlanTpid layers.EthernetType
109 DhcpRelay bool
110 ArpLearning bool
111 MacLearning MacLearningType
112 PppoeIa bool
113 ONTEtherTypeClassification int
114 VlanControl VlanControl
115 Encapsulation string
116 UsDhcpPbit []of.PbitType
117 DsDhcpPbit []of.PbitType
118 UsIGMPPbit []of.PbitType
119 DsIGMPPbit []of.PbitType
120 DevicesList []string //List of serial number of devices on which this vnet is applied
121 AllowTransparent bool
122 CtrlPktPbitRemark map[of.PbitType]of.PbitType
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530123 UsPonCTagPriority of.PbitType
124 UsPonSTagPriority of.PbitType
125 DsPonCTagPriority of.PbitType
126 DsPonSTagPriority of.PbitType
127 VnetType string
Naveen Sampath04696f72022-06-13 15:19:14 +0530128}
129
130// VnetOper structure
131type VnetOper struct {
132 PendingDeleteFlow map[string]map[string]bool
133 DeleteInProgress bool
134 PendingDeviceToDelete string
135 VnetLock sync.RWMutex `json:"-"`
136 VnetPortLock sync.RWMutex `json:"-"`
137 AssociatedPorts map[string]bool `json:"-"`
138}
139
140// VoltVnet sructure
141type VoltVnet struct {
142 VnetConfig
143 VnetOper
144 Version string
145}
146
147const (
148 // EncapsulationPPPoEIA constant
149 EncapsulationPPPoEIA string = "PPPoE-IA"
150 // EncapsulationPPPoE constant
151 EncapsulationPPPoE string = "PPPoE"
152 // EncapsulationIPoE constant
153 EncapsulationIPoE string = "IPoE"
154)
155
156// NewVoltVnet is constructor for the VNET structure
157func NewVoltVnet(cfg VnetConfig) *VoltVnet {
158 var vv VoltVnet
159 vv.VnetConfig = cfg
160 if vv.PendingDeleteFlow == nil {
161 vv.PendingDeleteFlow = make(map[string]map[string]bool)
162 }
163 vv.DeleteInProgress = false
164 if cfg.Encapsulation == EncapsulationPPPoEIA {
165 vv.PppoeIa = true
166 }
167 vv.AssociatedPorts = make(map[string]bool)
168 return &vv
169}
170
171//associatePortToVnet - associate a port to Vnet
172func (vv *VoltVnet) associatePortToVnet(port string) {
173 vv.VnetPortLock.Lock()
174 if vv.AssociatedPorts == nil {
175 vv.AssociatedPorts = make(map[string]bool)
176 }
177 vv.AssociatedPorts[port] = true
178 vv.VnetPortLock.Unlock()
179}
180
181//disassociatePortFromVnet - disassociate a port from Vnet and return true if the association map is empty
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530182func (vv *VoltVnet) disassociatePortFromVnet(cntx context.Context, device string, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530183 vv.VnetPortLock.Lock()
184 delete(vv.AssociatedPorts, port)
185 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})
186 vv.VnetPortLock.Unlock()
187
188 if vv.DeleteInProgress {
189 if !vv.isAssociatedPortsPresent() {
190 if len(vv.PendingDeleteFlow[device]) == 0 {
191 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vv.Name})
192 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530193 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530194 } else {
195 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow})
196 }
197 } else {
198 vv.VnetPortLock.RLock()
199 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts})
200 vv.VnetPortLock.RUnlock()
201 }
202 }
203}
204
205func (vv *VoltVnet) isAssociatedPortsPresent() bool {
206 vv.VnetPortLock.RLock()
207 defer vv.VnetPortLock.RUnlock()
208 return len(vv.AssociatedPorts) != 0
209}
210
211// WriteToDb commit the VNET to the database
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530212func (vv *VoltVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530213
214 if vv.DeleteInProgress {
215 logger.Warnw(ctx, "Skipping Redis Update for Vnet, Vnet delete in progress", log.Fields{"Vnet": vv.Name})
216 return
217 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530218 vv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530219}
220
221//ForceWriteToDb force commit a vnet to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530222func (vv *VoltVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530223 vv.VnetPortLock.RLock()
224 defer vv.VnetPortLock.RUnlock()
225 vv.Version = database.PresentVersionMap[database.VnetPath]
226 logger.Debugw(ctx, "Updating VNET....", log.Fields{"vnet": vv})
227 if b, err := json.Marshal(vv); err == nil {
Akash Sonia8246972023-01-03 10:37:08 +0530228 if err := db.PutVnet(cntx, vv.Name, string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530229 logger.Warnw(ctx, "Add Vnet to DB failed", log.Fields{"vnet name": vv.Name, "Error": err})
230 }
231 }
232}
233
234// VnetKey creates the key using the two VLAN tags
235// We append the two VLAN tags to create a single key
236func VnetKey(otag of.VlanType, itag of.VlanType, utag of.VlanType) string {
237 return strconv.Itoa(int(otag)) + "-" + strconv.Itoa(int(itag)) + "-" + strconv.Itoa(int(utag))
238}
239
240// GetVnet get VNET configuration related functionality associated with VOLT application
241func (va *VoltApplication) GetVnet(otag of.VlanType, itag of.VlanType, utag of.VlanType) *VoltVnet {
242 // When matching VNET, it is expected to match first just the outer
243 // tag, and then the combination to make sure there is no conflict
244 // for the new configuration.
245 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, of.VlanNone, utag)); ok {
246 return vnet.(*VoltVnet)
247 }
248 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, itag, utag)); ok {
249 return vnet.(*VoltVnet)
250 }
251 return nil
252}
253
254// The VNET may also be assigned name for easier references. For now,
255// the VNET is mainly identified by the two VLANs.
256
257// GetVnetByName to get vnet by name
258func (va *VoltApplication) GetVnetByName(name string) *VoltVnet {
259 if vnet, ok := va.VnetsByName.Load(name); ok {
260 return vnet.(*VoltVnet)
261 }
262 return nil
263}
264
265// storeVnetConfig to store vnet config
266func (va *VoltApplication) storeVnetConfig(cfg VnetConfig, vv *VoltVnet) {
267
268 var vnetMap *util.ConcurrentMap
269
270 va.VnetsByTag.Store(VnetKey(cfg.SVlan, cfg.CVlan, cfg.UniVlan), vv)
271 va.VnetsByName.Store(cfg.Name, vv)
272
273 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vv.SVlan); !ok {
274 vnetMap = util.NewConcurrentMap()
275 } else {
276 vnetMap = vnetMapIntf.(*util.ConcurrentMap)
277 }
278 vnetMap.Set(vv, true)
279 va.VnetsBySvlan.Set(vv.SVlan, vnetMap)
280}
281
282// deleteVnetConfig to delete vnet config
283func (va *VoltApplication) deleteVnetConfig(vnet *VoltVnet) {
284 va.VnetsByTag.Delete(VnetKey(vnet.SVlan, vnet.CVlan, vnet.UniVlan))
285 va.VnetsByName.Delete(vnet.Name)
286
287 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vnet.SVlan); ok {
288 vnetMap := vnetMapIntf.(*util.ConcurrentMap)
289 vnetMap.Remove(vnet)
290 va.VnetsBySvlan.Set(vnet.SVlan, vnetMap)
291 }
292}
293
294// AddVnet to add a VNET to the list of VNETs configured.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530295func (va *VoltApplication) AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530296
297 AppMutex.VnetMutex.Lock()
298 var vv *VoltVnet
299 devicesToHandle := []string{}
300 vv = va.GetVnetByName(cfg.Name)
301 if vv != nil {
302 //Could be for another OLT or could be case of backup-restore
303 for _, serialNum := range cfg.DevicesList {
304 if isDeviceInList(serialNum, vv.DevicesList) {
305 //This is backup restore scenario, just update the profile
306 logger.Info(ctx, "Add Vnet : Profile Name already exists with OLT, update-the-profile")
307 continue
308 }
309 devicesToHandle = append(devicesToHandle, serialNum)
310 }
311 if len(devicesToHandle) == 0 {
Tinoj Joseph1d108322022-07-13 10:07:39 +0530312 logger.Debugw(ctx, "Ignoring Duplicate VNET by name ", log.Fields{"Vnet": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530313 AppMutex.VnetMutex.Unlock()
314 return nil
315 }
316 }
317
318 if vv == nil {
319 vv = NewVoltVnet(cfg)
320 if oper != nil {
321 vv.PendingDeleteFlow = oper.PendingDeleteFlow
322 vv.DeleteInProgress = oper.DeleteInProgress
323 vv.AssociatedPorts = oper.AssociatedPorts
324 vv.PendingDeviceToDelete = oper.PendingDeviceToDelete
325 }
326 devicesToHandle = append(devicesToHandle, cfg.DevicesList...)
327 } else {
328 vv.DevicesList = append(vv.DevicesList, devicesToHandle...)
329 }
330
331 va.storeVnetConfig(cfg, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530332 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530333
334 logger.Infow(ctx, "Added VNET TO DB", log.Fields{"cfg": cfg, "devicesToHandle": devicesToHandle})
335
336 //va.PushDevFlowForVlan(vv)
337 AppMutex.VnetMutex.Unlock()
338 return nil
339}
340
341// DelVnet to delete a VNET from the list of VNETs configured
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530342func (va *VoltApplication) DelVnet(cntx context.Context, name, deviceSerialNum string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530343 logger.Infow(ctx, "Deleting Vnet", log.Fields{"Vnet": name})
344 AppMutex.VnetMutex.Lock()
345 if vnetIntf, ok := va.VnetsByName.Load(name); ok {
346 vnet := vnetIntf.(*VoltVnet)
347 //Delete from mvp list
348 vnet.DevicesList = util.RemoveFromSlice(vnet.DevicesList, deviceSerialNum)
349
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530350 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, deviceSerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +0530351 if len(vnet.DevicesList) == 0 {
352 vnet.DeleteInProgress = true
353 vnet.PendingDeviceToDelete = deviceSerialNum
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530354 vnet.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530355 vnet.VnetPortLock.RLock()
356 if len(vnet.PendingDeleteFlow) == 0 && !vnet.isAssociatedPortsPresent() {
357 logger.Warnw(ctx, "Deleting Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
358 va.deleteVnetConfig(vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530359 _ = db.DelVnet(cntx, vnet.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530360 } else {
361 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
362 }
363 vnet.VnetPortLock.RUnlock()
364 } else {
365 //Update the devicelist in db
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530366 vnet.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530367 }
368 }
369 //TODO: if no vnets are present on device remove icmpv6 group from device
370 AppMutex.VnetMutex.Unlock()
371 return nil
372}
373
374// UpdateVnet to update the VNET with associated service count
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530375func (va *VoltApplication) UpdateVnet(cntx context.Context, vv *VoltVnet) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530376 va.storeVnetConfig(vv.VnetConfig, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530377 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530378 logger.Infow(ctx, "Updated VNET TO DB", log.Fields{"vv": vv.VnetConfig})
379 return nil
380}
381
382// ------------------------------------------------------------
383// Manifestation of a VNET on a port is handled below
384// ------------------------------------------------------------
385//
386// The VNET on a port handles everything that is done for a VNET
387// such as DHCP relay state machine, MAC addresses, IP addresses
388// learnt, so on.
389
390// DhcpStatus type
391type DhcpStatus uint8
392
393const (
394 // DhcpStatusNone constant
395 DhcpStatusNone DhcpStatus = 0
396 // DhcpStatusAcked constant
397 DhcpStatusAcked DhcpStatus = 1
398 // DhcpStatusNacked constant
399 DhcpStatusNacked DhcpStatus = 2
400 // EthTypeNone constant
401 EthTypeNone int = 0
402 // EthTypeIPoE constant
403 EthTypeIPoE int = 1
404 // EthTypePPPoE constant
405 EthTypePPPoE int = 2
406)
407
408// VoltPortVnet structure
409type VoltPortVnet struct {
410 Device string
411 Port string
412 PonPort uint32
413 VnetName string
414 SVlan of.VlanType
415 CVlan of.VlanType
416 UniVlan of.VlanType
417 SVlanTpid layers.EthernetType
418 DhcpRelay bool
419 ArpRelay bool
420 PppoeIa bool
421 MacLearning MacLearningType
422 DhcpStatus DhcpStatus
423 DhcpExpiryTime time.Time
424 Dhcp6ExpiryTime time.Time
425 FlowsApplied bool
426 services sync.Map
427 servicesCount *atomic.Uint64
428 Ipv4Addr net.IP
429 Ipv6Addr net.IP
430 MacAddr net.HardwareAddr
431 LearntMacAddr net.HardwareAddr
432 CircuitID []byte //Will not be used
433 RemoteID []byte //Will not be used
434 IsOption82Disabled bool //Will not be used
435 RelayState DhcpRelayState
436 PPPoeState PppoeIaState
437 RelayStatev6 Dhcpv6RelayState
438 IgmpEnabled bool
439 IgmpFlowsApplied bool
440 McastService bool
441 ONTEtherTypeClassification int
442 VlanControl VlanControl
443 MvlanProfileName string
444 Version string
445 McastTechProfileID uint16
446 McastPbit of.PbitType
447 McastUsMeterID uint32
448 AllowTransparent bool
449 VpvLock sync.Mutex `json:"-"`
450 SchedID int
451 DHCPv6DUID [MaxLenDhcpv6DUID]byte
452 PendingFlowLock sync.RWMutex `json:"-"`
453 PendingDeleteFlow map[string]bool
454 DeleteInProgress bool
455 Blocked bool
456 DhcpPbit of.PbitType
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530457 UsPonCTagPriority of.PbitType
458 UsPonSTagPriority of.PbitType
459 DsPonCTagPriority of.PbitType
460 DsPonSTagPriority of.PbitType
461 VnetType string
Naveen Sampath04696f72022-06-13 15:19:14 +0530462}
463
464//VlanControl vlan control type
465type VlanControl uint8
466
467const (
468 // None constant
469 // ONU and OLT will passthrough UNIVLAN as is to BNG
470 None VlanControl = iota
471
472 // ONUCVlanOLTSVlan constant
473 // Tagged traffic, ONU will replace UNIVLAN with CVLAN and OLT will add SVLAN
474 // Untagged traffic, ONU will add CVLAN and OLT will add SVLAN
475 ONUCVlanOLTSVlan
476
477 // OLTCVlanOLTSVlan constant
478 // Tagged traffic, ONU will passthrough UNIVLAN as is to OLT and
479 // OLT will replace UNIVLAN with CVLAN and add SVLAN
480 OLTCVlanOLTSVlan
481
482 // ONUCVlan constant
483 // Tagged traffic, ONU will replace UNIVLAN with CVLAN
484 // Untagged traffic, ONU will add CVLAN
485 ONUCVlan
486
487 // OLTSVlan constant
488 // UnTagged traffic, OLT will add the SVLAN
489 OLTSVlan
490)
491
492// NewVoltPortVnet is constructor for VoltPortVnet
493func NewVoltPortVnet(vnet *VoltVnet) *VoltPortVnet {
494 var vpv VoltPortVnet
495
496 vpv.VnetName = vnet.Name
497 vpv.SVlan = vnet.SVlan
498 vpv.CVlan = vnet.CVlan
499 vpv.UniVlan = vnet.UniVlan
500 vpv.SVlanTpid = vnet.SVlanTpid
501 vpv.DhcpRelay = vnet.DhcpRelay
502 vpv.DhcpStatus = DhcpStatusNone
503 vpv.PPPoeState = PppoeIaStateNone
504 vpv.ArpRelay = vnet.ArpLearning
505 vpv.PppoeIa = vnet.PppoeIa
506 vpv.VlanControl = vnet.VlanControl
507 vpv.ONTEtherTypeClassification = vnet.ONTEtherTypeClassification
508 vpv.AllowTransparent = vnet.AllowTransparent
509 vpv.FlowsApplied = false
510 vpv.IgmpEnabled = false
511 vpv.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
512 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Naveen Sampath04696f72022-06-13 15:19:14 +0530513 vpv.servicesCount = atomic.NewUint64(0)
514 vpv.SchedID = 0
515 vpv.PendingDeleteFlow = make(map[string]bool)
516 vpv.DhcpPbit = vnet.UsDhcpPbit[0]
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530517 vpv.UsPonCTagPriority = vnet.UsPonCTagPriority
518 vpv.UsPonSTagPriority = vnet.UsPonSTagPriority
519 vpv.DsPonCTagPriority = vnet.UsPonCTagPriority
520 vpv.DsPonSTagPriority = vnet.UsPonSTagPriority
521
522 vpv.VnetType = vnet.VnetType
Naveen Sampath04696f72022-06-13 15:19:14 +0530523 return &vpv
524}
525
526func (vpv *VoltPortVnet) setDevice(device string) {
527
528 if vpv.Device != device && vpv.Device != "" {
529 GetApplication().DisassociateVpvsFromDevice(device, vpv)
530 //TEMP:
531 vpv.printAssociatedVPVs(false)
532 }
533
Tinoj Josephec742f62022-09-29 19:11:10 +0530534 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": device, "Port": vpv.Port, "SVlan": vpv.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530535
536 vpv.Device = device
537 GetApplication().AssociateVpvsToDevice(device, vpv)
538 //TEMP:
539 vpv.printAssociatedVPVs(true)
540}
541
542//TODO - Nav - Temp
543func (vpv *VoltPortVnet) printAssociatedVPVs(add bool) {
544 logger.Infow(ctx, "Start----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
545 if vMap := GetApplication().GetAssociatedVpvsForDevice(vpv.Device, vpv.SVlan); vMap != nil {
546 vMap.Range(func(key, value interface{}) bool {
547 vpvEntry := key.(*VoltPortVnet)
548 logger.Infow(ctx, "Associated VPVs", log.Fields{"SVlan": vpvEntry.SVlan, "CVlan": vpvEntry.CVlan, "UniVlan": vpvEntry.UniVlan})
549 return true
550 })
551 }
552 logger.Infow(ctx, "End----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
553
554}
555
556// GetCircuitID : The interface to be satisfied by the VoltPortVnet to be a DHCP relay
557// session is implemented below. The main functions still remain in
558// the service.go file.
559func (vpv *VoltPortVnet) GetCircuitID() []byte {
560 return []byte(vpv.CircuitID)
561}
562
563// GetRemoteID to get remote id
564func (vpv *VoltPortVnet) GetRemoteID() []byte {
565 return []byte(vpv.RemoteID)
566}
567
568// GetDhcpState to get dhcp state
569func (vpv *VoltPortVnet) GetDhcpState() DhcpRelayState {
570 return vpv.RelayState
571}
572
573// SetDhcpState to set the dhcp state
574func (vpv *VoltPortVnet) SetDhcpState(state DhcpRelayState) {
575 vpv.RelayState = state
576}
577
578// GetPppoeIaState to get pppoeia state
579func (vpv *VoltPortVnet) GetPppoeIaState() PppoeIaState {
580 return vpv.PPPoeState
581}
582
583// SetPppoeIaState to set pppoeia state
584func (vpv *VoltPortVnet) SetPppoeIaState(state PppoeIaState) {
585 vpv.PPPoeState = state
586}
587
588// GetDhcpv6State to get dhcpv6 state
589func (vpv *VoltPortVnet) GetDhcpv6State() Dhcpv6RelayState {
590 return vpv.RelayStatev6
591}
592
593// SetDhcpv6State to set dhcpv6 state
594func (vpv *VoltPortVnet) SetDhcpv6State(state Dhcpv6RelayState) {
595 vpv.RelayStatev6 = state
596}
597
598// DhcpResultInd for dhcp result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530599func (vpv *VoltPortVnet) DhcpResultInd(cntx context.Context, res *layers.DHCPv4) {
600 vpv.ProcessDhcpResult(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530601}
602
603// Dhcpv6ResultInd for dhcpv6 result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530604func (vpv *VoltPortVnet) Dhcpv6ResultInd(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
605 vpv.ProcessDhcpv6Result(cntx, ipv6Addr, leaseTime)
Naveen Sampath04696f72022-06-13 15:19:14 +0530606}
607
608// GetNniVlans to get nni vlans
609func (vpv *VoltPortVnet) GetNniVlans() (uint16, uint16) {
610 switch vpv.VlanControl {
611 case ONUCVlanOLTSVlan,
612 OLTCVlanOLTSVlan:
613 return uint16(vpv.SVlan), uint16(vpv.CVlan)
614 case ONUCVlan,
615 None:
616 return uint16(vpv.SVlan), uint16(of.VlanNone)
617 case OLTSVlan:
618 return uint16(vpv.SVlan), uint16(of.VlanNone)
619 }
620 return uint16(of.VlanNone), uint16(of.VlanNone)
621}
622
623// GetService to get service
624func (vpv *VoltPortVnet) GetService(name string) (*VoltService, bool) {
625 service, ok := vpv.services.Load(name)
626 if ok {
627 return service.(*VoltService), ok
628 }
629 return nil, ok
630}
631
632// AddService to add service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530633func (vpv *VoltPortVnet) AddService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530634 vpv.services.Store(service.Name, service)
635 vpv.servicesCount.Inc()
636 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()})
637}
638
639// DelService to delete service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530640func (vpv *VoltPortVnet) DelService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530641 vpv.services.Delete(service.Name)
642 vpv.servicesCount.Dec()
643
644 // If the only Igmp Enabled service is removed, remove the Igmp trap flow along with it
645 if service.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530646 if err := vpv.DelIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530647 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530648 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
649 }
650
651 vpv.IgmpEnabled = false
652 }
653 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()})
654}
655
656// ProcessDhcpResult to process dhcp results
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530657func (vpv *VoltPortVnet) ProcessDhcpResult(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530658 msgType := DhcpMsgType(res)
659 if msgType == layers.DHCPMsgTypeAck {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530660 vpv.ProcessDhcpSuccess(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530661 } else if msgType == layers.DHCPMsgTypeNak {
662 vpv.DhcpStatus = DhcpStatusNacked
663 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530664 vpv.WriteToDb(cntx)
665}
666
667// RangeOnServices to call a function on all services on the vpv
668func (vpv *VoltPortVnet) RangeOnServices(cntx context.Context, callback func(cntx context.Context, key, value interface{}) bool) {
669 vpv.services.Range(func(key, value interface{}) bool {
670 return callback(cntx, key, value)
671 })
Naveen Sampath04696f72022-06-13 15:19:14 +0530672}
673
674// ProcessDhcpSuccess : Learn the IPv4 address allocated to the services and update the
675// the services with the same. This also calls for adding flows
676// for the services as the DHCP procedure is completed
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530677func (vpv *VoltPortVnet) ProcessDhcpSuccess(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530678 vpv.DhcpStatus = DhcpStatusAcked
679 vpv.Ipv4Addr, _ = GetIpv4Addr(res)
680 logger.Infow(ctx, "Received IPv4 Address", log.Fields{"IP Address": vpv.Ipv4Addr.String()})
681 logger.Infow(ctx, "Services Configured", log.Fields{"Count": vpv.servicesCount.Load()})
682
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530683 vpv.RangeOnServices(cntx, vpv.updateIPv4AndProvisionFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530684 vpv.ProcessDhcpv4Options(res)
685}
686
687// ProcessDhcpv4Options : Currently we process lease time and store the validity of the
688// IP address allocated.
689func (vpv *VoltPortVnet) ProcessDhcpv4Options(res *layers.DHCPv4) {
690 for _, o := range res.Options {
691 switch o.Type {
692 case layers.DHCPOptLeaseTime:
693 leasetime := GetIPv4LeaseTime(o)
694 vpv.DhcpExpiryTime = time.Now().Add((time.Duration(leasetime) * time.Second))
695 logger.Infow(ctx, "Lease Expiry Set", log.Fields{"Time": vpv.DhcpExpiryTime})
696 }
697 }
698}
699
700// ProcessDhcpv6Result : Read the IPv6 address allocated to the device and store it on the
701// VNET. The same IPv6 address is also passed to the services. When a
702// service is fetched all the associated information such as MAC address,
703// IPv4 address and IPv6 addresses can be provided.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530704func (vpv *VoltPortVnet) ProcessDhcpv6Result(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530705 // TODO: Status based hanlding of flows
706 vpv.Dhcp6ExpiryTime = time.Now().Add((time.Duration(leaseTime) * time.Second))
707 vpv.Ipv6Addr = ipv6Addr
708
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530709 vpv.RangeOnServices(cntx, vpv.updateIPv6AndProvisionFlows)
710 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530711}
712
713// AddSvcUsMeterToDevice to add service upstream meter info to device
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530714func AddSvcUsMeterToDevice(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +0530715 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +0530716 logger.Infow(ctx, "Adding upstream meter profile to device", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530717 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
718 GetApplication().AddMeterToDevice(svc.Port, device.Name, svc.UsMeterID, 0)
719 return true
720 }
721 logger.Errorw(ctx, "Dropping US Meter request: Device not found", log.Fields{"Service": svc})
722 return false
723}
724
725// PushFlowsForPortVnet - triggers flow construction and push for provided VPV
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530726func (vpv *VoltPortVnet) PushFlowsForPortVnet(cntx context.Context, d *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530727
728 vp := d.GetPort(vpv.Port)
729
730 //Ignore if UNI port is not found or not UP
731 if vp == nil || vp.State != PortStateUp {
732 logger.Warnw(ctx, "Ignoring Vlan UP Ind for VPV: Port Not Found/Ready", log.Fields{"Port": vp})
733 return
734 }
735
736 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
737 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})
738 return
739 }
740
741 //Disable the flag so that flows can be pushed again
742 // vpv.IgmpFlowsApplied = false
743 // vpv.DsFlowsApplied = false
744 // vpv.UsFlowsApplied = false
745 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530746 vpv.PortUpInd(cntx, d, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530747 vpv.VpvLock.Unlock()
748}
749
750// PortUpInd : When a port transistions to UP state, the indication is passed
751// on to this module via the application. We read the VNET configuration
752// again here to apply the latest configuration if the configuration
753// changed. Thus, a reboot of ONT forces the new configuration to get
754// applied.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530755func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530756
757 if vpv.DeleteInProgress {
758 logger.Errorw(ctx, "Ignoring VPV Port UP Ind, VPV deleteion In-Progress", log.Fields{"Device": device, "Port": port, "Vnet": vpv.VnetName})
759 return
760 }
761 vpv.setDevice(device.Name)
762 logger.Infow(ctx, "Port UP Ind, pushing flows for the port", log.Fields{"Device": device, "Port": port, "VnetDhcp": vpv.DhcpRelay, "McastService": vpv.McastService})
763
764 nni, _ := GetApplication().GetNniPort(device.Name)
765 if nni == "" {
766 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name})
767 return
768 }
769
Akash Sonia8246972023-01-03 10:37:08 +0530770 if nniPort := device.GetPort(nni); nniPort != nil {
771 //If NNI port is not mached to nb nni port dont send flows
772 devConfig := GetApplication().GetDeviceConfig(device.SerialNum)
773 if devConfig != nil {
Akash Soni53da2852023-03-15 00:31:31 +0530774 if devConfig.UplinkPort != strconv.Itoa(int(nniPort.ID)) {
775 logger.Errorw(ctx, "NNI port not configured from NB, not pushing flows", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI port": nniPort.ID})
Akash Sonia8246972023-01-03 10:37:08 +0530776 return
777 }
778 }
779 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530780
Naveen Sampath04696f72022-06-13 15:19:14 +0530781 if vpv.Blocked {
782 logger.Errorw(ctx, "VPV Bocked for Processing. Ignoring flow push request", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
783 return
784 }
785
786 if vpv.DhcpRelay || vpv.ArpRelay || vpv.PppoeIa {
787 // If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
788 // DS HSIA flows are installed after learning the MAC.
789 logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530790 // no HSIA flows for multicast service and DPU_MGMT Service
791 if !vpv.McastService && vpv.VnetType != DPU_MGMT_TRAFFIC {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530792 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530793 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530794 if vpv.VnetType == DPU_MGMT_TRAFFIC {
795 vpv.RangeOnServices(cntx, AddMeterToDevice)
796 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530797 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530798 if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
799 logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530800 /*In case of DPU_MGMT_TRAFFIC, need to install both US and DS traffic */
Akash Soni53da2852023-03-15 00:31:31 +0530801 if vpv.VnetType == DPU_MGMT_TRAFFIC {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530802 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
803 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530804 // US & DS DHCP, US HSIA flows are already installed
805 // install only DS HSIA flow here.
806 // no HSIA flows for multicast service
Akash Soni53da2852023-03-15 00:31:31 +0530807 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530808 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530809 }
810 }
811
812 } else {
813 // DHCP relay is not configured. This implies that the service must use
814 // 1:1 and does not require MAC learning. In a completely uncommon but
815 // plausible case, the MAC address can be learnt from N:1 without DHCP
816 // relay by configuring any unknown MAC address to be reported. This
817 // however is not seen as a real use case.
818 logger.Infow(ctx, "Port Up - Service Flows", log.Fields{"Device": device.Name, "Port": port})
819 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530820 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530821 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530822 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530823 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530824 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530825 }
826 }
827
828 // Process IGMP proxy - install IGMP trap rules before DHCP trap rules
829 if vpv.IgmpEnabled {
830 logger.Infow(ctx, "Port Up - IGMP Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530831 vpv.RangeOnServices(cntx, AddSvcUsMeterToDevice)
832 if err := vpv.AddIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530833 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530834 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
835 }
836
837 if vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530838 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +0530839 }
840 }
841
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530842 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530843}
844
845// PortDownInd : When the port status changes to down, we delete all configured flows
846// The same indication is also passed to the services enqueued for them
847// to take appropriate actions
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530848func (vpv *VoltPortVnet) PortDownInd(cntx context.Context, device string, port string, nbRequest bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530849
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530850 if !nbRequest && !GetApplication().OltFlowServiceConfig.RemoveFlowsOnDisable {
851 logger.Info(ctx, "VPV Port DOWN Ind, Not deleting flows since RemoveOnDisable is disabled")
852 return
853 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530854 logger.Infow(ctx, "VPV Port DOWN Ind, deleting all flows for services",
855 log.Fields{"service count": vpv.servicesCount.Load()})
856
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530857 //vpv.RangeOnServices(cntx, DelAllFlows)
858 vpv.DelTrapFlows(cntx)
859 vpv.DelHsiaFlows(cntx)
860 vpv.WriteToDb(cntx)
861 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530862}
863
864// SetMacAddr : The MAC address is set when a MAC address is learnt through the
865// packets received from the network. Currently, DHCP packets are
866// only packets we learn the MAC address from
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530867func (vpv *VoltPortVnet) SetMacAddr(cntx context.Context, addr net.HardwareAddr) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530868
869 //Store Learnt MAC address and return if MACLearning is not enabled
870 vpv.LearntMacAddr = addr
871 if vpv.MacLearning == MacLearningNone || !NonZeroMacAddress(addr) ||
872 (NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn) {
873 return
874 }
875
876 // Compare the two MAC addresses to see if it is same
877 // If they are same, we just return. If not, we perform
878 // actions to address the change in MAC address
879 //if NonZeroMacAddress(vpv.MacAddr) && !util.MacAddrsMatch(vpv.MacAddr, addr) {
880 if !util.MacAddrsMatch(vpv.MacAddr, addr) {
881 expectedPort := GetApplication().GetMacInPortMap(addr)
882 if expectedPort != "" && expectedPort != vpv.Port {
883 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-setmacaddr",
884 log.Fields{"ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": addr.String()})
885 return
886 }
887 if NonZeroMacAddress(vpv.MacAddr) {
888 logger.Warnw(ctx, "MAC Address Changed. Remove old flows (if added) and re-add with updated MAC", log.Fields{"UpdatedMAC": addr})
889
890 // The newly learnt MAC address is different than earlier one.
891 // The existing MAC based HSIA flows need to be undone as the device
892 // may have been changed
893 // Atleast one HSIA flow should be present in adapter to retain the TP and GEM
894 // hence delete one after the other
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530895 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530896 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530897 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
898 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
899 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530900 GetApplication().DeleteMacInPortMap(vpv.MacAddr)
901 } else {
902 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530903 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530904 logger.Infow(ctx, "MAC Address learnt from DHCP or ARP", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
905 }
906 GetApplication().UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
907 } else {
908 logger.Infow(ctx, "Leant MAC Address is same", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
909 }
910
911 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
912 if err != nil {
913 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
Akash Sonia8246972023-01-03 10:37:08 +0530914 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530915 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
916 return
917 }
918 // Ds Hsia flows has to be pushed
919 if vpv.FlowsApplied {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530920 // In case of DPU_MGMT_TRAFFIC install both US and DS Flows
921 if vpv.VnetType == DPU_MGMT_TRAFFIC {
922 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
923 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530924 // no HSIA flows for multicast service
925 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530926 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530927 }
928 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530929 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530930}
931
932// MatchesVlans : If the VNET matches both S and C VLANs, return true. Else, return false
933func (vpv *VoltPortVnet) MatchesVlans(svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) bool {
934 if vpv.SVlan != svlan || vpv.CVlan != cvlan || vpv.UniVlan != univlan {
935 return false
936 }
937 return true
938}
939
940// MatchesCvlan : If the VNET matches CVLAN, return true. Else, return false
941func (vpv *VoltPortVnet) MatchesCvlan(cvlan []of.VlanType) bool {
942 if len(cvlan) != 1 && !vpv.AllowTransparent {
943 return false
944 }
945 if vpv.CVlan != cvlan[0] {
946 return false
947 }
948 return true
949}
950
951// MatchesPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
952func (vpv *VoltPortVnet) MatchesPriority(priority uint8) *VoltService {
953
954 var service *VoltService
955 pbitFound := false
956 matchpbitsFunc := func(key, value interface{}) bool {
957 svc := value.(*VoltService)
958 for _, pbit := range svc.Pbits {
959 if uint8(pbit) == priority {
960 logger.Infow(ctx, "Pbit match found with service",
961 log.Fields{"Pbit": priority, "serviceName": svc.Name})
962 pbitFound = true
963 service = svc
964 return false //Returning false to stop the Range loop
965 }
966 }
967 return true
968 }
969 _ = pbitFound
970 vpv.services.Range(matchpbitsFunc)
971 return service
972}
973
974// GetRemarkedPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
975func (vpv *VoltPortVnet) GetRemarkedPriority(priority uint8) uint8 {
976
977 dsPbit := uint8(0)
978 matchpbitsFunc := func(key, value interface{}) bool {
979 svc := value.(*VoltService)
980 if remarkPbit, ok := svc.DsRemarkPbitsMap[int(priority)]; ok {
981 logger.Infow(ctx, "Pbit match found with service",
982 log.Fields{"Pbit": priority, "serviceName": svc.Name, "remarkPbit": remarkPbit})
983 dsPbit = uint8(remarkPbit)
984 return false //Returning false to stop the Range loop
985 }
986 // When no remarking info is available, remark the incoming pbit
987 // to highest pbit configured for the subscriber (across all subservices associated)
988 svcPbit := uint8(svc.Pbits[0])
989 if svcPbit > dsPbit {
990 dsPbit = svcPbit
991 }
992 return true
993 }
994 vpv.services.Range(matchpbitsFunc)
995 logger.Debugw(ctx, "Remarked Pbit Value", log.Fields{"Incoming": priority, "Remarked": dsPbit})
996 return dsPbit
997}
998
999// AddSvc adds a service on the VNET on a port. The addition is
1000// triggered when NB requests for service addition
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301001func (vpv *VoltPortVnet) AddSvc(cntx context.Context, svc *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301002
1003 //vpv.services = append(vpv.services, svc)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301004 vpv.AddService(cntx, svc)
Naveen Sampath04696f72022-06-13 15:19:14 +05301005 logger.Debugw(ctx, "Added Service to VPV", log.Fields{"Num of SVCs": vpv.servicesCount.Load(), "SVC": svc})
1006
1007 // Learn the circuit-id and remote-id from the service
1008 // TODO: There must be a better way of doing this. This
1009 // may be explored
1010 if svc.IgmpEnabled {
1011 vpv.IgmpEnabled = true
1012 }
1013 // first time service activation MacLearning will have default value as None.
1014 // to handle reciliency if anythng other then None we should retain it .
1015 if svc.MacLearning == MacLearningNone {
1016 if !vpv.DhcpRelay && !vpv.ArpRelay {
1017 svc.MacLearning = MacLearningNone
1018 } else if vpv.MacLearning == Learn {
1019 svc.MacLearning = Learn
1020 } else if vpv.MacLearning == ReLearn {
1021 svc.MacLearning = ReLearn
1022 }
1023 }
1024
1025 //TODO: Temp Change - Need to address MAC Learning flow issues completely
1026 if (svc.MacLearning == Learn || svc.MacLearning == ReLearn) && NonZeroMacAddress(vpv.MacAddr) {
1027 svc.MacAddr = vpv.MacAddr
1028 } else if vpv.servicesCount.Load() == 1 {
1029 vpv.MacAddr = svc.MacAddr
1030 }
1031
1032 vpv.MacLearning = svc.MacLearning
1033 vpv.PonPort = svc.PonPort
1034 logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
1035 //Reconfigure Vlans based on Vlan Control type
1036 svc.VlanControl = vpv.VlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301037 if svc.McastService {
1038 vpv.McastService = true
1039 vpv.McastTechProfileID = svc.TechProfileID
1040 //Assumption: Only one Pbit for mcast service
1041 vpv.McastPbit = svc.Pbits[0]
1042 vpv.McastUsMeterID = svc.UsMeterID
1043 vpv.SchedID = svc.SchedID
1044 }
1045 svc.ONTEtherTypeClassification = vpv.ONTEtherTypeClassification
1046 svc.AllowTransparent = vpv.AllowTransparent
1047 svc.SVlanTpid = vpv.SVlanTpid
1048
1049 //Ensure configuring the mvlan profile only once
1050 //One subscriber cannot have multiple mvlan profiles. Only the first configuration is valid
1051 if svc.MvlanProfileName != "" {
1052 if vpv.MvlanProfileName == "" {
1053 vpv.MvlanProfileName = svc.MvlanProfileName
1054 } else {
1055 logger.Warnw(ctx, "Mvlan Profile already configured for subscriber. Ignoring new Mvlan", log.Fields{"Existing Mvlan": vpv.MvlanProfileName, "New Mvlan": svc.MvlanProfileName})
1056 }
1057 }
1058
Akash Sonia8246972023-01-03 10:37:08 +05301059 voltDevice, err := GetApplication().GetDeviceFromPort(vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301060 if err != nil {
1061 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
Akash Sonia8246972023-01-03 10:37:08 +05301062 //statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301063 //TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1064 return
1065 }
Tinoj Josephec742f62022-09-29 19:11:10 +05301066 if !svc.IsActivated {
1067 logger.Warn(ctx, "Not pushing Service Flows: Service Not activated")
1068 return
1069 }
Akash Sonia8246972023-01-03 10:37:08 +05301070
1071 //If NNI port is not mached to nb nni port
1072 devConfig := GetApplication().GetDeviceConfig(voltDevice.SerialNum)
1073
Akash Soni53da2852023-03-15 00:31:31 +05301074 if devConfig.UplinkPort != voltDevice.NniPort {
1075 logger.Errorw(ctx, "NNI port mismatch", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI port": voltDevice.NniPort})
Akash Sonia8246972023-01-03 10:37:08 +05301076 return
1077 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301078 //Push Service Flows if DHCP relay is not configured
1079 //or already DHCP flows are configured for the VPV
1080 //to which the serivce is associated
1081 if vpv.FlowsApplied {
1082 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301083 svc.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301084 } else {
Akash Sonia8246972023-01-03 10:37:08 +05301085 if err := svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301086 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1087 }
1088 }
1089 }
1090
1091 //Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
1092 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1093 // service with Igmp Enabled needs to be installed
1094 if svc.IgmpEnabled && vpv.FlowsApplied {
1095 logger.Infow(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301096 if err := vpv.AddIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301097 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301098 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1099 }
1100
1101 if vpv.McastService {
1102 //For McastService, send Service Activated indication once IGMP US flow is pushed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301103 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +05301104 }
1105 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301106 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301107}
1108
1109// setLearntMAC to set learnt mac
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301110func (vpv *VoltPortVnet) setLearntMAC(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301111 svc := value.(*VoltService)
1112 svc.SetMacAddr(vpv.MacAddr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301113 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301114 return true
1115}
1116
1117// PostAccessConfigSuccessInd for posting access config success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301118func PostAccessConfigSuccessInd(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301119 return true
1120}
1121
1122// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301123func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301124 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301125 logger.Infow(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301126 svc.SetIpv4Addr(vpv.Ipv4Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301127 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301128
1129 return true
1130}
1131
1132// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301133func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301134 svc := value.(*VoltService)
1135 svc.SetIpv6Addr(vpv.Ipv6Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301136 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301137
1138 return true
1139}
1140
1141// AddUsHsiaFlows to add upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301142func AddUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301143 svc := value.(*VoltService)
Akash Sonia8246972023-01-03 10:37:08 +05301144 if err := svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301145 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1146 }
1147 return true
1148}
1149
1150// AddDsHsiaFlows to add downstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301151func AddDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301152 svc := value.(*VoltService)
Akash Sonia8246972023-01-03 10:37:08 +05301153 if err := svc.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301154 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1155 }
1156 return true
1157}
1158
1159// ClearFlagsInService to clear the flags used in service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301160func ClearFlagsInService(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301161 svc := value.(*VoltService)
1162 svc.ServiceLock.Lock()
1163 svc.IgmpFlowsApplied = false
1164 svc.DsDhcpFlowsApplied = false
1165 svc.DsHSIAFlowsApplied = false
1166 svc.Icmpv6FlowsApplied = false
1167 svc.UsHSIAFlowsApplied = false
1168 svc.UsDhcpFlowsApplied = false
1169 svc.PendingFlows = make(map[string]bool)
1170 svc.AssociatedFlows = make(map[string]bool)
1171 svc.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301172 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301173 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1174 return true
1175}
1176
1177// DelDsHsiaFlows to delete hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301178func DelDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301179 svc := value.(*VoltService)
Akash Sonia8246972023-01-03 10:37:08 +05301180 if err := svc.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301181 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1182 }
1183 return true
1184}
1185
1186// DelUsHsiaFlows to delete upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301187func DelUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301188 svc := value.(*VoltService)
Akash Sonia8246972023-01-03 10:37:08 +05301189 if err := svc.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301190 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1191 }
1192 return true
1193}
1194
1195// ClearServiceCounters to clear the service counters
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301196func ClearServiceCounters(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301197 svc := value.(*VoltService)
1198 //Delete the per service counter too
1199 GetApplication().ServiceCounters.Delete(svc.Name)
1200 if svc.IgmpEnabled && svc.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301201 _ = db.DelAllServiceChannelCounter(cntx, svc.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301202 }
1203 return true
1204}
1205
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301206// AddMeterToDevice to add meter config to device, used in FTTB case
1207func AddMeterToDevice(cntx context.Context, key, value interface{}) bool {
1208 svc := value.(*VoltService)
Akash Soni53da2852023-03-15 00:31:31 +05301209 if err := svc.AddMeterToDevice(cntx); err != nil {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301210 logger.Warnw(ctx, "Add Meter failed", log.Fields{"service": svc.Name, "Error": err})
1211 }
1212 return true
1213}
1214
Naveen Sampath04696f72022-06-13 15:19:14 +05301215//AddTrapFlows - Adds US & DS Trap flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301216func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301217
1218 if !vpv.FlowsApplied || vgcRebooted {
1219 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301220 if err := vpv.AddUsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301221 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301222 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1223 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301224 if err := vpv.AddDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301225 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301226 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1227 }
1228 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1229 log.Fields{"port": vpv.Port})
1230 //vpv.updateICMPv6McGroup(true)
1231 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301232 if err := vpv.AddUsArpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301233 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301234 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1235 }
1236 logger.Info(ctx, "ARP trap rules not added in downstream direction")
1237
1238 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301239 if err := vpv.AddUsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301240 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301241 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1242 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301243 if err := vpv.AddDsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301244 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301245 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1246 }
1247 }
1248 vpv.FlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301249 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301250 }
1251}
1252
1253//DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301254func (vpv *VoltPortVnet) DelTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301255
1256 // Delete HSIA & DHCP flows before deleting IGMP flows
1257 if vpv.FlowsApplied || vgcRebooted {
1258 if vpv.DhcpRelay {
Akash Sonia8246972023-01-03 10:37:08 +05301259 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301260 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1261 "UniVlan": vpv.UniVlan, "Error": err})
1262 }
1263 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1264 log.Fields{"port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301265 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301266 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301267 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1268 }
1269 //vpv.updateICMPv6McGroup(false)
1270 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301271 if err := vpv.DelUsArpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301272 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301273 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1274 }
1275 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301276 if err := vpv.DelUsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301277 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301278 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1279 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301280 if err := vpv.DelDsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301281 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301282 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1283 }
1284 }
1285 vpv.FlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301286 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301287 }
Akash Sonia8246972023-01-03 10:37:08 +05301288 if err := vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301289 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1290 "UniVlan": vpv.UniVlan, "Error": err})
1291 }
1292}
1293
1294// DelHsiaFlows deletes the service flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301295func (vpv *VoltPortVnet) DelHsiaFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301296 // no HSIA flows for multicast service
1297 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301298 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
1299 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301300 }
1301}
1302
1303//ClearServiceCounters - Removes all igmp counters for a service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301304func (vpv *VoltPortVnet) ClearServiceCounters(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301305 //send flows deleted indication to submgr
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301306 vpv.RangeOnServices(cntx, ClearServiceCounters)
Naveen Sampath04696f72022-06-13 15:19:14 +05301307}
1308
1309// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301310func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301311 var vd *VoltDevice
1312 device := vpv.Device
1313
1314 if vd = GetApplication().GetDevice(device); vd != nil {
1315 if vd.State != controller.DeviceStateUP {
1316 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})
1317 return nil
1318 }
1319 } else {
1320 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})
1321 return errorCodes.ErrDeviceNotFound
1322 }
1323
1324 flows, err := vpv.BuildUsDhcpFlows()
1325 if err == nil {
1326 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301327 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301328 //push ind here ABHI
Akash Sonia8246972023-01-03 10:37:08 +05301329 statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301330 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1331 }
1332 } else {
1333 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1334 //push ind here ABHI
Akash Sonia8246972023-01-03 10:37:08 +05301335 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301336 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1337
1338 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301339 return nil
1340}
1341
1342// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301343func (vpv *VoltPortVnet) AddDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301344
1345 var vd *VoltDevice
1346 device := vpv.Device
1347
1348 if vd = GetApplication().GetDevice(device); vd != nil {
1349 if vd.State != controller.DeviceStateUP {
1350 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})
1351 return nil
1352 }
1353 } else {
1354 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})
1355 return errorCodes.ErrDeviceNotFound
1356 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301357 if vd.GlobalDhcpFlowAdded {
1358 logger.Info(ctx, "Global Dhcp flow already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301359 return nil
1360 }
1361
1362 flows, err := vpv.BuildDsDhcpFlows()
1363 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301364 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301365 //push ind here and procced
Akash Sonia8246972023-01-03 10:37:08 +05301366 statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301367 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1368
1369 }
1370 } else {
1371 logger.Errorw(ctx, "DS DHCP Flow Add Failed", log.Fields{"Reason": err.Error()})
1372 //send ind here and proceed
Akash Sonia8246972023-01-03 10:37:08 +05301373 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301374 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1375
1376 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301377 if GetApplication().GetVendorID() != Radisys {
1378 vd.GlobalDhcpFlowAdded = true
1379 }
1380 return nil
1381}
1382
1383// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301384func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
1385 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301386 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301387 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1388 }
1389
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301390 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301391 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301392 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1393 }
1394}
1395
1396// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1397// Write the status of the VPV to the DB once the delete is scheduled
1398// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301399func (vpv *VoltPortVnet) DelUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301400 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1401 if err != nil {
1402 return err
1403 }
1404
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301405 err = vpv.delDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301406 if err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301407 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301408 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1409 }
Akash Sonia8246972023-01-03 10:37:08 +05301410
Naveen Sampath04696f72022-06-13 15:19:14 +05301411 return nil
1412}
1413
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301414func (vpv *VoltPortVnet) delDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301415 flows, err := vpv.BuildUsDhcpFlows()
1416 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301417 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301418 }
1419 logger.Errorw(ctx, "US DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1420 return err
1421}
Naveen Sampath04696f72022-06-13 15:19:14 +05301422
1423// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1424// Write the status of the VPV to the DB once the delete is scheduled
1425// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301426func (vpv *VoltPortVnet) DelDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301427 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1428 if err != nil {
1429 return err
1430 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301431 err = vpv.delDsDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301432 if err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301433 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301434 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1435 }
1436 /*
Akash Sonia8246972023-01-03 10:37:08 +05301437 err = vpv.delDsDhcp6Flows(device)
1438 if err != nil {
1439 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
1440 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1441 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +05301442 return nil
1443}
1444
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301445func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301446 flows, err := vpv.BuildDsDhcpFlows()
1447 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301448 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301449 }
1450 logger.Errorw(ctx, "DS DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1451 return err
1452}
1453
1454/*
1455func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1456 flows, err := vpv.BuildDsDhcp6Flows()
1457 if err == nil {
1458 return vpv.RemoveFlows(device, flows)
1459 }
1460 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1461 return err
1462}*/
1463
1464// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301465func (vpv *VoltPortVnet) AddUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301466
1467 var vd *VoltDevice
1468 device := vpv.Device
1469 if vd = GetApplication().GetDevice(device); vd != nil {
1470 if vd.State != controller.DeviceStateUP {
1471 logger.Errorw(ctx, "Skipping US ARP Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1472 return nil
1473 }
1474 } else {
1475 logger.Errorw(ctx, "US ARP Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1476 return errorCodes.ErrDeviceNotFound
1477 }
1478
1479 flows, err := vpv.BuildUsArpFlows()
1480 if err == nil {
1481 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301482 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301483 return err1
1484 }
1485 } else {
1486 logger.Errorw(ctx, "US ARP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1487 return err
1488 }
1489 return nil
1490}
1491
1492// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1493// Write the status of the VPV to the DB once the delete is scheduled
1494// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301495func (vpv *VoltPortVnet) DelUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301496 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1497 if err != nil {
1498 return err
1499 }
1500 flows, err := vpv.BuildUsArpFlows()
1501 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301502 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301503 }
1504 logger.Errorw(ctx, "US ARP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1505 return err
1506}
1507
1508// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301509func (vpv *VoltPortVnet) AddUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301510 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1511
1512 var vd *VoltDevice
1513 device := vpv.Device
1514
1515 if vd = GetApplication().GetDevice(device); vd != nil {
1516 if vd.State != controller.DeviceStateUP {
1517 logger.Errorw(ctx, "Skipping US PPPoE Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1518 return nil
1519 }
1520 } else {
1521 logger.Errorw(ctx, "US PPPoE Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1522 return errorCodes.ErrDeviceNotFound
1523 }
1524
1525 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1526 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1527
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301528 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301529 return err1
1530 }
1531 } else {
1532 logger.Errorw(ctx, "US PPPoE Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1533 return err
1534 }
1535 return nil
1536}
1537
1538// AddDsPppoeFlows to add downstream pppoe flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301539func (vpv *VoltPortVnet) AddDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301540 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1541 var vd *VoltDevice
1542 device := vpv.Device
1543
1544 if vd = GetApplication().GetDevice(device); vd != nil {
1545 if vd.State != controller.DeviceStateUP {
1546 logger.Errorw(ctx, "Skipping DS PPPoE Flow Push - Device state DOWN", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1547 return nil
1548 }
1549 } else {
1550 logger.Errorw(ctx, "DS PPPoE Flow Push Failed- Device not found", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "device": device})
1551 return errorCodes.ErrDeviceNotFound
1552 }
1553
1554 flows, err := vpv.BuildDsPppoeFlows()
1555 if err == nil {
1556
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301557 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301558 return err1
1559 }
1560 } else {
1561 logger.Errorw(ctx, "DS PPPoE Flow Add Failed", log.Fields{"Reason": err.Error()})
1562 return err
1563 }
1564 return nil
1565}
1566
1567// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1568// Write the status of the VPV to the DB once the delete is scheduled
1569// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301570func (vpv *VoltPortVnet) DelUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301571 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1572 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1573 if err != nil {
1574 return err
1575 }
1576 flows, err := vpv.BuildUsPppoeFlows()
1577 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301578 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301579 }
1580 logger.Errorw(ctx, "US PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1581 return err
1582}
1583
1584// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1585// Write the status of the VPV to the DB once the delete is scheduled
1586// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301587func (vpv *VoltPortVnet) DelDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301588 logger.Debugw(ctx, "Deleting DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1589 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1590 if err != nil {
1591 return err
1592 }
1593 flows, err := vpv.BuildDsPppoeFlows()
1594 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301595 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301596 }
1597 logger.Errorw(ctx, "DS PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1598 return err
1599}
1600
1601// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301602func (vpv *VoltPortVnet) AddIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301603
1604 if !vpv.IgmpFlowsApplied || vgcRebooted {
1605 if vpv.MvlanProfileName == "" {
1606 logger.Info(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
1607 return nil
1608 }
1609 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1610 if err != nil {
1611 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1612 return err
1613 } else if device.State != controller.DeviceStateUP {
1614 logger.Warnw(ctx, "Device state Down. Ignoring US IGMP Flow Push", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan})
1615 return nil
1616 }
1617 flows, err := vpv.BuildIgmpFlows()
1618 if err == nil {
1619 for cookie := range flows.SubFlows {
1620 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1621 cookie := strconv.FormatUint(cookie, 10)
1622 fe := &FlowEvent{
1623 eType: EventTypeUsIgmpFlowAdded,
1624 cookie: cookie,
1625 eventData: vpv,
1626 }
1627 vd.RegisterFlowAddEvent(cookie, fe)
1628 }
1629 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301630 if err1 := cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301631 return err1
1632 }
1633 } else {
1634 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1635 return err
1636 }
1637 vpv.IgmpFlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301638 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301639 }
1640 return nil
1641}
1642
1643// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1644// Write the status of the VPV to the DB once the delete is scheduled
1645// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301646func (vpv *VoltPortVnet) DelIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301647
1648 if vpv.IgmpFlowsApplied || vgcRebooted {
1649 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1650 if err != nil {
1651 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1652 return err
1653 }
1654 flows, err := vpv.BuildIgmpFlows()
1655 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301656 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301657 return err1
1658 }
1659 } else {
1660 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1661 return err
1662 }
1663 vpv.IgmpFlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301664 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301665 }
1666 return nil
1667}
1668
1669// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1670// The flows included by this function cover US only as the DS is
1671// created either automatically by the VOLTHA or at the device level
1672// earlier
1673func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
1674 flow := &of.VoltFlow{}
1675 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1676
1677 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
1678 subFlow := of.NewVoltSubFlow()
1679 subFlow.SetTableID(0)
1680
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301681 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1682 subFlow.SetMatchVlan(vpv.CVlan)
1683 subFlow.SetMatchPbit(vpv.UsPonCTagPriority)
1684 subFlow.SetPcp(vpv.UsPonSTagPriority)
1685 subFlow.SetSetVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301686 } else {
1687 subFlow.SetMatchVlan(vpv.UniVlan)
1688 subFlow.SetSetVlan(vpv.CVlan)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301689 subFlow.SetPcp(vpv.DhcpPbit)
Naveen Sampath04696f72022-06-13 15:19:14 +05301690 }
1691 subFlow.SetUdpv4Match()
Naveen Sampath04696f72022-06-13 15:19:14 +05301692 subFlow.DstPort = 67
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301693 subFlow.SrcPort = 68
Naveen Sampath04696f72022-06-13 15:19:14 +05301694 uniport, err := GetApplication().GetPortID(vpv.Port)
1695 if err != nil {
1696 logger.Errorw(ctx, "Failed to fetch uni port from vpv", log.Fields{"error": err, "port": vpv.Port})
1697 return nil, err
1698 }
1699 subFlow.SetInPort(uniport)
1700 // PortName and PortID to be used for validation of port before flow pushing
1701 flow.PortID = uniport
1702 flow.PortName = vpv.Port
1703 subFlow.SetReportToController()
1704
1705 // Set techprofile, meterid of first service
1706 vpv.services.Range(func(key, value interface{}) bool {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301707 vs := value.(*VoltService)
1708 var writemetadata uint64
1709 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1710 writemetadata = uint64(vs.SVlan)<<48 + uint64(vs.TechProfileID)<<32
1711 } else {
1712 writemetadata = uint64(vs.TechProfileID) << 32
1713 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301714 subFlow.SetWriteMetadata(writemetadata)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301715 subFlow.SetMeterID(vs.UsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301716 return false
1717 })
1718
Naveen Sampath04696f72022-06-13 15:19:14 +05301719 // metadata := uint64(uniport)
1720 // subFlow.SetWriteMetadata(metadata)
1721 allowTransparent := 0
1722 if vpv.AllowTransparent {
1723 allowTransparent = 1
1724 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301725 if vpv.VnetType != DPU_MGMT_TRAFFIC {
1726 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1727 subFlow.SetTableMetadata(metadata)
1728 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301729 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1730 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1731 subFlow.Priority = of.DhcpFlowPriority
1732
1733 flow.SubFlows[subFlow.Cookie] = subFlow
1734 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1735 return flow, nil
1736}
1737
1738// BuildDsDhcpFlows to build the downstream dhcp flows
1739func (vpv *VoltPortVnet) BuildDsDhcpFlows() (*of.VoltFlow, error) {
1740
1741 logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1742 flow := &of.VoltFlow{}
1743 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1744 subFlow := of.NewVoltSubFlow()
1745 subFlow.SetTableID(0)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301746 // match on vlan only for fttb case
1747 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1748 subFlow.SetMatchVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301749 }
1750 subFlow.SetUdpv4Match()
1751 subFlow.SrcPort = 67
1752 subFlow.DstPort = 68
1753 uniport, _ := GetApplication().GetPortID(vpv.Port)
1754 nni, err := GetApplication().GetNniPort(vpv.Device)
1755 if err != nil {
1756 return nil, err
1757 }
1758 nniport, err := GetApplication().GetPortID(nni)
1759 if err != nil {
1760 return nil, err
1761 }
1762 subFlow.SetInPort(nniport)
1763 // PortName and PortID to be used for validation of port before flow pushing
1764 flow.PortID = uniport
1765 flow.PortName = vpv.Port
1766 // metadata := uint64(uniport)
1767 // subFlow.SetWriteMetadata(metadata)
1768 allowTransparent := 0
1769 if vpv.AllowTransparent {
1770 allowTransparent = 1
1771 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301772 if vpv.VnetType != DPU_MGMT_TRAFFIC {
1773 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1774 subFlow.SetTableMetadata(metadata)
1775 subFlow.Priority = of.DhcpFlowPriority
1776 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301777 subFlow.SetReportToController()
1778 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1779 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
Naveen Sampath04696f72022-06-13 15:19:14 +05301780
1781 flow.SubFlows[subFlow.Cookie] = subFlow
1782 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1783
1784 return flow, nil
1785}
1786
1787// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1788// application.
1789func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
1790 flow := &of.VoltFlow{}
1791 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1792
1793 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
1794 subFlow := of.NewVoltSubFlow()
1795 subFlow.SetTableID(0)
1796
1797 subFlow.SetMatchVlan(vpv.UniVlan)
1798 subFlow.SetSetVlan(vpv.CVlan)
1799 subFlow.SetUdpv6Match()
1800 subFlow.SrcPort = 546
1801 subFlow.DstPort = 547
1802 uniport, err := GetApplication().GetPortID(vpv.Port)
1803 if err != nil {
1804 return nil, err
1805 }
1806 // Set techprofile, meterid of first service
1807 vpv.services.Range(func(key, value interface{}) bool {
1808 svc := value.(*VoltService)
1809 writemetadata := uint64(svc.TechProfileID) << 32
1810 subFlow.SetWriteMetadata(writemetadata)
1811 subFlow.SetMeterID(svc.UsMeterID)
1812 return false
1813 })
1814 subFlow.SetInPort(uniport)
1815 // PortName and PortID to be used for validation of port before flow pushing
1816 flow.PortID = uniport
1817 flow.PortName = vpv.Port
1818 //subFlow.SetMeterId(vpv.UsDhcpMeterId)
1819 // metadata := uint64(uniport)
1820 // subFlow.SetWriteMetadata(metadata)
1821 allowTransparent := 0
1822 if vpv.AllowTransparent {
1823 allowTransparent = 1
1824 }
1825 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1826 subFlow.SetTableMetadata(metadata)
1827 subFlow.SetReportToController()
1828 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1829 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
1830 subFlow.Priority = of.DhcpFlowPriority
1831
1832 flow.SubFlows[subFlow.Cookie] = subFlow
1833 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1834 return flow, nil
1835}
1836
1837// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1838// application.
1839func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
1840 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1841
1842 flow := &of.VoltFlow{}
1843 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1844 subFlow := of.NewVoltSubFlow()
1845 subFlow.SetTableID(0)
1846
1847 vpv.setDsMatchVlan(subFlow)
1848 subFlow.SetUdpv6Match()
1849 subFlow.SrcPort = 547
1850 subFlow.DstPort = 547
1851 uniport, _ := GetApplication().GetPortID(vpv.Port)
1852 nni, err := GetApplication().GetNniPort(vpv.Device)
1853 if err != nil {
1854 return nil, err
1855 }
1856 nniport, err := GetApplication().GetPortID(nni)
1857 if err != nil {
1858 return nil, err
1859 }
1860 subFlow.SetInPort(nniport)
1861 // PortName and PortID to be used for validation of port before flow pushing
1862 flow.PortID = uniport
1863 flow.PortName = vpv.Port
1864 // metadata := uint64(uniport)
1865 // subFlow.SetWriteMetadata(metadata)
1866 allowTransparent := 0
1867 if vpv.AllowTransparent {
1868 allowTransparent = 1
1869 }
1870 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1871 subFlow.SetTableMetadata(metadata)
1872 subFlow.SetReportToController()
1873 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1874 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
1875 subFlow.Priority = of.DhcpFlowPriority
1876
1877 flow.SubFlows[subFlow.Cookie] = subFlow
1878 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1879 return flow, nil
1880}
1881
1882// BuildUsArpFlows builds the US ARP relay flows for a subscriber
1883// The flows included by this function cover US only as the DS is
1884// created either automatically by the VOLTHA or at the device level
1885// earlier
1886func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
1887 flow := &of.VoltFlow{}
1888 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1889
1890 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
1891 subFlow := of.NewVoltSubFlow()
1892 subFlow.SetTableID(0)
1893
1894 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1895 subFlow.SetMatchSrcMac(vpv.MacAddr)
1896 }
1897
1898 subFlow.SetMatchDstMac(BroadcastMAC)
1899 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1900 return nil, err
1901 }
1902 subFlow.SetArpMatch()
1903 uniport, err := GetApplication().GetPortID(vpv.Port)
1904 if err != nil {
1905 return nil, err
1906 }
1907 subFlow.SetInPort(uniport)
1908 // PortName and PortID to be used for validation of port before flow pushing
1909 flow.PortID = uniport
1910 flow.PortName = vpv.Port
1911 subFlow.SetReportToController()
1912 allowTransparent := 0
1913 if vpv.AllowTransparent {
1914 allowTransparent = 1
1915 }
1916 metadata := uint64(uniport)
1917 subFlow.SetWriteMetadata(metadata)
1918 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1919 subFlow.SetTableMetadata(metadata)
1920 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
1921 subFlow.Priority = of.ArpFlowPriority
1922
1923 flow.SubFlows[subFlow.Cookie] = subFlow
1924 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1925 return flow, nil
1926}
1927
1928// setUsMatchVlan to set upstream match vlan
1929func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
1930 switch vpv.VlanControl {
1931 case None:
1932 flow.SetMatchVlan(vpv.SVlan)
1933 case ONUCVlanOLTSVlan:
1934 flow.SetMatchVlan(vpv.CVlan)
1935 case OLTCVlanOLTSVlan:
1936 flow.SetMatchVlan(vpv.UniVlan)
1937 //flow.SetSetVlan(vpv.CVlan)
1938 case ONUCVlan:
1939 flow.SetMatchVlan(vpv.SVlan)
1940 case OLTSVlan:
1941 flow.SetMatchVlan(vpv.UniVlan)
1942 //flow.SetSetVlan(vpv.SVlan)
1943 default:
1944 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
1945 return errorCodes.ErrInvalidParamInRequest
1946 }
1947 return nil
1948}
1949
1950// BuildUsPppoeFlows to build upstream pppoe flows
1951func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
1952
1953 flow := &of.VoltFlow{}
1954 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1955 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
1956 subFlow := of.NewVoltSubFlow()
1957 subFlow.SetTableID(0)
1958
1959 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1960 subFlow.SetMatchSrcMac(vpv.MacAddr)
1961 }
1962
1963 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1964 return nil, err
1965 }
1966 subFlow.SetPppoeDiscoveryMatch()
1967 uniport, err := GetApplication().GetPortID(vpv.Port)
1968 if err != nil {
1969 return nil, err
1970 }
1971 subFlow.SetInPort(uniport)
1972 subFlow.SetReportToController()
1973 // PortName and PortID to be used for validation of port before flow pushing
1974 flow.PortID = uniport
1975 flow.PortName = vpv.Port
1976
1977 allowTransparent := 0
1978 if vpv.AllowTransparent {
1979 allowTransparent = 1
1980 }
1981 metadata := uint64(uniport)
1982 subFlow.SetWriteMetadata(metadata)
1983
1984 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1985 subFlow.SetTableMetadata(metadata)
1986
1987 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
1988 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
1989 subFlow.Priority = of.PppoeFlowPriority
1990
1991 flow.SubFlows[subFlow.Cookie] = subFlow
1992 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1993 return flow, nil
1994}
1995
1996// BuildDsPppoeFlows to build downstream pppoe flows
1997func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
1998
1999 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
2000 flow := &of.VoltFlow{}
2001 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2002 subFlow := of.NewVoltSubFlow()
2003 subFlow.SetTableID(0)
2004
2005 vpv.setDsMatchVlan(subFlow)
2006 subFlow.SetPppoeDiscoveryMatch()
2007
2008 if NonZeroMacAddress(vpv.MacAddr) {
2009 subFlow.SetMatchDstMac(vpv.MacAddr)
2010 }
2011
2012 uniport, _ := GetApplication().GetPortID(vpv.Port)
2013 nni, err := GetApplication().GetNniPort(vpv.Device)
2014 if err != nil {
2015 return nil, err
2016 }
2017 nniport, err := GetApplication().GetPortID(nni)
2018 if err != nil {
2019 return nil, err
2020 }
2021 subFlow.SetInPort(nniport)
2022 // PortName and PortID to be used for validation of port before flow pushing
2023 flow.PortID = uniport
2024 flow.PortName = vpv.Port
2025 metadata := uint64(uniport)
2026 subFlow.SetWriteMetadata(metadata)
2027 allowTransparent := 0
2028 if vpv.AllowTransparent {
2029 allowTransparent = 1
2030 }
2031 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2032 subFlow.SetTableMetadata(metadata)
2033 subFlow.SetReportToController()
2034 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
2035 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2036 subFlow.Priority = of.PppoeFlowPriority
2037
2038 flow.SubFlows[subFlow.Cookie] = subFlow
2039 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2040 return flow, nil
2041}
2042
2043// setDsMatchVlan to set downstream match vlan
2044func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
2045 switch vpv.VlanControl {
2046 case None:
2047 flow.SetMatchVlan(vpv.SVlan)
2048 case ONUCVlanOLTSVlan,
2049 OLTCVlanOLTSVlan,
2050 ONUCVlan,
2051 OLTSVlan:
2052 flow.SetMatchVlan(vpv.SVlan)
2053 default:
2054 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2055 }
2056}
2057
2058// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2059// in the US direction.
2060func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2061 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2062 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2063 if mvp == nil {
2064 return nil, errors.New("Mvlan Profile configured not found")
2065 }
2066 mvlan := mvp.GetUsMatchVlan()
2067 flow := &of.VoltFlow{}
2068 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2069 subFlow := of.NewVoltSubFlow()
2070 subFlow.SetTableID(0)
2071
Akash Sonia8246972023-01-03 10:37:08 +05302072 subFlow.SetMatchVlan(vpv.UniVlan)
2073 subFlow.SetSetVlan(vpv.CVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05302074
2075 uniport, err := GetApplication().GetPortID(vpv.Port)
2076 if err != nil {
2077 return nil, err
2078 }
2079 subFlow.SetInPort(uniport)
2080 // PortName and PortID to be used for validation of port before flow pushing
2081 flow.PortID = uniport
2082 flow.PortName = vpv.Port
2083
2084 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2085 subFlow.SetMatchSrcMac(vpv.MacAddr)
2086 }
2087 logger.Infow(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
2088 //metadata := uint64(mvlan)
2089
2090 if vpv.McastService {
2091 metadata := uint64(vpv.McastUsMeterID)
2092 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2093 subFlow.SetMatchPbit(vpv.McastPbit)
2094 subFlow.SetMeterID(vpv.McastUsMeterID)
2095 subFlow.SetWriteMetadata(metadata)
2096 } else {
2097 // Set techprofile, meterid of first service
2098 vpv.services.Range(func(key, value interface{}) bool {
2099 svc := value.(*VoltService)
2100 writemetadata := uint64(svc.TechProfileID) << 32
2101 subFlow.SetWriteMetadata(writemetadata)
2102 subFlow.SetMeterID(svc.UsMeterID)
2103 return false
2104 })
2105 }
2106
2107 allowTransparent := 0
2108 if vpv.AllowTransparent {
2109 allowTransparent = 1
2110 }
2111 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2112 subFlow.SetTableMetadata(metadata)
2113 subFlow.SetIgmpMatch()
2114 subFlow.SetReportToController()
2115 //| 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
2116 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2117 subFlow.Priority = of.IgmpFlowPriority
2118
2119 flow.SubFlows[subFlow.Cookie] = subFlow
2120 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2121 return flow, nil
2122}
2123
2124// WriteToDb for writing to database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302125func (vpv *VoltPortVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302126 if vpv.DeleteInProgress {
2127 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2128 return
2129 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302130 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302131}
2132
2133//ForceWriteToDb force commit a VPV to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302134func (vpv *VoltPortVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302135 vpv.PendingFlowLock.RLock()
2136 defer vpv.PendingFlowLock.RUnlock()
2137 vpv.Version = database.PresentVersionMap[database.VpvPath]
2138 if b, err := json.Marshal(vpv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302139 if err := db.PutVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302140 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2141 "UniVlan": vpv.UniVlan, "Error": err})
2142 }
2143 }
2144}
2145
2146// DelFromDb for deleting from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302147func (vpv *VoltPortVnet) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302148 logger.Debugw(ctx, "Deleting VPV from DB", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302149 _ = db.DelVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
Naveen Sampath04696f72022-06-13 15:19:14 +05302150}
2151
2152// ClearAllServiceFlags to clear all service flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302153func (vpv *VoltPortVnet) ClearAllServiceFlags(cntx context.Context) {
2154 vpv.RangeOnServices(cntx, ClearFlagsInService)
Naveen Sampath04696f72022-06-13 15:19:14 +05302155}
2156
2157// ClearAllVpvFlags to clear all vpv flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302158func (vpv *VoltPortVnet) ClearAllVpvFlags(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302159 vpv.PendingFlowLock.Lock()
2160 vpv.FlowsApplied = false
2161 vpv.IgmpFlowsApplied = false
2162 vpv.PendingDeleteFlow = make(map[string]bool)
2163 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302164 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302165 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2166 log.Fields{"device": vpv.Device, "port": vpv.Port,
2167 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2168}
2169
2170// CreateVpvFromString to create vpv from string
2171func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
2172 var vpv VoltPortVnet
2173 if err := json.Unmarshal(b, &vpv); err == nil {
2174 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2175 if !ok {
2176 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2177 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2178 }
2179 vpv.servicesCount = atomic.NewUint64(0)
2180 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2181 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2182 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2183 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2184 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2185 vnet.associatePortToVnet(vpv.Port)
2186 }
2187
2188 if vpv.DeleteInProgress {
2189 va.VoltPortVnetsToDelete[&vpv] = true
2190 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2191 }
2192 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2193 }
2194}
2195
2196// RestoreVpvsFromDb to restore vpvs from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302197func (va *VoltApplication) RestoreVpvsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302198 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302199 vpvs, _ := db.GetVpvs(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302200 for hash, vpv := range vpvs {
2201 b, ok := vpv.Value.([]byte)
2202 if !ok {
2203 logger.Warn(ctx, "The value type is not []byte")
2204 continue
2205 }
2206 va.CreateVpvFromString(b, hash)
2207 }
2208}
2209
2210// GetVnetByPort : VNET related functionality of VOLT Application here on.
2211// Get the VNET from a port. The port identity is passed as device and port identities in string.
2212// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2213// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2214func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
2215 if _, ok := va.VnetsByPort.Load(port); !ok {
2216 return nil
2217 }
2218 vpvs, _ := va.VnetsByPort.Load(port)
2219 for _, vpv := range vpvs.([]*VoltPortVnet) {
2220 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2221 return vpv
2222 }
2223 }
2224 return nil
2225}
2226
2227// AddVnetToPort to add vnet to port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302228func (va *VoltApplication) AddVnetToPort(cntx context.Context, port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
Naveen Sampath04696f72022-06-13 15:19:14 +05302229 // The VNET is not on the port and is to be added
2230 logger.Debugw(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
2231 vpv := NewVoltPortVnet(vvnet)
2232 vpv.MacLearning = vvnet.MacLearning
2233 vpv.Port = port
2234 vvnet.associatePortToVnet(port)
2235 if _, ok := va.VnetsByPort.Load(port); !ok {
2236 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2237 }
2238 vpvsIntf, _ := va.VnetsByPort.Load(port)
2239 vpvs := vpvsIntf.([]*VoltPortVnet)
2240 vpvs = append(vpvs, vpv)
2241 va.VnetsByPort.Store(port, vpvs)
2242 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2243
2244 vpv.VpvLock.Lock()
2245 defer vpv.VpvLock.Unlock()
2246
2247 // Add the service that is causing the VNET to be added to the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302248 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05302249
Tinoj Josephec742f62022-09-29 19:11:10 +05302250 if !vs.IsActivated {
2251 logger.Warn(ctx, "Not Checking port state: Service Not activated")
2252 // Process the PORT UP if the port is already up
2253 d, err := va.GetDeviceFromPort(port)
2254 if err == nil {
2255 vpv.setDevice(d.Name)
2256 }
2257 vpv.WriteToDb(cntx)
2258 return vpv
2259 }
2260
Naveen Sampath04696f72022-06-13 15:19:14 +05302261 // Process the PORT UP if the port is already up
2262 d, err := va.GetDeviceFromPort(port)
2263 if err == nil {
2264 vpv.setDevice(d.Name)
2265 p := d.GetPort(port)
2266 if p != nil {
2267
2268 if vs.PonPort != 0xFF && vs.PonPort != p.PonPort {
2269 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Push for VPV", log.Fields{"Device": d.Name, "Port": port, "DetectedPon": p.PonPort, "ExpectedPon": vs.PonPort, "Vnet": vpv.VnetName})
2270 } else {
2271 logger.Infow(ctx, "Checking UNI port state", log.Fields{"State": p.State})
2272 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302273 vpv.PortUpInd(cntx, d, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302274 }
2275 }
2276 }
2277 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302278 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302279 return vpv
2280}
2281
2282// DelVnetFromPort for deleting vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302283func (va *VoltApplication) DelVnetFromPort(cntx context.Context, port string, vpv *VoltPortVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302284
2285 //Delete DHCP Session
2286 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2287
2288 //Delete PPPoE session
2289 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2290
2291 //Delete Mac from MacPortMap
2292 va.DeleteMacInPortMap(vpv.MacAddr)
2293
2294 //Delete VPV
2295 vpvsIntf, ok := va.VnetsByPort.Load(port)
2296 if !ok {
2297 return
2298 }
2299 vpvs := vpvsIntf.([]*VoltPortVnet)
2300 for i, lvpv := range vpvs {
2301 if lvpv == vpv {
2302 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2303 "UNIVLAN": vpv.UniVlan})
2304
2305 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2306
2307 vpv.DeleteInProgress = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302308 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302309
2310 va.VnetsByPort.Store(port, vpvs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302311 vpv.DelTrapFlows(cntx)
2312 vpv.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302313 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2314 vpv.PendingFlowLock.RLock()
2315 if len(vpv.PendingDeleteFlow) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302316 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302317 }
2318 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302319 vnet.disassociatePortFromVnet(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302320 }
2321 vpv.PendingFlowLock.RUnlock()
2322 return
2323 }
2324 }
2325}
2326
2327// RestoreVnetsFromDb to restore vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302328func (va *VoltApplication) RestoreVnetsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302329 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302330 vnets, _ := db.GetVnets(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302331 for _, net := range vnets {
2332 b, ok := net.Value.([]byte)
2333 if !ok {
2334 logger.Warn(ctx, "The value type is not []byte")
2335 continue
2336 }
2337 var vnet VoltVnet
2338 err := json.Unmarshal(b, &vnet)
2339 if err != nil {
2340 logger.Warn(ctx, "Unmarshal of VNET failed")
2341 continue
2342 }
2343 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302344 if err := va.AddVnet(cntx, vnet.VnetConfig, &vnet.VnetOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302345 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2346 }
2347
2348 if vnet.DeleteInProgress {
2349 va.VnetsToDelete[vnet.Name] = true
2350 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2351 }
2352
2353 }
2354}
2355
2356// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2357// are used as the key to locate the service. If more than one service is on the
2358// same port (essentially a UNI of ONU), the services must be separated by different
2359// CVLANs
2360func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
2361 // Fetch the device first to make sure the device exists
2362 dIntf, ok := va.DevicesDisc.Load(device)
2363 if !ok {
2364 return nil
2365 }
2366 d := dIntf.(*VoltDevice)
2367
2368 // If the port is NNI port, the services dont exist on it. The svc then
2369 // must be obtained from a different context and is not included here
2370 if port == d.NniPort {
2371 return nil
2372 }
2373
2374 //To return the matched service
2375 var service *VoltService
2376
2377 // This is an access port and the port should have all the associated
2378 // services which can be uniquely identified by the VLANs in the packet
2379 vnets, ok := va.VnetsByPort.Load(port)
2380
2381 if !ok {
2382 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2383 return nil
2384 }
2385 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2386 for _, vnet := range vnets.([]*VoltPortVnet) {
2387 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2388 switch vnet.VlanControl {
2389 case ONUCVlanOLTSVlan:
2390 service = vnet.MatchesPriority(priority)
2391 if vnet.MatchesCvlan(vlans) && service != nil {
2392 return service
2393 }
2394 case ONUCVlan,
2395 None:
2396 service = vnet.MatchesPriority(priority)
2397 // In case of DHCP Flow - cvlan == VlanNone
2398 // In case of HSIA Flow - cvlan == Svlan
2399 if len(vlans) == 1 && (vlans[0] == vnet.SVlan || vlans[0] == of.VlanNone) && service != nil {
2400 return service
2401 }
2402 case OLTCVlanOLTSVlan,
2403 OLTSVlan:
2404 service = vnet.MatchesPriority(priority)
2405 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2406 return service
2407 }
2408 default:
2409 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2410 }
2411 }
2412 return nil
2413}
2414
2415// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2416// are used as the key to locate the service. If more than one service is on the
2417// same port (essentially a UNI of ONU), the services must be separated by different
2418// CVLANs
2419func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2420 // Fetch the device first to make sure the device exists
2421 dIntf, ok := va.DevicesDisc.Load(device)
2422 if !ok {
2423 return nil, nil
2424 }
2425 d := dIntf.(*VoltDevice)
2426
2427 // If the port is NNI port, the services dont exist on it. The svc then
2428 // must be obtained from a different context and is not included here
2429 if port == d.NniPort {
2430 return nil, nil
2431 }
2432
2433 //To return the matched service
2434 var service *VoltService
2435
2436 // This is an access port and the port should have all the associated
2437 // services which can be uniquely identified by the VLANs in the packet
2438 if vnets, ok := va.VnetsByPort.Load(port); ok {
2439 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2440 for _, vnet := range vnets.([]*VoltPortVnet) {
2441 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2442 switch vnet.VlanControl {
2443 case ONUCVlanOLTSVlan:
2444 service = vnet.MatchesPriority(priority)
2445 if vnet.MatchesCvlan(vlans) && service != nil {
2446 return vnet, service
2447 }
2448 case ONUCVlan,
2449 None:
2450 service = vnet.MatchesPriority(priority)
2451 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2452 return vnet, service
2453 }
2454 case OLTCVlanOLTSVlan,
2455 OLTSVlan:
2456 service = vnet.MatchesPriority(priority)
2457 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2458 return vnet, service
2459 }
2460 default:
2461 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2462 }
2463 }
2464 }
2465 return nil, nil
2466}
2467
2468// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2469// are used as the key to locate the service. If more than one service is on the
2470// same port (essentially a UNI of ONU), the services must be separated by different
2471// CVLANs
2472func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
2473 vlans := GetVlans(pkt)
2474 priority := GetPriority(pkt)
2475 return va.GetVnetFromFields(device, port, vlans, priority)
2476}
2477
2478// PushDevFlowForVlan to push icmpv6 flows for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302479func (va *VoltApplication) PushDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302480 logger.Infow(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2481 pushflow := func(key interface{}, value interface{}) bool {
2482 device := value.(*VoltDevice)
2483 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302484 logger.Infow(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +05302485 return true
2486 }
2487 if device.State != controller.DeviceStateUP {
2488 logger.Errorw(ctx, "Push Dev Flows Failed - Device state DOWN", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan, "device": device})
2489 return true
2490 }
2491 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2492 logger.Errorw(ctx, "Push Dev Flows Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2493 return true
2494 }
2495
2496 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2497 vnetList := vnetListIntf.(*util.ConcurrentMap)
2498 vnetList.Set(vnet.Name, true)
2499 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2500 logger.Infow(ctx, "Flow already pushed for these Vlans. Adding profile to list", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2501 return true
2502 }
2503 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2504 err := ProcessIcmpv6McGroup(device.Name, false)
2505 if err != nil {
2506 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2507 return true
2508 }
2509 if portID, err := va.GetPortID(device.NniPort); err == nil {
2510 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2511 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2512 return true
2513 }
2514
2515 //Pushing ICMPv6 Flow
2516 flow := BuildICMPv6Flow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302517 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302518 if err != nil {
2519 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2520 return true
2521 }
2522 logger.Infow(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
2523
2524 // Pushing ARP Flow
2525 flow = BuildDSArpFlow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302526 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302527 if err != nil {
2528 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2529 return true
2530 }
2531 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2532
2533 vnetList := util.NewConcurrentMap()
2534 vnetList.Set(vnet.Name, true)
2535 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2536 }
2537 return true
2538 }
2539 va.DevicesDisc.Range(pushflow)
2540}
2541
2542// PushDevFlowForDevice to push icmpv6 flows for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302543func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302544 logger.Infow(ctx, "PushDevFlowForDevice", log.Fields{"device": device})
2545
2546 logger.Debugw(ctx, "Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2547 err := ProcessIcmpv6McGroup(device.Name, false)
2548 if err != nil {
2549 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2550 return
2551 }
2552 pushicmpv6 := func(key, value interface{}) bool {
2553 vnet := value.(*VoltVnet)
2554 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2555 vnetList := vnetListIntf.(*util.ConcurrentMap)
2556 vnetList.Set(vnet.Name, true)
2557 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2558 logger.Infow(ctx, "Flow already pushed for these Vlans. Adding profile to list", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2559 return true
2560 }
2561 nniPortID, err := va.GetPortID(device.NniPort)
2562 if err != nil {
2563 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2564 }
2565 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2566 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2567 return true
2568 }
2569 flow := BuildICMPv6Flow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302570 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302571 if err != nil {
2572 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2573 return true
2574 }
2575 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2576
2577 flow = BuildDSArpFlow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302578 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302579 if err != nil {
2580 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2581 return true
2582 }
2583 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2584
2585 vnetList := util.NewConcurrentMap()
2586 vnetList.Set(vnet.Name, true)
2587 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2588 return true
2589 }
2590 va.VnetsByName.Range(pushicmpv6)
2591}
2592
2593// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302594func (va *VoltApplication) DeleteDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302595 logger.Infow(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2596 delflows := func(key interface{}, value interface{}) bool {
2597 device := value.(*VoltDevice)
2598
2599 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2600 vnetList := vnetListIntf.(*util.ConcurrentMap)
2601 vnetList.Remove(vnet.Name)
2602 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2603 if vnetList.Length() != 0 {
2604 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2605 return true
2606 }
2607 }
2608 if portID, err := va.GetPortID(device.NniPort); err == nil {
2609 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2610 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2611 return true
2612 }
2613 //Pushing ICMPv6 Flow
2614 flow := BuildICMPv6Flow(portID, vnet)
2615 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302616 err := vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302617 if err != nil {
2618 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2619 return true
2620 }
2621 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2622
2623 //Pushing ARP Flow
2624 flow = BuildDSArpFlow(portID, vnet)
2625 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302626 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302627 if err != nil {
2628 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2629 return true
2630 }
2631 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2632
2633 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2634 }
2635 return true
2636 }
2637 va.DevicesDisc.Range(delflows)
2638}
2639
2640// DeleteDevFlowForDevice to delete icmpv6 flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302641func (va *VoltApplication) DeleteDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302642 logger.Infow(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
2643 delicmpv6 := func(key, value interface{}) bool {
2644 vnet := value.(*VoltVnet)
2645 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2646 vnetList := vnetListIntf.(*util.ConcurrentMap)
2647 vnetList.Remove(vnet.Name)
2648 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2649 if vnetList.Length() != 0 {
2650 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2651 return true
2652 }
2653 } else {
2654 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2655 return true
2656 }
2657 nniPortID, err := va.GetPortID(device.NniPort)
2658 if err != nil {
2659 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2660 }
2661 flow := BuildICMPv6Flow(nniPortID, vnet)
2662 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302663 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302664 if err != nil {
2665 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2666 return true
2667 }
2668
2669 flow = BuildDSArpFlow(nniPortID, vnet)
2670 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302671 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302672 if err != nil {
2673 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2674 return true
2675 }
2676
2677 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2678 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2679 return true
2680 }
2681 va.VnetsByName.Range(delicmpv6)
2682 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2683 err := ProcessIcmpv6McGroup(device.Name, true)
2684 if err != nil {
2685 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2686 return
2687 }
2688}
2689
2690// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302691func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(cntx context.Context, vnet *VoltVnet, deviceSerialNum string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302692 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2693 delflows := func(key interface{}, value interface{}) bool {
2694 device := value.(*VoltDevice)
2695 if device.SerialNum != deviceSerialNum {
2696 return true
2697 }
2698 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2699 vnetList := vnetListIntf.(*util.ConcurrentMap)
2700 vnetList.Remove(vnet.Name)
2701 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2702 if vnetList.Length() != 0 {
2703 logger.Warnw(ctx, "Similar VNet associated to diff service. Not removing ICMPv6 flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
2704 return true
2705 }
2706 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2707 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2708 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2709 // The step will be as follow:
2710 // 1. Deact Service
2711 // 2. Pod Reboot
2712 // 3. Pending Delete Service triggered
2713 // 4. Del Service Ind followed by DelVnet req from NB
2714 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2715 // hence the flow will not be cleared
2716 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2717 return true
2718 }
2719 if portID, err := va.GetPortID(device.NniPort); err == nil {
2720 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2721 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2722 return false
2723 }
2724 flow := BuildICMPv6Flow(portID, vnet)
2725 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302726 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302727 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2728 }
2729 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2730
2731 flow = BuildDSArpFlow(portID, vnet)
2732 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302733 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302734 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2735 }
2736 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2737 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2738 }
2739 return false
2740 }
2741 va.DevicesDisc.Range(delflows)
2742}
2743
2744// BuildICMPv6Flow to Build DS flow for ICMPv6
2745func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302746 logger.Infow(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302747 flow := &of.VoltFlow{}
2748 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2749 subFlow := of.NewVoltSubFlow()
2750
2751 subFlow.SetICMPv6Match()
2752 subFlow.SetMatchVlan(vnet.SVlan)
2753 subFlow.SetInPort(inport)
2754 subFlow.SetPopVlan()
2755 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2756 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2757 subFlow.Priority = of.McFlowPriority
2758 var metadata uint64
2759 if vnet.VlanControl == None {
2760 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2761 } else {
2762 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2763 }
2764 subFlow.SetTableMetadata(metadata)
2765 metadata = uint64(vnet.setPbitRemarking())
2766
2767 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2768 subFlow.SetWriteMetadata(metadata)
2769 flow.SubFlows[subFlow.Cookie] = subFlow
2770 return flow
2771}
2772
2773//BuildDSArpFlow Builds DS flow for ARP
2774func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302775 logger.Infow(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302776
2777 flow := &of.VoltFlow{}
2778 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2779 subFlow := of.NewVoltSubFlow()
2780
2781 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
2782 subFlow.SetArpMatch()
2783 subFlow.SetMatchDstMac(BcastMAC)
2784 subFlow.SetMatchVlan(vnet.SVlan)
2785 subFlow.SetInPort(inport)
2786 subFlow.SetPopVlan()
2787 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2788
2789 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
2790 subFlow.Priority = of.McFlowPriority
2791
2792 var metadata uint64
2793 if vnet.VlanControl == None {
2794 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2795 } else {
2796 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2797 }
2798 subFlow.SetTableMetadata(metadata)
2799 metadata = uint64(vnet.setPbitRemarking())
2800 subFlow.SetWriteMetadata(metadata)
2801
2802 flow.SubFlows[subFlow.Cookie] = subFlow
2803 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2804 return flow
2805}
2806
2807// setPbitRemarking to set Pbit remarking
2808func (vv *VoltVnet) setPbitRemarking() uint32 {
2809
2810 // Remarkable
2811 // Remarked Pbit Pbit
2812 // |-----------------------------| |------|
2813 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
2814 // 000 000 000 000 000 000 000 000 00000000
2815
2816 // Eg:
2817 // For 6:3 & 7:1
2818 // 001 011 000 000 000 000 000 000 11000000
2819
2820 var remarkable uint8
2821 var remarked uint32
2822 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
2823 remarkable = remarkable | 1<<refPbit
2824 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
2825 }
2826 return remarked<<8 | uint32(remarkable)
2827}
2828
2829// ProcessIcmpv6McGroup to add icmpv6 multicast group
2830func ProcessIcmpv6McGroup(device string, delete bool) error {
2831
2832 logger.Info(ctx, "Creating ICMPv6 MC Group")
2833 va := GetApplication()
2834 vd := va.GetDevice(device)
2835 group := &of.Group{}
2836 group.GroupID = ICMPv6ArpGroupID
2837 group.Device = device
2838 if delete {
2839 if !vd.icmpv6GroupAdded {
2840 logger.Info(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
2841 return nil //TODO
2842 }
2843 vd.icmpv6GroupAdded = false
2844 group.Command = of.GroupCommandDel
2845 group.ForceAction = true
2846 } else {
2847 if vd.icmpv6GroupAdded {
2848 logger.Info(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
2849 return nil //TODO
2850 }
2851 vd.icmpv6GroupAdded = true
2852 group.Command = of.GroupCommandAdd
2853 receivers := GetApplication().GetIcmpv6Receivers(device)
2854 group.Buckets = append(group.Buckets, receivers...)
2855 }
2856 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
2857 port, _ := GetApplication().GetNniPort(device)
2858 err := cntlr.GetController().GroupUpdate(port, device, group)
2859 return err
2860}
2861
2862//isVlanMatching - checks is vlans matches with vpv based on vlan control
2863func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
2864
2865 switch vpv.VlanControl {
2866 case ONUCVlanOLTSVlan,
2867 OLTCVlanOLTSVlan:
2868 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
2869 return true
2870 }
2871 case ONUCVlan,
2872 OLTSVlan,
2873 None:
2874 if vpv.SVlan == svlan {
2875 return true
2876 }
2877 default:
2878 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2879 }
2880 return false
2881}
2882
2883//PushFlows - Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302884func (vpv *VoltPortVnet) PushFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302885
2886 for cookie := range flow.SubFlows {
2887 cookie := strconv.FormatUint(cookie, 10)
2888 fe := &FlowEvent{
2889 eType: EventTypeControlFlowAdded,
2890 cookie: cookie,
2891 eventData: vpv,
2892 }
2893 device.RegisterFlowAddEvent(cookie, fe)
2894 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302895 return cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302896}
2897
2898//FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
2899func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
2900
2901 sendFlowFailureInd := func(key, value interface{}) bool {
2902 //svc := value.(*VoltService)
2903 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
2904 return true
2905 }
2906 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2907 vpv.services.Range(sendFlowFailureInd)
2908}
2909
2910//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302911func (vpv *VoltPortVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302912
2913 vpv.PendingFlowLock.Lock()
2914 defer vpv.PendingFlowLock.Unlock()
2915
2916 for cookie := range flow.SubFlows {
2917 cookie := strconv.FormatUint(cookie, 10)
2918 fe := &FlowEvent{
2919 eType: EventTypeControlFlowRemoved,
2920 device: device.Name,
2921 cookie: cookie,
2922 eventData: vpv,
2923 }
2924 device.RegisterFlowDelEvent(cookie, fe)
2925 vpv.PendingDeleteFlow[cookie] = true
2926 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302927 return cntlr.GetController().DelFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302928}
2929
2930//CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302931func (vpv *VoltPortVnet) CheckAndDeleteVpv(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302932 vpv.PendingFlowLock.RLock()
2933 defer vpv.PendingFlowLock.RUnlock()
2934 if !vpv.DeleteInProgress {
2935 return
2936 }
2937 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
2938 logger.Infow(ctx, "All Flows removed for VPV. Triggering VPV Deletion from DB", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302939 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302940 logger.Infow(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
2941 }
2942}
2943
2944//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302945func (vpv *VoltPortVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302946 vpv.PendingFlowLock.Lock()
2947 logger.Infow(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
2948
2949 delete(vpv.PendingDeleteFlow, cookie)
2950 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302951 vpv.CheckAndDeleteVpv(cntx)
2952 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302953}
2954
2955//FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302956func (vpv *VoltPortVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302957 vpv.PendingFlowLock.Lock()
2958
2959 logger.Errorw(ctx, "VPV Flow Remove Failure Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
2960
2961 sendFlowFailureInd := func(key, value interface{}) bool {
2962 svc := value.(*VoltService)
2963 svc.triggerServiceFailureInd(errorCode, errReason)
2964 return true
2965 }
2966 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2967 vpv.services.Range(sendFlowFailureInd)
2968
2969 if vpv.DeleteInProgress {
2970 delete(vpv.PendingDeleteFlow, cookie)
2971 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302972 vpv.CheckAndDeleteVpv(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302973 } else {
2974 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302975 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302976 }
2977}
2978
2979//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302980func (vv *VoltVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302981
2982 vv.VnetLock.Lock()
2983 defer vv.VnetLock.Unlock()
2984
2985 var flowMap map[string]bool
2986 var ok bool
2987
2988 for cookie := range flow.SubFlows {
2989 cookie := strconv.FormatUint(cookie, 10)
2990 fe := &FlowEvent{
2991 eType: EventTypeDeviceFlowRemoved,
2992 device: device.Name,
2993 cookie: cookie,
2994 eventData: vv,
2995 }
2996 device.RegisterFlowDelEvent(cookie, fe)
2997 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
2998 flowMap = make(map[string]bool)
2999 }
3000 flowMap[cookie] = true
3001 vv.PendingDeleteFlow[device.Name] = flowMap
3002 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303003 vv.WriteToDb(cntx)
3004 return cntlr.GetController().DelFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05303005}
3006
3007//CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303008func (vv *VoltVnet) CheckAndDeleteVnet(cntx context.Context, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303009 if !vv.DeleteInProgress {
3010 return
3011 }
3012 vv.VnetPortLock.RLock()
3013 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
3014 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
3015 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303016 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05303017 logger.Infow(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
3018 } else {
3019 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
3020 }
3021 vv.VnetPortLock.RUnlock()
3022}
3023
3024//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303025func (vv *VoltVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303026 vv.VnetLock.Lock()
3027 defer vv.VnetLock.Unlock()
3028
3029 logger.Infow(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
3030
3031 if _, ok := vv.PendingDeleteFlow[device]; ok {
3032 delete(vv.PendingDeleteFlow[device], cookie)
3033 }
3034
3035 //Check and update success for pending disable request
3036 if d := GetApplication().GetDevice(device); d != nil {
3037 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3038 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303039 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303040 }
3041 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303042 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303043}
3044
3045//FlowRemoveFailure - Process flow failure indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303046func (vv *VoltVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303047
3048 vv.VnetLock.Lock()
3049 defer vv.VnetLock.Unlock()
3050
3051 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3052 if _, ok := flowMap[cookie]; ok {
3053 logger.Errorw(ctx, "Device Flow Remove Failure Notification", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
3054
3055 if vv.DeleteInProgress {
3056 delete(vv.PendingDeleteFlow[device], cookie)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303057 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303058 }
3059 return
3060 }
3061 }
3062 logger.Errorw(ctx, "Device Flow Remove Failure Notification for Unknown cookie", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3063}
3064
3065//IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
3066func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
3067
3068 //Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3069 //When multiple Igmp-suported service enabled, comment "return false"
3070
3071 sendFlowFailureInd := func(key, value interface{}) bool {
3072 svc := value.(*VoltService)
3073 if svc.IgmpEnabled {
3074 svc.triggerServiceFailureInd(errorCode, errReason)
3075 return false
3076 }
3077 return true
3078 }
3079 logger.Errorw(ctx, "US IGMP Flow Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3080 vpv.services.Range(sendFlowFailureInd)
3081}
3082
3083// GetMatchingMcastService to get matching multicast service
3084func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
3085
3086 var service *VoltService
3087 dIntf, ok := va.DevicesDisc.Load(device)
3088 if !ok {
3089 return nil
3090 }
3091 d := dIntf.(*VoltDevice)
3092
3093 // If the port is NNI port, the services dont exist on it. The svc then
3094 // must be obtained from a different context and is not included here
3095 if port == d.NniPort {
3096 return nil
3097 }
3098
3099 // This is an access port and the port should have all the associated
3100 // services which can be uniquely identified by the VLANs in the packet
3101 vnets, ok := va.VnetsByPort.Load(port)
3102
3103 if !ok {
3104 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3105 return nil
3106 }
3107 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3108 getMcastService := func(key, value interface{}) bool {
3109 srv := value.(*VoltService)
3110 if srv.IgmpEnabled {
3111 service = srv
3112
3113 //TODO: Current implementation supports only for single service with Igmp Enabled
3114 //FIX-ME: When multiple service suports Igmp, update of logic required
3115 return false
3116 }
3117 return true
3118 }
3119
3120 for _, vpv := range vnets.([]*VoltPortVnet) {
3121 if vpv.CVlan == cvlan {
3122 vpv.services.Range(getMcastService)
3123 if service != nil {
3124 break
3125 }
3126 }
3127 }
3128 return service
3129}
3130
3131//TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303132func (vv *VoltVnet) TriggerAssociatedFlowDelete(cntx context.Context, device string) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05303133 vv.VnetLock.Lock()
3134 cookieList := []uint64{}
3135 flowMap := vv.PendingDeleteFlow[device]
3136
3137 for cookie := range flowMap {
3138 cookieList = append(cookieList, convertToUInt64(cookie))
3139 }
3140 vv.VnetLock.Unlock()
3141
3142 if len(cookieList) == 0 {
3143 return false
3144 }
3145
3146 for _, cookie := range cookieList {
3147 if vd := GetApplication().GetDevice(device); vd != nil {
3148 flow := &of.VoltFlow{}
3149 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3150 subFlow := of.NewVoltSubFlow()
3151 subFlow.Cookie = cookie
3152 flow.SubFlows[cookie] = subFlow
3153 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303154 if err := vv.RemoveFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05303155 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3156 }
3157 }
3158 }
3159 return true
3160}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303161
3162// JsonMarshal wrapper function for json Marshal VoltVnet
3163func (vv *VoltVnet) JsonMarshal() ([]byte, error) {
3164 return json.Marshal(VoltVnet{
3165 VnetConfig: vv.VnetConfig,
Akash Sonia8246972023-01-03 10:37:08 +05303166 Version: vv.Version,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303167 VnetOper: VnetOper{
3168 PendingDeleteFlow: vv.VnetOper.PendingDeleteFlow,
3169 DeleteInProgress: vv.VnetOper.DeleteInProgress,
3170 PendingDeviceToDelete: vv.VnetOper.PendingDeviceToDelete,
3171 },
3172 })
3173}
3174
3175// JsonMarshal wrapper function for json Marshal VoltPortVnet
3176func (vpv *VoltPortVnet) JsonMarshal() ([]byte, error) {
3177 return json.Marshal(VoltPortVnet{
3178 Device: vpv.Device,
3179 Port: vpv.Port,
3180 PonPort: vpv.PonPort,
3181 VnetName: vpv.VnetName,
3182 SVlan: vpv.SVlan,
3183 CVlan: vpv.CVlan,
3184 UniVlan: vpv.UniVlan,
3185 SVlanTpid: vpv.SVlanTpid,
3186 DhcpRelay: vpv.DhcpRelay,
3187 ArpRelay: vpv.ArpRelay,
3188 PppoeIa: vpv.PppoeIa,
3189 MacLearning: vpv.MacLearning,
3190 DhcpStatus: vpv.DhcpStatus,
3191 DhcpExpiryTime: vpv.DhcpExpiryTime,
3192 Dhcp6ExpiryTime: vpv.Dhcp6ExpiryTime,
3193 FlowsApplied: vpv.FlowsApplied,
3194 Ipv4Addr: vpv.Ipv4Addr,
3195 Ipv6Addr: vpv.Ipv6Addr,
3196 MacAddr: vpv.MacAddr,
3197 LearntMacAddr: vpv.LearntMacAddr,
3198 CircuitID: vpv.CircuitID,
3199 RemoteID: vpv.RemoteID,
3200 IsOption82Disabled: vpv.IsOption82Disabled,
3201 RelayState: vpv.RelayState,
3202 PPPoeState: vpv.PPPoeState,
3203 RelayStatev6: vpv.RelayStatev6,
3204 IgmpEnabled: vpv.IgmpEnabled,
3205 IgmpFlowsApplied: vpv.IgmpFlowsApplied,
3206 McastService: vpv.McastService,
3207 ONTEtherTypeClassification: vpv.ONTEtherTypeClassification,
3208 VlanControl: vpv.VlanControl,
3209 MvlanProfileName: vpv.MvlanProfileName,
3210 Version: vpv.Version,
3211 McastTechProfileID: vpv.McastTechProfileID,
3212 McastPbit: vpv.McastPbit,
3213 McastUsMeterID: vpv.McastUsMeterID,
3214 AllowTransparent: vpv.AllowTransparent,
3215 SchedID: vpv.SchedID,
3216 DHCPv6DUID: vpv.DHCPv6DUID,
3217 PendingDeleteFlow: vpv.PendingDeleteFlow,
3218 DeleteInProgress: vpv.DeleteInProgress,
3219 Blocked: vpv.Blocked,
3220 DhcpPbit: vpv.DhcpPbit,
3221 })
3222}
Tinoj Josephec742f62022-09-29 19:11:10 +05303223
3224func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) bool {
3225 isActivated := false
3226 vpv.services.Range(func(key, value interface{}) bool {
3227 svc := value.(*VoltService)
3228 if svc.IsActivated {
3229 logger.Infow(ctx, "Found activated service on the vpv", log.Fields{"Name": svc.Name})
3230 isActivated = true
3231 return false //to exit loop
3232 }
3233 return true
3234 })
3235 return isActivated
3236}