blob: ef60ce31bd5e2626265ba0842202362486cc7aa9 [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"
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +053022 "fmt"
Naveen Sampath04696f72022-06-13 15:19:14 +053023 "net"
vinokuma04dc9f82023-07-31 15:47:49 +053024 "reflect"
Naveen Sampath04696f72022-06-13 15:19:14 +053025 "strconv"
26 "sync"
27 "time"
28
Akash Sonia8246972023-01-03 10:37:08 +053029 //errorCodes "voltha-go-controller/internal/pkg/errorcodes"
30
Naveen Sampath04696f72022-06-13 15:19:14 +053031 "github.com/google/gopacket"
32 "github.com/google/gopacket/layers"
33 "go.uber.org/atomic"
34
Akash Sonia8246972023-01-03 10:37:08 +053035 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053036 "voltha-go-controller/internal/pkg/controller"
37 cntlr "voltha-go-controller/internal/pkg/controller"
Akash Sonia8246972023-01-03 10:37:08 +053038
39 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053040 "voltha-go-controller/internal/pkg/of"
41 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053042 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053043)
44
45const (
46 // ICMPv6ArpGroupID constant
47 ICMPv6ArpGroupID uint32 = 1
48
49 // Radisys vendor id constant
50 Radisys string = "Radisys"
Tinoj Joseph50d722c2022-12-06 22:53:22 +053051
52 // DPU_MGMT_TRAFFIC serviceType, vnetType constant
vinokuma926cb3e2023-03-29 11:41:06 +053053 DpuMgmtTraffic string = "DPU_MGMT_TRAFFIC"
Tinoj Joseph50d722c2022-12-06 22:53:22 +053054
55 // DPU_ANCP_TRAFFIC serviceType, vnetType constant
vinokuma926cb3e2023-03-29 11:41:06 +053056 DpuAncpTraffic string = "DPU_ANCP_TRAFFIC"
Tinoj Joseph50d722c2022-12-06 22:53:22 +053057
58 // FTTB_SUBSCRIBER_TRAFFIC serviceType, vnetType constant
vinokuma926cb3e2023-03-29 11:41:06 +053059 FttbSubscriberTraffic string = "FTTB_SUBSCRIBER_TRAFFIC"
Naveen Sampath04696f72022-06-13 15:19:14 +053060)
61
62var (
63 //BroadcastMAC - Broadcast MAC Address
64 BroadcastMAC, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")
65)
66
67// NonZeroMacAddress utility to identify if the MAC address is non-zero.
68// We use zero MAC address as an unset MAC address
69func NonZeroMacAddress(h net.HardwareAddr) bool {
70 for i := 0; i < 6; i++ {
71 if h[i] != 0 {
72 return true
73 }
74 }
75 return false
76}
77
78// VNET package manages the different virtual networks that are part of the
79// the network. In the case of VOLT, the networks can be single tagged or
80// double tagged networks. In addition, the networks may be used for unicast
81// and multicast traffic. The unicast traffic further has two models, the
82// 1:1 and N:1 model. In case of a 1:1 model, the outer tag is same for many
83// subscribers and the inner tag is unique to each subscriber for the same
84// outer tag. The N:1 uses the same inner and outer tags, or for that matter
85// a single tag that can also be shared by subscribers. The VNET implementation
86// manages all these possibilities and the associated configuration.
87
88const (
89 // PbitMatchNone constant
90 PbitMatchNone of.PbitType = 8
91 // PbitMatchAll constant
92 PbitMatchAll of.PbitType = 0xFF
93)
94
95// SVlan - Value of the outer tag if double tagged or the only tag if single
96// tagged
97// SVlanTpid - SVlan Tag Protocol Identifier
98// CVlan - Value of the inner tag. Set to VlanNone if single tagged
99// DhcpRelay - Set to true if the DHCP relay is enabled on the virtual network
100// MacLearning - Set to true if the flows should include MAC address
101// UsDhcpPbit - The pbit used for US DHCP packets
102// DsDhcpPbit - The pbit used for DS DHCP packets
103
104// VnetConfig structure
105type VnetConfig struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530106 CtrlPktPbitRemark map[of.PbitType]of.PbitType
Naveen Sampath04696f72022-06-13 15:19:14 +0530107 Name string
vinokuma926cb3e2023-03-29 11:41:06 +0530108 VnetType string
Naveen Sampath04696f72022-06-13 15:19:14 +0530109 Encapsulation string
vinokuma926cb3e2023-03-29 11:41:06 +0530110 DevicesList []string //List of serial number of devices on which this vnet is applied
Naveen Sampath04696f72022-06-13 15:19:14 +0530111 UsDhcpPbit []of.PbitType
112 DsDhcpPbit []of.PbitType
113 UsIGMPPbit []of.PbitType
114 DsIGMPPbit []of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +0530115 ONTEtherTypeClassification int
116 MacLearning MacLearningType
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530117 UsPonCTagPriority of.PbitType
118 UsPonSTagPriority of.PbitType
119 DsPonCTagPriority of.PbitType
120 DsPonSTagPriority of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +0530121 SVlan of.VlanType
122 CVlan of.VlanType
123 UniVlan of.VlanType
124 SVlanTpid layers.EthernetType
125 VlanControl VlanControl
126 DhcpRelay bool
127 ArpLearning bool
128 AllowTransparent bool
129 PppoeIa bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530130}
131
132// VnetOper structure
133type VnetOper struct {
134 PendingDeleteFlow map[string]map[string]bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530135 AssociatedPorts map[string]bool `json:"-"`
vinokuma926cb3e2023-03-29 11:41:06 +0530136 PendingDeviceToDelete string
137 VnetLock sync.RWMutex `json:"-"`
138 VnetPortLock sync.RWMutex `json:"-"`
139 DeleteInProgress bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530140}
141
142// VoltVnet sructure
143type VoltVnet struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530144 Version string
Naveen Sampath04696f72022-06-13 15:19:14 +0530145 VnetConfig
146 VnetOper
Naveen Sampath04696f72022-06-13 15:19:14 +0530147}
148
149const (
150 // EncapsulationPPPoEIA constant
151 EncapsulationPPPoEIA string = "PPPoE-IA"
152 // EncapsulationPPPoE constant
153 EncapsulationPPPoE string = "PPPoE"
154 // EncapsulationIPoE constant
155 EncapsulationIPoE string = "IPoE"
156)
157
158// NewVoltVnet is constructor for the VNET structure
159func NewVoltVnet(cfg VnetConfig) *VoltVnet {
160 var vv VoltVnet
161 vv.VnetConfig = cfg
162 if vv.PendingDeleteFlow == nil {
163 vv.PendingDeleteFlow = make(map[string]map[string]bool)
164 }
165 vv.DeleteInProgress = false
166 if cfg.Encapsulation == EncapsulationPPPoEIA {
167 vv.PppoeIa = true
168 }
169 vv.AssociatedPorts = make(map[string]bool)
170 return &vv
171}
172
vinokuma926cb3e2023-03-29 11:41:06 +0530173// associatePortToVnet - associate a port to Vnet
Naveen Sampath04696f72022-06-13 15:19:14 +0530174func (vv *VoltVnet) associatePortToVnet(port string) {
175 vv.VnetPortLock.Lock()
176 if vv.AssociatedPorts == nil {
177 vv.AssociatedPorts = make(map[string]bool)
178 }
179 vv.AssociatedPorts[port] = true
180 vv.VnetPortLock.Unlock()
181}
182
vinokuma926cb3e2023-03-29 11:41:06 +0530183// disassociatePortFromVnet - disassociate a port from Vnet and return true if the association map is empty
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530184func (vv *VoltVnet) disassociatePortFromVnet(cntx context.Context, device string, port string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530185 logger.Infow(ctx, "Disassociate Port from Vnet", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530186 vv.VnetPortLock.Lock()
187 delete(vv.AssociatedPorts, port)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530188 logger.Debugw(ctx, "Disassociated Port from Vnet", log.Fields{"Device": device, "Port": port, "Vnet": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow, "AssociatedPorts": vv.AssociatedPorts, "DeleteFlag": vv.DeleteInProgress})
Naveen Sampath04696f72022-06-13 15:19:14 +0530189 vv.VnetPortLock.Unlock()
190
191 if vv.DeleteInProgress {
192 if !vv.isAssociatedPortsPresent() {
193 if len(vv.PendingDeleteFlow[device]) == 0 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530194 logger.Debugw(ctx, "Deleting Vnet", log.Fields{"Name": vv.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530195 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530196 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530197 } else {
198 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow})
199 }
200 } else {
201 vv.VnetPortLock.RLock()
202 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts})
203 vv.VnetPortLock.RUnlock()
204 }
205 }
206}
207
208func (vv *VoltVnet) isAssociatedPortsPresent() bool {
209 vv.VnetPortLock.RLock()
210 defer vv.VnetPortLock.RUnlock()
211 return len(vv.AssociatedPorts) != 0
212}
213
214// WriteToDb commit the VNET to the database
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530215func (vv *VoltVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530216 if vv.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530217 logger.Warnw(ctx, "Skipping Redis Update for Vnet, Vnet delete in progress", log.Fields{"Vnet": vv.Name, "SVlan": vv.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530218 return
219 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530220 vv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530221}
222
vinokuma926cb3e2023-03-29 11:41:06 +0530223// ForceWriteToDb force commit a vnet to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530224func (vv *VoltVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530225 vv.VnetPortLock.RLock()
226 defer vv.VnetPortLock.RUnlock()
227 vv.Version = database.PresentVersionMap[database.VnetPath]
228 logger.Debugw(ctx, "Updating VNET....", log.Fields{"vnet": vv})
229 if b, err := json.Marshal(vv); err == nil {
Akash Sonia8246972023-01-03 10:37:08 +0530230 if err := db.PutVnet(cntx, vv.Name, string(b)); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530231 logger.Warnw(ctx, "Add Vnet to DB failed", log.Fields{"Vnet": vv.Name, "SVlan": vv.SVlan, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530232 }
233 }
234}
235
236// VnetKey creates the key using the two VLAN tags
237// We append the two VLAN tags to create a single key
238func VnetKey(otag of.VlanType, itag of.VlanType, utag of.VlanType) string {
239 return strconv.Itoa(int(otag)) + "-" + strconv.Itoa(int(itag)) + "-" + strconv.Itoa(int(utag))
240}
241
242// GetVnet get VNET configuration related functionality associated with VOLT application
243func (va *VoltApplication) GetVnet(otag of.VlanType, itag of.VlanType, utag of.VlanType) *VoltVnet {
244 // When matching VNET, it is expected to match first just the outer
245 // tag, and then the combination to make sure there is no conflict
246 // for the new configuration.
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530247 logger.Debugw(ctx, "Get Vnet configuration", log.Fields{"SVlan": otag, "CVlan": itag, "UniVlan": utag})
Naveen Sampath04696f72022-06-13 15:19:14 +0530248 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, of.VlanNone, utag)); ok {
249 return vnet.(*VoltVnet)
250 }
251 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, itag, utag)); ok {
252 return vnet.(*VoltVnet)
253 }
254 return nil
255}
256
257// The VNET may also be assigned name for easier references. For now,
258// the VNET is mainly identified by the two VLANs.
259
260// GetVnetByName to get vnet by name
261func (va *VoltApplication) GetVnetByName(name string) *VoltVnet {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530262 logger.Debugw(ctx, "Get Vnet by Name", log.Fields{"Name": name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530263 if vnet, ok := va.VnetsByName.Load(name); ok {
264 return vnet.(*VoltVnet)
265 }
266 return nil
267}
268
269// storeVnetConfig to store vnet config
270func (va *VoltApplication) storeVnetConfig(cfg VnetConfig, vv *VoltVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530271 logger.Debugw(ctx, "Store Vnet config", log.Fields{"Name": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530272 var vnetMap *util.ConcurrentMap
273
274 va.VnetsByTag.Store(VnetKey(cfg.SVlan, cfg.CVlan, cfg.UniVlan), vv)
275 va.VnetsByName.Store(cfg.Name, vv)
276
277 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vv.SVlan); !ok {
278 vnetMap = util.NewConcurrentMap()
279 } else {
280 vnetMap = vnetMapIntf.(*util.ConcurrentMap)
281 }
282 vnetMap.Set(vv, true)
283 va.VnetsBySvlan.Set(vv.SVlan, vnetMap)
284}
285
286// deleteVnetConfig to delete vnet config
287func (va *VoltApplication) deleteVnetConfig(vnet *VoltVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530288 logger.Debugw(ctx, "Delete Vnet config", log.Fields{"Name": vnet.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530289 va.VnetsByTag.Delete(VnetKey(vnet.SVlan, vnet.CVlan, vnet.UniVlan))
290 va.VnetsByName.Delete(vnet.Name)
291
292 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vnet.SVlan); ok {
293 vnetMap := vnetMapIntf.(*util.ConcurrentMap)
294 vnetMap.Remove(vnet)
295 va.VnetsBySvlan.Set(vnet.SVlan, vnetMap)
296 }
297}
298
299// AddVnet to add a VNET to the list of VNETs configured.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530300func (va *VoltApplication) AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530301 logger.Debugw(ctx, "Add Vnet config", log.Fields{"Name": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530302 AppMutex.VnetMutex.Lock()
303 var vv *VoltVnet
304 devicesToHandle := []string{}
305 vv = va.GetVnetByName(cfg.Name)
306 if vv != nil {
307 //Could be for another OLT or could be case of backup-restore
308 for _, serialNum := range cfg.DevicesList {
309 if isDeviceInList(serialNum, vv.DevicesList) {
310 //This is backup restore scenario, just update the profile
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530311 logger.Infow(ctx, "Add Vnet : Profile Name already exists with OLT, update-the-profile", log.Fields{"SerialNum": serialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +0530312 continue
313 }
314 devicesToHandle = append(devicesToHandle, serialNum)
315 }
316 if len(devicesToHandle) == 0 {
Akash Sonief452f12024-12-12 18:20:28 +0530317 logger.Warnw(ctx, "Ignoring Duplicate VNET by name ", log.Fields{"Vnet": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530318 AppMutex.VnetMutex.Unlock()
319 return nil
320 }
321 }
322
323 if vv == nil {
324 vv = NewVoltVnet(cfg)
325 if oper != nil {
326 vv.PendingDeleteFlow = oper.PendingDeleteFlow
327 vv.DeleteInProgress = oper.DeleteInProgress
328 vv.AssociatedPorts = oper.AssociatedPorts
329 vv.PendingDeviceToDelete = oper.PendingDeviceToDelete
330 }
331 devicesToHandle = append(devicesToHandle, cfg.DevicesList...)
332 } else {
333 vv.DevicesList = append(vv.DevicesList, devicesToHandle...)
334 }
335
336 va.storeVnetConfig(cfg, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530337 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530338
339 logger.Infow(ctx, "Added VNET TO DB", log.Fields{"cfg": cfg, "devicesToHandle": devicesToHandle})
340
341 //va.PushDevFlowForVlan(vv)
342 AppMutex.VnetMutex.Unlock()
343 return nil
344}
345
346// DelVnet to delete a VNET from the list of VNETs configured
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530347func (va *VoltApplication) DelVnet(cntx context.Context, name, deviceSerialNum string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530348 logger.Infow(ctx, "Deleting Vnet", log.Fields{"Vnet": name})
349 AppMutex.VnetMutex.Lock()
350 if vnetIntf, ok := va.VnetsByName.Load(name); ok {
351 vnet := vnetIntf.(*VoltVnet)
vinokuma926cb3e2023-03-29 11:41:06 +0530352 // Delete from mvp list
Naveen Sampath04696f72022-06-13 15:19:14 +0530353 vnet.DevicesList = util.RemoveFromSlice(vnet.DevicesList, deviceSerialNum)
354
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530355 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, deviceSerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +0530356 if len(vnet.DevicesList) == 0 {
357 vnet.DeleteInProgress = true
358 vnet.PendingDeviceToDelete = deviceSerialNum
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530359 vnet.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530360 vnet.VnetPortLock.RLock()
361 if len(vnet.PendingDeleteFlow) == 0 && !vnet.isAssociatedPortsPresent() {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530362 logger.Debugw(ctx, "Deleting Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
Naveen Sampath04696f72022-06-13 15:19:14 +0530363 va.deleteVnetConfig(vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530364 _ = db.DelVnet(cntx, vnet.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530365 } else {
366 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
367 }
368 vnet.VnetPortLock.RUnlock()
369 } else {
vinokuma926cb3e2023-03-29 11:41:06 +0530370 // Update the devicelist in db
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530371 vnet.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530372 }
373 }
vinokuma926cb3e2023-03-29 11:41:06 +0530374 // TODO: if no vnets are present on device remove icmpv6 group from device
Naveen Sampath04696f72022-06-13 15:19:14 +0530375 AppMutex.VnetMutex.Unlock()
376 return nil
377}
378
379// UpdateVnet to update the VNET with associated service count
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530380func (va *VoltApplication) UpdateVnet(cntx context.Context, vv *VoltVnet) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530381 va.storeVnetConfig(vv.VnetConfig, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530382 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530383 logger.Infow(ctx, "Updated VNET TO DB", log.Fields{"vv": vv.VnetConfig})
384 return nil
385}
386
387// ------------------------------------------------------------
388// Manifestation of a VNET on a port is handled below
389// ------------------------------------------------------------
390//
391// The VNET on a port handles everything that is done for a VNET
392// such as DHCP relay state machine, MAC addresses, IP addresses
393// learnt, so on.
394
395// DhcpStatus type
396type DhcpStatus uint8
397
398const (
399 // DhcpStatusNone constant
400 DhcpStatusNone DhcpStatus = 0
401 // DhcpStatusAcked constant
402 DhcpStatusAcked DhcpStatus = 1
403 // DhcpStatusNacked constant
404 DhcpStatusNacked DhcpStatus = 2
405 // EthTypeNone constant
406 EthTypeNone int = 0
407 // EthTypeIPoE constant
408 EthTypeIPoE int = 1
409 // EthTypePPPoE constant
410 EthTypePPPoE int = 2
411)
412
413// VoltPortVnet structure
414type VoltPortVnet struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530415 PendingDeleteFlow map[string]bool
416 servicesCount *atomic.Uint64
417 services sync.Map
Naveen Sampath04696f72022-06-13 15:19:14 +0530418 Device string
419 Port string
Naveen Sampath04696f72022-06-13 15:19:14 +0530420 VnetName string
vinokuma926cb3e2023-03-29 11:41:06 +0530421 VnetType string
422 MvlanProfileName string
423 Version string
Naveen Sampath04696f72022-06-13 15:19:14 +0530424 DhcpExpiryTime time.Time
425 Dhcp6ExpiryTime time.Time
Naveen Sampath04696f72022-06-13 15:19:14 +0530426 Ipv4Addr net.IP
427 Ipv6Addr net.IP
428 MacAddr net.HardwareAddr
429 LearntMacAddr net.HardwareAddr
vinokuma926cb3e2023-03-29 11:41:06 +0530430 CircuitID []byte //Will not be used
431 RemoteID []byte //Will not be used
432 VpvLock sync.Mutex `json:"-"`
433 PendingFlowLock sync.RWMutex `json:"-"`
434 SchedID int
Naveen Sampath04696f72022-06-13 15:19:14 +0530435 ONTEtherTypeClassification int
vinokuma926cb3e2023-03-29 11:41:06 +0530436 MacLearning MacLearningType
437 PonPort uint32
438 McastUsMeterID uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530439 McastTechProfileID uint16
440 McastPbit of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +0530441 SVlanTpid layers.EthernetType
Naveen Sampath04696f72022-06-13 15:19:14 +0530442 DhcpPbit of.PbitType
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530443 UsPonCTagPriority of.PbitType
444 UsPonSTagPriority of.PbitType
445 DsPonCTagPriority of.PbitType
446 DsPonSTagPriority of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +0530447 SVlan of.VlanType
448 CVlan of.VlanType
449 UniVlan of.VlanType
450 VlanControl VlanControl
451 RelayState DhcpRelayState
452 DhcpStatus DhcpStatus
453 PPPoeState PppoeIaState
454 RelayStatev6 Dhcpv6RelayState
455 DHCPv6DUID [MaxLenDhcpv6DUID]byte
456 DhcpRelay bool
457 ArpRelay bool
458 PppoeIa bool
459 DeleteInProgress bool
460 Blocked bool
461 AllowTransparent bool
462 IgmpEnabled bool
463 IgmpFlowsApplied bool
464 McastService bool
465 FlowsApplied bool
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530466 IsOption82Enabled bool //Will not be used
Naveen Sampath04696f72022-06-13 15:19:14 +0530467}
468
vinokuma926cb3e2023-03-29 11:41:06 +0530469// VlanControl vlan control type
Naveen Sampath04696f72022-06-13 15:19:14 +0530470type VlanControl uint8
471
472const (
473 // None constant
474 // ONU and OLT will passthrough UNIVLAN as is to BNG
475 None VlanControl = iota
476
477 // ONUCVlanOLTSVlan constant
478 // Tagged traffic, ONU will replace UNIVLAN with CVLAN and OLT will add SVLAN
479 // Untagged traffic, ONU will add CVLAN and OLT will add SVLAN
480 ONUCVlanOLTSVlan
481
482 // OLTCVlanOLTSVlan constant
483 // Tagged traffic, ONU will passthrough UNIVLAN as is to OLT and
484 // OLT will replace UNIVLAN with CVLAN and add SVLAN
485 OLTCVlanOLTSVlan
486
487 // ONUCVlan constant
488 // Tagged traffic, ONU will replace UNIVLAN with CVLAN
489 // Untagged traffic, ONU will add CVLAN
490 ONUCVlan
491
492 // OLTSVlan constant
493 // UnTagged traffic, OLT will add the SVLAN
494 OLTSVlan
495)
496
497// NewVoltPortVnet is constructor for VoltPortVnet
498func NewVoltPortVnet(vnet *VoltVnet) *VoltPortVnet {
499 var vpv VoltPortVnet
500
501 vpv.VnetName = vnet.Name
502 vpv.SVlan = vnet.SVlan
503 vpv.CVlan = vnet.CVlan
504 vpv.UniVlan = vnet.UniVlan
505 vpv.SVlanTpid = vnet.SVlanTpid
506 vpv.DhcpRelay = vnet.DhcpRelay
507 vpv.DhcpStatus = DhcpStatusNone
508 vpv.PPPoeState = PppoeIaStateNone
509 vpv.ArpRelay = vnet.ArpLearning
510 vpv.PppoeIa = vnet.PppoeIa
511 vpv.VlanControl = vnet.VlanControl
512 vpv.ONTEtherTypeClassification = vnet.ONTEtherTypeClassification
513 vpv.AllowTransparent = vnet.AllowTransparent
514 vpv.FlowsApplied = false
515 vpv.IgmpEnabled = false
516 vpv.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
517 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Naveen Sampath04696f72022-06-13 15:19:14 +0530518 vpv.servicesCount = atomic.NewUint64(0)
519 vpv.SchedID = 0
520 vpv.PendingDeleteFlow = make(map[string]bool)
521 vpv.DhcpPbit = vnet.UsDhcpPbit[0]
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530522 vpv.UsPonCTagPriority = vnet.UsPonCTagPriority
523 vpv.UsPonSTagPriority = vnet.UsPonSTagPriority
524 vpv.DsPonCTagPriority = vnet.UsPonCTagPriority
525 vpv.DsPonSTagPriority = vnet.UsPonSTagPriority
526
527 vpv.VnetType = vnet.VnetType
Naveen Sampath04696f72022-06-13 15:19:14 +0530528 return &vpv
529}
530
531func (vpv *VoltPortVnet) setDevice(device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530532 logger.Debugw(ctx, "Set Device", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +0530533 if vpv.Device != device && vpv.Device != "" {
534 GetApplication().DisassociateVpvsFromDevice(device, vpv)
vinokuma926cb3e2023-03-29 11:41:06 +0530535 // TEMP:
Naveen Sampath04696f72022-06-13 15:19:14 +0530536 vpv.printAssociatedVPVs(false)
537 }
538
Tinoj Josephec742f62022-09-29 19:11:10 +0530539 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": device, "Port": vpv.Port, "SVlan": vpv.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530540
541 vpv.Device = device
542 GetApplication().AssociateVpvsToDevice(device, vpv)
vinokuma926cb3e2023-03-29 11:41:06 +0530543 // TEMP:
Naveen Sampath04696f72022-06-13 15:19:14 +0530544 vpv.printAssociatedVPVs(true)
545}
546
vinokuma926cb3e2023-03-29 11:41:06 +0530547// TODO - Nav - Temp
Naveen Sampath04696f72022-06-13 15:19:14 +0530548func (vpv *VoltPortVnet) printAssociatedVPVs(add bool) {
549 logger.Infow(ctx, "Start----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
550 if vMap := GetApplication().GetAssociatedVpvsForDevice(vpv.Device, vpv.SVlan); vMap != nil {
551 vMap.Range(func(key, value interface{}) bool {
552 vpvEntry := key.(*VoltPortVnet)
553 logger.Infow(ctx, "Associated VPVs", log.Fields{"SVlan": vpvEntry.SVlan, "CVlan": vpvEntry.CVlan, "UniVlan": vpvEntry.UniVlan})
554 return true
555 })
556 }
557 logger.Infow(ctx, "End----Printing all associated VPV", log.Fields{"Device": vpv.Device, "Add": add})
Naveen Sampath04696f72022-06-13 15:19:14 +0530558}
559
560// GetCircuitID : The interface to be satisfied by the VoltPortVnet to be a DHCP relay
561// session is implemented below. The main functions still remain in
562// the service.go file.
563func (vpv *VoltPortVnet) GetCircuitID() []byte {
564 return []byte(vpv.CircuitID)
565}
566
567// GetRemoteID to get remote id
568func (vpv *VoltPortVnet) GetRemoteID() []byte {
569 return []byte(vpv.RemoteID)
570}
571
572// GetDhcpState to get dhcp state
573func (vpv *VoltPortVnet) GetDhcpState() DhcpRelayState {
574 return vpv.RelayState
575}
576
577// SetDhcpState to set the dhcp state
578func (vpv *VoltPortVnet) SetDhcpState(state DhcpRelayState) {
579 vpv.RelayState = state
580}
581
582// GetPppoeIaState to get pppoeia state
583func (vpv *VoltPortVnet) GetPppoeIaState() PppoeIaState {
584 return vpv.PPPoeState
585}
586
587// SetPppoeIaState to set pppoeia state
588func (vpv *VoltPortVnet) SetPppoeIaState(state PppoeIaState) {
589 vpv.PPPoeState = state
590}
591
592// GetDhcpv6State to get dhcpv6 state
593func (vpv *VoltPortVnet) GetDhcpv6State() Dhcpv6RelayState {
594 return vpv.RelayStatev6
595}
596
597// SetDhcpv6State to set dhcpv6 state
598func (vpv *VoltPortVnet) SetDhcpv6State(state Dhcpv6RelayState) {
599 vpv.RelayStatev6 = state
600}
601
602// DhcpResultInd for dhcp result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530603func (vpv *VoltPortVnet) DhcpResultInd(cntx context.Context, res *layers.DHCPv4) {
604 vpv.ProcessDhcpResult(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530605}
606
607// Dhcpv6ResultInd for dhcpv6 result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530608func (vpv *VoltPortVnet) Dhcpv6ResultInd(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
609 vpv.ProcessDhcpv6Result(cntx, ipv6Addr, leaseTime)
Naveen Sampath04696f72022-06-13 15:19:14 +0530610}
611
612// GetNniVlans to get nni vlans
613func (vpv *VoltPortVnet) GetNniVlans() (uint16, uint16) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530614 logger.Debugw(ctx, "Get Nni Vlans", log.Fields{"vpv.VlanControl": vpv.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530615 switch vpv.VlanControl {
616 case ONUCVlanOLTSVlan,
617 OLTCVlanOLTSVlan:
618 return uint16(vpv.SVlan), uint16(vpv.CVlan)
619 case ONUCVlan,
620 None:
621 return uint16(vpv.SVlan), uint16(of.VlanNone)
622 case OLTSVlan:
623 return uint16(vpv.SVlan), uint16(of.VlanNone)
624 }
625 return uint16(of.VlanNone), uint16(of.VlanNone)
626}
627
628// GetService to get service
629func (vpv *VoltPortVnet) GetService(name string) (*VoltService, bool) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530630 logger.Debugw(ctx, "Get Service", log.Fields{"name": name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530631 service, ok := vpv.services.Load(name)
632 if ok {
633 return service.(*VoltService), ok
634 }
635 return nil, ok
636}
637
638// AddService to add service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530639func (vpv *VoltPortVnet) AddService(cntx context.Context, service *VoltService) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530640 logger.Debugw(ctx, "Add Service", log.Fields{"ServiceName": service.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530641 vpv.services.Store(service.Name, service)
642 vpv.servicesCount.Inc()
643 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()})
644}
645
646// DelService to delete service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530647func (vpv *VoltPortVnet) DelService(cntx context.Context, service *VoltService) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530648 logger.Debugw(ctx, "Delete Service", log.Fields{"ServiceName": service.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530649 vpv.services.Delete(service.Name)
650 vpv.servicesCount.Dec()
651
652 // If the only Igmp Enabled service is removed, remove the Igmp trap flow along with it
653 if service.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530654 if err := vpv.DelIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530655 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530656 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
657 }
658
659 vpv.IgmpEnabled = false
660 }
661 logger.Infow(ctx, "Service deleted from VPV", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan, "UNIVlan": vpv.UniVlan, "Service": service.Name, "Count": vpv.servicesCount.Load()})
662}
663
664// ProcessDhcpResult to process dhcp results
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530665func (vpv *VoltPortVnet) ProcessDhcpResult(cntx context.Context, res *layers.DHCPv4) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530666 logger.Debug(ctx, "Process Dhcp Result")
Naveen Sampath04696f72022-06-13 15:19:14 +0530667 msgType := DhcpMsgType(res)
668 if msgType == layers.DHCPMsgTypeAck {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530669 vpv.ProcessDhcpSuccess(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530670 } else if msgType == layers.DHCPMsgTypeNak {
671 vpv.DhcpStatus = DhcpStatusNacked
672 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530673 vpv.WriteToDb(cntx)
674}
675
676// RangeOnServices to call a function on all services on the vpv
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530677func (vpv *VoltPortVnet) RangeOnServices(cntx context.Context, callback func(cntx context.Context, key, value interface{}, flag bool) bool, delFlowsInDevice bool) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530678 vpv.services.Range(func(key, value interface{}) bool {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530679 return callback(cntx, key, value, delFlowsInDevice)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530680 })
Naveen Sampath04696f72022-06-13 15:19:14 +0530681}
682
683// ProcessDhcpSuccess : Learn the IPv4 address allocated to the services and update the
684// the services with the same. This also calls for adding flows
685// for the services as the DHCP procedure is completed
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530686func (vpv *VoltPortVnet) ProcessDhcpSuccess(cntx context.Context, res *layers.DHCPv4) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530687 logger.Info(ctx, "Process Dhcp Success")
Naveen Sampath04696f72022-06-13 15:19:14 +0530688 vpv.DhcpStatus = DhcpStatusAcked
689 vpv.Ipv4Addr, _ = GetIpv4Addr(res)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530690 logger.Debugw(ctx, "Received IPv4 Address and Services Configured", log.Fields{"IP Address": vpv.Ipv4Addr.String(), "Count": vpv.servicesCount.Load()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530691
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530692 vpv.RangeOnServices(cntx, vpv.updateIPv4AndProvisionFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530693 vpv.ProcessDhcpv4Options(res)
694}
695
696// ProcessDhcpv4Options : Currently we process lease time and store the validity of the
697// IP address allocated.
698func (vpv *VoltPortVnet) ProcessDhcpv4Options(res *layers.DHCPv4) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530699 logger.Debug(ctx, "Process Dhcp v4 Options")
Naveen Sampath04696f72022-06-13 15:19:14 +0530700 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) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530715 logger.Debugw(ctx, "Process Dhcp v6 Result", log.Fields{"ipv6Addr": ipv6Addr, "leaseTime": leaseTime})
Naveen Sampath04696f72022-06-13 15:19:14 +0530716 // TODO: Status based hanlding of flows
717 vpv.Dhcp6ExpiryTime = time.Now().Add((time.Duration(leaseTime) * time.Second))
718 vpv.Ipv6Addr = ipv6Addr
719
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530720 vpv.RangeOnServices(cntx, vpv.updateIPv6AndProvisionFlows, false)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530721 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530722}
723
724// AddSvcUsMeterToDevice to add service upstream meter info to device
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530725func AddSvcUsMeterToDevice(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +0530726 svc := value.(*VoltService)
Tinoj Joseph1d108322022-07-13 10:07:39 +0530727 logger.Infow(ctx, "Adding upstream meter profile to device", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530728 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
729 GetApplication().AddMeterToDevice(svc.Port, device.Name, svc.UsMeterID, 0)
730 return true
731 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530732 logger.Warnw(ctx, "Dropping US Meter request: Device not found", log.Fields{"Service": svc})
Naveen Sampath04696f72022-06-13 15:19:14 +0530733 return false
734}
735
736// PushFlowsForPortVnet - triggers flow construction and push for provided VPV
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530737func (vpv *VoltPortVnet) PushFlowsForPortVnet(cntx context.Context, d *VoltDevice) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530738 logger.Debugw(ctx, "Push Flows For Port Vnet", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530739 vp := d.GetPort(vpv.Port)
740
741 //Ignore if UNI port is not found or not UP
742 if vp == nil || vp.State != PortStateUp {
743 logger.Warnw(ctx, "Ignoring Vlan UP Ind for VPV: Port Not Found/Ready", log.Fields{"Port": vp})
744 return
745 }
746
Naveen Sampath04696f72022-06-13 15:19:14 +0530747 //Disable the flag so that flows can be pushed again
748 // vpv.IgmpFlowsApplied = false
749 // vpv.DsFlowsApplied = false
750 // vpv.UsFlowsApplied = false
751 vpv.VpvLock.Lock()
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530752 vpv.PortUpInd(cntx, d, vpv.Port, "")
Naveen Sampath04696f72022-06-13 15:19:14 +0530753 vpv.VpvLock.Unlock()
754}
755
756// PortUpInd : When a port transistions to UP state, the indication is passed
757// on to this module via the application. We read the VNET configuration
758// again here to apply the latest configuration if the configuration
759// changed. Thus, a reboot of ONT forces the new configuration to get
760// applied.
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530761func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string, nniPort string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530762 logger.Infow(ctx, "Port UP Ind, pushing flows for the port", log.Fields{"Device": device, "Port": port, "VnetDhcp": vpv.DhcpRelay, "McastService": vpv.McastService})
Naveen Sampath04696f72022-06-13 15:19:14 +0530763 if vpv.DeleteInProgress {
Akash Sonief452f12024-12-12 18:20:28 +0530764 logger.Warnw(ctx, "Ignoring VPV Port UP Ind, VPV deletion In-Progress", log.Fields{"Device": device, "Port": port, "Vnet": vpv.VnetName})
Naveen Sampath04696f72022-06-13 15:19:14 +0530765 return
766 }
767 vpv.setDevice(device.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530768
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530769 if nniPort != "" {
770 err := vpv.ValidateNniPort(device, nniPort)
771 if err != nil {
772 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is not configured", log.Fields{"Port": vpv.Port, "Device": device.Name, "NNI": nniPort, "Error": err})
773 return
774 }
775 } else {
776 nni, err := GetApplication().GetNniPort(device.Name)
777 if nni == "" {
778 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: Default NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name, "Error": err})
779 return
Akash Sonia8246972023-01-03 10:37:08 +0530780 }
781 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530782
Naveen Sampath04696f72022-06-13 15:19:14 +0530783 if vpv.Blocked {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530784 logger.Warnw(ctx, "VPV Blocked for Processing. Ignoring flow push request", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
Naveen Sampath04696f72022-06-13 15:19:14 +0530785 return
786 }
787
788 if vpv.DhcpRelay || vpv.ArpRelay || vpv.PppoeIa {
789 // If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
790 // DS HSIA flows are installed after learning the MAC.
791 logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530792 // no HSIA flows for multicast service and DPU_MGMT Service
vinokuma926cb3e2023-03-29 11:41:06 +0530793 if !vpv.McastService && vpv.VnetType != DpuMgmtTraffic {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530794 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530795 }
vinokuma926cb3e2023-03-29 11:41:06 +0530796 if vpv.VnetType == DpuMgmtTraffic {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530797 vpv.RangeOnServices(cntx, AddMeterToDevice, false)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530798 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530799 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530800 if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
801 logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530802 /*In case of DPU_MGMT_TRAFFIC, need to install both US and DS traffic */
vinokuma926cb3e2023-03-29 11:41:06 +0530803 if vpv.VnetType == DpuMgmtTraffic {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530804 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530805 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530806 // US & DS DHCP, US HSIA flows are already installed
807 // install only DS HSIA flow here.
808 // no HSIA flows for multicast service
Akash Soni53da2852023-03-15 00:31:31 +0530809 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530810 vpv.RangeOnServices(cntx, AddDsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530811 }
812 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530813 } else {
814 // DHCP relay is not configured. This implies that the service must use
815 // 1:1 and does not require MAC learning. In a completely uncommon but
816 // plausible case, the MAC address can be learnt from N:1 without DHCP
817 // relay by configuring any unknown MAC address to be reported. This
818 // however is not seen as a real use case.
819 logger.Infow(ctx, "Port Up - Service Flows", log.Fields{"Device": device.Name, "Port": port})
820 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530821 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530822 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530823 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530824 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530825 vpv.RangeOnServices(cntx, AddDsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530826 }
827 }
828
829 // Process IGMP proxy - install IGMP trap rules before DHCP trap rules
830 if vpv.IgmpEnabled {
831 logger.Infow(ctx, "Port Up - IGMP Flows", log.Fields{"Device": device.Name, "Port": port})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530832 vpv.RangeOnServices(cntx, AddSvcUsMeterToDevice, false)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530833 if err := vpv.AddIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530834 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530835 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
836 }
837
838 if vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530839 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530840 }
841 }
842
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530843 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530844}
845
846// PortDownInd : When the port status changes to down, we delete all configured flows
847// The same indication is also passed to the services enqueued for them
848// to take appropriate actions
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530849// delFlowsInDevice flag indicates that flows should be deleted only in DB/device and should not be forwarded to core
850func (vpv *VoltPortVnet) PortDownInd(cntx context.Context, device string, port string, nbRequest bool, delFlowsInDevice bool) {
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530851 if !nbRequest && !GetApplication().OltFlowServiceConfig.RemoveFlowsOnDisable {
852 logger.Info(ctx, "VPV Port DOWN Ind, Not deleting flows since RemoveOnDisable is disabled")
853 return
854 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530855 logger.Infow(ctx, "VPV Port DOWN Ind, deleting all flows for services",
Akash Sonief452f12024-12-12 18:20:28 +0530856 log.Fields{"service count": vpv.servicesCount.Load(), "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530857
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530858 //vpv.RangeOnServices(cntx, DelAllFlows)
859 vpv.DelTrapFlows(cntx)
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530860 vpv.DelHsiaFlows(cntx, delFlowsInDevice)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530861 vpv.WriteToDb(cntx)
862 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530863}
864
865// SetMacAddr : The MAC address is set when a MAC address is learnt through the
866// packets received from the network. Currently, DHCP packets are
867// only packets we learn the MAC address from
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530868func (vpv *VoltPortVnet) SetMacAddr(cntx context.Context, addr net.HardwareAddr) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530869 logger.Infow(ctx, "Set Mac Addr", log.Fields{"MAC addr": addr.String(), "Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530870 //Store Learnt MAC address and return if MACLearning is not enabled
871 vpv.LearntMacAddr = addr
872 if vpv.MacLearning == MacLearningNone || !NonZeroMacAddress(addr) ||
873 (NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn) {
874 return
875 }
876
877 // Compare the two MAC addresses to see if it is same
878 // If they are same, we just return. If not, we perform
879 // actions to address the change in MAC address
880 //if NonZeroMacAddress(vpv.MacAddr) && !util.MacAddrsMatch(vpv.MacAddr, addr) {
881 if !util.MacAddrsMatch(vpv.MacAddr, addr) {
882 expectedPort := GetApplication().GetMacInPortMap(addr)
883 if expectedPort != "" && expectedPort != vpv.Port {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530884 logger.Warnw(ctx, "mac-learnt-from-different-port-ignoring-setmacaddr",
Naveen Sampath04696f72022-06-13 15:19:14 +0530885 log.Fields{"ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": addr.String()})
886 return
887 }
888 if NonZeroMacAddress(vpv.MacAddr) {
889 logger.Warnw(ctx, "MAC Address Changed. Remove old flows (if added) and re-add with updated MAC", log.Fields{"UpdatedMAC": addr})
890
891 // The newly learnt MAC address is different than earlier one.
892 // The existing MAC based HSIA flows need to be undone as the device
893 // may have been changed
894 // Atleast one HSIA flow should be present in adapter to retain the TP and GEM
895 // hence delete one after the other
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530896 vpv.RangeOnServices(cntx, DelUsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530897 vpv.MacAddr = addr
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530898 vpv.RangeOnServices(cntx, vpv.setLearntMAC, false)
899 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
900 vpv.RangeOnServices(cntx, DelDsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530901 GetApplication().DeleteMacInPortMap(vpv.MacAddr)
902 } else {
903 vpv.MacAddr = addr
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530904 vpv.RangeOnServices(cntx, vpv.setLearntMAC, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530905 logger.Infow(ctx, "MAC Address learnt from DHCP or ARP", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
906 }
907 GetApplication().UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
908 } else {
909 logger.Infow(ctx, "Leant MAC Address is same", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
910 }
911
912 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
913 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530914 logger.Errorw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
Akash Sonia8246972023-01-03 10:37:08 +0530915 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530916 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
917 return
918 }
919 // Ds Hsia flows has to be pushed
920 if vpv.FlowsApplied {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530921 // In case of DPU_MGMT_TRAFFIC install both US and DS Flows
vinokuma926cb3e2023-03-29 11:41:06 +0530922 if vpv.VnetType == DpuMgmtTraffic {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530923 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530924 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530925 // no HSIA flows for multicast service
926 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530927 vpv.RangeOnServices(cntx, AddDsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530928 }
929 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530930 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530931}
932
933// MatchesVlans : If the VNET matches both S and C VLANs, return true. Else, return false
934func (vpv *VoltPortVnet) MatchesVlans(svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530935 logger.Debugw(ctx, "Matches Vlans", log.Fields{"Svlan": svlan, "Cvlan": cvlan, "Univlan": univlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530936 if vpv.SVlan != svlan || vpv.CVlan != cvlan || vpv.UniVlan != univlan {
937 return false
938 }
939 return true
940}
941
942// MatchesCvlan : If the VNET matches CVLAN, return true. Else, return false
943func (vpv *VoltPortVnet) MatchesCvlan(cvlan []of.VlanType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530944 logger.Debugw(ctx, "Matches Cvlans", log.Fields{"Cvlan": cvlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530945 if len(cvlan) != 1 && !vpv.AllowTransparent {
946 return false
947 }
948 if vpv.CVlan != cvlan[0] {
949 return false
950 }
951 return true
952}
953
954// MatchesPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
955func (vpv *VoltPortVnet) MatchesPriority(priority uint8) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530956 logger.Debugw(ctx, "Matches Priority", log.Fields{"Priority": priority})
Naveen Sampath04696f72022-06-13 15:19:14 +0530957 var service *VoltService
958 pbitFound := false
959 matchpbitsFunc := func(key, value interface{}) bool {
960 svc := value.(*VoltService)
961 for _, pbit := range svc.Pbits {
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530962 if uint8(pbit) == priority || uint8(pbit) == uint8(of.PbitMatchAll) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530963 logger.Infow(ctx, "Pbit match found with service",
964 log.Fields{"Pbit": priority, "serviceName": svc.Name})
965 pbitFound = true
966 service = svc
967 return false //Returning false to stop the Range loop
968 }
969 }
970 return true
971 }
972 _ = pbitFound
973 vpv.services.Range(matchpbitsFunc)
974 return service
975}
976
Akash Sonief452f12024-12-12 18:20:28 +0530977func (vpv *VoltPortVnet) GetSvcFromVPV() *VoltService {
978 var service *VoltService
979 vpv.services.Range(func(key, value interface{}) bool {
980 service = value.(*VoltService)
981 logger.Debugw(ctx, "Get Service from VPV", log.Fields{"Service": value})
982 return false
983 })
984 return service
985}
986
Naveen Sampath04696f72022-06-13 15:19:14 +0530987// GetRemarkedPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
988func (vpv *VoltPortVnet) GetRemarkedPriority(priority uint8) uint8 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530989 logger.Debugw(ctx, "Get Remarked Priority", log.Fields{"Priority": priority})
Naveen Sampath04696f72022-06-13 15:19:14 +0530990 dsPbit := uint8(0)
991 matchpbitsFunc := func(key, value interface{}) bool {
992 svc := value.(*VoltService)
993 if remarkPbit, ok := svc.DsRemarkPbitsMap[int(priority)]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530994 logger.Warnw(ctx, "Pbit match found with service",
Naveen Sampath04696f72022-06-13 15:19:14 +0530995 log.Fields{"Pbit": priority, "serviceName": svc.Name, "remarkPbit": remarkPbit})
996 dsPbit = uint8(remarkPbit)
997 return false //Returning false to stop the Range loop
998 }
999 // When no remarking info is available, remark the incoming pbit
1000 // to highest pbit configured for the subscriber (across all subservices associated)
1001 svcPbit := uint8(svc.Pbits[0])
1002 if svcPbit > dsPbit {
1003 dsPbit = svcPbit
1004 }
1005 return true
1006 }
1007 vpv.services.Range(matchpbitsFunc)
1008 logger.Debugw(ctx, "Remarked Pbit Value", log.Fields{"Incoming": priority, "Remarked": dsPbit})
1009 return dsPbit
1010}
1011
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301012func (vpv *VoltPortVnet) ValidateNniPort(device *VoltDevice, nniPortName string) error {
1013 devConfig := GetApplication().GetDeviceConfig(device.SerialNum)
1014 if devConfig == nil {
1015 return fmt.Errorf("device config not found for serial number %s", device.SerialNum)
1016 }
1017
1018 var nniPort string
1019 var nniPortID uint32
1020 if nniPortID = device.GetPortIDFromPortName(nniPortName); nniPortID == 0 {
1021 logger.Errorw(ctx, "Port Not Found", log.Fields{"NNI Port": nniPortName})
1022 return errors.New("port not found for service")
1023 }
1024 if !device.IsPortNni(nniPortName) {
1025 logger.Errorw(ctx, "Port Not Found in device", log.Fields{"NNI Port": nniPortName})
1026 return fmt.Errorf("port not found in device")
1027 }
1028
1029 nniPort = strconv.Itoa(int(nniPortID))
1030 if len(devConfig.NniPorts) > 0 {
1031 for _, port := range devConfig.NniPorts {
1032 if port == nniPort {
1033 logger.Debugw(ctx, "NNI port is configured from NB", log.Fields{"NB NniPorts": devConfig.NniPorts, "NniPort": nniPortName})
1034 return nil // Match found
1035 }
1036 }
1037 } else {
1038 if devConfig.UplinkPort == nniPort {
1039 logger.Debugw(ctx, "NNI port is configured as default from NB", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI Ports": device.NniPort})
1040 return nil // Match found
1041 }
1042 }
1043 return fmt.Errorf("nni port mismatch: NB NNI Port: %s, SB NNI Ports: %v", devConfig.UplinkPort, device.NniPort)
1044}
1045
Naveen Sampath04696f72022-06-13 15:19:14 +05301046// AddSvc adds a service on the VNET on a port. The addition is
1047// triggered when NB requests for service addition
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301048func (vpv *VoltPortVnet) AddSvc(cntx context.Context, svc *VoltService) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301049 logger.Infow(ctx, "Add Service to VPV", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301050 //vpv.services = append(vpv.services, svc)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301051 vpv.AddService(cntx, svc)
Naveen Sampath04696f72022-06-13 15:19:14 +05301052 logger.Debugw(ctx, "Added Service to VPV", log.Fields{"Num of SVCs": vpv.servicesCount.Load(), "SVC": svc})
1053
1054 // Learn the circuit-id and remote-id from the service
1055 // TODO: There must be a better way of doing this. This
1056 // may be explored
1057 if svc.IgmpEnabled {
1058 vpv.IgmpEnabled = true
1059 }
1060 // first time service activation MacLearning will have default value as None.
1061 // to handle reciliency if anythng other then None we should retain it .
1062 if svc.MacLearning == MacLearningNone {
1063 if !vpv.DhcpRelay && !vpv.ArpRelay {
1064 svc.MacLearning = MacLearningNone
1065 } else if vpv.MacLearning == Learn {
1066 svc.MacLearning = Learn
1067 } else if vpv.MacLearning == ReLearn {
1068 svc.MacLearning = ReLearn
1069 }
1070 }
1071
vinokuma926cb3e2023-03-29 11:41:06 +05301072 // TODO: Temp Change - Need to address MAC Learning flow issues completely
Naveen Sampath04696f72022-06-13 15:19:14 +05301073 if (svc.MacLearning == Learn || svc.MacLearning == ReLearn) && NonZeroMacAddress(vpv.MacAddr) {
1074 svc.MacAddr = vpv.MacAddr
1075 } else if vpv.servicesCount.Load() == 1 {
1076 vpv.MacAddr = svc.MacAddr
1077 }
1078
1079 vpv.MacLearning = svc.MacLearning
1080 vpv.PonPort = svc.PonPort
1081 logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
vinokuma926cb3e2023-03-29 11:41:06 +05301082 // Reconfigure Vlans based on Vlan Control type
Naveen Sampath04696f72022-06-13 15:19:14 +05301083 svc.VlanControl = vpv.VlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301084 if svc.McastService {
1085 vpv.McastService = true
1086 vpv.McastTechProfileID = svc.TechProfileID
vinokuma926cb3e2023-03-29 11:41:06 +05301087 // Assumption: Only one Pbit for mcast service
Naveen Sampath04696f72022-06-13 15:19:14 +05301088 vpv.McastPbit = svc.Pbits[0]
1089 vpv.McastUsMeterID = svc.UsMeterID
1090 vpv.SchedID = svc.SchedID
1091 }
1092 svc.ONTEtherTypeClassification = vpv.ONTEtherTypeClassification
1093 svc.AllowTransparent = vpv.AllowTransparent
1094 svc.SVlanTpid = vpv.SVlanTpid
1095
vinokuma926cb3e2023-03-29 11:41:06 +05301096 // Ensure configuring the mvlan profile only once
1097 // One subscriber cannot have multiple mvlan profiles. Only the first configuration is valid
Naveen Sampath04696f72022-06-13 15:19:14 +05301098 if svc.MvlanProfileName != "" {
1099 if vpv.MvlanProfileName == "" {
1100 vpv.MvlanProfileName = svc.MvlanProfileName
1101 } else {
1102 logger.Warnw(ctx, "Mvlan Profile already configured for subscriber. Ignoring new Mvlan", log.Fields{"Existing Mvlan": vpv.MvlanProfileName, "New Mvlan": svc.MvlanProfileName})
1103 }
1104 }
1105
Akash Sonia8246972023-01-03 10:37:08 +05301106 voltDevice, err := GetApplication().GetDeviceFromPort(vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301107 if err != nil {
Akash Sonief452f12024-12-12 18:20:28 +05301108 logger.Errorw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
vinokuma926cb3e2023-03-29 11:41:06 +05301109 // statusCode, statusMessage := errorCodes.GetErrorInfo(err)
1110 // TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
Naveen Sampath04696f72022-06-13 15:19:14 +05301111 return
1112 }
Tinoj Josephec742f62022-09-29 19:11:10 +05301113 if !svc.IsActivated {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301114 logger.Warnw(ctx, "Not pushing Service Flows: Service Not activated", log.Fields{"ServiceName": svc.Name})
Tinoj Josephec742f62022-09-29 19:11:10 +05301115 return
1116 }
Akash Sonia8246972023-01-03 10:37:08 +05301117
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301118 if svc.NniPort != "" {
1119 err := vpv.ValidateNniPort(voltDevice, svc.NniPort)
1120 if err != nil {
1121 logger.Warnw(ctx, "Not pushing service flows: NNI is not configured", log.Fields{"Port": vpv.Port, "Device": voltDevice.Name, "NNI": svc.NniPort, "Error": err})
1122 return
1123 }
1124 } else {
1125 nni, err := GetApplication().GetNniPort(voltDevice.Name)
1126 if nni == "" {
1127 logger.Warnw(ctx, "Not pushing service flows: Default NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": voltDevice.Name, "Error": err})
1128 return
1129 }
Akash Sonia8246972023-01-03 10:37:08 +05301130 }
vinokuma926cb3e2023-03-29 11:41:06 +05301131 // Push Service Flows if DHCP relay is not configured
1132 // or already DHCP flows are configured for the VPV
1133 // to which the serivce is associated
Naveen Sampath04696f72022-06-13 15:19:14 +05301134 if vpv.FlowsApplied {
1135 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301136 svc.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301137 } else {
Akash Sonia8246972023-01-03 10:37:08 +05301138 if err := svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301139 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1140 }
1141 }
1142 }
1143
vinokuma926cb3e2023-03-29 11:41:06 +05301144 // Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
Naveen Sampath04696f72022-06-13 15:19:14 +05301145 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1146 // service with Igmp Enabled needs to be installed
1147 if svc.IgmpEnabled && vpv.FlowsApplied {
1148 logger.Infow(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301149 if err := vpv.AddIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301150 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301151 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1152 }
1153
1154 if vpv.McastService {
vinokuma926cb3e2023-03-29 11:41:06 +05301155 // For McastService, send Service Activated indication once IGMP US flow is pushed
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301156 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301157 }
1158 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301159 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301160}
1161
1162// setLearntMAC to set learnt mac
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301163func (vpv *VoltPortVnet) setLearntMAC(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301164 svc := value.(*VoltService)
1165 svc.SetMacAddr(vpv.MacAddr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301166 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301167 return true
1168}
1169
1170// PostAccessConfigSuccessInd for posting access config success indication
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301171func PostAccessConfigSuccessInd(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301172 return true
1173}
1174
1175// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301176func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301177 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301178 logger.Debugw(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301179 svc.SetIpv4Addr(vpv.Ipv4Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301180 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301181
1182 return true
1183}
1184
1185// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301186func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301187 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301188 logger.Debugw(ctx, "Updating Ipv6 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301189 svc.SetIpv6Addr(vpv.Ipv6Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301190 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301191
1192 return true
1193}
1194
1195// AddUsHsiaFlows to add upstream hsia flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301196func AddUsHsiaFlows(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301197 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301198 logger.Debugw(ctx, "Add US Hsia Flows", log.Fields{"ServiceName": svc.Name})
Akash Sonia8246972023-01-03 10:37:08 +05301199 if err := svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301200 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1201 }
1202 return true
1203}
1204
1205// AddDsHsiaFlows to add downstream hsia flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301206func AddDsHsiaFlows(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301207 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301208 logger.Debugw(ctx, "Add DS Hsia Flows", log.Fields{"ServiceName": svc.Name})
Akash Sonia8246972023-01-03 10:37:08 +05301209 if err := svc.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301210 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1211 }
1212 return true
1213}
1214
1215// ClearFlagsInService to clear the flags used in service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301216func ClearFlagsInService(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301217 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301218 logger.Debugw(ctx, "Received Cleared Flow Flags for service", log.Fields{"name": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301219 svc.ServiceLock.Lock()
1220 svc.IgmpFlowsApplied = false
1221 svc.DsDhcpFlowsApplied = false
1222 svc.DsHSIAFlowsApplied = false
1223 svc.Icmpv6FlowsApplied = false
1224 svc.UsHSIAFlowsApplied = false
1225 svc.UsDhcpFlowsApplied = false
1226 svc.PendingFlows = make(map[string]bool)
1227 svc.AssociatedFlows = make(map[string]bool)
1228 svc.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301229 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301230 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1231 return true
1232}
1233
1234// DelDsHsiaFlows to delete hsia flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301235// delFlowsInDevice flag indicates that flows should be deleted only in DB/device and should not be forwarded to core
1236func DelDsHsiaFlows(cntx context.Context, key, value interface{}, delFlowsInDevice bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301237 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301238 logger.Debugw(ctx, "Delete DS Hsia Flows", log.Fields{"ServiceName": svc.Name})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301239 if err := svc.DelDsHsiaFlows(cntx, delFlowsInDevice); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301240 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1241 }
1242 return true
1243}
1244
1245// DelUsHsiaFlows to delete upstream hsia flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301246// delFlowsInDevice flag indicates that flows should be deleted only in DB/device and should not be forwarded to core
1247func DelUsHsiaFlows(cntx context.Context, key, value interface{}, delFlowsInDevice bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301248 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301249 logger.Debugw(ctx, "Delete US Hsia Flows", log.Fields{"ServiceName": svc.Name})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301250 if err := svc.DelUsHsiaFlows(cntx, delFlowsInDevice); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301251 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1252 }
1253 return true
1254}
1255
1256// ClearServiceCounters to clear the service counters
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301257func ClearServiceCounters(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301258 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301259 logger.Debugw(ctx, "Received Clear Service Counters", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301260 //Delete the per service counter too
1261 GetApplication().ServiceCounters.Delete(svc.Name)
1262 if svc.IgmpEnabled && svc.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301263 _ = db.DelAllServiceChannelCounter(cntx, svc.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301264 }
1265 return true
1266}
1267
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301268// AddMeterToDevice to add meter config to device, used in FTTB case
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301269func AddMeterToDevice(cntx context.Context, key, value interface{}, flag bool) bool {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301270 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301271 logger.Debugw(ctx, "Received Add Meter To Device", log.Fields{"ServiceName": svc.Name})
Akash Soni53da2852023-03-15 00:31:31 +05301272 if err := svc.AddMeterToDevice(cntx); err != nil {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301273 logger.Warnw(ctx, "Add Meter failed", log.Fields{"service": svc.Name, "Error": err})
1274 }
1275 return true
1276}
1277
vinokuma926cb3e2023-03-29 11:41:06 +05301278// AddTrapFlows - Adds US & DS Trap flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301279func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301280 logger.Debugw(ctx, "Received Add US & DS DHCP, IGMP Trap Flows", log.Fields{"FlowsApplied": vpv.FlowsApplied, "VgcRebooted": vgcRebooted})
Naveen Sampath04696f72022-06-13 15:19:14 +05301281 if !vpv.FlowsApplied || vgcRebooted {
1282 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301283 if err := vpv.AddUsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301284 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301285 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1286 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301287 if err := vpv.AddDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301288 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301289 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1290 }
1291 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1292 log.Fields{"port": vpv.Port})
1293 //vpv.updateICMPv6McGroup(true)
1294 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301295 if err := vpv.AddUsArpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301296 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301297 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1298 }
1299 logger.Info(ctx, "ARP trap rules not added in downstream direction")
Naveen Sampath04696f72022-06-13 15:19:14 +05301300 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301301 if err := vpv.AddUsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301302 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301303 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1304 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301305 if err := vpv.AddDsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301306 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301307 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1308 }
1309 }
1310 vpv.FlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301311 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301312 }
1313}
1314
vinokuma926cb3e2023-03-29 11:41:06 +05301315// DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301316func (vpv *VoltPortVnet) DelTrapFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301317 logger.Debugw(ctx, "Received Delete US & DS DHCP, IGMP Trap Flows", log.Fields{"FlowsApplied": vpv.FlowsApplied, "VgcRebooted": vgcRebooted})
Naveen Sampath04696f72022-06-13 15:19:14 +05301318 // Delete HSIA & DHCP flows before deleting IGMP flows
1319 if vpv.FlowsApplied || vgcRebooted {
1320 if vpv.DhcpRelay {
Akash Sonia8246972023-01-03 10:37:08 +05301321 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301322 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1323 "UniVlan": vpv.UniVlan, "Error": err})
1324 }
1325 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1326 log.Fields{"port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301327 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301328 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301329 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1330 }
1331 //vpv.updateICMPv6McGroup(false)
1332 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301333 if err := vpv.DelUsArpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301334 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301335 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1336 }
1337 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301338 if err := vpv.DelUsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301339 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301340 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1341 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301342 if err := vpv.DelDsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301343 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301344 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1345 }
1346 }
1347 vpv.FlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301348 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301349 }
Akash Sonia8246972023-01-03 10:37:08 +05301350 if err := vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301351 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1352 "UniVlan": vpv.UniVlan, "Error": err})
1353 }
1354}
1355
1356// DelHsiaFlows deletes the service flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301357func (vpv *VoltPortVnet) DelHsiaFlows(cntx context.Context, delFlowsInDevice bool) {
Akash Sonief452f12024-12-12 18:20:28 +05301358 logger.Debugw(ctx, "Received Delete Hsia Flows", log.Fields{"McastService": vpv.McastService})
Naveen Sampath04696f72022-06-13 15:19:14 +05301359 // no HSIA flows for multicast service
1360 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301361 vpv.RangeOnServices(cntx, DelUsHsiaFlows, delFlowsInDevice)
1362 vpv.RangeOnServices(cntx, DelDsHsiaFlows, delFlowsInDevice)
Naveen Sampath04696f72022-06-13 15:19:14 +05301363 }
1364}
1365
vinokuma926cb3e2023-03-29 11:41:06 +05301366// ClearServiceCounters - Removes all igmp counters for a service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301367func (vpv *VoltPortVnet) ClearServiceCounters(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301368 //send flows deleted indication to submgr
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301369 vpv.RangeOnServices(cntx, ClearServiceCounters, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301370}
1371
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301372// BuildDefaultDhcpTrapFlow to build the downstream dhcp flows
1373func (va *VoltApplication) BuildDefaultDhcpTrapFlow(ctx context.Context, device *VoltDevice, port string) (*of.VoltFlow, error) {
1374 logger.Infow(ctx, "Building NNI DS DHCP flow", log.Fields{"Port": port, "device": device.Name})
1375 flow := &of.VoltFlow{}
1376 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1377 subFlow := of.NewVoltSubFlow()
1378 subFlow.SetTableID(0)
1379
1380 subFlow.SetUdpv4Match()
1381 subFlow.SrcPort = 67
1382 subFlow.DstPort = 68
1383
1384 nniport, err := GetApplication().GetPortID(port)
1385 if err != nil {
1386 return nil, fmt.Errorf("failed to fetch port id %d for nni : %w", nniport, err)
1387 }
1388 subFlow.SetInPort(nniport)
1389 // PortName and PortID to be used for validation of port before flow pushing
1390 flow.PortID = nniport
1391 flow.PortName = port
1392 allowTransparent := 0
1393
1394 ontEtherTypeClass := 0
1395 vlanControl := OLTSVlan
1396 uniVlan := of.VlanNone
1397 cVlan := of.VlanNone
1398
1399 metadata := uint64(allowTransparent)<<56 | uint64(ontEtherTypeClass)<<36 | uint64(vlanControl)<<32 | uint64(uniVlan)<<16 | uint64(cVlan)
1400 subFlow.SetTableMetadata(metadata)
1401 subFlow.Priority = of.DhcpFlowPriority
1402
1403 subFlow.SetReportToController()
1404 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1405 subFlow.Cookie = uint64(cVlan)<<52 | uint64(nniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
1406
1407 flow.SubFlows[subFlow.Cookie] = subFlow
1408 logger.Infow(ctx, "Built NNI DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1409
1410 return flow, nil
1411}
1412
1413// AddDefaultDhcpTrapFlow function pushes the default DHCP flows to the VOLTHA via the controller
1414func (va *VoltApplication) AddDefaultDhcpTrapFlow(cntx context.Context, vd *VoltDevice, p *VoltPort) error {
1415 if vd.GlobalDhcpFlowAdded {
1416 logger.Info(ctx, "Global Dhcp flow already exists")
1417 return nil
1418 }
1419
1420 flows, err := va.BuildDefaultDhcpTrapFlow(cntx, vd, p.Name)
1421 if err == nil {
1422 if err1 := va.PushTrapFlows(cntx, vd, p.Name, flows); err1 != nil {
1423 logger.Errorw(cntx, "Failure pushing nni trap flows", log.Fields{"device": vd.Name, "port": p.Name})
1424 return fmt.Errorf("failed to push trap flow for nni : %s, error : %w", p.Name, err1)
1425 }
1426 } else {
1427 logger.Errorw(cntx, "Failure building nni trap flows", log.Fields{"device": vd.Name, "port": p.Name})
1428 return fmt.Errorf("failed to build trap flow for nni : %s, error : %w", p.Name, err)
1429 }
1430 p.NniDhcpTrapFlowAdded = true
1431 if GetApplication().GetVendorID() != Radisys && va.IsDhcpTrapFlowAdded(cntx, vd) {
1432 logger.Debugw(ctx, "Global DHCP trap flow set", log.Fields{"device": vd.Name})
1433 vd.GlobalDhcpFlowAdded = true
1434 }
1435 return nil
1436}
1437
1438func (va *VoltApplication) IsDhcpTrapFlowAdded(ctx context.Context, vd *VoltDevice) bool {
1439 if len(vd.NniPort) == 0 {
1440 return false
1441 }
1442 flag := true
1443 for _, nniPort := range vd.NniPort {
1444 if p := vd.GetPort(nniPort); p != nil {
1445 if !p.NniDhcpTrapFlowAdded {
1446 flag = false
1447 }
1448 } else {
1449 flag = false
1450 }
1451 }
1452
1453 return flag
1454}
1455
Naveen Sampath04696f72022-06-13 15:19:14 +05301456// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301457func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301458 var vd *VoltDevice
1459 device := vpv.Device
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301460 logger.Debugw(ctx, "Received Add US DHCP Flows", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301461
1462 if vd = GetApplication().GetDevice(device); vd != nil {
1463 if vd.State != controller.DeviceStateUP {
1464 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})
1465 return nil
1466 }
1467 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301468 err := errorCodes.ErrDeviceNotFound
1469 return fmt.Errorf("us dhcp flow push failed - device not found for Port %s, Svlan %d, Cvlan %d, UniVlan %d. Device %s : %w", vpv.Port, vpv.SVlan, vpv.CVlan, vpv.UniVlan, device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301470 }
1471
1472 flows, err := vpv.BuildUsDhcpFlows()
1473 if err == nil {
1474 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301475 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
vinokuma926cb3e2023-03-29 11:41:06 +05301476 // push ind here ABHI
Akash Sonia8246972023-01-03 10:37:08 +05301477 statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301478 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1479 }
1480 } else {
1481 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
vinokuma926cb3e2023-03-29 11:41:06 +05301482 // push ind here ABHI
Akash Sonia8246972023-01-03 10:37:08 +05301483 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301484 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
Naveen Sampath04696f72022-06-13 15:19:14 +05301485 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301486 return nil
1487}
1488
1489// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301490func (vpv *VoltPortVnet) AddDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301491 var vd *VoltDevice
1492 device := vpv.Device
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301493 logger.Debugw(ctx, "Received Add DS DHCP Flows", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301494
1495 if vd = GetApplication().GetDevice(device); vd != nil {
1496 if vd.State != controller.DeviceStateUP {
1497 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})
1498 return nil
1499 }
1500 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301501 err := errorCodes.ErrDeviceNotFound
1502 return fmt.Errorf("ds dhcp flow push failed - device not found for Port %s, Svlan %d, Cvlan %d, UniVlan %d. Device %s : %w", vpv.Port, vpv.SVlan, vpv.CVlan, vpv.UniVlan, device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301503 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301504
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301505 if vd.GlobalDhcpFlowAdded {
1506 logger.Info(ctx, "Global Dhcp flow already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301507 return nil
1508 }
1509
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301510 nniPorts := make([]string, 0)
1511 vpv.services.Range(func(key, value interface{}) bool {
1512 svc := value.(*VoltService)
1513 logger.Infow(ctx, "Found service on the vpv", log.Fields{"Name": svc.Name, "NNIPort": svc.NniPort})
1514 nniPorts = append(nniPorts, svc.NniPort)
1515 return true
1516 })
1517
1518 if len(nniPorts) == 0 {
1519 vpv.BuildAndPushDSDhcpFlows(cntx, vd, "")
Naveen Sampath04696f72022-06-13 15:19:14 +05301520 } else {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301521 for _, nniPort := range nniPorts {
1522 vpv.BuildAndPushDSDhcpFlows(cntx, vd, nniPort)
1523 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301524 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301525
Naveen Sampath04696f72022-06-13 15:19:14 +05301526 if GetApplication().GetVendorID() != Radisys {
1527 vd.GlobalDhcpFlowAdded = true
1528 }
1529 return nil
1530}
1531
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301532func (vpv *VoltPortVnet) BuildAndPushDSDhcpFlows(cntx context.Context, device *VoltDevice, nniPort string) {
1533 var err error
1534 var flows *of.VoltFlow
1535 flows, err = vpv.BuildDsDhcpFlows(nniPort)
1536 if err == nil {
1537 if err1 := vpv.PushFlows(cntx, device, flows); err1 != nil {
1538 statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
1539 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1540 }
1541 } else {
1542 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
1543 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1544 }
1545}
1546
Naveen Sampath04696f72022-06-13 15:19:14 +05301547// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301548func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301549 logger.Info(ctx, "Received Delete DHCP Flows")
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301550 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301551 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301552 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1553 }
1554
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301555 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301556 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301557 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1558 }
1559}
1560
1561// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1562// Write the status of the VPV to the DB once the delete is scheduled
1563// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301564func (vpv *VoltPortVnet) DelUsDhcpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301565 logger.Debugw(ctx, "Received Delete US DHCP Flows", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301566 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1567 if err != nil {
1568 return err
1569 }
1570
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301571 err = vpv.delDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301572 if err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301573 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301574 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1575 }
Akash Sonia8246972023-01-03 10:37:08 +05301576
Naveen Sampath04696f72022-06-13 15:19:14 +05301577 return nil
1578}
1579
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301580func (vpv *VoltPortVnet) delDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301581 logger.Debugw(ctx, "Received US Delete DHCP4 Flows", log.Fields{"DeviceName": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301582 flows, err := vpv.BuildUsDhcpFlows()
1583 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301584 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301585 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301586 return fmt.Errorf("US DHCP Flow Delete Failed : %w", err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301587}
Naveen Sampath04696f72022-06-13 15:19:14 +05301588
1589// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1590// Write the status of the VPV to the DB once the delete is scheduled
1591// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301592func (vpv *VoltPortVnet) DelDsDhcpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301593 logger.Debugw(ctx, "Received Delete DS DHCP Flows", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301594 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1595 if err != nil {
1596 return err
1597 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301598 err = vpv.delDsDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301599 if err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301600 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301601 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1602 }
1603 /*
Akash Sonia8246972023-01-03 10:37:08 +05301604 err = vpv.delDsDhcp6Flows(device)
1605 if err != nil {
1606 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
1607 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1608 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +05301609 return nil
1610}
1611
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301612func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301613 logger.Debugw(ctx, "Received DS Delete DHCP4 Flows", log.Fields{"DeviceName": device.Name})
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301614 nniPorts := make([]string, 0)
1615 vpv.services.Range(func(key, value interface{}) bool {
1616 svc := value.(*VoltService)
1617 logger.Infow(ctx, "Found service on the vpv", log.Fields{"Name": svc.Name, "NNIPort": svc.NniPort})
1618 nniPorts = append(nniPorts, svc.NniPort)
1619 return true
1620 })
1621
1622 if len(nniPorts) == 0 {
1623 if err := vpv.BuildAndRemoveDSDhcpFlows(cntx, device, ""); err != nil {
1624 return err
1625 }
1626 } else {
1627 for _, nniPort := range nniPorts {
1628 if err := vpv.BuildAndRemoveDSDhcpFlows(cntx, device, nniPort); err != nil {
1629 return err
1630 }
1631 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301632 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301633 return nil
1634}
1635
1636func (vpv *VoltPortVnet) BuildAndRemoveDSDhcpFlows(cntx context.Context, device *VoltDevice, nniPort string) error {
1637 var err error
1638 var flows *of.VoltFlow
1639 flows, err = vpv.BuildDsDhcpFlows(nniPort)
1640 if err == nil {
1641 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
1642 logger.Errorw(ctx, "DS DHCP Flow Remove Failed", log.Fields{"Reason": err.Error()})
1643 return fmt.Errorf("ds dhcp flow remove failed - Port %s, NNIPort %s, Svlan %d, Cvlan %d, UniVlan %d. Device %s : %w", vpv.Port, nniPort, vpv.SVlan, vpv.CVlan, vpv.UniVlan, vpv.Device, err)
1644 }
1645 } else {
1646 logger.Errorw(ctx, "DS DHCP Flow Build Failed", log.Fields{"Reason": err.Error()})
1647 return fmt.Errorf("ds dhcp flow build failed - Port %s, NNIPort %s, Svlan %d, Cvlan %d, UniVlan %d. Device %s : %w", vpv.Port, nniPort, vpv.SVlan, vpv.CVlan, vpv.UniVlan, vpv.Device, err)
1648 }
1649 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301650}
1651
1652/*
1653func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1654 flows, err := vpv.BuildDsDhcp6Flows()
1655 if err == nil {
1656 return vpv.RemoveFlows(device, flows)
1657 }
1658 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1659 return err
1660}*/
1661
1662// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301663func (vpv *VoltPortVnet) AddUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301664 var vd *VoltDevice
1665 device := vpv.Device
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301666 logger.Debugw(ctx, "Received Add US Arp Flows", log.Fields{"DeviceName": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301667 if vd = GetApplication().GetDevice(device); vd != nil {
1668 if vd.State != controller.DeviceStateUP {
1669 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})
1670 return nil
1671 }
1672 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301673 err := errorCodes.ErrDeviceNotFound
1674 return fmt.Errorf("US ARP Flow Push Failed- Device not found : Port %s : SVLAN %d : CVLAN %d : UNIVlan %d : device %s : %w", vpv.Port, vpv.SVlan, vpv.CVlan, vpv.UniVlan, device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301675 }
1676
1677 flows, err := vpv.BuildUsArpFlows()
1678 if err == nil {
1679 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301680 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301681 return fmt.Errorf("Pushing US ARP Flow Failed : %w", err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301682 }
1683 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301684 return fmt.Errorf("US ARP Flow Add Failed : Device %s : %w", device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301685 }
1686 return nil
1687}
1688
1689// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1690// Write the status of the VPV to the DB once the delete is scheduled
1691// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301692func (vpv *VoltPortVnet) DelUsArpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301693 logger.Debugw(ctx, "Delete US ARP Flows", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301694 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1695 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301696 return fmt.Errorf("US ARP Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301697 }
1698 flows, err := vpv.BuildUsArpFlows()
1699 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301700 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301701 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301702 return fmt.Errorf("US ARP Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301703}
1704
1705// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301706func (vpv *VoltPortVnet) AddUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301707 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1708
1709 var vd *VoltDevice
1710 device := vpv.Device
1711
1712 if vd = GetApplication().GetDevice(device); vd != nil {
1713 if vd.State != controller.DeviceStateUP {
1714 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})
1715 return nil
1716 }
1717 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301718 err := errorCodes.ErrDeviceNotFound
1719 return fmt.Errorf("US PPPoE Flow Push Failed- Device not found : Port %s : SVLAN %d : CVLAN %d : UNIVlan %d : device %s : %w", vpv.Port, vpv.SVlan, vpv.CVlan, vpv.UniVlan, device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301720 }
1721
1722 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1723 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1724
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301725 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301726 return fmt.Errorf("Pushing US PPPoE Flows Failed : %w", err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301727 }
1728 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301729 return fmt.Errorf("US PPPoE Flow Add Failed : Device %s : %w", device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301730 }
1731 return nil
1732}
1733
1734// AddDsPppoeFlows to add downstream pppoe flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301735func (vpv *VoltPortVnet) AddDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301736 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1737 var vd *VoltDevice
1738 device := vpv.Device
1739
1740 if vd = GetApplication().GetDevice(device); vd != nil {
1741 if vd.State != controller.DeviceStateUP {
1742 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})
1743 return nil
1744 }
1745 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301746 err := errorCodes.ErrDeviceNotFound
1747 return fmt.Errorf("DS PPPoE Flow Push Failed- Device not found : Port %s : SVLAN %d : CVLAN %d : UNIVlan %d : device %s : %w", vpv.Port, vpv.SVlan, vpv.CVlan, vpv.UniVlan, device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301748 }
1749
1750 flows, err := vpv.BuildDsPppoeFlows()
1751 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301752 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301753 return fmt.Errorf("Pushing DS PPPoE Flows Failed : %w", err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301754 }
1755 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301756 return fmt.Errorf("DS PPPoE Flow Add Failed : Device %s : %w", device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301757 }
1758 return nil
1759}
1760
1761// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1762// Write the status of the VPV to the DB once the delete is scheduled
1763// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301764func (vpv *VoltPortVnet) DelUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301765 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1766 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1767 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301768 return fmt.Errorf("US PPPoE Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301769 }
1770 flows, err := vpv.BuildUsPppoeFlows()
1771 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301772 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301773 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301774 return fmt.Errorf("US PPPoE Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301775}
1776
1777// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1778// Write the status of the VPV to the DB once the delete is scheduled
1779// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301780func (vpv *VoltPortVnet) DelDsPppoeFlows(cntx context.Context) error {
Akash Sonief452f12024-12-12 18:20:28 +05301781 logger.Infow(ctx, "Deleting DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301782 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1783 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301784 return fmt.Errorf("DS PPPoE Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301785 }
1786 flows, err := vpv.BuildDsPppoeFlows()
1787 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301788 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301789 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301790 return fmt.Errorf("DS PPPoE Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301791}
1792
1793// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301794func (vpv *VoltPortVnet) AddIgmpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301795 logger.Debugw(ctx, "Received Add Igmp Flows", log.Fields{"IgmpFlowsApplied": vpv.IgmpFlowsApplied, "VgcRebooted": vgcRebooted})
Naveen Sampath04696f72022-06-13 15:19:14 +05301796 if !vpv.IgmpFlowsApplied || vgcRebooted {
1797 if vpv.MvlanProfileName == "" {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301798 logger.Warn(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
Naveen Sampath04696f72022-06-13 15:19:14 +05301799 return nil
1800 }
1801 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1802 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301803 return fmt.Errorf("Error getting device from port : Port %s : %w", vpv.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301804 } else if device.State != controller.DeviceStateUP {
1805 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})
1806 return nil
1807 }
1808 flows, err := vpv.BuildIgmpFlows()
1809 if err == nil {
1810 for cookie := range flows.SubFlows {
1811 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1812 cookie := strconv.FormatUint(cookie, 10)
1813 fe := &FlowEvent{
1814 eType: EventTypeUsIgmpFlowAdded,
1815 cookie: cookie,
1816 eventData: vpv,
1817 }
1818 vd.RegisterFlowAddEvent(cookie, fe)
1819 }
1820 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301821 if err1 := cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301822 return err1
1823 }
1824 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301825 return fmt.Errorf("IGMP Flow Add Failed : %w", err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301826 }
1827 vpv.IgmpFlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301828 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301829 }
1830 return nil
1831}
1832
1833// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1834// Write the status of the VPV to the DB once the delete is scheduled
1835// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301836func (vpv *VoltPortVnet) DelIgmpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301837 logger.Debugw(ctx, "Received Delete Igmp Flows", log.Fields{"IgmpFlowsApplied": vpv.IgmpFlowsApplied, "VgcRebooted": vgcRebooted})
Naveen Sampath04696f72022-06-13 15:19:14 +05301838 if vpv.IgmpFlowsApplied || vgcRebooted {
1839 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1840 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301841 return fmt.Errorf("Error getting device from port : Port %s : %w", vpv.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301842 }
1843 flows, err := vpv.BuildIgmpFlows()
1844 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301845 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301846 return err1
1847 }
1848 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301849 return fmt.Errorf("IGMP Flow Delete Failed : %w", err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301850 }
1851 vpv.IgmpFlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301852 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301853 }
1854 return nil
1855}
1856
1857// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1858// The flows included by this function cover US only as the DS is
1859// created either automatically by the VOLTHA or at the device level
1860// earlier
1861func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301862 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301863 flow := &of.VoltFlow{}
1864 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1865
Naveen Sampath04696f72022-06-13 15:19:14 +05301866 subFlow := of.NewVoltSubFlow()
1867 subFlow.SetTableID(0)
1868
vinokuma926cb3e2023-03-29 11:41:06 +05301869 if vpv.VnetType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301870 subFlow.SetMatchVlan(vpv.CVlan)
1871 subFlow.SetMatchPbit(vpv.UsPonCTagPriority)
1872 subFlow.SetPcp(vpv.UsPonSTagPriority)
1873 subFlow.SetSetVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301874 } else {
1875 subFlow.SetMatchVlan(vpv.UniVlan)
1876 subFlow.SetSetVlan(vpv.CVlan)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301877 subFlow.SetPcp(vpv.DhcpPbit)
Naveen Sampath04696f72022-06-13 15:19:14 +05301878 }
1879 subFlow.SetUdpv4Match()
Naveen Sampath04696f72022-06-13 15:19:14 +05301880 subFlow.DstPort = 67
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301881 subFlow.SrcPort = 68
Naveen Sampath04696f72022-06-13 15:19:14 +05301882 uniport, err := GetApplication().GetPortID(vpv.Port)
1883 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301884 return nil, fmt.Errorf("failed to fetch uni port %s from vpv : %w", vpv.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301885 }
1886 subFlow.SetInPort(uniport)
1887 // PortName and PortID to be used for validation of port before flow pushing
1888 flow.PortID = uniport
1889 flow.PortName = vpv.Port
1890 subFlow.SetReportToController()
1891
1892 // Set techprofile, meterid of first service
1893 vpv.services.Range(func(key, value interface{}) bool {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301894 vs := value.(*VoltService)
1895 var writemetadata uint64
vinokuma926cb3e2023-03-29 11:41:06 +05301896 if vpv.VnetType == DpuMgmtTraffic {
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +05301897 writemetadata = uint64(vs.TechProfileID)<<32 + uint64(vs.UsMeterID)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301898 } else {
1899 writemetadata = uint64(vs.TechProfileID) << 32
1900 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301901 subFlow.SetWriteMetadata(writemetadata)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301902 subFlow.SetMeterID(vs.UsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301903 return false
1904 })
1905
Naveen Sampath04696f72022-06-13 15:19:14 +05301906 // metadata := uint64(uniport)
1907 // subFlow.SetWriteMetadata(metadata)
1908 allowTransparent := 0
1909 if vpv.AllowTransparent {
1910 allowTransparent = 1
1911 }
vinokuma926cb3e2023-03-29 11:41:06 +05301912 if vpv.VnetType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301913 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1914 subFlow.SetTableMetadata(metadata)
1915 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301916 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1917 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1918 subFlow.Priority = of.DhcpFlowPriority
1919
1920 flow.SubFlows[subFlow.Cookie] = subFlow
1921 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1922 return flow, nil
1923}
1924
1925// BuildDsDhcpFlows to build the downstream dhcp flows
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301926func (vpv *VoltPortVnet) BuildDsDhcpFlows(nniPort string) (*of.VoltFlow, error) {
1927 logger.Infow(ctx, "Building DS DHCP flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr, "NNIPort": nniPort})
Naveen Sampath04696f72022-06-13 15:19:14 +05301928 flow := &of.VoltFlow{}
1929 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1930 subFlow := of.NewVoltSubFlow()
1931 subFlow.SetTableID(0)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301932 // match on vlan only for fttb case
vinokuma926cb3e2023-03-29 11:41:06 +05301933 if vpv.VnetType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301934 subFlow.SetMatchVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301935 }
1936 subFlow.SetUdpv4Match()
1937 subFlow.SrcPort = 67
1938 subFlow.DstPort = 68
1939 uniport, _ := GetApplication().GetPortID(vpv.Port)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301940
1941 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301942 if err != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301943 return nil, fmt.Errorf("error getting device for vpv %s and port %s : %w", vpv.VnetName, vpv.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301944 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301945 var inport uint32
1946 if nniPort != "" {
1947 if nniPortID := device.GetPortIDFromPortName(nniPort); nniPortID != 0 {
1948 inport = nniPortID
1949 } else {
1950 return nil, fmt.Errorf("error getting portID for NNI port %s : %w", nniPort, err)
1951 }
1952 } else {
1953 nniPort, err := GetApplication().GetNniPort(device.Name)
1954 if err != nil {
1955 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
1956 return nil, err
1957 }
1958 inport, _ = GetApplication().GetPortID(nniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05301959 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301960
1961 subFlow.SetInPort(inport)
Naveen Sampath04696f72022-06-13 15:19:14 +05301962 // PortName and PortID to be used for validation of port before flow pushing
1963 flow.PortID = uniport
1964 flow.PortName = vpv.Port
1965 // metadata := uint64(uniport)
1966 // subFlow.SetWriteMetadata(metadata)
1967 allowTransparent := 0
1968 if vpv.AllowTransparent {
1969 allowTransparent = 1
1970 }
vinokuma926cb3e2023-03-29 11:41:06 +05301971 if vpv.VnetType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301972 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1973 subFlow.SetTableMetadata(metadata)
1974 subFlow.Priority = of.DhcpFlowPriority
1975 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301976 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05301977 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05301978 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
Naveen Sampath04696f72022-06-13 15:19:14 +05301979
1980 flow.SubFlows[subFlow.Cookie] = subFlow
1981 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1982
1983 return flow, nil
1984}
1985
1986// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1987// application.
1988func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301989 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301990 flow := &of.VoltFlow{}
1991 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1992
Naveen Sampath04696f72022-06-13 15:19:14 +05301993 subFlow := of.NewVoltSubFlow()
1994 subFlow.SetTableID(0)
1995
1996 subFlow.SetMatchVlan(vpv.UniVlan)
1997 subFlow.SetSetVlan(vpv.CVlan)
1998 subFlow.SetUdpv6Match()
1999 subFlow.SrcPort = 546
2000 subFlow.DstPort = 547
2001 uniport, err := GetApplication().GetPortID(vpv.Port)
2002 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302003 return nil, fmt.Errorf("failed to fetch uni port %d from vpv : %w", uniport, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05302004 }
2005 // Set techprofile, meterid of first service
2006 vpv.services.Range(func(key, value interface{}) bool {
2007 svc := value.(*VoltService)
2008 writemetadata := uint64(svc.TechProfileID) << 32
2009 subFlow.SetWriteMetadata(writemetadata)
2010 subFlow.SetMeterID(svc.UsMeterID)
2011 return false
2012 })
2013 subFlow.SetInPort(uniport)
2014 // PortName and PortID to be used for validation of port before flow pushing
2015 flow.PortID = uniport
2016 flow.PortName = vpv.Port
vinokuma926cb3e2023-03-29 11:41:06 +05302017 // subFlow.SetMeterId(vpv.UsDhcpMeterId)
Naveen Sampath04696f72022-06-13 15:19:14 +05302018 // metadata := uint64(uniport)
2019 // subFlow.SetWriteMetadata(metadata)
2020 allowTransparent := 0
2021 if vpv.AllowTransparent {
2022 allowTransparent = 1
2023 }
2024 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2025 subFlow.SetTableMetadata(metadata)
2026 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05302027 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302028 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
2029 subFlow.Priority = of.DhcpFlowPriority
2030
2031 flow.SubFlows[subFlow.Cookie] = subFlow
2032 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2033 return flow, nil
2034}
2035
2036// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
2037// application.
2038func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
2039 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
2040
2041 flow := &of.VoltFlow{}
2042 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2043 subFlow := of.NewVoltSubFlow()
2044 subFlow.SetTableID(0)
2045
2046 vpv.setDsMatchVlan(subFlow)
2047 subFlow.SetUdpv6Match()
2048 subFlow.SrcPort = 547
2049 subFlow.DstPort = 547
2050 uniport, _ := GetApplication().GetPortID(vpv.Port)
2051 nni, err := GetApplication().GetNniPort(vpv.Device)
2052 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302053 logger.Errorw(ctx, "Failed to fetch nni port from vpv", log.Fields{"error": err, "device": vpv.Device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302054 return nil, err
2055 }
2056 nniport, err := GetApplication().GetPortID(nni)
2057 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302058 logger.Errorw(ctx, "Failed to fetch port ID for nni", log.Fields{"error": err, "nni": nni})
Naveen Sampath04696f72022-06-13 15:19:14 +05302059 return nil, err
2060 }
2061 subFlow.SetInPort(nniport)
2062 // PortName and PortID to be used for validation of port before flow pushing
2063 flow.PortID = uniport
2064 flow.PortName = vpv.Port
2065 // metadata := uint64(uniport)
2066 // subFlow.SetWriteMetadata(metadata)
2067 allowTransparent := 0
2068 if vpv.AllowTransparent {
2069 allowTransparent = 1
2070 }
2071 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2072 subFlow.SetTableMetadata(metadata)
2073 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05302074 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302075 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
2076 subFlow.Priority = of.DhcpFlowPriority
2077
2078 flow.SubFlows[subFlow.Cookie] = subFlow
2079 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2080 return flow, nil
2081}
2082
2083// BuildUsArpFlows builds the US ARP relay flows for a subscriber
2084// The flows included by this function cover US only as the DS is
2085// created either automatically by the VOLTHA or at the device level
2086// earlier
2087func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302088 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05302089 flow := &of.VoltFlow{}
2090 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2091
Naveen Sampath04696f72022-06-13 15:19:14 +05302092 subFlow := of.NewVoltSubFlow()
2093 subFlow.SetTableID(0)
2094
2095 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2096 subFlow.SetMatchSrcMac(vpv.MacAddr)
2097 }
2098
2099 subFlow.SetMatchDstMac(BroadcastMAC)
2100 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2101 return nil, err
2102 }
2103 subFlow.SetArpMatch()
2104 uniport, err := GetApplication().GetPortID(vpv.Port)
2105 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302106 return nil, fmt.Errorf("failed to fetch uni port %d from vpv : %w", uniport, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05302107 }
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 subFlow.SetReportToController()
2113 allowTransparent := 0
2114 if vpv.AllowTransparent {
2115 allowTransparent = 1
2116 }
2117 metadata := uint64(uniport)
2118 subFlow.SetWriteMetadata(metadata)
2119 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2120 subFlow.SetTableMetadata(metadata)
2121 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
2122 subFlow.Priority = of.ArpFlowPriority
2123
2124 flow.SubFlows[subFlow.Cookie] = subFlow
2125 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2126 return flow, nil
2127}
2128
2129// setUsMatchVlan to set upstream match vlan
2130func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302131 logger.Debugw(ctx, "Set Us Match Vlan", log.Fields{"Value": vpv.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05302132 switch vpv.VlanControl {
2133 case None:
2134 flow.SetMatchVlan(vpv.SVlan)
2135 case ONUCVlanOLTSVlan:
2136 flow.SetMatchVlan(vpv.CVlan)
2137 case OLTCVlanOLTSVlan:
2138 flow.SetMatchVlan(vpv.UniVlan)
2139 //flow.SetSetVlan(vpv.CVlan)
2140 case ONUCVlan:
2141 flow.SetMatchVlan(vpv.SVlan)
2142 case OLTSVlan:
2143 flow.SetMatchVlan(vpv.UniVlan)
2144 //flow.SetSetVlan(vpv.SVlan)
2145 default:
2146 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2147 return errorCodes.ErrInvalidParamInRequest
2148 }
2149 return nil
2150}
2151
2152// BuildUsPppoeFlows to build upstream pppoe flows
2153func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302154 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05302155 flow := &of.VoltFlow{}
2156 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302157 subFlow := of.NewVoltSubFlow()
2158 subFlow.SetTableID(0)
2159
2160 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2161 subFlow.SetMatchSrcMac(vpv.MacAddr)
2162 }
2163
2164 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2165 return nil, err
2166 }
2167 subFlow.SetPppoeDiscoveryMatch()
2168 uniport, err := GetApplication().GetPortID(vpv.Port)
2169 if err != nil {
2170 return nil, err
2171 }
2172 subFlow.SetInPort(uniport)
2173 subFlow.SetReportToController()
2174 // PortName and PortID to be used for validation of port before flow pushing
2175 flow.PortID = uniport
2176 flow.PortName = vpv.Port
2177
2178 allowTransparent := 0
2179 if vpv.AllowTransparent {
2180 allowTransparent = 1
2181 }
2182 metadata := uint64(uniport)
2183 subFlow.SetWriteMetadata(metadata)
2184
2185 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2186 subFlow.SetTableMetadata(metadata)
2187
vinokuma926cb3e2023-03-29 11:41:06 +05302188 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302189 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
2190 subFlow.Priority = of.PppoeFlowPriority
2191
2192 flow.SubFlows[subFlow.Cookie] = subFlow
2193 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2194 return flow, nil
2195}
2196
2197// BuildDsPppoeFlows to build downstream pppoe flows
2198func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302199 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
2200 flow := &of.VoltFlow{}
2201 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2202 subFlow := of.NewVoltSubFlow()
2203 subFlow.SetTableID(0)
2204
2205 vpv.setDsMatchVlan(subFlow)
2206 subFlow.SetPppoeDiscoveryMatch()
2207
2208 if NonZeroMacAddress(vpv.MacAddr) {
2209 subFlow.SetMatchDstMac(vpv.MacAddr)
2210 }
2211
2212 uniport, _ := GetApplication().GetPortID(vpv.Port)
2213 nni, err := GetApplication().GetNniPort(vpv.Device)
2214 if err != nil {
2215 return nil, err
2216 }
2217 nniport, err := GetApplication().GetPortID(nni)
2218 if err != nil {
2219 return nil, err
2220 }
2221 subFlow.SetInPort(nniport)
2222 // PortName and PortID to be used for validation of port before flow pushing
2223 flow.PortID = uniport
2224 flow.PortName = vpv.Port
2225 metadata := uint64(uniport)
2226 subFlow.SetWriteMetadata(metadata)
2227 allowTransparent := 0
2228 if vpv.AllowTransparent {
2229 allowTransparent = 1
2230 }
2231 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2232 subFlow.SetTableMetadata(metadata)
2233 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05302234 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302235 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2236 subFlow.Priority = of.PppoeFlowPriority
2237
2238 flow.SubFlows[subFlow.Cookie] = subFlow
2239 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2240 return flow, nil
2241}
2242
2243// setDsMatchVlan to set downstream match vlan
2244func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302245 logger.Debugw(ctx, "Set Ds Match Vlan", log.Fields{"Vlan": vpv.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05302246 switch vpv.VlanControl {
2247 case None:
2248 flow.SetMatchVlan(vpv.SVlan)
2249 case ONUCVlanOLTSVlan,
2250 OLTCVlanOLTSVlan,
2251 ONUCVlan,
2252 OLTSVlan:
2253 flow.SetMatchVlan(vpv.SVlan)
2254 default:
2255 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2256 }
2257}
2258
2259// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2260// in the US direction.
2261func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2262 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2263 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2264 if mvp == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302265 return nil, errors.New("mvlan profile configured not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05302266 }
2267 mvlan := mvp.GetUsMatchVlan()
2268 flow := &of.VoltFlow{}
2269 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2270 subFlow := of.NewVoltSubFlow()
2271 subFlow.SetTableID(0)
2272
Akash Sonia8246972023-01-03 10:37:08 +05302273 subFlow.SetMatchVlan(vpv.UniVlan)
2274 subFlow.SetSetVlan(vpv.CVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05302275
2276 uniport, err := GetApplication().GetPortID(vpv.Port)
2277 if err != nil {
2278 return nil, err
2279 }
2280 subFlow.SetInPort(uniport)
2281 // PortName and PortID to be used for validation of port before flow pushing
2282 flow.PortID = uniport
2283 flow.PortName = vpv.Port
2284
2285 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2286 subFlow.SetMatchSrcMac(vpv.MacAddr)
2287 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302288 logger.Debugw(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
vinokuma926cb3e2023-03-29 11:41:06 +05302289 // metadata := uint64(mvlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05302290
2291 if vpv.McastService {
2292 metadata := uint64(vpv.McastUsMeterID)
2293 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2294 subFlow.SetMatchPbit(vpv.McastPbit)
2295 subFlow.SetMeterID(vpv.McastUsMeterID)
2296 subFlow.SetWriteMetadata(metadata)
2297 } else {
2298 // Set techprofile, meterid of first service
2299 vpv.services.Range(func(key, value interface{}) bool {
2300 svc := value.(*VoltService)
2301 writemetadata := uint64(svc.TechProfileID) << 32
2302 subFlow.SetWriteMetadata(writemetadata)
2303 subFlow.SetMeterID(svc.UsMeterID)
2304 return false
2305 })
2306 }
2307
2308 allowTransparent := 0
2309 if vpv.AllowTransparent {
2310 allowTransparent = 1
2311 }
2312 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2313 subFlow.SetTableMetadata(metadata)
2314 subFlow.SetIgmpMatch()
2315 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05302316 // | 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302317 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2318 subFlow.Priority = of.IgmpFlowPriority
2319
2320 flow.SubFlows[subFlow.Cookie] = subFlow
2321 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2322 return flow, nil
2323}
2324
2325// WriteToDb for writing to database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302326func (vpv *VoltPortVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302327 if vpv.DeleteInProgress {
2328 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2329 return
2330 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302331 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302332}
2333
vinokuma926cb3e2023-03-29 11:41:06 +05302334// ForceWriteToDb force commit a VPV to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302335func (vpv *VoltPortVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302336 vpv.PendingFlowLock.RLock()
2337 defer vpv.PendingFlowLock.RUnlock()
2338 vpv.Version = database.PresentVersionMap[database.VpvPath]
2339 if b, err := json.Marshal(vpv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302340 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 +05302341 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2342 "UniVlan": vpv.UniVlan, "Error": err})
2343 }
2344 }
2345}
2346
2347// DelFromDb for deleting from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302348func (vpv *VoltPortVnet) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302349 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 +05302350 _ = db.DelVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
Naveen Sampath04696f72022-06-13 15:19:14 +05302351}
2352
2353// ClearAllServiceFlags to clear all service flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302354func (vpv *VoltPortVnet) ClearAllServiceFlags(cntx context.Context) {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302355 vpv.RangeOnServices(cntx, ClearFlagsInService, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05302356}
2357
2358// ClearAllVpvFlags to clear all vpv flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302359func (vpv *VoltPortVnet) ClearAllVpvFlags(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302360 logger.Debugw(ctx, "Clear All Vpv Flags", log.Fields{"Port": vpv.Port, "Device": vpv.Device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302361 vpv.PendingFlowLock.Lock()
2362 vpv.FlowsApplied = false
2363 vpv.IgmpFlowsApplied = false
2364 vpv.PendingDeleteFlow = make(map[string]bool)
2365 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302366 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302367 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2368 log.Fields{"device": vpv.Device, "port": vpv.Port,
2369 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2370}
2371
2372// CreateVpvFromString to create vpv from string
2373func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302374 logger.Info(ctx, "Create Vpv From String")
Naveen Sampath04696f72022-06-13 15:19:14 +05302375 var vpv VoltPortVnet
2376 if err := json.Unmarshal(b, &vpv); err == nil {
2377 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2378 if !ok {
2379 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2380 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2381 }
2382 vpv.servicesCount = atomic.NewUint64(0)
2383 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2384 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2385 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2386 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2387 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2388 vnet.associatePortToVnet(vpv.Port)
2389 }
2390
2391 if vpv.DeleteInProgress {
2392 va.VoltPortVnetsToDelete[&vpv] = true
2393 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2394 }
2395 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2396 }
2397}
2398
2399// RestoreVpvsFromDb to restore vpvs from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302400func (va *VoltApplication) RestoreVpvsFromDb(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302401 logger.Info(ctx, "Restore Vpvs From Db")
Naveen Sampath04696f72022-06-13 15:19:14 +05302402 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302403 vpvs, _ := db.GetVpvs(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302404 for hash, vpv := range vpvs {
2405 b, ok := vpv.Value.([]byte)
2406 if !ok {
2407 logger.Warn(ctx, "The value type is not []byte")
2408 continue
2409 }
2410 va.CreateVpvFromString(b, hash)
2411 }
2412}
2413
2414// GetVnetByPort : VNET related functionality of VOLT Application here on.
2415// Get the VNET from a port. The port identity is passed as device and port identities in string.
2416// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2417// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2418func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302419 logger.Debugw(ctx, "Get Vnet By Port", log.Fields{"port": port, "svlan": svlan, "cvlan": cvlan, "univlan": univlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302420 if _, ok := va.VnetsByPort.Load(port); !ok {
2421 return nil
2422 }
2423 vpvs, _ := va.VnetsByPort.Load(port)
2424 for _, vpv := range vpvs.([]*VoltPortVnet) {
2425 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2426 return vpv
2427 }
2428 }
2429 return nil
2430}
2431
2432// AddVnetToPort to add vnet to port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302433func (va *VoltApplication) AddVnetToPort(cntx context.Context, port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
Naveen Sampath04696f72022-06-13 15:19:14 +05302434 // The VNET is not on the port and is to be added
2435 logger.Debugw(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
2436 vpv := NewVoltPortVnet(vvnet)
2437 vpv.MacLearning = vvnet.MacLearning
2438 vpv.Port = port
2439 vvnet.associatePortToVnet(port)
2440 if _, ok := va.VnetsByPort.Load(port); !ok {
2441 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2442 }
2443 vpvsIntf, _ := va.VnetsByPort.Load(port)
2444 vpvs := vpvsIntf.([]*VoltPortVnet)
2445 vpvs = append(vpvs, vpv)
2446 va.VnetsByPort.Store(port, vpvs)
2447 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2448
2449 vpv.VpvLock.Lock()
2450 defer vpv.VpvLock.Unlock()
2451
2452 // Add the service that is causing the VNET to be added to the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302453 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05302454
Tinoj Josephec742f62022-09-29 19:11:10 +05302455 if !vs.IsActivated {
2456 logger.Warn(ctx, "Not Checking port state: Service Not activated")
2457 // Process the PORT UP if the port is already up
2458 d, err := va.GetDeviceFromPort(port)
2459 if err == nil {
2460 vpv.setDevice(d.Name)
2461 }
2462 vpv.WriteToDb(cntx)
2463 return vpv
2464 }
2465
Naveen Sampath04696f72022-06-13 15:19:14 +05302466 // Process the PORT UP if the port is already up
2467 d, err := va.GetDeviceFromPort(port)
2468 if err == nil {
2469 vpv.setDevice(d.Name)
2470 p := d.GetPort(port)
2471 if p != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302472 logger.Debugw(ctx, "Checking UNI port state", log.Fields{"State": p.State})
Akash Soni024eb8e2023-04-28 16:25:09 +05302473 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302474 vpv.PortUpInd(cntx, d, port, vs.NniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05302475 }
2476 }
2477 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302478 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302479 return vpv
2480}
2481
2482// DelVnetFromPort for deleting vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302483func (va *VoltApplication) DelVnetFromPort(cntx context.Context, port string, vpv *VoltPortVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302484 logger.Debugw(ctx, "Delete Vnet From Port", log.Fields{"Port": port, "VNET": vpv.Device})
vinokuma926cb3e2023-03-29 11:41:06 +05302485 // Delete DHCP Session
Naveen Sampath04696f72022-06-13 15:19:14 +05302486 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2487
vinokuma926cb3e2023-03-29 11:41:06 +05302488 // Delete PPPoE session
Naveen Sampath04696f72022-06-13 15:19:14 +05302489 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2490
vinokuma926cb3e2023-03-29 11:41:06 +05302491 // Delete Mac from MacPortMap
Naveen Sampath04696f72022-06-13 15:19:14 +05302492 va.DeleteMacInPortMap(vpv.MacAddr)
2493
vinokuma926cb3e2023-03-29 11:41:06 +05302494 // Delete VPV
Naveen Sampath04696f72022-06-13 15:19:14 +05302495 vpvsIntf, ok := va.VnetsByPort.Load(port)
2496 if !ok {
2497 return
2498 }
2499 vpvs := vpvsIntf.([]*VoltPortVnet)
2500 for i, lvpv := range vpvs {
vinokuma04dc9f82023-07-31 15:47:49 +05302501 if reflect.DeepEqual(lvpv, vpv) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302502 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2503 "UNIVLAN": vpv.UniVlan})
2504
2505 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2506
2507 vpv.DeleteInProgress = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302508 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302509
2510 va.VnetsByPort.Store(port, vpvs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302511 vpv.DelTrapFlows(cntx)
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302512 vpv.DelHsiaFlows(cntx, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05302513 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2514 vpv.PendingFlowLock.RLock()
2515 if len(vpv.PendingDeleteFlow) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302516 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302517 }
2518 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302519 vnet.disassociatePortFromVnet(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302520 }
2521 vpv.PendingFlowLock.RUnlock()
2522 return
2523 }
2524 }
2525}
2526
2527// RestoreVnetsFromDb to restore vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302528func (va *VoltApplication) RestoreVnetsFromDb(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302529 logger.Info(ctx, "Restore Vnets From Db")
Naveen Sampath04696f72022-06-13 15:19:14 +05302530 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302531 vnets, _ := db.GetVnets(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302532 for _, net := range vnets {
2533 b, ok := net.Value.([]byte)
2534 if !ok {
2535 logger.Warn(ctx, "The value type is not []byte")
2536 continue
2537 }
2538 var vnet VoltVnet
2539 err := json.Unmarshal(b, &vnet)
2540 if err != nil {
2541 logger.Warn(ctx, "Unmarshal of VNET failed")
2542 continue
2543 }
2544 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302545 if err := va.AddVnet(cntx, vnet.VnetConfig, &vnet.VnetOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302546 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2547 }
2548
2549 if vnet.DeleteInProgress {
2550 va.VnetsToDelete[vnet.Name] = true
2551 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2552 }
Naveen Sampath04696f72022-06-13 15:19:14 +05302553 }
2554}
2555
2556// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2557// are used as the key to locate the service. If more than one service is on the
2558// same port (essentially a UNI of ONU), the services must be separated by different
2559// CVLANs
2560func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302561 logger.Debugw(ctx, "Get Service From Cvlan", log.Fields{"Device": device, "Port": port, "VLANs": vlans, "Priority": priority})
Naveen Sampath04696f72022-06-13 15:19:14 +05302562 // Fetch the device first to make sure the device exists
2563 dIntf, ok := va.DevicesDisc.Load(device)
2564 if !ok {
2565 return nil
2566 }
2567 d := dIntf.(*VoltDevice)
2568
2569 // If the port is NNI port, the services dont exist on it. The svc then
2570 // must be obtained from a different context and is not included here
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302571 if d.IsPortNni(port) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302572 return nil
2573 }
2574
vinokuma926cb3e2023-03-29 11:41:06 +05302575 // To return the matched service
Naveen Sampath04696f72022-06-13 15:19:14 +05302576 var service *VoltService
2577
2578 // This is an access port and the port should have all the associated
2579 // services which can be uniquely identified by the VLANs in the packet
2580 vnets, ok := va.VnetsByPort.Load(port)
2581
2582 if !ok {
2583 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2584 return nil
2585 }
2586 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2587 for _, vnet := range vnets.([]*VoltPortVnet) {
2588 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2589 switch vnet.VlanControl {
2590 case ONUCVlanOLTSVlan:
2591 service = vnet.MatchesPriority(priority)
2592 if vnet.MatchesCvlan(vlans) && service != nil {
2593 return service
2594 }
2595 case ONUCVlan,
2596 None:
2597 service = vnet.MatchesPriority(priority)
Naveen Sampath04696f72022-06-13 15:19:14 +05302598 // In case of HSIA Flow - cvlan == Svlan
Akash Sonief452f12024-12-12 18:20:28 +05302599 // In case of DHCP flow, match for cvlan as we are setting cvlan for DHCP flows
2600 if len(vlans) == 1 && (vlans[0] == vnet.CVlan || vlans[0] == of.VlanNone) && (service != nil && service.IsActivated) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302601 return service
2602 }
Akash Sonief452f12024-12-12 18:20:28 +05302603 case OLTCVlanOLTSVlan:
Naveen Sampath04696f72022-06-13 15:19:14 +05302604 service = vnet.MatchesPriority(priority)
2605 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2606 return service
2607 }
Akash Sonief452f12024-12-12 18:20:28 +05302608 case OLTSVlan:
2609 // For OLTSVlan, return only the active service attached to the VPV.
2610 service = vnet.GetSvcFromVPV()
2611 if service != nil && service.IsActivated {
2612 return service
2613 }
Naveen Sampath04696f72022-06-13 15:19:14 +05302614 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302615 logger.Warnw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05302616 }
2617 }
2618 return nil
2619}
2620
2621// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2622// are used as the key to locate the service. If more than one service is on the
2623// same port (essentially a UNI of ONU), the services must be separated by different
2624// CVLANs
2625func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2626 // Fetch the device first to make sure the device exists
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302627 logger.Debugw(ctx, "Get Vnet From Fields", log.Fields{"Device": device, "Port": port, "VLANs": vlans, "Priority": priority})
Naveen Sampath04696f72022-06-13 15:19:14 +05302628 dIntf, ok := va.DevicesDisc.Load(device)
2629 if !ok {
2630 return nil, nil
2631 }
2632 d := dIntf.(*VoltDevice)
2633
2634 // If the port is NNI port, the services dont exist on it. The svc then
2635 // must be obtained from a different context and is not included here
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302636 if d.IsPortNni(port) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302637 return nil, nil
2638 }
2639
2640 //To return the matched service
2641 var service *VoltService
2642
2643 // This is an access port and the port should have all the associated
2644 // services which can be uniquely identified by the VLANs in the packet
2645 if vnets, ok := va.VnetsByPort.Load(port); ok {
2646 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2647 for _, vnet := range vnets.([]*VoltPortVnet) {
2648 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2649 switch vnet.VlanControl {
2650 case ONUCVlanOLTSVlan:
2651 service = vnet.MatchesPriority(priority)
2652 if vnet.MatchesCvlan(vlans) && service != nil {
2653 return vnet, service
2654 }
2655 case ONUCVlan,
2656 None:
2657 service = vnet.MatchesPriority(priority)
2658 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2659 return vnet, service
2660 }
2661 case OLTCVlanOLTSVlan,
2662 OLTSVlan:
2663 service = vnet.MatchesPriority(priority)
2664 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2665 return vnet, service
2666 }
2667 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302668 logger.Warnw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05302669 }
2670 }
2671 }
2672 return nil, nil
2673}
2674
2675// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2676// are used as the key to locate the service. If more than one service is on the
2677// same port (essentially a UNI of ONU), the services must be separated by different
2678// CVLANs
2679func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302680 logger.Debugw(ctx, "Get Vnet From Pkt", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05302681 vlans := GetVlans(pkt)
2682 priority := GetPriority(pkt)
2683 return va.GetVnetFromFields(device, port, vlans, priority)
2684}
2685
2686// PushDevFlowForVlan to push icmpv6 flows for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302687func (va *VoltApplication) PushDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302688 logger.Debugw(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302689 pushflow := func(key interface{}, value interface{}) bool {
2690 device := value.(*VoltDevice)
2691 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302692 logger.Warnw(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +05302693 return true
2694 }
2695 if device.State != controller.DeviceStateUP {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302696 logger.Warnw(ctx, "Push Dev Flows Failed - Device state DOWN", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan, "device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302697 return true
2698 }
2699 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302700 logger.Warnw(ctx, "Push Dev Flows Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302701 return true
2702 }
2703
2704 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2705 vnetList := vnetListIntf.(*util.ConcurrentMap)
2706 vnetList.Set(vnet.Name, true)
2707 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2708 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()})
2709 return true
2710 }
2711 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2712 err := ProcessIcmpv6McGroup(device.Name, false)
2713 if err != nil {
2714 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2715 return true
2716 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302717 nniPort, err := GetApplication().GetNniPort(device.Name)
2718 if err != nil {
2719 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2720 return true
2721 }
2722 if portID, err := va.GetPortID(nniPort); err == nil {
2723 if state, _ := cntlr.GetController().GetPortState(device.Name, nniPort); state != cntlr.PortStateUp {
Naveen Sampath04696f72022-06-13 15:19:14 +05302724 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2725 return true
2726 }
2727
vinokuma926cb3e2023-03-29 11:41:06 +05302728 // Pushing ICMPv6 Flow
Naveen Sampath04696f72022-06-13 15:19:14 +05302729 flow := BuildICMPv6Flow(portID, vnet)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302730 err = cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302731 if err != nil {
2732 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2733 return true
2734 }
2735 logger.Infow(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
2736
2737 // Pushing ARP Flow
2738 flow = BuildDSArpFlow(portID, vnet)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302739 err = cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302740 if err != nil {
2741 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2742 return true
2743 }
2744 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2745
2746 vnetList := util.NewConcurrentMap()
2747 vnetList.Set(vnet.Name, true)
2748 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2749 }
2750 return true
2751 }
2752 va.DevicesDisc.Range(pushflow)
2753}
2754
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302755func (va *VoltApplication) PushTrapFlows(cntx context.Context, device *VoltDevice, nniPort string, flow *of.VoltFlow) error {
2756 logger.Debugw(ctx, "Push NNI DHCP Trap Flows", log.Fields{"DeviceName": device.Name, "Flow port": flow.PortID})
2757 return cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
2758}
2759
Naveen Sampath04696f72022-06-13 15:19:14 +05302760// PushDevFlowForDevice to push icmpv6 flows for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302761func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302762 logger.Debugw(ctx, "PushDevFlowForDevice", log.Fields{"device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05302763 err := ProcessIcmpv6McGroup(device.Name, false)
2764 if err != nil {
2765 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2766 return
2767 }
2768 pushicmpv6 := func(key, value interface{}) bool {
2769 vnet := value.(*VoltVnet)
2770 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2771 vnetList := vnetListIntf.(*util.ConcurrentMap)
2772 vnetList.Set(vnet.Name, true)
2773 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2774 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()})
2775 return true
2776 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302777 nniPort, err := GetApplication().GetNniPort(device.Name)
2778 if err != nil {
2779 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2780 return true
2781 }
2782 nniPortID, err := va.GetPortID(nniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05302783 if err != nil {
2784 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2785 }
2786 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2787 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2788 return true
2789 }
2790 flow := BuildICMPv6Flow(nniPortID, vnet)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302791 err = cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302792 if err != nil {
2793 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2794 return true
2795 }
2796 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2797
2798 flow = BuildDSArpFlow(nniPortID, vnet)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302799 err = cntlr.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302800 if err != nil {
2801 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2802 return true
2803 }
2804 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2805
2806 vnetList := util.NewConcurrentMap()
2807 vnetList.Set(vnet.Name, true)
2808 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2809 return true
2810 }
2811 va.VnetsByName.Range(pushicmpv6)
2812}
2813
2814// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302815func (va *VoltApplication) DeleteDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302816 logger.Debugw(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302817 delflows := func(key interface{}, value interface{}) bool {
2818 device := value.(*VoltDevice)
2819
2820 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2821 vnetList := vnetListIntf.(*util.ConcurrentMap)
2822 vnetList.Remove(vnet.Name)
2823 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2824 if vnetList.Length() != 0 {
2825 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()})
2826 return true
2827 }
2828 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302829 nniPort, err := GetApplication().GetNniPort(device.Name)
2830 if err != nil {
2831 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2832 return true
2833 }
2834 if portID, err := va.GetPortID(nniPort); err == nil {
2835 if state, _ := cntlr.GetController().GetPortState(device.Name, nniPort); state != cntlr.PortStateUp {
Naveen Sampath04696f72022-06-13 15:19:14 +05302836 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2837 return true
2838 }
vinokuma926cb3e2023-03-29 11:41:06 +05302839 // Pushing ICMPv6 Flow
Naveen Sampath04696f72022-06-13 15:19:14 +05302840 flow := BuildICMPv6Flow(portID, vnet)
2841 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302842 err := vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302843 if err != nil {
2844 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2845 return true
2846 }
2847 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2848
vinokuma926cb3e2023-03-29 11:41:06 +05302849 // Pushing ARP Flow
Naveen Sampath04696f72022-06-13 15:19:14 +05302850 flow = BuildDSArpFlow(portID, vnet)
2851 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302852 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302853 if err != nil {
2854 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2855 return true
2856 }
2857 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2858
2859 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2860 }
2861 return true
2862 }
2863 va.DevicesDisc.Range(delflows)
2864}
2865
2866// DeleteDevFlowForDevice to delete icmpv6 flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302867func (va *VoltApplication) DeleteDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302868 logger.Debugw(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302869 delicmpv6 := func(key, value interface{}) bool {
2870 vnet := value.(*VoltVnet)
2871 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2872 vnetList := vnetListIntf.(*util.ConcurrentMap)
2873 vnetList.Remove(vnet.Name)
2874 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2875 if vnetList.Length() != 0 {
2876 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()})
2877 return true
2878 }
2879 } else {
2880 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2881 return true
2882 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302883 nniPort, err := GetApplication().GetNniPort(device.Name)
2884 if err != nil {
2885 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2886 return true
2887 }
2888 nniPortID, err := va.GetPortID(nniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05302889 if err != nil {
2890 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2891 }
2892 flow := BuildICMPv6Flow(nniPortID, vnet)
2893 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302894 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302895 if err != nil {
2896 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2897 return true
2898 }
2899
2900 flow = BuildDSArpFlow(nniPortID, vnet)
2901 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302902 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302903 if err != nil {
2904 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2905 return true
2906 }
2907
2908 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2909 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2910 return true
2911 }
2912 va.VnetsByName.Range(delicmpv6)
2913 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2914 err := ProcessIcmpv6McGroup(device.Name, true)
2915 if err != nil {
2916 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2917 return
2918 }
2919}
2920
2921// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302922func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(cntx context.Context, vnet *VoltVnet, deviceSerialNum string) {
Akash Sonief452f12024-12-12 18:20:28 +05302923 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302924 delflows := func(key interface{}, value interface{}) bool {
2925 device := value.(*VoltDevice)
2926 if device.SerialNum != deviceSerialNum {
2927 return true
2928 }
2929 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2930 vnetList := vnetListIntf.(*util.ConcurrentMap)
2931 vnetList.Remove(vnet.Name)
2932 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2933 if vnetList.Length() != 0 {
2934 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()})
2935 return true
2936 }
2937 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2938 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2939 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2940 // The step will be as follow:
2941 // 1. Deact Service
2942 // 2. Pod Reboot
2943 // 3. Pending Delete Service triggered
2944 // 4. Del Service Ind followed by DelVnet req from NB
2945 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2946 // hence the flow will not be cleared
2947 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2948 return true
2949 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302950 nniPort, err := GetApplication().GetNniPort(device.Name)
2951 if err != nil {
2952 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2953 return true
2954 }
2955 if portID, err := va.GetPortID(nniPort); err == nil {
2956 if state, _ := cntlr.GetController().GetPortState(device.Name, nniPort); state != cntlr.PortStateUp {
Naveen Sampath04696f72022-06-13 15:19:14 +05302957 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2958 return false
2959 }
2960 flow := BuildICMPv6Flow(portID, vnet)
2961 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302962 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302963 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2964 }
2965 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2966
2967 flow = BuildDSArpFlow(portID, vnet)
2968 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302969 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302970 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2971 }
2972 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2973 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2974 }
2975 return false
2976 }
2977 va.DevicesDisc.Range(delflows)
2978}
2979
2980// BuildICMPv6Flow to Build DS flow for ICMPv6
2981func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302982 logger.Debugw(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302983 flow := &of.VoltFlow{}
2984 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2985 subFlow := of.NewVoltSubFlow()
2986
2987 subFlow.SetICMPv6Match()
2988 subFlow.SetMatchVlan(vnet.SVlan)
2989 subFlow.SetInPort(inport)
2990 subFlow.SetPopVlan()
2991 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2992 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2993 subFlow.Priority = of.McFlowPriority
2994 var metadata uint64
2995 if vnet.VlanControl == None {
2996 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2997 } else {
2998 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2999 }
3000 subFlow.SetTableMetadata(metadata)
3001 metadata = uint64(vnet.setPbitRemarking())
3002
3003 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
3004 subFlow.SetWriteMetadata(metadata)
3005 flow.SubFlows[subFlow.Cookie] = subFlow
3006 return flow
3007}
3008
vinokuma926cb3e2023-03-29 11:41:06 +05303009// BuildDSArpFlow Builds DS flow for ARP
Naveen Sampath04696f72022-06-13 15:19:14 +05303010func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303011 logger.Debugw(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05303012
3013 flow := &of.VoltFlow{}
3014 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3015 subFlow := of.NewVoltSubFlow()
3016
3017 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
3018 subFlow.SetArpMatch()
3019 subFlow.SetMatchDstMac(BcastMAC)
3020 subFlow.SetMatchVlan(vnet.SVlan)
3021 subFlow.SetInPort(inport)
3022 subFlow.SetPopVlan()
3023 subFlow.SetOutGroup(ICMPv6ArpGroupID)
3024
3025 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
3026 subFlow.Priority = of.McFlowPriority
3027
3028 var metadata uint64
3029 if vnet.VlanControl == None {
3030 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
3031 } else {
3032 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
3033 }
3034 subFlow.SetTableMetadata(metadata)
3035 metadata = uint64(vnet.setPbitRemarking())
3036 subFlow.SetWriteMetadata(metadata)
3037
3038 flow.SubFlows[subFlow.Cookie] = subFlow
3039 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
3040 return flow
3041}
3042
3043// setPbitRemarking to set Pbit remarking
3044func (vv *VoltVnet) setPbitRemarking() uint32 {
Naveen Sampath04696f72022-06-13 15:19:14 +05303045 // Remarkable
3046 // Remarked Pbit Pbit
3047 // |-----------------------------| |------|
3048 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
3049 // 000 000 000 000 000 000 000 000 00000000
3050
3051 // Eg:
3052 // For 6:3 & 7:1
3053 // 001 011 000 000 000 000 000 000 11000000
3054
3055 var remarkable uint8
3056 var remarked uint32
3057 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
3058 remarkable = remarkable | 1<<refPbit
3059 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
3060 }
3061 return remarked<<8 | uint32(remarkable)
3062}
3063
3064// ProcessIcmpv6McGroup to add icmpv6 multicast group
3065func ProcessIcmpv6McGroup(device string, delete bool) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05303066 logger.Info(ctx, "Creating ICMPv6 MC Group")
3067 va := GetApplication()
3068 vd := va.GetDevice(device)
3069 group := &of.Group{}
3070 group.GroupID = ICMPv6ArpGroupID
3071 group.Device = device
3072 if delete {
3073 if !vd.icmpv6GroupAdded {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303074 logger.Debug(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
Naveen Sampath04696f72022-06-13 15:19:14 +05303075 return nil //TODO
3076 }
3077 vd.icmpv6GroupAdded = false
3078 group.Command = of.GroupCommandDel
3079 group.ForceAction = true
3080 } else {
3081 if vd.icmpv6GroupAdded {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303082 logger.Debug(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
Naveen Sampath04696f72022-06-13 15:19:14 +05303083 return nil //TODO
3084 }
3085 vd.icmpv6GroupAdded = true
3086 group.Command = of.GroupCommandAdd
3087 receivers := GetApplication().GetIcmpv6Receivers(device)
3088 group.Buckets = append(group.Buckets, receivers...)
3089 }
3090 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
3091 port, _ := GetApplication().GetNniPort(device)
3092 err := cntlr.GetController().GroupUpdate(port, device, group)
3093 return err
3094}
3095
vinokuma926cb3e2023-03-29 11:41:06 +05303096// isVlanMatching - checks is vlans matches with vpv based on vlan control
Naveen Sampath04696f72022-06-13 15:19:14 +05303097func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303098 logger.Debugw(ctx, "Is Vlan Matching", log.Fields{"cvlan": cvlan, "svlan": svlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05303099 switch vpv.VlanControl {
3100 case ONUCVlanOLTSVlan,
3101 OLTCVlanOLTSVlan:
3102 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
3103 return true
3104 }
3105 case ONUCVlan,
3106 OLTSVlan,
3107 None:
3108 if vpv.SVlan == svlan {
3109 return true
3110 }
3111 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303112 logger.Warnw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05303113 }
3114 return false
3115}
3116
vinokuma926cb3e2023-03-29 11:41:06 +05303117// PushFlows - Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303118func (vpv *VoltPortVnet) PushFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303119 logger.Debugw(ctx, "Push Flows", log.Fields{"DeviceName": device.Name, "Flow port": flow.PortID})
Naveen Sampath04696f72022-06-13 15:19:14 +05303120 for cookie := range flow.SubFlows {
3121 cookie := strconv.FormatUint(cookie, 10)
3122 fe := &FlowEvent{
3123 eType: EventTypeControlFlowAdded,
3124 cookie: cookie,
3125 eventData: vpv,
3126 }
3127 device.RegisterFlowAddEvent(cookie, fe)
3128 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303129 return cntlr.GetController().AddFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05303130}
3131
vinokuma926cb3e2023-03-29 11:41:06 +05303132// FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
Naveen Sampath04696f72022-06-13 15:19:14 +05303133func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303134 logger.Debugw(ctx, "Flow Install Failure", log.Fields{"Cookie": cookie, "ErrorCode": errorCode, "ErrReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05303135 sendFlowFailureInd := func(key, value interface{}) bool {
3136 //svc := value.(*VoltService)
3137 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
3138 return true
3139 }
3140 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3141 vpv.services.Range(sendFlowFailureInd)
3142}
3143
vinokuma926cb3e2023-03-29 11:41:06 +05303144// RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303145func (vpv *VoltPortVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303146 logger.Debugw(ctx, "Remove Flows", log.Fields{"DeviceName": device.Name, "Flow port": flow.PortID})
Naveen Sampath04696f72022-06-13 15:19:14 +05303147 vpv.PendingFlowLock.Lock()
3148 defer vpv.PendingFlowLock.Unlock()
3149
3150 for cookie := range flow.SubFlows {
3151 cookie := strconv.FormatUint(cookie, 10)
3152 fe := &FlowEvent{
3153 eType: EventTypeControlFlowRemoved,
3154 device: device.Name,
3155 cookie: cookie,
3156 eventData: vpv,
3157 }
3158 device.RegisterFlowDelEvent(cookie, fe)
3159 vpv.PendingDeleteFlow[cookie] = true
3160 }
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05303161 return cntlr.GetController().DelFlows(cntx, vpv.Port, device.Name, flow, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05303162}
3163
vinokuma926cb3e2023-03-29 11:41:06 +05303164// CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303165func (vpv *VoltPortVnet) CheckAndDeleteVpv(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303166 logger.Debugw(ctx, "Check And Delete Vpv", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
Naveen Sampath04696f72022-06-13 15:19:14 +05303167 vpv.PendingFlowLock.RLock()
3168 defer vpv.PendingFlowLock.RUnlock()
3169 if !vpv.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303170 logger.Warnw(ctx, "Skipping removing VPV from DB as VPV delete is in progress", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
Naveen Sampath04696f72022-06-13 15:19:14 +05303171 return
3172 }
3173 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303174 logger.Debugw(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 +05303175 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303176 logger.Infow(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
3177 }
3178}
3179
vinokuma926cb3e2023-03-29 11:41:06 +05303180// FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303181func (vpv *VoltPortVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303182 vpv.PendingFlowLock.Lock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303183 logger.Debugw(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303184
3185 delete(vpv.PendingDeleteFlow, cookie)
3186 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303187 vpv.CheckAndDeleteVpv(cntx)
3188 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303189}
3190
vinokuma926cb3e2023-03-29 11:41:06 +05303191// FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303192func (vpv *VoltPortVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303193 vpv.PendingFlowLock.Lock()
3194
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303195 logger.Debugw(ctx, "VPV Flow Remove Failure Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303196
3197 sendFlowFailureInd := func(key, value interface{}) bool {
3198 svc := value.(*VoltService)
3199 svc.triggerServiceFailureInd(errorCode, errReason)
3200 return true
3201 }
3202 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3203 vpv.services.Range(sendFlowFailureInd)
3204
3205 if vpv.DeleteInProgress {
3206 delete(vpv.PendingDeleteFlow, cookie)
3207 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303208 vpv.CheckAndDeleteVpv(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303209 } else {
3210 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303211 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303212 }
3213}
3214
vinokuma926cb3e2023-03-29 11:41:06 +05303215// RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303216func (vv *VoltVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303217 logger.Debugw(ctx, "Remove Flows", log.Fields{"PortName": flow.PortName, "DeviceName": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05303218 vv.VnetLock.Lock()
3219 defer vv.VnetLock.Unlock()
3220
3221 var flowMap map[string]bool
3222 var ok bool
3223
3224 for cookie := range flow.SubFlows {
3225 cookie := strconv.FormatUint(cookie, 10)
3226 fe := &FlowEvent{
3227 eType: EventTypeDeviceFlowRemoved,
3228 device: device.Name,
3229 cookie: cookie,
3230 eventData: vv,
3231 }
3232 device.RegisterFlowDelEvent(cookie, fe)
3233 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
3234 flowMap = make(map[string]bool)
3235 }
3236 flowMap[cookie] = true
3237 vv.PendingDeleteFlow[device.Name] = flowMap
3238 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303239 vv.WriteToDb(cntx)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303240 nniPort, err := GetApplication().GetNniPort(device.Name)
3241 if err != nil {
3242 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
3243 return err
3244 }
3245 return cntlr.GetController().DelFlows(cntx, nniPort, device.Name, flow, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05303246}
3247
vinokuma926cb3e2023-03-29 11:41:06 +05303248// CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303249func (vv *VoltVnet) CheckAndDeleteVnet(cntx context.Context, device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303250 logger.Debugw(ctx, "Check And Delete Vnet", log.Fields{"Device": device, "Vnet": vv.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05303251 if !vv.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303252 logger.Warnw(ctx, "Skipping removing Vnet from DB as Vnet delete is in progress", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303253 return
3254 }
3255 vv.VnetPortLock.RLock()
3256 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
3257 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
3258 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303259 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05303260 logger.Infow(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
3261 } else {
3262 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
3263 }
3264 vv.VnetPortLock.RUnlock()
3265}
3266
vinokuma926cb3e2023-03-29 11:41:06 +05303267// FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303268func (vv *VoltVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303269 vv.VnetLock.Lock()
3270 defer vv.VnetLock.Unlock()
3271
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303272 logger.Debugw(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303273
3274 if _, ok := vv.PendingDeleteFlow[device]; ok {
3275 delete(vv.PendingDeleteFlow[device], cookie)
3276 }
3277
3278 //Check and update success for pending disable request
3279 if d := GetApplication().GetDevice(device); d != nil {
3280 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3281 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303282 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303283 }
3284 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303285 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303286}
3287
vinokuma926cb3e2023-03-29 11:41:06 +05303288// FlowRemoveFailure - Process flow failure indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303289func (vv *VoltVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303290 vv.VnetLock.Lock()
3291 defer vv.VnetLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303292 logger.Debugw(ctx, "Vnet Flow Remove Failure Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device, "ErrorCode": errorCode, "ErrorReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05303293
3294 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3295 if _, ok := flowMap[cookie]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303296 logger.Debugw(ctx, "Device Flow Remove Failure Notification", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303297
3298 if vv.DeleteInProgress {
3299 delete(vv.PendingDeleteFlow[device], cookie)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303300 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303301 }
3302 return
3303 }
3304 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303305 logger.Debugw(ctx, "Device Flow Remove Failure Notification for Unknown cookie", log.Fields{"Vnet": vv.Name, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05303306}
3307
vinokuma926cb3e2023-03-29 11:41:06 +05303308// IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
Naveen Sampath04696f72022-06-13 15:19:14 +05303309func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
vinokuma926cb3e2023-03-29 11:41:06 +05303310 // Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3311 // When multiple Igmp-suported service enabled, comment "return false"
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303312 logger.Debugw(ctx, "Igmp Flow Install Failure", log.Fields{"Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05303313
3314 sendFlowFailureInd := func(key, value interface{}) bool {
3315 svc := value.(*VoltService)
3316 if svc.IgmpEnabled {
3317 svc.triggerServiceFailureInd(errorCode, errReason)
3318 return false
3319 }
3320 return true
3321 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303322 logger.Debugw(ctx, "US IGMP Flow Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05303323 vpv.services.Range(sendFlowFailureInd)
3324}
3325
3326// GetMatchingMcastService to get matching multicast service
3327func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303328 logger.Debugw(ctx, "Get Matching Mcast Service", log.Fields{"Port": port, "Device": device, "Cvlan": cvlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05303329 var service *VoltService
3330 dIntf, ok := va.DevicesDisc.Load(device)
3331 if !ok {
3332 return nil
3333 }
3334 d := dIntf.(*VoltDevice)
3335
3336 // If the port is NNI port, the services dont exist on it. The svc then
3337 // must be obtained from a different context and is not included here
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303338 if d.IsPortNni(port) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303339 return nil
3340 }
3341
3342 // This is an access port and the port should have all the associated
3343 // services which can be uniquely identified by the VLANs in the packet
3344 vnets, ok := va.VnetsByPort.Load(port)
3345
3346 if !ok {
3347 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3348 return nil
3349 }
3350 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3351 getMcastService := func(key, value interface{}) bool {
3352 srv := value.(*VoltService)
3353 if srv.IgmpEnabled {
3354 service = srv
3355
3356 //TODO: Current implementation supports only for single service with Igmp Enabled
3357 //FIX-ME: When multiple service suports Igmp, update of logic required
3358 return false
3359 }
3360 return true
3361 }
3362
3363 for _, vpv := range vnets.([]*VoltPortVnet) {
3364 if vpv.CVlan == cvlan {
3365 vpv.services.Range(getMcastService)
3366 if service != nil {
3367 break
3368 }
3369 }
3370 }
3371 return service
3372}
3373
vinokuma926cb3e2023-03-29 11:41:06 +05303374// TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303375func (vv *VoltVnet) TriggerAssociatedFlowDelete(cntx context.Context, device string) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303376 logger.Infow(ctx, "Trigger Associated Flow Delete", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303377 vv.VnetLock.Lock()
3378 cookieList := []uint64{}
3379 flowMap := vv.PendingDeleteFlow[device]
3380
3381 for cookie := range flowMap {
3382 cookieList = append(cookieList, convertToUInt64(cookie))
3383 }
3384 vv.VnetLock.Unlock()
3385
3386 if len(cookieList) == 0 {
3387 return false
3388 }
3389
3390 for _, cookie := range cookieList {
3391 if vd := GetApplication().GetDevice(device); vd != nil {
3392 flow := &of.VoltFlow{}
3393 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3394 subFlow := of.NewVoltSubFlow()
3395 subFlow.Cookie = cookie
3396 flow.SubFlows[cookie] = subFlow
3397 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303398 if err := vv.RemoveFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05303399 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3400 }
3401 }
3402 }
3403 return true
3404}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303405
vinokuma926cb3e2023-03-29 11:41:06 +05303406// JSONMarshal wrapper function for json Marshal VoltVnet
3407func (vv *VoltVnet) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303408 return json.Marshal(VoltVnet{
3409 VnetConfig: vv.VnetConfig,
Akash Sonia8246972023-01-03 10:37:08 +05303410 Version: vv.Version,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303411 VnetOper: VnetOper{
3412 PendingDeleteFlow: vv.VnetOper.PendingDeleteFlow,
3413 DeleteInProgress: vv.VnetOper.DeleteInProgress,
3414 PendingDeviceToDelete: vv.VnetOper.PendingDeviceToDelete,
3415 },
3416 })
3417}
3418
vinokuma926cb3e2023-03-29 11:41:06 +05303419// JSONMarshal wrapper function for json Marshal VoltPortVnet
3420func (vpv *VoltPortVnet) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303421 return json.Marshal(VoltPortVnet{
3422 Device: vpv.Device,
3423 Port: vpv.Port,
3424 PonPort: vpv.PonPort,
3425 VnetName: vpv.VnetName,
3426 SVlan: vpv.SVlan,
3427 CVlan: vpv.CVlan,
3428 UniVlan: vpv.UniVlan,
3429 SVlanTpid: vpv.SVlanTpid,
3430 DhcpRelay: vpv.DhcpRelay,
3431 ArpRelay: vpv.ArpRelay,
3432 PppoeIa: vpv.PppoeIa,
3433 MacLearning: vpv.MacLearning,
3434 DhcpStatus: vpv.DhcpStatus,
3435 DhcpExpiryTime: vpv.DhcpExpiryTime,
3436 Dhcp6ExpiryTime: vpv.Dhcp6ExpiryTime,
3437 FlowsApplied: vpv.FlowsApplied,
3438 Ipv4Addr: vpv.Ipv4Addr,
3439 Ipv6Addr: vpv.Ipv6Addr,
3440 MacAddr: vpv.MacAddr,
3441 LearntMacAddr: vpv.LearntMacAddr,
3442 CircuitID: vpv.CircuitID,
3443 RemoteID: vpv.RemoteID,
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05303444 IsOption82Enabled: vpv.IsOption82Enabled,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303445 RelayState: vpv.RelayState,
3446 PPPoeState: vpv.PPPoeState,
3447 RelayStatev6: vpv.RelayStatev6,
3448 IgmpEnabled: vpv.IgmpEnabled,
3449 IgmpFlowsApplied: vpv.IgmpFlowsApplied,
3450 McastService: vpv.McastService,
3451 ONTEtherTypeClassification: vpv.ONTEtherTypeClassification,
3452 VlanControl: vpv.VlanControl,
3453 MvlanProfileName: vpv.MvlanProfileName,
3454 Version: vpv.Version,
3455 McastTechProfileID: vpv.McastTechProfileID,
3456 McastPbit: vpv.McastPbit,
3457 McastUsMeterID: vpv.McastUsMeterID,
3458 AllowTransparent: vpv.AllowTransparent,
3459 SchedID: vpv.SchedID,
3460 DHCPv6DUID: vpv.DHCPv6DUID,
3461 PendingDeleteFlow: vpv.PendingDeleteFlow,
3462 DeleteInProgress: vpv.DeleteInProgress,
3463 Blocked: vpv.Blocked,
3464 DhcpPbit: vpv.DhcpPbit,
3465 })
3466}
Tinoj Josephec742f62022-09-29 19:11:10 +05303467
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303468func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) (bool, string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303469 logger.Debugw(ctx, "Is Service Activated", log.Fields{"Name": vpv.Port})
Tinoj Josephec742f62022-09-29 19:11:10 +05303470 isActivated := false
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303471 nniPort := ""
Tinoj Josephec742f62022-09-29 19:11:10 +05303472 vpv.services.Range(func(key, value interface{}) bool {
3473 svc := value.(*VoltService)
3474 if svc.IsActivated {
3475 logger.Infow(ctx, "Found activated service on the vpv", log.Fields{"Name": svc.Name})
3476 isActivated = true
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303477 nniPort = svc.NniPort
Tinoj Josephec742f62022-09-29 19:11:10 +05303478 return false //to exit loop
3479 }
3480 return true
3481 })
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303482 return isActivated, nniPort
Tinoj Josephec742f62022-09-29 19:11:10 +05303483}