blob: a95104c9b34ffa67ad1a2e247998ca25d921d955 [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")
513 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530514 /*
Naveen Sampath04696f72022-06-13 15:19:14 +0530515 if vpv.VlanControl == ONUCVlan {
516 vpv.CVlan = vpv.SVlan
517 }
518 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
519 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
520 if vpv.VlanControl == OLTSVlan {
521 vpv.CVlan = vpv.UniVlan
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530522 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +0530523 vpv.servicesCount = atomic.NewUint64(0)
524 vpv.SchedID = 0
525 vpv.PendingDeleteFlow = make(map[string]bool)
526 vpv.DhcpPbit = vnet.UsDhcpPbit[0]
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530527 vpv.UsPonCTagPriority = vnet.UsPonCTagPriority
528 vpv.UsPonSTagPriority = vnet.UsPonSTagPriority
529 vpv.DsPonCTagPriority = vnet.UsPonCTagPriority
530 vpv.DsPonSTagPriority = vnet.UsPonSTagPriority
531
532 vpv.VnetType = vnet.VnetType
Naveen Sampath04696f72022-06-13 15:19:14 +0530533 return &vpv
534}
535
536func (vpv *VoltPortVnet) setDevice(device string) {
537
538 if vpv.Device != device && vpv.Device != "" {
539 GetApplication().DisassociateVpvsFromDevice(device, vpv)
540 //TEMP:
541 vpv.printAssociatedVPVs(false)
542 }
543
Tinoj Josephec742f62022-09-29 19:11:10 +0530544 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": device, "Port": vpv.Port, "SVlan": vpv.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530545
546 vpv.Device = device
547 GetApplication().AssociateVpvsToDevice(device, vpv)
548 //TEMP:
549 vpv.printAssociatedVPVs(true)
550}
551
552//TODO - Nav - Temp
553func (vpv *VoltPortVnet) printAssociatedVPVs(add bool) {
554 logger.Infow(ctx, "Start----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
555 if vMap := GetApplication().GetAssociatedVpvsForDevice(vpv.Device, vpv.SVlan); vMap != nil {
556 vMap.Range(func(key, value interface{}) bool {
557 vpvEntry := key.(*VoltPortVnet)
558 logger.Infow(ctx, "Associated VPVs", log.Fields{"SVlan": vpvEntry.SVlan, "CVlan": vpvEntry.CVlan, "UniVlan": vpvEntry.UniVlan})
559 return true
560 })
561 }
562 logger.Infow(ctx, "End----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
563
564}
565
566// GetCircuitID : The interface to be satisfied by the VoltPortVnet to be a DHCP relay
567// session is implemented below. The main functions still remain in
568// the service.go file.
569func (vpv *VoltPortVnet) GetCircuitID() []byte {
570 return []byte(vpv.CircuitID)
571}
572
573// GetRemoteID to get remote id
574func (vpv *VoltPortVnet) GetRemoteID() []byte {
575 return []byte(vpv.RemoteID)
576}
577
578// GetDhcpState to get dhcp state
579func (vpv *VoltPortVnet) GetDhcpState() DhcpRelayState {
580 return vpv.RelayState
581}
582
583// SetDhcpState to set the dhcp state
584func (vpv *VoltPortVnet) SetDhcpState(state DhcpRelayState) {
585 vpv.RelayState = state
586}
587
588// GetPppoeIaState to get pppoeia state
589func (vpv *VoltPortVnet) GetPppoeIaState() PppoeIaState {
590 return vpv.PPPoeState
591}
592
593// SetPppoeIaState to set pppoeia state
594func (vpv *VoltPortVnet) SetPppoeIaState(state PppoeIaState) {
595 vpv.PPPoeState = state
596}
597
598// GetDhcpv6State to get dhcpv6 state
599func (vpv *VoltPortVnet) GetDhcpv6State() Dhcpv6RelayState {
600 return vpv.RelayStatev6
601}
602
603// SetDhcpv6State to set dhcpv6 state
604func (vpv *VoltPortVnet) SetDhcpv6State(state Dhcpv6RelayState) {
605 vpv.RelayStatev6 = state
606}
607
608// DhcpResultInd for dhcp result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530609func (vpv *VoltPortVnet) DhcpResultInd(cntx context.Context, res *layers.DHCPv4) {
610 vpv.ProcessDhcpResult(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530611}
612
613// Dhcpv6ResultInd for dhcpv6 result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530614func (vpv *VoltPortVnet) Dhcpv6ResultInd(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
615 vpv.ProcessDhcpv6Result(cntx, ipv6Addr, leaseTime)
Naveen Sampath04696f72022-06-13 15:19:14 +0530616}
617
618// GetNniVlans to get nni vlans
619func (vpv *VoltPortVnet) GetNniVlans() (uint16, uint16) {
620 switch vpv.VlanControl {
621 case ONUCVlanOLTSVlan,
622 OLTCVlanOLTSVlan:
623 return uint16(vpv.SVlan), uint16(vpv.CVlan)
624 case ONUCVlan,
625 None:
626 return uint16(vpv.SVlan), uint16(of.VlanNone)
627 case OLTSVlan:
628 return uint16(vpv.SVlan), uint16(of.VlanNone)
629 }
630 return uint16(of.VlanNone), uint16(of.VlanNone)
631}
632
633// GetService to get service
634func (vpv *VoltPortVnet) GetService(name string) (*VoltService, bool) {
635 service, ok := vpv.services.Load(name)
636 if ok {
637 return service.(*VoltService), ok
638 }
639 return nil, ok
640}
641
642// AddService to add service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530643func (vpv *VoltPortVnet) AddService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530644 vpv.services.Store(service.Name, service)
645 vpv.servicesCount.Inc()
646 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()})
647}
648
649// DelService to delete service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530650func (vpv *VoltPortVnet) DelService(cntx context.Context, service *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530651 vpv.services.Delete(service.Name)
652 vpv.servicesCount.Dec()
653
654 // If the only Igmp Enabled service is removed, remove the Igmp trap flow along with it
655 if service.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530656 if err := vpv.DelIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530657 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530658 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
659 }
660
661 vpv.IgmpEnabled = false
662 }
663 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()})
664}
665
666// ProcessDhcpResult to process dhcp results
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530667func (vpv *VoltPortVnet) ProcessDhcpResult(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530668 msgType := DhcpMsgType(res)
669 if msgType == layers.DHCPMsgTypeAck {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530670 vpv.ProcessDhcpSuccess(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530671 } else if msgType == layers.DHCPMsgTypeNak {
672 vpv.DhcpStatus = DhcpStatusNacked
673 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530674 vpv.WriteToDb(cntx)
675}
676
677// RangeOnServices to call a function on all services on the vpv
678func (vpv *VoltPortVnet) RangeOnServices(cntx context.Context, callback func(cntx context.Context, key, value interface{}) bool) {
679 vpv.services.Range(func(key, value interface{}) bool {
680 return callback(cntx, key, value)
681 })
Naveen Sampath04696f72022-06-13 15:19:14 +0530682}
683
684// ProcessDhcpSuccess : Learn the IPv4 address allocated to the services and update the
685// the services with the same. This also calls for adding flows
686// for the services as the DHCP procedure is completed
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530687func (vpv *VoltPortVnet) ProcessDhcpSuccess(cntx context.Context, res *layers.DHCPv4) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530688 vpv.DhcpStatus = DhcpStatusAcked
689 vpv.Ipv4Addr, _ = GetIpv4Addr(res)
690 logger.Infow(ctx, "Received IPv4 Address", log.Fields{"IP Address": vpv.Ipv4Addr.String()})
691 logger.Infow(ctx, "Services Configured", log.Fields{"Count": vpv.servicesCount.Load()})
692
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530693 vpv.RangeOnServices(cntx, vpv.updateIPv4AndProvisionFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530694 vpv.ProcessDhcpv4Options(res)
695}
696
697// ProcessDhcpv4Options : Currently we process lease time and store the validity of the
698// IP address allocated.
699func (vpv *VoltPortVnet) ProcessDhcpv4Options(res *layers.DHCPv4) {
700 for _, o := range res.Options {
701 switch o.Type {
702 case layers.DHCPOptLeaseTime:
703 leasetime := GetIPv4LeaseTime(o)
704 vpv.DhcpExpiryTime = time.Now().Add((time.Duration(leasetime) * time.Second))
705 logger.Infow(ctx, "Lease Expiry Set", log.Fields{"Time": vpv.DhcpExpiryTime})
706 }
707 }
708}
709
710// ProcessDhcpv6Result : Read the IPv6 address allocated to the device and store it on the
711// VNET. The same IPv6 address is also passed to the services. When a
712// service is fetched all the associated information such as MAC address,
713// IPv4 address and IPv6 addresses can be provided.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530714func (vpv *VoltPortVnet) ProcessDhcpv6Result(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530715 // TODO: Status based hanlding of flows
716 vpv.Dhcp6ExpiryTime = time.Now().Add((time.Duration(leaseTime) * time.Second))
717 vpv.Ipv6Addr = ipv6Addr
718
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530719 vpv.RangeOnServices(cntx, vpv.updateIPv6AndProvisionFlows)
720 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530721}
722
723// AddSvcUsMeterToDevice to add service upstream meter info to device
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530724func AddSvcUsMeterToDevice(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +0530725 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +0530726 logger.Infow(ctx, "Adding upstream meter profile to device", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530727 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
728 GetApplication().AddMeterToDevice(svc.Port, device.Name, svc.UsMeterID, 0)
729 return true
730 }
731 logger.Errorw(ctx, "Dropping US Meter request: Device not found", log.Fields{"Service": svc})
732 return false
733}
734
735// PushFlowsForPortVnet - triggers flow construction and push for provided VPV
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530736func (vpv *VoltPortVnet) PushFlowsForPortVnet(cntx context.Context, d *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530737
738 vp := d.GetPort(vpv.Port)
739
740 //Ignore if UNI port is not found or not UP
741 if vp == nil || vp.State != PortStateUp {
742 logger.Warnw(ctx, "Ignoring Vlan UP Ind for VPV: Port Not Found/Ready", log.Fields{"Port": vp})
743 return
744 }
745
746 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
747 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})
748 return
749 }
750
751 //Disable the flag so that flows can be pushed again
752 // vpv.IgmpFlowsApplied = false
753 // vpv.DsFlowsApplied = false
754 // vpv.UsFlowsApplied = false
755 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530756 vpv.PortUpInd(cntx, d, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +0530757 vpv.VpvLock.Unlock()
758}
759
760// PortUpInd : When a port transistions to UP state, the indication is passed
761// on to this module via the application. We read the VNET configuration
762// again here to apply the latest configuration if the configuration
763// changed. Thus, a reboot of ONT forces the new configuration to get
764// applied.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530765func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530766
767 if vpv.DeleteInProgress {
768 logger.Errorw(ctx, "Ignoring VPV Port UP Ind, VPV deleteion In-Progress", log.Fields{"Device": device, "Port": port, "Vnet": vpv.VnetName})
769 return
770 }
771 vpv.setDevice(device.Name)
772 logger.Infow(ctx, "Port UP Ind, pushing flows for the port", log.Fields{"Device": device, "Port": port, "VnetDhcp": vpv.DhcpRelay, "McastService": vpv.McastService})
773
774 nni, _ := GetApplication().GetNniPort(device.Name)
775 if nni == "" {
776 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name})
777 return
778 }
779
Akash Sonia8246972023-01-03 10:37:08 +0530780 if nniPort := device.GetPort(nni); nniPort != nil {
781 //If NNI port is not mached to nb nni port dont send flows
782 devConfig := GetApplication().GetDeviceConfig(device.SerialNum)
783 if devConfig != nil {
784 if devConfig.UplinkPort != int(nniPort.ID) {
785 logger.Errorw(ctx, "NNI port not configured from NB, not pushing flows", log.Fields{"NNI Port": devConfig.UplinkPort, "NB NNI port": nniPort.ID})
786 return
787 }
788 }
789 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530790
Akash Sonia8246972023-01-03 10:37:08 +0530791 if vp := device.GetPort(port); vp != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530792 if vpv.PonPort != 0xFF && vpv.PonPort != vp.PonPort {
793 logger.Errorw(ctx, "UNI port discovered on wrong PON Port. Dropping Flow Config for VPV", log.Fields{"Device": device.Name, "Port": port, "DetectedPon": vp.PonPort, "ExpectedPon": vpv.PonPort, "Vnet": vpv.VnetName})
794 return
795 }
796 }
797
798 if vpv.Blocked {
799 logger.Errorw(ctx, "VPV Bocked for Processing. Ignoring flow push request", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
800 return
801 }
802
803 if vpv.DhcpRelay || vpv.ArpRelay || vpv.PppoeIa {
804 // If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
805 // DS HSIA flows are installed after learning the MAC.
806 logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530807 // no HSIA flows for multicast service and DPU_MGMT Service
808 if !vpv.McastService && vpv.VnetType != DPU_MGMT_TRAFFIC {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530809 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530810 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530811 if vpv.VnetType == DPU_MGMT_TRAFFIC {
812 vpv.RangeOnServices(cntx, AddMeterToDevice)
813 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530814 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530815 if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
816 logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530817 /*In case of DPU_MGMT_TRAFFIC, need to install both US and DS traffic */
818 if vpv.VnetType == DPU_MGMT_TRAFFIC {
819 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
820 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530821 // US & DS DHCP, US HSIA flows are already installed
822 // install only DS HSIA flow here.
823 // no HSIA flows for multicast service
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530824 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530825 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530826 }
827 }
828
829 } else {
830 // DHCP relay is not configured. This implies that the service must use
831 // 1:1 and does not require MAC learning. In a completely uncommon but
832 // plausible case, the MAC address can be learnt from N:1 without DHCP
833 // relay by configuring any unknown MAC address to be reported. This
834 // however is not seen as a real use case.
835 logger.Infow(ctx, "Port Up - Service Flows", log.Fields{"Device": device.Name, "Port": port})
836 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530837 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530838 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530839 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530840 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530841 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530842 }
843 }
844
845 // Process IGMP proxy - install IGMP trap rules before DHCP trap rules
846 if vpv.IgmpEnabled {
847 logger.Infow(ctx, "Port Up - IGMP Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530848 vpv.RangeOnServices(cntx, AddSvcUsMeterToDevice)
849 if err := vpv.AddIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530850 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530851 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
852 }
853
854 if vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530855 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +0530856 }
857 }
858
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530859 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530860}
861
862// PortDownInd : When the port status changes to down, we delete all configured flows
863// The same indication is also passed to the services enqueued for them
864// to take appropriate actions
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530865func (vpv *VoltPortVnet) PortDownInd(cntx context.Context, device string, port string, nbRequest bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530866
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530867 if !nbRequest && !GetApplication().OltFlowServiceConfig.RemoveFlowsOnDisable {
868 logger.Info(ctx, "VPV Port DOWN Ind, Not deleting flows since RemoveOnDisable is disabled")
869 return
870 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530871 logger.Infow(ctx, "VPV Port DOWN Ind, deleting all flows for services",
872 log.Fields{"service count": vpv.servicesCount.Load()})
873
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530874 //vpv.RangeOnServices(cntx, DelAllFlows)
875 vpv.DelTrapFlows(cntx)
876 vpv.DelHsiaFlows(cntx)
877 vpv.WriteToDb(cntx)
878 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530879}
880
881// SetMacAddr : The MAC address is set when a MAC address is learnt through the
882// packets received from the network. Currently, DHCP packets are
883// only packets we learn the MAC address from
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530884func (vpv *VoltPortVnet) SetMacAddr(cntx context.Context, addr net.HardwareAddr) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530885
886 //Store Learnt MAC address and return if MACLearning is not enabled
887 vpv.LearntMacAddr = addr
888 if vpv.MacLearning == MacLearningNone || !NonZeroMacAddress(addr) ||
889 (NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn) {
890 return
891 }
892
893 // Compare the two MAC addresses to see if it is same
894 // If they are same, we just return. If not, we perform
895 // actions to address the change in MAC address
896 //if NonZeroMacAddress(vpv.MacAddr) && !util.MacAddrsMatch(vpv.MacAddr, addr) {
897 if !util.MacAddrsMatch(vpv.MacAddr, addr) {
898 expectedPort := GetApplication().GetMacInPortMap(addr)
899 if expectedPort != "" && expectedPort != vpv.Port {
900 logger.Errorw(ctx, "mac-learnt-from-different-port-ignoring-setmacaddr",
901 log.Fields{"ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": addr.String()})
902 return
903 }
904 if NonZeroMacAddress(vpv.MacAddr) {
905 logger.Warnw(ctx, "MAC Address Changed. Remove old flows (if added) and re-add with updated MAC", log.Fields{"UpdatedMAC": addr})
906
907 // The newly learnt MAC address is different than earlier one.
908 // The existing MAC based HSIA flows need to be undone as the device
909 // may have been changed
910 // Atleast one HSIA flow should be present in adapter to retain the TP and GEM
911 // hence delete one after the other
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530912 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530913 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530914 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
915 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
916 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530917 GetApplication().DeleteMacInPortMap(vpv.MacAddr)
918 } else {
919 vpv.MacAddr = addr
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530920 vpv.RangeOnServices(cntx, vpv.setLearntMAC)
Naveen Sampath04696f72022-06-13 15:19:14 +0530921 logger.Infow(ctx, "MAC Address learnt from DHCP or ARP", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
922 }
923 GetApplication().UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
924 } else {
925 logger.Infow(ctx, "Leant MAC Address is same", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
926 }
927
928 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
929 if err != nil {
930 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
Akash Sonia8246972023-01-03 10:37:08 +0530931 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530932 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
933 return
934 }
935 // Ds Hsia flows has to be pushed
936 if vpv.FlowsApplied {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530937 // In case of DPU_MGMT_TRAFFIC install both US and DS Flows
938 if vpv.VnetType == DPU_MGMT_TRAFFIC {
939 vpv.RangeOnServices(cntx, AddUsHsiaFlows)
940 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530941 // no HSIA flows for multicast service
942 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530943 vpv.RangeOnServices(cntx, AddDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +0530944 }
945 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530946 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530947}
948
949// MatchesVlans : If the VNET matches both S and C VLANs, return true. Else, return false
950func (vpv *VoltPortVnet) MatchesVlans(svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) bool {
951 if vpv.SVlan != svlan || vpv.CVlan != cvlan || vpv.UniVlan != univlan {
952 return false
953 }
954 return true
955}
956
957// MatchesCvlan : If the VNET matches CVLAN, return true. Else, return false
958func (vpv *VoltPortVnet) MatchesCvlan(cvlan []of.VlanType) bool {
959 if len(cvlan) != 1 && !vpv.AllowTransparent {
960 return false
961 }
962 if vpv.CVlan != cvlan[0] {
963 return false
964 }
965 return true
966}
967
968// MatchesPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
969func (vpv *VoltPortVnet) MatchesPriority(priority uint8) *VoltService {
970
971 var service *VoltService
972 pbitFound := false
973 matchpbitsFunc := func(key, value interface{}) bool {
974 svc := value.(*VoltService)
975 for _, pbit := range svc.Pbits {
976 if uint8(pbit) == priority {
977 logger.Infow(ctx, "Pbit match found with service",
978 log.Fields{"Pbit": priority, "serviceName": svc.Name})
979 pbitFound = true
980 service = svc
981 return false //Returning false to stop the Range loop
982 }
983 }
984 return true
985 }
986 _ = pbitFound
987 vpv.services.Range(matchpbitsFunc)
988 return service
989}
990
991// GetRemarkedPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
992func (vpv *VoltPortVnet) GetRemarkedPriority(priority uint8) uint8 {
993
994 dsPbit := uint8(0)
995 matchpbitsFunc := func(key, value interface{}) bool {
996 svc := value.(*VoltService)
997 if remarkPbit, ok := svc.DsRemarkPbitsMap[int(priority)]; ok {
998 logger.Infow(ctx, "Pbit match found with service",
999 log.Fields{"Pbit": priority, "serviceName": svc.Name, "remarkPbit": remarkPbit})
1000 dsPbit = uint8(remarkPbit)
1001 return false //Returning false to stop the Range loop
1002 }
1003 // When no remarking info is available, remark the incoming pbit
1004 // to highest pbit configured for the subscriber (across all subservices associated)
1005 svcPbit := uint8(svc.Pbits[0])
1006 if svcPbit > dsPbit {
1007 dsPbit = svcPbit
1008 }
1009 return true
1010 }
1011 vpv.services.Range(matchpbitsFunc)
1012 logger.Debugw(ctx, "Remarked Pbit Value", log.Fields{"Incoming": priority, "Remarked": dsPbit})
1013 return dsPbit
1014}
1015
1016// AddSvc adds a service on the VNET on a port. The addition is
1017// triggered when NB requests for service addition
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301018func (vpv *VoltPortVnet) AddSvc(cntx context.Context, svc *VoltService) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301019
1020 //vpv.services = append(vpv.services, svc)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301021 vpv.AddService(cntx, svc)
Naveen Sampath04696f72022-06-13 15:19:14 +05301022 logger.Debugw(ctx, "Added Service to VPV", log.Fields{"Num of SVCs": vpv.servicesCount.Load(), "SVC": svc})
1023
1024 // Learn the circuit-id and remote-id from the service
1025 // TODO: There must be a better way of doing this. This
1026 // may be explored
1027 if svc.IgmpEnabled {
1028 vpv.IgmpEnabled = true
1029 }
1030 // first time service activation MacLearning will have default value as None.
1031 // to handle reciliency if anythng other then None we should retain it .
1032 if svc.MacLearning == MacLearningNone {
1033 if !vpv.DhcpRelay && !vpv.ArpRelay {
1034 svc.MacLearning = MacLearningNone
1035 } else if vpv.MacLearning == Learn {
1036 svc.MacLearning = Learn
1037 } else if vpv.MacLearning == ReLearn {
1038 svc.MacLearning = ReLearn
1039 }
1040 }
1041
1042 //TODO: Temp Change - Need to address MAC Learning flow issues completely
1043 if (svc.MacLearning == Learn || svc.MacLearning == ReLearn) && NonZeroMacAddress(vpv.MacAddr) {
1044 svc.MacAddr = vpv.MacAddr
1045 } else if vpv.servicesCount.Load() == 1 {
1046 vpv.MacAddr = svc.MacAddr
1047 }
1048
1049 vpv.MacLearning = svc.MacLearning
1050 vpv.PonPort = svc.PonPort
1051 logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
1052 //Reconfigure Vlans based on Vlan Control type
1053 svc.VlanControl = vpv.VlanControl
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301054 //TODO Is it good to change NB config?? commenting for now
1055 /*
Naveen Sampath04696f72022-06-13 15:19:14 +05301056 // for OLTCVLAN SVLAN=CVLAN, UNIVLAN can differ.
1057 if vpv.VlanControl == ONUCVlan {
1058 svc.CVlan = svc.SVlan
1059 }
1060 // for OLTSVLAN CVLAN=UNIVLAN , SVLAN can differ,
1061 // hence assigning UNIVLAN to CVLAN, so that ONU will transparently forward the packet.
1062 if vpv.VlanControl == OLTSVlan {
1063 svc.CVlan = svc.UniVlan
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301064 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +05301065 if svc.McastService {
1066 vpv.McastService = true
1067 vpv.McastTechProfileID = svc.TechProfileID
1068 //Assumption: Only one Pbit for mcast service
1069 vpv.McastPbit = svc.Pbits[0]
1070 vpv.McastUsMeterID = svc.UsMeterID
1071 vpv.SchedID = svc.SchedID
1072 }
1073 svc.ONTEtherTypeClassification = vpv.ONTEtherTypeClassification
1074 svc.AllowTransparent = vpv.AllowTransparent
1075 svc.SVlanTpid = vpv.SVlanTpid
1076
1077 //Ensure configuring the mvlan profile only once
1078 //One subscriber cannot have multiple mvlan profiles. Only the first configuration is valid
1079 if svc.MvlanProfileName != "" {
1080 if vpv.MvlanProfileName == "" {
1081 vpv.MvlanProfileName = svc.MvlanProfileName
1082 } else {
1083 logger.Warnw(ctx, "Mvlan Profile already configured for subscriber. Ignoring new Mvlan", log.Fields{"Existing Mvlan": vpv.MvlanProfileName, "New Mvlan": svc.MvlanProfileName})
1084 }
1085 }
1086
Akash Sonia8246972023-01-03 10:37:08 +05301087 voltDevice, err := GetApplication().GetDeviceFromPort(vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301088 if err != nil {
1089 logger.Warnw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
Akash Sonia8246972023-01-03 10:37:08 +05301090 //statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301091 //TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1092 return
1093 }
Tinoj Josephec742f62022-09-29 19:11:10 +05301094 if !svc.IsActivated {
1095 logger.Warn(ctx, "Not pushing Service Flows: Service Not activated")
1096 return
1097 }
Akash Sonia8246972023-01-03 10:37:08 +05301098
1099 //If NNI port is not mached to nb nni port
1100 devConfig := GetApplication().GetDeviceConfig(voltDevice.SerialNum)
1101
1102 if strconv.Itoa(devConfig.UplinkPort) != voltDevice.NniPort {
1103 logger.Errorw(ctx, "NNI port mismatch", log.Fields{"NNI Port": devConfig.UplinkPort, "NB NNI port": voltDevice.NniPort})
1104 return
1105 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301106 //Push Service Flows if DHCP relay is not configured
1107 //or already DHCP flows are configured for the VPV
1108 //to which the serivce is associated
1109 if vpv.FlowsApplied {
1110 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301111 svc.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301112 } else {
Akash Sonia8246972023-01-03 10:37:08 +05301113 if err := svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301114 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1115 }
1116 }
1117 }
1118
1119 //Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
1120 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1121 // service with Igmp Enabled needs to be installed
1122 if svc.IgmpEnabled && vpv.FlowsApplied {
1123 logger.Infow(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301124 if err := vpv.AddIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301125 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301126 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1127 }
1128
1129 if vpv.McastService {
1130 //For McastService, send Service Activated indication once IGMP US flow is pushed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301131 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd)
Naveen Sampath04696f72022-06-13 15:19:14 +05301132 }
1133 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301134 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301135}
1136
1137// setLearntMAC to set learnt mac
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301138func (vpv *VoltPortVnet) setLearntMAC(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301139 svc := value.(*VoltService)
1140 svc.SetMacAddr(vpv.MacAddr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301141 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301142 return true
1143}
1144
1145// PostAccessConfigSuccessInd for posting access config success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301146func PostAccessConfigSuccessInd(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301147 return true
1148}
1149
1150// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301151func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301152 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301153 logger.Infow(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301154 svc.SetIpv4Addr(vpv.Ipv4Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301155 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301156
1157 return true
1158}
1159
1160// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301161func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301162 svc := value.(*VoltService)
1163 svc.SetIpv6Addr(vpv.Ipv6Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301164 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301165
1166 return true
1167}
1168
1169// AddUsHsiaFlows to add upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301170func AddUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301171 svc := value.(*VoltService)
Akash Sonia8246972023-01-03 10:37:08 +05301172 if err := svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301173 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1174 }
1175 return true
1176}
1177
1178// AddDsHsiaFlows to add downstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301179func AddDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301180 svc := value.(*VoltService)
Akash Sonia8246972023-01-03 10:37:08 +05301181 if err := svc.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301182 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1183 }
1184 return true
1185}
1186
1187// ClearFlagsInService to clear the flags used in service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301188func ClearFlagsInService(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301189 svc := value.(*VoltService)
1190 svc.ServiceLock.Lock()
1191 svc.IgmpFlowsApplied = false
1192 svc.DsDhcpFlowsApplied = false
1193 svc.DsHSIAFlowsApplied = false
1194 svc.Icmpv6FlowsApplied = false
1195 svc.UsHSIAFlowsApplied = false
1196 svc.UsDhcpFlowsApplied = false
1197 svc.PendingFlows = make(map[string]bool)
1198 svc.AssociatedFlows = make(map[string]bool)
1199 svc.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301200 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301201 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1202 return true
1203}
1204
1205// DelDsHsiaFlows to delete hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301206func DelDsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301207 svc := value.(*VoltService)
Akash Sonia8246972023-01-03 10:37:08 +05301208 if err := svc.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301209 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1210 }
1211 return true
1212}
1213
1214// DelUsHsiaFlows to delete upstream hsia flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301215func DelUsHsiaFlows(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301216 svc := value.(*VoltService)
Akash Sonia8246972023-01-03 10:37:08 +05301217 if err := svc.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301218 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1219 }
1220 return true
1221}
1222
1223// ClearServiceCounters to clear the service counters
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301224func ClearServiceCounters(cntx context.Context, key, value interface{}) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301225 svc := value.(*VoltService)
1226 //Delete the per service counter too
1227 GetApplication().ServiceCounters.Delete(svc.Name)
1228 if svc.IgmpEnabled && svc.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301229 _ = db.DelAllServiceChannelCounter(cntx, svc.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301230 }
1231 return true
1232}
1233
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301234// AddMeterToDevice to add meter config to device, used in FTTB case
1235func AddMeterToDevice(cntx context.Context, key, value interface{}) bool {
1236 svc := value.(*VoltService)
1237 if err:= svc.AddMeterToDevice(cntx); err != nil {
1238 logger.Warnw(ctx, "Add Meter failed", log.Fields{"service": svc.Name, "Error": err})
1239 }
1240 return true
1241}
1242
Naveen Sampath04696f72022-06-13 15:19:14 +05301243//AddTrapFlows - Adds US & DS Trap flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301244func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301245
1246 if !vpv.FlowsApplied || vgcRebooted {
1247 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301248 if err := vpv.AddUsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301249 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301250 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1251 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301252 if err := vpv.AddDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301253 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301254 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1255 }
1256 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1257 log.Fields{"port": vpv.Port})
1258 //vpv.updateICMPv6McGroup(true)
1259 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301260 if err := vpv.AddUsArpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301261 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301262 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1263 }
1264 logger.Info(ctx, "ARP trap rules not added in downstream direction")
1265
1266 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301267 if err := vpv.AddUsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301268 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301269 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1270 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301271 if err := vpv.AddDsPppoeFlows(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 }
1276 vpv.FlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301277 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301278 }
1279}
1280
1281//DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301282func (vpv *VoltPortVnet) DelTrapFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301283
1284 // Delete HSIA & DHCP flows before deleting IGMP flows
1285 if vpv.FlowsApplied || vgcRebooted {
1286 if vpv.DhcpRelay {
Akash Sonia8246972023-01-03 10:37:08 +05301287 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301288 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1289 "UniVlan": vpv.UniVlan, "Error": err})
1290 }
1291 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1292 log.Fields{"port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301293 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301294 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301295 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1296 }
1297 //vpv.updateICMPv6McGroup(false)
1298 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301299 if err := vpv.DelUsArpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301300 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301301 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1302 }
1303 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301304 if err := vpv.DelUsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301305 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301306 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1307 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301308 if err := vpv.DelDsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301309 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301310 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1311 }
1312 }
1313 vpv.FlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301314 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301315 }
Akash Sonia8246972023-01-03 10:37:08 +05301316 if err := vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301317 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1318 "UniVlan": vpv.UniVlan, "Error": err})
1319 }
1320}
1321
1322// DelHsiaFlows deletes the service flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301323func (vpv *VoltPortVnet) DelHsiaFlows(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301324 // no HSIA flows for multicast service
1325 if !vpv.McastService {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301326 vpv.RangeOnServices(cntx, DelUsHsiaFlows)
1327 vpv.RangeOnServices(cntx, DelDsHsiaFlows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301328 }
1329}
1330
1331//ClearServiceCounters - Removes all igmp counters for a service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301332func (vpv *VoltPortVnet) ClearServiceCounters(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301333 //send flows deleted indication to submgr
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301334 vpv.RangeOnServices(cntx, ClearServiceCounters)
Naveen Sampath04696f72022-06-13 15:19:14 +05301335}
1336
1337// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301338func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301339 var vd *VoltDevice
1340 device := vpv.Device
1341
1342 if vd = GetApplication().GetDevice(device); vd != nil {
1343 if vd.State != controller.DeviceStateUP {
1344 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})
1345 return nil
1346 }
1347 } else {
1348 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})
1349 return errorCodes.ErrDeviceNotFound
1350 }
1351
1352 flows, err := vpv.BuildUsDhcpFlows()
1353 if err == nil {
1354 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301355 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301356 //push ind here ABHI
Akash Sonia8246972023-01-03 10:37:08 +05301357 statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301358 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1359 }
1360 } else {
1361 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1362 //push ind here ABHI
Akash Sonia8246972023-01-03 10:37:08 +05301363 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301364 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1365
1366 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301367 return nil
1368}
1369
1370// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301371func (vpv *VoltPortVnet) AddDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301372
1373 var vd *VoltDevice
1374 device := vpv.Device
1375
1376 if vd = GetApplication().GetDevice(device); vd != nil {
1377 if vd.State != controller.DeviceStateUP {
1378 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})
1379 return nil
1380 }
1381 } else {
1382 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})
1383 return errorCodes.ErrDeviceNotFound
1384 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301385 if vd.GlobalDhcpFlowAdded {
1386 logger.Info(ctx, "Global Dhcp flow already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301387 return nil
1388 }
1389
1390 flows, err := vpv.BuildDsDhcpFlows()
1391 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301392 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301393 //push ind here and procced
Akash Sonia8246972023-01-03 10:37:08 +05301394 statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301395 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1396
1397 }
1398 } else {
1399 logger.Errorw(ctx, "DS DHCP Flow Add Failed", log.Fields{"Reason": err.Error()})
1400 //send ind here and proceed
Akash Sonia8246972023-01-03 10:37:08 +05301401 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301402 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1403
1404 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301405 if GetApplication().GetVendorID() != Radisys {
1406 vd.GlobalDhcpFlowAdded = true
1407 }
1408 return nil
1409}
1410
1411// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301412func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
1413 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301414 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301415 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1416 }
1417
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301418 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301419 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301420 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1421 }
1422}
1423
1424// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1425// Write the status of the VPV to the DB once the delete is scheduled
1426// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301427func (vpv *VoltPortVnet) DelUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301428 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1429 if err != nil {
1430 return err
1431 }
1432
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301433 err = vpv.delDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301434 if err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301435 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301436 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1437 }
Akash Sonia8246972023-01-03 10:37:08 +05301438
Naveen Sampath04696f72022-06-13 15:19:14 +05301439 return nil
1440}
1441
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301442func (vpv *VoltPortVnet) delDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301443 flows, err := vpv.BuildUsDhcpFlows()
1444 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301445 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301446 }
1447 logger.Errorw(ctx, "US DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1448 return err
1449}
Naveen Sampath04696f72022-06-13 15:19:14 +05301450
1451// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1452// Write the status of the VPV to the DB once the delete is scheduled
1453// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301454func (vpv *VoltPortVnet) DelDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301455 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1456 if err != nil {
1457 return err
1458 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301459 err = vpv.delDsDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301460 if err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301461 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301462 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1463 }
1464 /*
Akash Sonia8246972023-01-03 10:37:08 +05301465 err = vpv.delDsDhcp6Flows(device)
1466 if err != nil {
1467 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
1468 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1469 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +05301470 return nil
1471}
1472
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301473func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301474 flows, err := vpv.BuildDsDhcpFlows()
1475 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301476 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301477 }
1478 logger.Errorw(ctx, "DS DHCP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1479 return err
1480}
1481
1482/*
1483func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1484 flows, err := vpv.BuildDsDhcp6Flows()
1485 if err == nil {
1486 return vpv.RemoveFlows(device, flows)
1487 }
1488 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1489 return err
1490}*/
1491
1492// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301493func (vpv *VoltPortVnet) AddUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301494
1495 var vd *VoltDevice
1496 device := vpv.Device
1497 if vd = GetApplication().GetDevice(device); vd != nil {
1498 if vd.State != controller.DeviceStateUP {
1499 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})
1500 return nil
1501 }
1502 } else {
1503 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})
1504 return errorCodes.ErrDeviceNotFound
1505 }
1506
1507 flows, err := vpv.BuildUsArpFlows()
1508 if err == nil {
1509 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301510 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301511 return err1
1512 }
1513 } else {
1514 logger.Errorw(ctx, "US ARP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1515 return err
1516 }
1517 return nil
1518}
1519
1520// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1521// Write the status of the VPV to the DB once the delete is scheduled
1522// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301523func (vpv *VoltPortVnet) DelUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301524 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1525 if err != nil {
1526 return err
1527 }
1528 flows, err := vpv.BuildUsArpFlows()
1529 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301530 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301531 }
1532 logger.Errorw(ctx, "US ARP Flow Delete Failed", log.Fields{"Reason": err.Error()})
1533 return err
1534}
1535
1536// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301537func (vpv *VoltPortVnet) AddUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301538 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1539
1540 var vd *VoltDevice
1541 device := vpv.Device
1542
1543 if vd = GetApplication().GetDevice(device); vd != nil {
1544 if vd.State != controller.DeviceStateUP {
1545 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})
1546 return nil
1547 }
1548 } else {
1549 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})
1550 return errorCodes.ErrDeviceNotFound
1551 }
1552
1553 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1554 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1555
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301556 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301557 return err1
1558 }
1559 } else {
1560 logger.Errorw(ctx, "US PPPoE Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
1561 return err
1562 }
1563 return nil
1564}
1565
1566// AddDsPppoeFlows to add downstream pppoe flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301567func (vpv *VoltPortVnet) AddDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301568 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1569 var vd *VoltDevice
1570 device := vpv.Device
1571
1572 if vd = GetApplication().GetDevice(device); vd != nil {
1573 if vd.State != controller.DeviceStateUP {
1574 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})
1575 return nil
1576 }
1577 } else {
1578 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})
1579 return errorCodes.ErrDeviceNotFound
1580 }
1581
1582 flows, err := vpv.BuildDsPppoeFlows()
1583 if err == nil {
1584
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301585 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301586 return err1
1587 }
1588 } else {
1589 logger.Errorw(ctx, "DS PPPoE Flow Add Failed", log.Fields{"Reason": err.Error()})
1590 return err
1591 }
1592 return nil
1593}
1594
1595// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1596// Write the status of the VPV to the DB once the delete is scheduled
1597// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301598func (vpv *VoltPortVnet) DelUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301599 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1600 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1601 if err != nil {
1602 return err
1603 }
1604 flows, err := vpv.BuildUsPppoeFlows()
1605 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301606 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301607 }
1608 logger.Errorw(ctx, "US PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1609 return err
1610}
1611
1612// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1613// Write the status of the VPV to the DB once the delete is scheduled
1614// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301615func (vpv *VoltPortVnet) DelDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301616 logger.Debugw(ctx, "Deleting DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1617 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1618 if err != nil {
1619 return err
1620 }
1621 flows, err := vpv.BuildDsPppoeFlows()
1622 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301623 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301624 }
1625 logger.Errorw(ctx, "DS PPPoE Flow Delete Failed", log.Fields{"Reason": err.Error()})
1626 return err
1627}
1628
1629// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301630func (vpv *VoltPortVnet) AddIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301631
1632 if !vpv.IgmpFlowsApplied || vgcRebooted {
1633 if vpv.MvlanProfileName == "" {
1634 logger.Info(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
1635 return nil
1636 }
1637 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1638 if err != nil {
1639 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1640 return err
1641 } else if device.State != controller.DeviceStateUP {
1642 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})
1643 return nil
1644 }
1645 flows, err := vpv.BuildIgmpFlows()
1646 if err == nil {
1647 for cookie := range flows.SubFlows {
1648 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1649 cookie := strconv.FormatUint(cookie, 10)
1650 fe := &FlowEvent{
1651 eType: EventTypeUsIgmpFlowAdded,
1652 cookie: cookie,
1653 eventData: vpv,
1654 }
1655 vd.RegisterFlowAddEvent(cookie, fe)
1656 }
1657 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301658 if err1 := cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301659 return err1
1660 }
1661 } else {
1662 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1663 return err
1664 }
1665 vpv.IgmpFlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301666 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301667 }
1668 return nil
1669}
1670
1671// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1672// Write the status of the VPV to the DB once the delete is scheduled
1673// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301674func (vpv *VoltPortVnet) DelIgmpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301675
1676 if vpv.IgmpFlowsApplied || vgcRebooted {
1677 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1678 if err != nil {
1679 logger.Errorw(ctx, "Error getting device from port", log.Fields{"Port": vpv.Port, "Reason": err.Error()})
1680 return err
1681 }
1682 flows, err := vpv.BuildIgmpFlows()
1683 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301684 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301685 return err1
1686 }
1687 } else {
1688 logger.Errorw(ctx, "IGMP Flow Add Failed", log.Fields{"Reason": err.Error()})
1689 return err
1690 }
1691 vpv.IgmpFlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301692 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301693 }
1694 return nil
1695}
1696
1697// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1698// The flows included by this function cover US only as the DS is
1699// created either automatically by the VOLTHA or at the device level
1700// earlier
1701func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
1702 flow := &of.VoltFlow{}
1703 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1704
1705 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
1706 subFlow := of.NewVoltSubFlow()
1707 subFlow.SetTableID(0)
1708
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301709
1710 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1711 subFlow.SetMatchVlan(vpv.CVlan)
1712 subFlow.SetMatchPbit(vpv.UsPonCTagPriority)
1713 subFlow.SetPcp(vpv.UsPonSTagPriority)
1714 subFlow.SetSetVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301715 } else {
1716 subFlow.SetMatchVlan(vpv.UniVlan)
1717 subFlow.SetSetVlan(vpv.CVlan)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301718 subFlow.SetPcp(vpv.DhcpPbit)
Naveen Sampath04696f72022-06-13 15:19:14 +05301719 }
1720 subFlow.SetUdpv4Match()
Naveen Sampath04696f72022-06-13 15:19:14 +05301721 subFlow.DstPort = 67
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301722 subFlow.SrcPort = 68
Naveen Sampath04696f72022-06-13 15:19:14 +05301723 uniport, err := GetApplication().GetPortID(vpv.Port)
1724 if err != nil {
1725 logger.Errorw(ctx, "Failed to fetch uni port from vpv", log.Fields{"error": err, "port": vpv.Port})
1726 return nil, err
1727 }
1728 subFlow.SetInPort(uniport)
1729 // PortName and PortID to be used for validation of port before flow pushing
1730 flow.PortID = uniport
1731 flow.PortName = vpv.Port
1732 subFlow.SetReportToController()
1733
1734 // Set techprofile, meterid of first service
1735 vpv.services.Range(func(key, value interface{}) bool {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301736 vs := value.(*VoltService)
1737 var writemetadata uint64
1738 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1739 writemetadata = uint64(vs.SVlan)<<48 + uint64(vs.TechProfileID)<<32
1740 } else {
1741 writemetadata = uint64(vs.TechProfileID) << 32
1742 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301743 subFlow.SetWriteMetadata(writemetadata)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301744 subFlow.SetMeterID(vs.UsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301745 return false
1746 })
1747
Naveen Sampath04696f72022-06-13 15:19:14 +05301748 // metadata := uint64(uniport)
1749 // subFlow.SetWriteMetadata(metadata)
1750 allowTransparent := 0
1751 if vpv.AllowTransparent {
1752 allowTransparent = 1
1753 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301754 if vpv.VnetType != DPU_MGMT_TRAFFIC {
1755 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1756 subFlow.SetTableMetadata(metadata)
1757 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301758 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1759 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1760 subFlow.Priority = of.DhcpFlowPriority
1761
1762 flow.SubFlows[subFlow.Cookie] = subFlow
1763 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1764 return flow, nil
1765}
1766
1767// BuildDsDhcpFlows to build the downstream dhcp flows
1768func (vpv *VoltPortVnet) BuildDsDhcpFlows() (*of.VoltFlow, error) {
1769
1770 logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1771 flow := &of.VoltFlow{}
1772 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1773 subFlow := of.NewVoltSubFlow()
1774 subFlow.SetTableID(0)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301775 // match on vlan only for fttb case
1776 if vpv.VnetType == DPU_MGMT_TRAFFIC {
1777 subFlow.SetMatchVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301778 }
1779 subFlow.SetUdpv4Match()
1780 subFlow.SrcPort = 67
1781 subFlow.DstPort = 68
1782 uniport, _ := GetApplication().GetPortID(vpv.Port)
1783 nni, err := GetApplication().GetNniPort(vpv.Device)
1784 if err != nil {
1785 return nil, err
1786 }
1787 nniport, err := GetApplication().GetPortID(nni)
1788 if err != nil {
1789 return nil, err
1790 }
1791 subFlow.SetInPort(nniport)
1792 // PortName and PortID to be used for validation of port before flow pushing
1793 flow.PortID = uniport
1794 flow.PortName = vpv.Port
1795 // metadata := uint64(uniport)
1796 // subFlow.SetWriteMetadata(metadata)
1797 allowTransparent := 0
1798 if vpv.AllowTransparent {
1799 allowTransparent = 1
1800 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301801 if vpv.VnetType != DPU_MGMT_TRAFFIC {
1802 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1803 subFlow.SetTableMetadata(metadata)
1804 subFlow.Priority = of.DhcpFlowPriority
1805 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301806 subFlow.SetReportToController()
1807 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1808 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
Naveen Sampath04696f72022-06-13 15:19:14 +05301809
1810 flow.SubFlows[subFlow.Cookie] = subFlow
1811 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1812
1813 return flow, nil
1814}
1815
1816// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1817// application.
1818func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
1819 flow := &of.VoltFlow{}
1820 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1821
1822 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
1823 subFlow := of.NewVoltSubFlow()
1824 subFlow.SetTableID(0)
1825
1826 subFlow.SetMatchVlan(vpv.UniVlan)
1827 subFlow.SetSetVlan(vpv.CVlan)
1828 subFlow.SetUdpv6Match()
1829 subFlow.SrcPort = 546
1830 subFlow.DstPort = 547
1831 uniport, err := GetApplication().GetPortID(vpv.Port)
1832 if err != nil {
1833 return nil, err
1834 }
1835 // Set techprofile, meterid of first service
1836 vpv.services.Range(func(key, value interface{}) bool {
1837 svc := value.(*VoltService)
1838 writemetadata := uint64(svc.TechProfileID) << 32
1839 subFlow.SetWriteMetadata(writemetadata)
1840 subFlow.SetMeterID(svc.UsMeterID)
1841 return false
1842 })
1843 subFlow.SetInPort(uniport)
1844 // PortName and PortID to be used for validation of port before flow pushing
1845 flow.PortID = uniport
1846 flow.PortName = vpv.Port
1847 //subFlow.SetMeterId(vpv.UsDhcpMeterId)
1848 // metadata := uint64(uniport)
1849 // subFlow.SetWriteMetadata(metadata)
1850 allowTransparent := 0
1851 if vpv.AllowTransparent {
1852 allowTransparent = 1
1853 }
1854 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1855 subFlow.SetTableMetadata(metadata)
1856 subFlow.SetReportToController()
1857 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1858 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
1859 subFlow.Priority = of.DhcpFlowPriority
1860
1861 flow.SubFlows[subFlow.Cookie] = subFlow
1862 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1863 return flow, nil
1864}
1865
1866// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1867// application.
1868func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
1869 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
1870
1871 flow := &of.VoltFlow{}
1872 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1873 subFlow := of.NewVoltSubFlow()
1874 subFlow.SetTableID(0)
1875
1876 vpv.setDsMatchVlan(subFlow)
1877 subFlow.SetUdpv6Match()
1878 subFlow.SrcPort = 547
1879 subFlow.DstPort = 547
1880 uniport, _ := GetApplication().GetPortID(vpv.Port)
1881 nni, err := GetApplication().GetNniPort(vpv.Device)
1882 if err != nil {
1883 return nil, err
1884 }
1885 nniport, err := GetApplication().GetPortID(nni)
1886 if err != nil {
1887 return nil, err
1888 }
1889 subFlow.SetInPort(nniport)
1890 // PortName and PortID to be used for validation of port before flow pushing
1891 flow.PortID = uniport
1892 flow.PortName = vpv.Port
1893 // metadata := uint64(uniport)
1894 // subFlow.SetWriteMetadata(metadata)
1895 allowTransparent := 0
1896 if vpv.AllowTransparent {
1897 allowTransparent = 1
1898 }
1899 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1900 subFlow.SetTableMetadata(metadata)
1901 subFlow.SetReportToController()
1902 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1903 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
1904 subFlow.Priority = of.DhcpFlowPriority
1905
1906 flow.SubFlows[subFlow.Cookie] = subFlow
1907 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1908 return flow, nil
1909}
1910
1911// BuildUsArpFlows builds the US ARP relay flows for a subscriber
1912// The flows included by this function cover US only as the DS is
1913// created either automatically by the VOLTHA or at the device level
1914// earlier
1915func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
1916 flow := &of.VoltFlow{}
1917 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1918
1919 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
1920 subFlow := of.NewVoltSubFlow()
1921 subFlow.SetTableID(0)
1922
1923 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1924 subFlow.SetMatchSrcMac(vpv.MacAddr)
1925 }
1926
1927 subFlow.SetMatchDstMac(BroadcastMAC)
1928 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1929 return nil, err
1930 }
1931 subFlow.SetArpMatch()
1932 uniport, err := GetApplication().GetPortID(vpv.Port)
1933 if err != nil {
1934 return nil, err
1935 }
1936 subFlow.SetInPort(uniport)
1937 // PortName and PortID to be used for validation of port before flow pushing
1938 flow.PortID = uniport
1939 flow.PortName = vpv.Port
1940 subFlow.SetReportToController()
1941 allowTransparent := 0
1942 if vpv.AllowTransparent {
1943 allowTransparent = 1
1944 }
1945 metadata := uint64(uniport)
1946 subFlow.SetWriteMetadata(metadata)
1947 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1948 subFlow.SetTableMetadata(metadata)
1949 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
1950 subFlow.Priority = of.ArpFlowPriority
1951
1952 flow.SubFlows[subFlow.Cookie] = subFlow
1953 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1954 return flow, nil
1955}
1956
1957// setUsMatchVlan to set upstream match vlan
1958func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
1959 switch vpv.VlanControl {
1960 case None:
1961 flow.SetMatchVlan(vpv.SVlan)
1962 case ONUCVlanOLTSVlan:
1963 flow.SetMatchVlan(vpv.CVlan)
1964 case OLTCVlanOLTSVlan:
1965 flow.SetMatchVlan(vpv.UniVlan)
1966 //flow.SetSetVlan(vpv.CVlan)
1967 case ONUCVlan:
1968 flow.SetMatchVlan(vpv.SVlan)
1969 case OLTSVlan:
1970 flow.SetMatchVlan(vpv.UniVlan)
1971 //flow.SetSetVlan(vpv.SVlan)
1972 default:
1973 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
1974 return errorCodes.ErrInvalidParamInRequest
1975 }
1976 return nil
1977}
1978
1979// BuildUsPppoeFlows to build upstream pppoe flows
1980func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
1981
1982 flow := &of.VoltFlow{}
1983 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1984 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
1985 subFlow := of.NewVoltSubFlow()
1986 subFlow.SetTableID(0)
1987
1988 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
1989 subFlow.SetMatchSrcMac(vpv.MacAddr)
1990 }
1991
1992 if err := vpv.setUsMatchVlan(subFlow); err != nil {
1993 return nil, err
1994 }
1995 subFlow.SetPppoeDiscoveryMatch()
1996 uniport, err := GetApplication().GetPortID(vpv.Port)
1997 if err != nil {
1998 return nil, err
1999 }
2000 subFlow.SetInPort(uniport)
2001 subFlow.SetReportToController()
2002 // PortName and PortID to be used for validation of port before flow pushing
2003 flow.PortID = uniport
2004 flow.PortName = vpv.Port
2005
2006 allowTransparent := 0
2007 if vpv.AllowTransparent {
2008 allowTransparent = 1
2009 }
2010 metadata := uint64(uniport)
2011 subFlow.SetWriteMetadata(metadata)
2012
2013 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2014 subFlow.SetTableMetadata(metadata)
2015
2016 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
2017 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
2018 subFlow.Priority = of.PppoeFlowPriority
2019
2020 flow.SubFlows[subFlow.Cookie] = subFlow
2021 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2022 return flow, nil
2023}
2024
2025// BuildDsPppoeFlows to build downstream pppoe flows
2026func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
2027
2028 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
2029 flow := &of.VoltFlow{}
2030 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2031 subFlow := of.NewVoltSubFlow()
2032 subFlow.SetTableID(0)
2033
2034 vpv.setDsMatchVlan(subFlow)
2035 subFlow.SetPppoeDiscoveryMatch()
2036
2037 if NonZeroMacAddress(vpv.MacAddr) {
2038 subFlow.SetMatchDstMac(vpv.MacAddr)
2039 }
2040
2041 uniport, _ := GetApplication().GetPortID(vpv.Port)
2042 nni, err := GetApplication().GetNniPort(vpv.Device)
2043 if err != nil {
2044 return nil, err
2045 }
2046 nniport, err := GetApplication().GetPortID(nni)
2047 if err != nil {
2048 return nil, err
2049 }
2050 subFlow.SetInPort(nniport)
2051 // PortName and PortID to be used for validation of port before flow pushing
2052 flow.PortID = uniport
2053 flow.PortName = vpv.Port
2054 metadata := uint64(uniport)
2055 subFlow.SetWriteMetadata(metadata)
2056 allowTransparent := 0
2057 if vpv.AllowTransparent {
2058 allowTransparent = 1
2059 }
2060 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2061 subFlow.SetTableMetadata(metadata)
2062 subFlow.SetReportToController()
2063 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
2064 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2065 subFlow.Priority = of.PppoeFlowPriority
2066
2067 flow.SubFlows[subFlow.Cookie] = subFlow
2068 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2069 return flow, nil
2070}
2071
2072// setDsMatchVlan to set downstream match vlan
2073func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
2074 switch vpv.VlanControl {
2075 case None:
2076 flow.SetMatchVlan(vpv.SVlan)
2077 case ONUCVlanOLTSVlan,
2078 OLTCVlanOLTSVlan,
2079 ONUCVlan,
2080 OLTSVlan:
2081 flow.SetMatchVlan(vpv.SVlan)
2082 default:
2083 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2084 }
2085}
2086
2087// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2088// in the US direction.
2089func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2090 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2091 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2092 if mvp == nil {
2093 return nil, errors.New("Mvlan Profile configured not found")
2094 }
2095 mvlan := mvp.GetUsMatchVlan()
2096 flow := &of.VoltFlow{}
2097 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2098 subFlow := of.NewVoltSubFlow()
2099 subFlow.SetTableID(0)
2100
Akash Sonia8246972023-01-03 10:37:08 +05302101 subFlow.SetMatchVlan(vpv.UniVlan)
2102 subFlow.SetSetVlan(vpv.CVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05302103
2104 uniport, err := GetApplication().GetPortID(vpv.Port)
2105 if err != nil {
2106 return nil, err
2107 }
2108 subFlow.SetInPort(uniport)
2109 // PortName and PortID to be used for validation of port before flow pushing
2110 flow.PortID = uniport
2111 flow.PortName = vpv.Port
2112
2113 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2114 subFlow.SetMatchSrcMac(vpv.MacAddr)
2115 }
2116 logger.Infow(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
2117 //metadata := uint64(mvlan)
2118
2119 if vpv.McastService {
2120 metadata := uint64(vpv.McastUsMeterID)
2121 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2122 subFlow.SetMatchPbit(vpv.McastPbit)
2123 subFlow.SetMeterID(vpv.McastUsMeterID)
2124 subFlow.SetWriteMetadata(metadata)
2125 } else {
2126 // Set techprofile, meterid of first service
2127 vpv.services.Range(func(key, value interface{}) bool {
2128 svc := value.(*VoltService)
2129 writemetadata := uint64(svc.TechProfileID) << 32
2130 subFlow.SetWriteMetadata(writemetadata)
2131 subFlow.SetMeterID(svc.UsMeterID)
2132 return false
2133 })
2134 }
2135
2136 allowTransparent := 0
2137 if vpv.AllowTransparent {
2138 allowTransparent = 1
2139 }
2140 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2141 subFlow.SetTableMetadata(metadata)
2142 subFlow.SetIgmpMatch()
2143 subFlow.SetReportToController()
2144 //| 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
2145 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2146 subFlow.Priority = of.IgmpFlowPriority
2147
2148 flow.SubFlows[subFlow.Cookie] = subFlow
2149 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2150 return flow, nil
2151}
2152
2153// WriteToDb for writing to database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302154func (vpv *VoltPortVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302155 if vpv.DeleteInProgress {
2156 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2157 return
2158 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302159 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302160}
2161
2162//ForceWriteToDb force commit a VPV to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302163func (vpv *VoltPortVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302164 vpv.PendingFlowLock.RLock()
2165 defer vpv.PendingFlowLock.RUnlock()
2166 vpv.Version = database.PresentVersionMap[database.VpvPath]
2167 if b, err := json.Marshal(vpv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302168 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 +05302169 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2170 "UniVlan": vpv.UniVlan, "Error": err})
2171 }
2172 }
2173}
2174
2175// DelFromDb for deleting from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302176func (vpv *VoltPortVnet) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302177 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 +05302178 _ = db.DelVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
Naveen Sampath04696f72022-06-13 15:19:14 +05302179}
2180
2181// ClearAllServiceFlags to clear all service flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302182func (vpv *VoltPortVnet) ClearAllServiceFlags(cntx context.Context) {
2183 vpv.RangeOnServices(cntx, ClearFlagsInService)
Naveen Sampath04696f72022-06-13 15:19:14 +05302184}
2185
2186// ClearAllVpvFlags to clear all vpv flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302187func (vpv *VoltPortVnet) ClearAllVpvFlags(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302188 vpv.PendingFlowLock.Lock()
2189 vpv.FlowsApplied = false
2190 vpv.IgmpFlowsApplied = false
2191 vpv.PendingDeleteFlow = make(map[string]bool)
2192 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302193 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302194 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2195 log.Fields{"device": vpv.Device, "port": vpv.Port,
2196 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2197}
2198
2199// CreateVpvFromString to create vpv from string
2200func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
2201 var vpv VoltPortVnet
2202 if err := json.Unmarshal(b, &vpv); err == nil {
2203 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2204 if !ok {
2205 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2206 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2207 }
2208 vpv.servicesCount = atomic.NewUint64(0)
2209 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2210 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2211 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2212 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2213 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2214 vnet.associatePortToVnet(vpv.Port)
2215 }
2216
2217 if vpv.DeleteInProgress {
2218 va.VoltPortVnetsToDelete[&vpv] = true
2219 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2220 }
2221 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2222 }
2223}
2224
2225// RestoreVpvsFromDb to restore vpvs from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302226func (va *VoltApplication) RestoreVpvsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302227 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302228 vpvs, _ := db.GetVpvs(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302229 for hash, vpv := range vpvs {
2230 b, ok := vpv.Value.([]byte)
2231 if !ok {
2232 logger.Warn(ctx, "The value type is not []byte")
2233 continue
2234 }
2235 va.CreateVpvFromString(b, hash)
2236 }
2237}
2238
2239// GetVnetByPort : VNET related functionality of VOLT Application here on.
2240// Get the VNET from a port. The port identity is passed as device and port identities in string.
2241// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2242// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2243func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
2244 if _, ok := va.VnetsByPort.Load(port); !ok {
2245 return nil
2246 }
2247 vpvs, _ := va.VnetsByPort.Load(port)
2248 for _, vpv := range vpvs.([]*VoltPortVnet) {
2249 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2250 return vpv
2251 }
2252 }
2253 return nil
2254}
2255
2256// AddVnetToPort to add vnet to port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302257func (va *VoltApplication) AddVnetToPort(cntx context.Context, port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
Naveen Sampath04696f72022-06-13 15:19:14 +05302258 // The VNET is not on the port and is to be added
2259 logger.Debugw(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
2260 vpv := NewVoltPortVnet(vvnet)
2261 vpv.MacLearning = vvnet.MacLearning
2262 vpv.Port = port
2263 vvnet.associatePortToVnet(port)
2264 if _, ok := va.VnetsByPort.Load(port); !ok {
2265 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2266 }
2267 vpvsIntf, _ := va.VnetsByPort.Load(port)
2268 vpvs := vpvsIntf.([]*VoltPortVnet)
2269 vpvs = append(vpvs, vpv)
2270 va.VnetsByPort.Store(port, vpvs)
2271 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2272
2273 vpv.VpvLock.Lock()
2274 defer vpv.VpvLock.Unlock()
2275
2276 // Add the service that is causing the VNET to be added to the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302277 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05302278
Tinoj Josephec742f62022-09-29 19:11:10 +05302279 if !vs.IsActivated {
2280 logger.Warn(ctx, "Not Checking port state: Service Not activated")
2281 // Process the PORT UP if the port is already up
2282 d, err := va.GetDeviceFromPort(port)
2283 if err == nil {
2284 vpv.setDevice(d.Name)
2285 }
2286 vpv.WriteToDb(cntx)
2287 return vpv
2288 }
2289
Naveen Sampath04696f72022-06-13 15:19:14 +05302290 // Process the PORT UP if the port is already up
2291 d, err := va.GetDeviceFromPort(port)
2292 if err == nil {
2293 vpv.setDevice(d.Name)
2294 p := d.GetPort(port)
2295 if p != nil {
2296
2297 if vs.PonPort != 0xFF && vs.PonPort != p.PonPort {
2298 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})
2299 } else {
2300 logger.Infow(ctx, "Checking UNI port state", log.Fields{"State": p.State})
2301 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302302 vpv.PortUpInd(cntx, d, port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302303 }
2304 }
2305 }
2306 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302307 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302308 return vpv
2309}
2310
2311// DelVnetFromPort for deleting vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302312func (va *VoltApplication) DelVnetFromPort(cntx context.Context, port string, vpv *VoltPortVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302313
2314 //Delete DHCP Session
2315 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2316
2317 //Delete PPPoE session
2318 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2319
2320 //Delete Mac from MacPortMap
2321 va.DeleteMacInPortMap(vpv.MacAddr)
2322
2323 //Delete VPV
2324 vpvsIntf, ok := va.VnetsByPort.Load(port)
2325 if !ok {
2326 return
2327 }
2328 vpvs := vpvsIntf.([]*VoltPortVnet)
2329 for i, lvpv := range vpvs {
2330 if lvpv == vpv {
2331 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2332 "UNIVLAN": vpv.UniVlan})
2333
2334 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2335
2336 vpv.DeleteInProgress = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302337 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302338
2339 va.VnetsByPort.Store(port, vpvs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302340 vpv.DelTrapFlows(cntx)
2341 vpv.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302342 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2343 vpv.PendingFlowLock.RLock()
2344 if len(vpv.PendingDeleteFlow) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302345 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302346 }
2347 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302348 vnet.disassociatePortFromVnet(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302349 }
2350 vpv.PendingFlowLock.RUnlock()
2351 return
2352 }
2353 }
2354}
2355
2356// RestoreVnetsFromDb to restore vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302357func (va *VoltApplication) RestoreVnetsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302358 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302359 vnets, _ := db.GetVnets(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302360 for _, net := range vnets {
2361 b, ok := net.Value.([]byte)
2362 if !ok {
2363 logger.Warn(ctx, "The value type is not []byte")
2364 continue
2365 }
2366 var vnet VoltVnet
2367 err := json.Unmarshal(b, &vnet)
2368 if err != nil {
2369 logger.Warn(ctx, "Unmarshal of VNET failed")
2370 continue
2371 }
2372 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302373 if err := va.AddVnet(cntx, vnet.VnetConfig, &vnet.VnetOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302374 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2375 }
2376
2377 if vnet.DeleteInProgress {
2378 va.VnetsToDelete[vnet.Name] = true
2379 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2380 }
2381
2382 }
2383}
2384
2385// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2386// are used as the key to locate the service. If more than one service is on the
2387// same port (essentially a UNI of ONU), the services must be separated by different
2388// CVLANs
2389func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
2390 // Fetch the device first to make sure the device exists
2391 dIntf, ok := va.DevicesDisc.Load(device)
2392 if !ok {
2393 return nil
2394 }
2395 d := dIntf.(*VoltDevice)
2396
2397 // If the port is NNI port, the services dont exist on it. The svc then
2398 // must be obtained from a different context and is not included here
2399 if port == d.NniPort {
2400 return nil
2401 }
2402
2403 //To return the matched service
2404 var service *VoltService
2405
2406 // This is an access port and the port should have all the associated
2407 // services which can be uniquely identified by the VLANs in the packet
2408 vnets, ok := va.VnetsByPort.Load(port)
2409
2410 if !ok {
2411 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2412 return nil
2413 }
2414 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2415 for _, vnet := range vnets.([]*VoltPortVnet) {
2416 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2417 switch vnet.VlanControl {
2418 case ONUCVlanOLTSVlan:
2419 service = vnet.MatchesPriority(priority)
2420 if vnet.MatchesCvlan(vlans) && service != nil {
2421 return service
2422 }
2423 case ONUCVlan,
2424 None:
2425 service = vnet.MatchesPriority(priority)
2426 // In case of DHCP Flow - cvlan == VlanNone
2427 // In case of HSIA Flow - cvlan == Svlan
2428 if len(vlans) == 1 && (vlans[0] == vnet.SVlan || vlans[0] == of.VlanNone) && service != nil {
2429 return service
2430 }
2431 case OLTCVlanOLTSVlan,
2432 OLTSVlan:
2433 service = vnet.MatchesPriority(priority)
2434 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2435 return service
2436 }
2437 default:
2438 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2439 }
2440 }
2441 return nil
2442}
2443
2444// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2445// are used as the key to locate the service. If more than one service is on the
2446// same port (essentially a UNI of ONU), the services must be separated by different
2447// CVLANs
2448func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2449 // Fetch the device first to make sure the device exists
2450 dIntf, ok := va.DevicesDisc.Load(device)
2451 if !ok {
2452 return nil, nil
2453 }
2454 d := dIntf.(*VoltDevice)
2455
2456 // If the port is NNI port, the services dont exist on it. The svc then
2457 // must be obtained from a different context and is not included here
2458 if port == d.NniPort {
2459 return nil, nil
2460 }
2461
2462 //To return the matched service
2463 var service *VoltService
2464
2465 // This is an access port and the port should have all the associated
2466 // services which can be uniquely identified by the VLANs in the packet
2467 if vnets, ok := va.VnetsByPort.Load(port); ok {
2468 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2469 for _, vnet := range vnets.([]*VoltPortVnet) {
2470 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2471 switch vnet.VlanControl {
2472 case ONUCVlanOLTSVlan:
2473 service = vnet.MatchesPriority(priority)
2474 if vnet.MatchesCvlan(vlans) && service != nil {
2475 return vnet, service
2476 }
2477 case ONUCVlan,
2478 None:
2479 service = vnet.MatchesPriority(priority)
2480 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2481 return vnet, service
2482 }
2483 case OLTCVlanOLTSVlan,
2484 OLTSVlan:
2485 service = vnet.MatchesPriority(priority)
2486 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2487 return vnet, service
2488 }
2489 default:
2490 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
2491 }
2492 }
2493 }
2494 return nil, nil
2495}
2496
2497// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2498// are used as the key to locate the service. If more than one service is on the
2499// same port (essentially a UNI of ONU), the services must be separated by different
2500// CVLANs
2501func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
2502 vlans := GetVlans(pkt)
2503 priority := GetPriority(pkt)
2504 return va.GetVnetFromFields(device, port, vlans, priority)
2505}
2506
2507// PushDevFlowForVlan to push icmpv6 flows for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302508func (va *VoltApplication) PushDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302509 logger.Infow(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2510 pushflow := func(key interface{}, value interface{}) bool {
2511 device := value.(*VoltDevice)
2512 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302513 logger.Infow(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +05302514 return true
2515 }
2516 if device.State != controller.DeviceStateUP {
2517 logger.Errorw(ctx, "Push Dev Flows Failed - Device state DOWN", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan, "device": device})
2518 return true
2519 }
2520 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2521 logger.Errorw(ctx, "Push Dev Flows Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2522 return true
2523 }
2524
2525 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2526 vnetList := vnetListIntf.(*util.ConcurrentMap)
2527 vnetList.Set(vnet.Name, true)
2528 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2529 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()})
2530 return true
2531 }
2532 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2533 err := ProcessIcmpv6McGroup(device.Name, false)
2534 if err != nil {
2535 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2536 return true
2537 }
2538 if portID, err := va.GetPortID(device.NniPort); err == nil {
2539 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2540 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2541 return true
2542 }
2543
2544 //Pushing ICMPv6 Flow
2545 flow := BuildICMPv6Flow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302546 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302547 if err != nil {
2548 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2549 return true
2550 }
2551 logger.Infow(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
2552
2553 // Pushing ARP Flow
2554 flow = BuildDSArpFlow(portID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302555 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302556 if err != nil {
2557 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2558 return true
2559 }
2560 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2561
2562 vnetList := util.NewConcurrentMap()
2563 vnetList.Set(vnet.Name, true)
2564 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2565 }
2566 return true
2567 }
2568 va.DevicesDisc.Range(pushflow)
2569}
2570
2571// PushDevFlowForDevice to push icmpv6 flows for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302572func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302573 logger.Infow(ctx, "PushDevFlowForDevice", log.Fields{"device": device})
2574
2575 logger.Debugw(ctx, "Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2576 err := ProcessIcmpv6McGroup(device.Name, false)
2577 if err != nil {
2578 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2579 return
2580 }
2581 pushicmpv6 := func(key, value interface{}) bool {
2582 vnet := value.(*VoltVnet)
2583 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2584 vnetList := vnetListIntf.(*util.ConcurrentMap)
2585 vnetList.Set(vnet.Name, true)
2586 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2587 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()})
2588 return true
2589 }
2590 nniPortID, err := va.GetPortID(device.NniPort)
2591 if err != nil {
2592 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2593 }
2594 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2595 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2596 return true
2597 }
2598 flow := BuildICMPv6Flow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302599 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302600 if err != nil {
2601 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2602 return true
2603 }
2604 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2605
2606 flow = BuildDSArpFlow(nniPortID, vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302607 err = cntlr.GetController().AddFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302608 if err != nil {
2609 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2610 return true
2611 }
2612 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2613
2614 vnetList := util.NewConcurrentMap()
2615 vnetList.Set(vnet.Name, true)
2616 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2617 return true
2618 }
2619 va.VnetsByName.Range(pushicmpv6)
2620}
2621
2622// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302623func (va *VoltApplication) DeleteDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302624 logger.Infow(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2625 delflows := func(key interface{}, value interface{}) bool {
2626 device := value.(*VoltDevice)
2627
2628 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2629 vnetList := vnetListIntf.(*util.ConcurrentMap)
2630 vnetList.Remove(vnet.Name)
2631 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2632 if vnetList.Length() != 0 {
2633 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()})
2634 return true
2635 }
2636 }
2637 if portID, err := va.GetPortID(device.NniPort); err == nil {
2638 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2639 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2640 return true
2641 }
2642 //Pushing ICMPv6 Flow
2643 flow := BuildICMPv6Flow(portID, vnet)
2644 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302645 err := vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302646 if err != nil {
2647 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2648 return true
2649 }
2650 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2651
2652 //Pushing ARP Flow
2653 flow = BuildDSArpFlow(portID, vnet)
2654 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302655 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302656 if err != nil {
2657 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2658 return true
2659 }
2660 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2661
2662 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2663 }
2664 return true
2665 }
2666 va.DevicesDisc.Range(delflows)
2667}
2668
2669// DeleteDevFlowForDevice to delete icmpv6 flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302670func (va *VoltApplication) DeleteDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302671 logger.Infow(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
2672 delicmpv6 := func(key, value interface{}) bool {
2673 vnet := value.(*VoltVnet)
2674 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2675 vnetList := vnetListIntf.(*util.ConcurrentMap)
2676 vnetList.Remove(vnet.Name)
2677 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2678 if vnetList.Length() != 0 {
2679 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()})
2680 return true
2681 }
2682 } else {
2683 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2684 return true
2685 }
2686 nniPortID, err := va.GetPortID(device.NniPort)
2687 if err != nil {
2688 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2689 }
2690 flow := BuildICMPv6Flow(nniPortID, vnet)
2691 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302692 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302693 if err != nil {
2694 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2695 return true
2696 }
2697
2698 flow = BuildDSArpFlow(nniPortID, vnet)
2699 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302700 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302701 if err != nil {
2702 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2703 return true
2704 }
2705
2706 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2707 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2708 return true
2709 }
2710 va.VnetsByName.Range(delicmpv6)
2711 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2712 err := ProcessIcmpv6McGroup(device.Name, true)
2713 if err != nil {
2714 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2715 return
2716 }
2717}
2718
2719// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302720func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(cntx context.Context, vnet *VoltVnet, deviceSerialNum string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302721 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
2722 delflows := func(key interface{}, value interface{}) bool {
2723 device := value.(*VoltDevice)
2724 if device.SerialNum != deviceSerialNum {
2725 return true
2726 }
2727 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2728 vnetList := vnetListIntf.(*util.ConcurrentMap)
2729 vnetList.Remove(vnet.Name)
2730 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2731 if vnetList.Length() != 0 {
2732 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()})
2733 return true
2734 }
2735 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2736 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2737 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2738 // The step will be as follow:
2739 // 1. Deact Service
2740 // 2. Pod Reboot
2741 // 3. Pending Delete Service triggered
2742 // 4. Del Service Ind followed by DelVnet req from NB
2743 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2744 // hence the flow will not be cleared
2745 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2746 return true
2747 }
2748 if portID, err := va.GetPortID(device.NniPort); err == nil {
2749 if state, _ := cntlr.GetController().GetPortState(device.Name, device.NniPort); state != cntlr.PortStateUp {
2750 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2751 return false
2752 }
2753 flow := BuildICMPv6Flow(portID, vnet)
2754 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302755 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302756 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2757 }
2758 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2759
2760 flow = BuildDSArpFlow(portID, vnet)
2761 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302762 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302763 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2764 }
2765 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2766 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2767 }
2768 return false
2769 }
2770 va.DevicesDisc.Range(delflows)
2771}
2772
2773// BuildICMPv6Flow to Build DS flow for ICMPv6
2774func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302775 logger.Infow(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302776 flow := &of.VoltFlow{}
2777 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2778 subFlow := of.NewVoltSubFlow()
2779
2780 subFlow.SetICMPv6Match()
2781 subFlow.SetMatchVlan(vnet.SVlan)
2782 subFlow.SetInPort(inport)
2783 subFlow.SetPopVlan()
2784 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2785 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2786 subFlow.Priority = of.McFlowPriority
2787 var metadata uint64
2788 if vnet.VlanControl == None {
2789 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2790 } else {
2791 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2792 }
2793 subFlow.SetTableMetadata(metadata)
2794 metadata = uint64(vnet.setPbitRemarking())
2795
2796 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2797 subFlow.SetWriteMetadata(metadata)
2798 flow.SubFlows[subFlow.Cookie] = subFlow
2799 return flow
2800}
2801
2802//BuildDSArpFlow Builds DS flow for ARP
2803func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Tinoj Joseph1d108322022-07-13 10:07:39 +05302804 logger.Infow(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302805
2806 flow := &of.VoltFlow{}
2807 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2808 subFlow := of.NewVoltSubFlow()
2809
2810 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
2811 subFlow.SetArpMatch()
2812 subFlow.SetMatchDstMac(BcastMAC)
2813 subFlow.SetMatchVlan(vnet.SVlan)
2814 subFlow.SetInPort(inport)
2815 subFlow.SetPopVlan()
2816 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2817
2818 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
2819 subFlow.Priority = of.McFlowPriority
2820
2821 var metadata uint64
2822 if vnet.VlanControl == None {
2823 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2824 } else {
2825 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2826 }
2827 subFlow.SetTableMetadata(metadata)
2828 metadata = uint64(vnet.setPbitRemarking())
2829 subFlow.SetWriteMetadata(metadata)
2830
2831 flow.SubFlows[subFlow.Cookie] = subFlow
2832 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
2833 return flow
2834}
2835
2836// setPbitRemarking to set Pbit remarking
2837func (vv *VoltVnet) setPbitRemarking() uint32 {
2838
2839 // Remarkable
2840 // Remarked Pbit Pbit
2841 // |-----------------------------| |------|
2842 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
2843 // 000 000 000 000 000 000 000 000 00000000
2844
2845 // Eg:
2846 // For 6:3 & 7:1
2847 // 001 011 000 000 000 000 000 000 11000000
2848
2849 var remarkable uint8
2850 var remarked uint32
2851 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
2852 remarkable = remarkable | 1<<refPbit
2853 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
2854 }
2855 return remarked<<8 | uint32(remarkable)
2856}
2857
2858// ProcessIcmpv6McGroup to add icmpv6 multicast group
2859func ProcessIcmpv6McGroup(device string, delete bool) error {
2860
2861 logger.Info(ctx, "Creating ICMPv6 MC Group")
2862 va := GetApplication()
2863 vd := va.GetDevice(device)
2864 group := &of.Group{}
2865 group.GroupID = ICMPv6ArpGroupID
2866 group.Device = device
2867 if delete {
2868 if !vd.icmpv6GroupAdded {
2869 logger.Info(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
2870 return nil //TODO
2871 }
2872 vd.icmpv6GroupAdded = false
2873 group.Command = of.GroupCommandDel
2874 group.ForceAction = true
2875 } else {
2876 if vd.icmpv6GroupAdded {
2877 logger.Info(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
2878 return nil //TODO
2879 }
2880 vd.icmpv6GroupAdded = true
2881 group.Command = of.GroupCommandAdd
2882 receivers := GetApplication().GetIcmpv6Receivers(device)
2883 group.Buckets = append(group.Buckets, receivers...)
2884 }
2885 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
2886 port, _ := GetApplication().GetNniPort(device)
2887 err := cntlr.GetController().GroupUpdate(port, device, group)
2888 return err
2889}
2890
2891//isVlanMatching - checks is vlans matches with vpv based on vlan control
2892func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
2893
2894 switch vpv.VlanControl {
2895 case ONUCVlanOLTSVlan,
2896 OLTCVlanOLTSVlan:
2897 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
2898 return true
2899 }
2900 case ONUCVlan,
2901 OLTSVlan,
2902 None:
2903 if vpv.SVlan == svlan {
2904 return true
2905 }
2906 default:
2907 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2908 }
2909 return false
2910}
2911
2912//PushFlows - Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302913func (vpv *VoltPortVnet) PushFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302914
2915 for cookie := range flow.SubFlows {
2916 cookie := strconv.FormatUint(cookie, 10)
2917 fe := &FlowEvent{
2918 eType: EventTypeControlFlowAdded,
2919 cookie: cookie,
2920 eventData: vpv,
2921 }
2922 device.RegisterFlowAddEvent(cookie, fe)
2923 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302924 return cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302925}
2926
2927//FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
2928func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
2929
2930 sendFlowFailureInd := func(key, value interface{}) bool {
2931 //svc := value.(*VoltService)
2932 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
2933 return true
2934 }
2935 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2936 vpv.services.Range(sendFlowFailureInd)
2937}
2938
2939//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302940func (vpv *VoltPortVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05302941
2942 vpv.PendingFlowLock.Lock()
2943 defer vpv.PendingFlowLock.Unlock()
2944
2945 for cookie := range flow.SubFlows {
2946 cookie := strconv.FormatUint(cookie, 10)
2947 fe := &FlowEvent{
2948 eType: EventTypeControlFlowRemoved,
2949 device: device.Name,
2950 cookie: cookie,
2951 eventData: vpv,
2952 }
2953 device.RegisterFlowDelEvent(cookie, fe)
2954 vpv.PendingDeleteFlow[cookie] = true
2955 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302956 return cntlr.GetController().DelFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302957}
2958
2959//CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302960func (vpv *VoltPortVnet) CheckAndDeleteVpv(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302961 vpv.PendingFlowLock.RLock()
2962 defer vpv.PendingFlowLock.RUnlock()
2963 if !vpv.DeleteInProgress {
2964 return
2965 }
2966 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
2967 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 +05302968 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302969 logger.Infow(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
2970 }
2971}
2972
2973//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302974func (vpv *VoltPortVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302975 vpv.PendingFlowLock.Lock()
2976 logger.Infow(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
2977
2978 delete(vpv.PendingDeleteFlow, cookie)
2979 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302980 vpv.CheckAndDeleteVpv(cntx)
2981 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302982}
2983
2984//FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302985func (vpv *VoltPortVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302986 vpv.PendingFlowLock.Lock()
2987
2988 logger.Errorw(ctx, "VPV Flow Remove Failure Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
2989
2990 sendFlowFailureInd := func(key, value interface{}) bool {
2991 svc := value.(*VoltService)
2992 svc.triggerServiceFailureInd(errorCode, errReason)
2993 return true
2994 }
2995 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
2996 vpv.services.Range(sendFlowFailureInd)
2997
2998 if vpv.DeleteInProgress {
2999 delete(vpv.PendingDeleteFlow, cookie)
3000 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303001 vpv.CheckAndDeleteVpv(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303002 } else {
3003 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303004 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303005 }
3006}
3007
3008//RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303009func (vv *VoltVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05303010
3011 vv.VnetLock.Lock()
3012 defer vv.VnetLock.Unlock()
3013
3014 var flowMap map[string]bool
3015 var ok bool
3016
3017 for cookie := range flow.SubFlows {
3018 cookie := strconv.FormatUint(cookie, 10)
3019 fe := &FlowEvent{
3020 eType: EventTypeDeviceFlowRemoved,
3021 device: device.Name,
3022 cookie: cookie,
3023 eventData: vv,
3024 }
3025 device.RegisterFlowDelEvent(cookie, fe)
3026 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
3027 flowMap = make(map[string]bool)
3028 }
3029 flowMap[cookie] = true
3030 vv.PendingDeleteFlow[device.Name] = flowMap
3031 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303032 vv.WriteToDb(cntx)
3033 return cntlr.GetController().DelFlows(cntx, device.NniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05303034}
3035
3036//CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303037func (vv *VoltVnet) CheckAndDeleteVnet(cntx context.Context, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303038 if !vv.DeleteInProgress {
3039 return
3040 }
3041 vv.VnetPortLock.RLock()
3042 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
3043 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
3044 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303045 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05303046 logger.Infow(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
3047 } else {
3048 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
3049 }
3050 vv.VnetPortLock.RUnlock()
3051}
3052
3053//FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303054func (vv *VoltVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303055 vv.VnetLock.Lock()
3056 defer vv.VnetLock.Unlock()
3057
3058 logger.Infow(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
3059
3060 if _, ok := vv.PendingDeleteFlow[device]; ok {
3061 delete(vv.PendingDeleteFlow[device], cookie)
3062 }
3063
3064 //Check and update success for pending disable request
3065 if d := GetApplication().GetDevice(device); d != nil {
3066 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3067 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303068 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303069 }
3070 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303071 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303072}
3073
3074//FlowRemoveFailure - Process flow failure indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303075func (vv *VoltVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303076
3077 vv.VnetLock.Lock()
3078 defer vv.VnetLock.Unlock()
3079
3080 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3081 if _, ok := flowMap[cookie]; ok {
3082 logger.Errorw(ctx, "Device Flow Remove Failure Notification", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
3083
3084 if vv.DeleteInProgress {
3085 delete(vv.PendingDeleteFlow[device], cookie)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303086 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303087 }
3088 return
3089 }
3090 }
3091 logger.Errorw(ctx, "Device Flow Remove Failure Notification for Unknown cookie", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3092}
3093
3094//IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
3095func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
3096
3097 //Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3098 //When multiple Igmp-suported service enabled, comment "return false"
3099
3100 sendFlowFailureInd := func(key, value interface{}) bool {
3101 svc := value.(*VoltService)
3102 if svc.IgmpEnabled {
3103 svc.triggerServiceFailureInd(errorCode, errReason)
3104 return false
3105 }
3106 return true
3107 }
3108 logger.Errorw(ctx, "US IGMP Flow Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3109 vpv.services.Range(sendFlowFailureInd)
3110}
3111
3112// GetMatchingMcastService to get matching multicast service
3113func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
3114
3115 var service *VoltService
3116 dIntf, ok := va.DevicesDisc.Load(device)
3117 if !ok {
3118 return nil
3119 }
3120 d := dIntf.(*VoltDevice)
3121
3122 // If the port is NNI port, the services dont exist on it. The svc then
3123 // must be obtained from a different context and is not included here
3124 if port == d.NniPort {
3125 return nil
3126 }
3127
3128 // This is an access port and the port should have all the associated
3129 // services which can be uniquely identified by the VLANs in the packet
3130 vnets, ok := va.VnetsByPort.Load(port)
3131
3132 if !ok {
3133 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3134 return nil
3135 }
3136 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3137 getMcastService := func(key, value interface{}) bool {
3138 srv := value.(*VoltService)
3139 if srv.IgmpEnabled {
3140 service = srv
3141
3142 //TODO: Current implementation supports only for single service with Igmp Enabled
3143 //FIX-ME: When multiple service suports Igmp, update of logic required
3144 return false
3145 }
3146 return true
3147 }
3148
3149 for _, vpv := range vnets.([]*VoltPortVnet) {
3150 if vpv.CVlan == cvlan {
3151 vpv.services.Range(getMcastService)
3152 if service != nil {
3153 break
3154 }
3155 }
3156 }
3157 return service
3158}
3159
3160//TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303161func (vv *VoltVnet) TriggerAssociatedFlowDelete(cntx context.Context, device string) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05303162 vv.VnetLock.Lock()
3163 cookieList := []uint64{}
3164 flowMap := vv.PendingDeleteFlow[device]
3165
3166 for cookie := range flowMap {
3167 cookieList = append(cookieList, convertToUInt64(cookie))
3168 }
3169 vv.VnetLock.Unlock()
3170
3171 if len(cookieList) == 0 {
3172 return false
3173 }
3174
3175 for _, cookie := range cookieList {
3176 if vd := GetApplication().GetDevice(device); vd != nil {
3177 flow := &of.VoltFlow{}
3178 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3179 subFlow := of.NewVoltSubFlow()
3180 subFlow.Cookie = cookie
3181 flow.SubFlows[cookie] = subFlow
3182 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303183 if err := vv.RemoveFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05303184 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3185 }
3186 }
3187 }
3188 return true
3189}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303190
3191// JsonMarshal wrapper function for json Marshal VoltVnet
3192func (vv *VoltVnet) JsonMarshal() ([]byte, error) {
3193 return json.Marshal(VoltVnet{
3194 VnetConfig: vv.VnetConfig,
Akash Sonia8246972023-01-03 10:37:08 +05303195 Version: vv.Version,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303196 VnetOper: VnetOper{
3197 PendingDeleteFlow: vv.VnetOper.PendingDeleteFlow,
3198 DeleteInProgress: vv.VnetOper.DeleteInProgress,
3199 PendingDeviceToDelete: vv.VnetOper.PendingDeviceToDelete,
3200 },
3201 })
3202}
3203
3204// JsonMarshal wrapper function for json Marshal VoltPortVnet
3205func (vpv *VoltPortVnet) JsonMarshal() ([]byte, error) {
3206 return json.Marshal(VoltPortVnet{
3207 Device: vpv.Device,
3208 Port: vpv.Port,
3209 PonPort: vpv.PonPort,
3210 VnetName: vpv.VnetName,
3211 SVlan: vpv.SVlan,
3212 CVlan: vpv.CVlan,
3213 UniVlan: vpv.UniVlan,
3214 SVlanTpid: vpv.SVlanTpid,
3215 DhcpRelay: vpv.DhcpRelay,
3216 ArpRelay: vpv.ArpRelay,
3217 PppoeIa: vpv.PppoeIa,
3218 MacLearning: vpv.MacLearning,
3219 DhcpStatus: vpv.DhcpStatus,
3220 DhcpExpiryTime: vpv.DhcpExpiryTime,
3221 Dhcp6ExpiryTime: vpv.Dhcp6ExpiryTime,
3222 FlowsApplied: vpv.FlowsApplied,
3223 Ipv4Addr: vpv.Ipv4Addr,
3224 Ipv6Addr: vpv.Ipv6Addr,
3225 MacAddr: vpv.MacAddr,
3226 LearntMacAddr: vpv.LearntMacAddr,
3227 CircuitID: vpv.CircuitID,
3228 RemoteID: vpv.RemoteID,
3229 IsOption82Disabled: vpv.IsOption82Disabled,
3230 RelayState: vpv.RelayState,
3231 PPPoeState: vpv.PPPoeState,
3232 RelayStatev6: vpv.RelayStatev6,
3233 IgmpEnabled: vpv.IgmpEnabled,
3234 IgmpFlowsApplied: vpv.IgmpFlowsApplied,
3235 McastService: vpv.McastService,
3236 ONTEtherTypeClassification: vpv.ONTEtherTypeClassification,
3237 VlanControl: vpv.VlanControl,
3238 MvlanProfileName: vpv.MvlanProfileName,
3239 Version: vpv.Version,
3240 McastTechProfileID: vpv.McastTechProfileID,
3241 McastPbit: vpv.McastPbit,
3242 McastUsMeterID: vpv.McastUsMeterID,
3243 AllowTransparent: vpv.AllowTransparent,
3244 SchedID: vpv.SchedID,
3245 DHCPv6DUID: vpv.DHCPv6DUID,
3246 PendingDeleteFlow: vpv.PendingDeleteFlow,
3247 DeleteInProgress: vpv.DeleteInProgress,
3248 Blocked: vpv.Blocked,
3249 DhcpPbit: vpv.DhcpPbit,
3250 })
3251}
Tinoj Josephec742f62022-09-29 19:11:10 +05303252
3253func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) bool {
3254 isActivated := false
3255 vpv.services.Range(func(key, value interface{}) bool {
3256 svc := value.(*VoltService)
3257 if svc.IsActivated {
3258 logger.Infow(ctx, "Found activated service on the vpv", log.Fields{"Name": svc.Name})
3259 isActivated = true
3260 return false //to exit loop
3261 }
3262 return true
3263 })
3264 return isActivated
3265}