blob: e4f96be36fd2b757986d4327dc59fb3ae22903ab [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"
Akash Sonia8246972023-01-03 10:37:08 +053037
38 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053039 "voltha-go-controller/internal/pkg/of"
40 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053041 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053042)
43
44const (
45 // ICMPv6ArpGroupID constant
46 ICMPv6ArpGroupID uint32 = 1
47
48 // Radisys vendor id constant
49 Radisys string = "Radisys"
Tinoj Joseph50d722c2022-12-06 22:53:22 +053050
51 // DPU_MGMT_TRAFFIC serviceType, vnetType constant
vinokuma926cb3e2023-03-29 11:41:06 +053052 DpuMgmtTraffic string = "DPU_MGMT_TRAFFIC"
Tinoj Joseph50d722c2022-12-06 22:53:22 +053053
54 // DPU_ANCP_TRAFFIC serviceType, vnetType constant
vinokuma926cb3e2023-03-29 11:41:06 +053055 DpuAncpTraffic string = "DPU_ANCP_TRAFFIC"
Tinoj Joseph50d722c2022-12-06 22:53:22 +053056
57 // FTTB_SUBSCRIBER_TRAFFIC serviceType, vnetType constant
vinokuma926cb3e2023-03-29 11:41:06 +053058 FttbSubscriberTraffic string = "FTTB_SUBSCRIBER_TRAFFIC"
Naveen Sampath04696f72022-06-13 15:19:14 +053059)
60
61var (
62 //BroadcastMAC - Broadcast MAC Address
63 BroadcastMAC, _ = net.ParseMAC("ff:ff:ff:ff:ff:ff")
64)
65
66// NonZeroMacAddress utility to identify if the MAC address is non-zero.
67// We use zero MAC address as an unset MAC address
68func NonZeroMacAddress(h net.HardwareAddr) bool {
69 for i := 0; i < 6; i++ {
70 if h[i] != 0 {
71 return true
72 }
73 }
74 return false
75}
76
77// VNET package manages the different virtual networks that are part of the
78// the network. In the case of VOLT, the networks can be single tagged or
79// double tagged networks. In addition, the networks may be used for unicast
80// and multicast traffic. The unicast traffic further has two models, the
81// 1:1 and N:1 model. In case of a 1:1 model, the outer tag is same for many
82// subscribers and the inner tag is unique to each subscriber for the same
83// outer tag. The N:1 uses the same inner and outer tags, or for that matter
84// a single tag that can also be shared by subscribers. The VNET implementation
85// manages all these possibilities and the associated configuration.
86
87const (
88 // PbitMatchNone constant
89 PbitMatchNone of.PbitType = 8
90 // PbitMatchAll constant
91 PbitMatchAll of.PbitType = 0xFF
92)
93
94// SVlan - Value of the outer tag if double tagged or the only tag if single
95// tagged
96// SVlanTpid - SVlan Tag Protocol Identifier
97// CVlan - Value of the inner tag. Set to VlanNone if single tagged
98// DhcpRelay - Set to true if the DHCP relay is enabled on the virtual network
99// MacLearning - Set to true if the flows should include MAC address
100// UsDhcpPbit - The pbit used for US DHCP packets
101// DsDhcpPbit - The pbit used for DS DHCP packets
102
103// VnetConfig structure
104type VnetConfig struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530105 CtrlPktPbitRemark map[of.PbitType]of.PbitType
Naveen Sampath04696f72022-06-13 15:19:14 +0530106 Name string
vinokuma926cb3e2023-03-29 11:41:06 +0530107 VnetType string
Naveen Sampath04696f72022-06-13 15:19:14 +0530108 Encapsulation string
vinokuma926cb3e2023-03-29 11:41:06 +0530109 DevicesList []string //List of serial number of devices on which this vnet is applied
Naveen Sampath04696f72022-06-13 15:19:14 +0530110 UsDhcpPbit []of.PbitType
111 DsDhcpPbit []of.PbitType
112 UsIGMPPbit []of.PbitType
113 DsIGMPPbit []of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +0530114 ONTEtherTypeClassification int
115 MacLearning MacLearningType
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530116 UsPonCTagPriority of.PbitType
117 UsPonSTagPriority of.PbitType
118 DsPonCTagPriority of.PbitType
119 DsPonSTagPriority of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +0530120 SVlan of.VlanType
121 CVlan of.VlanType
122 UniVlan of.VlanType
123 SVlanTpid layers.EthernetType
124 VlanControl VlanControl
125 DhcpRelay bool
126 ArpLearning bool
127 AllowTransparent bool
128 PppoeIa bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530129}
130
131// VnetOper structure
132type VnetOper struct {
133 PendingDeleteFlow map[string]map[string]bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530134 AssociatedPorts map[string]bool `json:"-"`
vinokuma926cb3e2023-03-29 11:41:06 +0530135 PendingDeviceToDelete string
136 VnetLock sync.RWMutex `json:"-"`
137 VnetPortLock sync.RWMutex `json:"-"`
138 DeleteInProgress bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530139}
140
141// VoltVnet sructure
142type VoltVnet struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530143 Version string
Naveen Sampath04696f72022-06-13 15:19:14 +0530144 VnetConfig
145 VnetOper
Naveen Sampath04696f72022-06-13 15:19:14 +0530146}
147
148const (
149 // EncapsulationPPPoEIA constant
150 EncapsulationPPPoEIA string = "PPPoE-IA"
151 // EncapsulationPPPoE constant
152 EncapsulationPPPoE string = "PPPoE"
153 // EncapsulationIPoE constant
154 EncapsulationIPoE string = "IPoE"
155)
156
157// NewVoltVnet is constructor for the VNET structure
158func NewVoltVnet(cfg VnetConfig) *VoltVnet {
159 var vv VoltVnet
160 vv.VnetConfig = cfg
161 if vv.PendingDeleteFlow == nil {
162 vv.PendingDeleteFlow = make(map[string]map[string]bool)
163 }
164 vv.DeleteInProgress = false
165 if cfg.Encapsulation == EncapsulationPPPoEIA {
166 vv.PppoeIa = true
167 }
168 vv.AssociatedPorts = make(map[string]bool)
169 return &vv
170}
171
vinokuma926cb3e2023-03-29 11:41:06 +0530172// associatePortToVnet - associate a port to Vnet
Naveen Sampath04696f72022-06-13 15:19:14 +0530173func (vv *VoltVnet) associatePortToVnet(port string) {
174 vv.VnetPortLock.Lock()
175 if vv.AssociatedPorts == nil {
176 vv.AssociatedPorts = make(map[string]bool)
177 }
178 vv.AssociatedPorts[port] = true
179 vv.VnetPortLock.Unlock()
180}
181
vinokuma926cb3e2023-03-29 11:41:06 +0530182// disassociatePortFromVnet - disassociate a port from Vnet and return true if the association map is empty
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530183func (vv *VoltVnet) disassociatePortFromVnet(cntx context.Context, device string, port string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530184 logger.Infow(ctx, "Disassociate Port from Vnet", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530185 vv.VnetPortLock.Lock()
186 delete(vv.AssociatedPorts, port)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530187 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 +0530188 vv.VnetPortLock.Unlock()
189
190 if vv.DeleteInProgress {
191 if !vv.isAssociatedPortsPresent() {
192 if len(vv.PendingDeleteFlow[device]) == 0 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530193 logger.Debugw(ctx, "Deleting Vnet", log.Fields{"Name": vv.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530194 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530195 _ = db.DelVnet(cntx, vv.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530196 } else {
197 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "PendingDeleteFlow": vv.PendingDeleteFlow})
198 }
199 } else {
200 vv.VnetPortLock.RLock()
201 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts})
202 vv.VnetPortLock.RUnlock()
203 }
204 }
205}
206
207func (vv *VoltVnet) isAssociatedPortsPresent() bool {
208 vv.VnetPortLock.RLock()
209 defer vv.VnetPortLock.RUnlock()
210 return len(vv.AssociatedPorts) != 0
211}
212
213// WriteToDb commit the VNET to the database
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530214func (vv *VoltVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530215 if vv.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530216 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 +0530217 return
218 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530219 vv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530220}
221
vinokuma926cb3e2023-03-29 11:41:06 +0530222// ForceWriteToDb force commit a vnet to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530223func (vv *VoltVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530224 vv.VnetPortLock.RLock()
225 defer vv.VnetPortLock.RUnlock()
226 vv.Version = database.PresentVersionMap[database.VnetPath]
227 logger.Debugw(ctx, "Updating VNET....", log.Fields{"vnet": vv})
228 if b, err := json.Marshal(vv); err == nil {
Akash Sonia8246972023-01-03 10:37:08 +0530229 if err := db.PutVnet(cntx, vv.Name, string(b)); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530230 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 +0530231 }
232 }
233}
234
235// VnetKey creates the key using the two VLAN tags
236// We append the two VLAN tags to create a single key
237func VnetKey(otag of.VlanType, itag of.VlanType, utag of.VlanType) string {
238 return strconv.Itoa(int(otag)) + "-" + strconv.Itoa(int(itag)) + "-" + strconv.Itoa(int(utag))
239}
240
241// GetVnet get VNET configuration related functionality associated with VOLT application
242func (va *VoltApplication) GetVnet(otag of.VlanType, itag of.VlanType, utag of.VlanType) *VoltVnet {
243 // When matching VNET, it is expected to match first just the outer
244 // tag, and then the combination to make sure there is no conflict
245 // for the new configuration.
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530246 logger.Debugw(ctx, "Get Vnet configuration", log.Fields{"SVlan": otag, "CVlan": itag, "UniVlan": utag})
Naveen Sampath04696f72022-06-13 15:19:14 +0530247 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, of.VlanNone, utag)); ok {
248 return vnet.(*VoltVnet)
249 }
250 if vnet, ok := va.VnetsByTag.Load(VnetKey(otag, itag, utag)); ok {
251 return vnet.(*VoltVnet)
252 }
253 return nil
254}
255
256// The VNET may also be assigned name for easier references. For now,
257// the VNET is mainly identified by the two VLANs.
258
259// GetVnetByName to get vnet by name
260func (va *VoltApplication) GetVnetByName(name string) *VoltVnet {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530261 logger.Debugw(ctx, "Get Vnet by Name", log.Fields{"Name": name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530262 if vnet, ok := va.VnetsByName.Load(name); ok {
263 return vnet.(*VoltVnet)
264 }
265 return nil
266}
267
268// storeVnetConfig to store vnet config
269func (va *VoltApplication) storeVnetConfig(cfg VnetConfig, vv *VoltVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530270 logger.Debugw(ctx, "Store Vnet config", log.Fields{"Name": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530271 var vnetMap *util.ConcurrentMap
272
273 va.VnetsByTag.Store(VnetKey(cfg.SVlan, cfg.CVlan, cfg.UniVlan), vv)
274 va.VnetsByName.Store(cfg.Name, vv)
275
276 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vv.SVlan); !ok {
277 vnetMap = util.NewConcurrentMap()
278 } else {
279 vnetMap = vnetMapIntf.(*util.ConcurrentMap)
280 }
281 vnetMap.Set(vv, true)
282 va.VnetsBySvlan.Set(vv.SVlan, vnetMap)
283}
284
285// deleteVnetConfig to delete vnet config
286func (va *VoltApplication) deleteVnetConfig(vnet *VoltVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530287 logger.Debugw(ctx, "Delete Vnet config", log.Fields{"Name": vnet.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530288 va.VnetsByTag.Delete(VnetKey(vnet.SVlan, vnet.CVlan, vnet.UniVlan))
289 va.VnetsByName.Delete(vnet.Name)
290
291 if vnetMapIntf, ok := va.VnetsBySvlan.Get(vnet.SVlan); ok {
292 vnetMap := vnetMapIntf.(*util.ConcurrentMap)
293 vnetMap.Remove(vnet)
294 va.VnetsBySvlan.Set(vnet.SVlan, vnetMap)
295 }
296}
297
298// AddVnet to add a VNET to the list of VNETs configured.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530299func (va *VoltApplication) AddVnet(cntx context.Context, cfg VnetConfig, oper *VnetOper) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530300 logger.Debugw(ctx, "Add Vnet config", log.Fields{"Name": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530301 AppMutex.VnetMutex.Lock()
302 var vv *VoltVnet
303 devicesToHandle := []string{}
304 vv = va.GetVnetByName(cfg.Name)
305 if vv != nil {
306 //Could be for another OLT or could be case of backup-restore
307 for _, serialNum := range cfg.DevicesList {
308 if isDeviceInList(serialNum, vv.DevicesList) {
309 //This is backup restore scenario, just update the profile
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530310 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 +0530311 continue
312 }
313 devicesToHandle = append(devicesToHandle, serialNum)
314 }
315 if len(devicesToHandle) == 0 {
Akash Sonief452f12024-12-12 18:20:28 +0530316 logger.Warnw(ctx, "Ignoring Duplicate VNET by name ", log.Fields{"Vnet": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530317 AppMutex.VnetMutex.Unlock()
318 return nil
319 }
320 }
321
322 if vv == nil {
323 vv = NewVoltVnet(cfg)
324 if oper != nil {
325 vv.PendingDeleteFlow = oper.PendingDeleteFlow
326 vv.DeleteInProgress = oper.DeleteInProgress
327 vv.AssociatedPorts = oper.AssociatedPorts
328 vv.PendingDeviceToDelete = oper.PendingDeviceToDelete
329 }
330 devicesToHandle = append(devicesToHandle, cfg.DevicesList...)
331 } else {
332 vv.DevicesList = append(vv.DevicesList, devicesToHandle...)
333 }
334
335 va.storeVnetConfig(cfg, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530336 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530337
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530338 logger.Debugw(ctx, "Added VNET TO DB", log.Fields{"cfg": cfg, "devicesToHandle": devicesToHandle})
Naveen Sampath04696f72022-06-13 15:19:14 +0530339
340 //va.PushDevFlowForVlan(vv)
341 AppMutex.VnetMutex.Unlock()
342 return nil
343}
344
345// DelVnet to delete a VNET from the list of VNETs configured
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530346func (va *VoltApplication) DelVnet(cntx context.Context, name, deviceSerialNum string) error {
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530347 logger.Debugw(ctx, "Deleting Vnet", log.Fields{"Vnet": name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530348 AppMutex.VnetMutex.Lock()
349 if vnetIntf, ok := va.VnetsByName.Load(name); ok {
350 vnet := vnetIntf.(*VoltVnet)
vinokuma926cb3e2023-03-29 11:41:06 +0530351 // Delete from mvp list
Naveen Sampath04696f72022-06-13 15:19:14 +0530352 vnet.DevicesList = util.RemoveFromSlice(vnet.DevicesList, deviceSerialNum)
353
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530354 va.DeleteDevFlowForVlanFromDevice(cntx, vnet, deviceSerialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +0530355 if len(vnet.DevicesList) == 0 {
356 vnet.DeleteInProgress = true
357 vnet.PendingDeviceToDelete = deviceSerialNum
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530358 vnet.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530359 vnet.VnetPortLock.RLock()
360 if len(vnet.PendingDeleteFlow) == 0 && !vnet.isAssociatedPortsPresent() {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530361 logger.Debugw(ctx, "Deleting Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
Naveen Sampath04696f72022-06-13 15:19:14 +0530362 va.deleteVnetConfig(vnet)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530363 _ = db.DelVnet(cntx, vnet.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530364 } else {
365 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vnet.Name, "AssociatedPorts": vnet.AssociatedPorts, "PendingDelFlows": vnet.PendingDeleteFlow})
366 }
367 vnet.VnetPortLock.RUnlock()
368 } else {
vinokuma926cb3e2023-03-29 11:41:06 +0530369 // Update the devicelist in db
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530370 vnet.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530371 }
372 }
vinokuma926cb3e2023-03-29 11:41:06 +0530373 // TODO: if no vnets are present on device remove icmpv6 group from device
Naveen Sampath04696f72022-06-13 15:19:14 +0530374 AppMutex.VnetMutex.Unlock()
375 return nil
376}
377
378// UpdateVnet to update the VNET with associated service count
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530379func (va *VoltApplication) UpdateVnet(cntx context.Context, vv *VoltVnet) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530380 va.storeVnetConfig(vv.VnetConfig, vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530381 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530382 logger.Infow(ctx, "Updated VNET TO DB", log.Fields{"vv": vv.VnetConfig})
383 return nil
384}
385
386// ------------------------------------------------------------
387// Manifestation of a VNET on a port is handled below
388// ------------------------------------------------------------
389//
390// The VNET on a port handles everything that is done for a VNET
391// such as DHCP relay state machine, MAC addresses, IP addresses
392// learnt, so on.
393
394// DhcpStatus type
395type DhcpStatus uint8
396
397const (
398 // DhcpStatusNone constant
399 DhcpStatusNone DhcpStatus = 0
400 // DhcpStatusAcked constant
401 DhcpStatusAcked DhcpStatus = 1
402 // DhcpStatusNacked constant
403 DhcpStatusNacked DhcpStatus = 2
404 // EthTypeNone constant
405 EthTypeNone int = 0
406 // EthTypeIPoE constant
407 EthTypeIPoE int = 1
408 // EthTypePPPoE constant
409 EthTypePPPoE int = 2
410)
411
412// VoltPortVnet structure
413type VoltPortVnet struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530414 PendingDeleteFlow map[string]bool
415 servicesCount *atomic.Uint64
416 services sync.Map
Naveen Sampath04696f72022-06-13 15:19:14 +0530417 Device string
418 Port string
Naveen Sampath04696f72022-06-13 15:19:14 +0530419 VnetName string
vinokuma926cb3e2023-03-29 11:41:06 +0530420 VnetType string
421 MvlanProfileName string
422 Version string
Naveen Sampath04696f72022-06-13 15:19:14 +0530423 DhcpExpiryTime time.Time
424 Dhcp6ExpiryTime time.Time
Naveen Sampath04696f72022-06-13 15:19:14 +0530425 Ipv4Addr net.IP
426 Ipv6Addr net.IP
427 MacAddr net.HardwareAddr
428 LearntMacAddr net.HardwareAddr
vinokuma926cb3e2023-03-29 11:41:06 +0530429 CircuitID []byte //Will not be used
430 RemoteID []byte //Will not be used
431 VpvLock sync.Mutex `json:"-"`
432 PendingFlowLock sync.RWMutex `json:"-"`
433 SchedID int
Naveen Sampath04696f72022-06-13 15:19:14 +0530434 ONTEtherTypeClassification int
vinokuma926cb3e2023-03-29 11:41:06 +0530435 MacLearning MacLearningType
436 PonPort uint32
437 McastUsMeterID uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530438 McastTechProfileID uint16
439 McastPbit of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +0530440 SVlanTpid layers.EthernetType
Naveen Sampath04696f72022-06-13 15:19:14 +0530441 DhcpPbit of.PbitType
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530442 UsPonCTagPriority of.PbitType
443 UsPonSTagPriority of.PbitType
444 DsPonCTagPriority of.PbitType
445 DsPonSTagPriority of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +0530446 SVlan of.VlanType
447 CVlan of.VlanType
448 UniVlan of.VlanType
449 VlanControl VlanControl
450 RelayState DhcpRelayState
451 DhcpStatus DhcpStatus
452 PPPoeState PppoeIaState
453 RelayStatev6 Dhcpv6RelayState
454 DHCPv6DUID [MaxLenDhcpv6DUID]byte
455 DhcpRelay bool
456 ArpRelay bool
457 PppoeIa bool
458 DeleteInProgress bool
459 Blocked bool
460 AllowTransparent bool
461 IgmpEnabled bool
462 IgmpFlowsApplied bool
463 McastService bool
464 FlowsApplied bool
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530465 IsOption82Enabled bool //Will not be used
Naveen Sampath04696f72022-06-13 15:19:14 +0530466}
467
vinokuma926cb3e2023-03-29 11:41:06 +0530468// VlanControl vlan control type
Naveen Sampath04696f72022-06-13 15:19:14 +0530469type VlanControl uint8
470
471const (
472 // None constant
473 // ONU and OLT will passthrough UNIVLAN as is to BNG
474 None VlanControl = iota
475
476 // ONUCVlanOLTSVlan constant
477 // Tagged traffic, ONU will replace UNIVLAN with CVLAN and OLT will add SVLAN
478 // Untagged traffic, ONU will add CVLAN and OLT will add SVLAN
479 ONUCVlanOLTSVlan
480
481 // OLTCVlanOLTSVlan constant
482 // Tagged traffic, ONU will passthrough UNIVLAN as is to OLT and
483 // OLT will replace UNIVLAN with CVLAN and add SVLAN
484 OLTCVlanOLTSVlan
485
486 // ONUCVlan constant
487 // Tagged traffic, ONU will replace UNIVLAN with CVLAN
488 // Untagged traffic, ONU will add CVLAN
489 ONUCVlan
490
491 // OLTSVlan constant
492 // UnTagged traffic, OLT will add the SVLAN
493 OLTSVlan
494)
495
496// NewVoltPortVnet is constructor for VoltPortVnet
497func NewVoltPortVnet(vnet *VoltVnet) *VoltPortVnet {
498 var vpv VoltPortVnet
499
500 vpv.VnetName = vnet.Name
501 vpv.SVlan = vnet.SVlan
502 vpv.CVlan = vnet.CVlan
503 vpv.UniVlan = vnet.UniVlan
504 vpv.SVlanTpid = vnet.SVlanTpid
505 vpv.DhcpRelay = vnet.DhcpRelay
506 vpv.DhcpStatus = DhcpStatusNone
507 vpv.PPPoeState = PppoeIaStateNone
508 vpv.ArpRelay = vnet.ArpLearning
509 vpv.PppoeIa = vnet.PppoeIa
510 vpv.VlanControl = vnet.VlanControl
511 vpv.ONTEtherTypeClassification = vnet.ONTEtherTypeClassification
512 vpv.AllowTransparent = vnet.AllowTransparent
513 vpv.FlowsApplied = false
514 vpv.IgmpEnabled = false
515 vpv.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
516 vpv.LearntMacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Naveen Sampath04696f72022-06-13 15:19:14 +0530517 vpv.servicesCount = atomic.NewUint64(0)
518 vpv.SchedID = 0
519 vpv.PendingDeleteFlow = make(map[string]bool)
520 vpv.DhcpPbit = vnet.UsDhcpPbit[0]
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530521 vpv.UsPonCTagPriority = vnet.UsPonCTagPriority
522 vpv.UsPonSTagPriority = vnet.UsPonSTagPriority
523 vpv.DsPonCTagPriority = vnet.UsPonCTagPriority
524 vpv.DsPonSTagPriority = vnet.UsPonSTagPriority
525
526 vpv.VnetType = vnet.VnetType
Naveen Sampath04696f72022-06-13 15:19:14 +0530527 return &vpv
528}
529
530func (vpv *VoltPortVnet) setDevice(device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530531 logger.Debugw(ctx, "Set Device", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +0530532 if vpv.Device != device && vpv.Device != "" {
533 GetApplication().DisassociateVpvsFromDevice(device, vpv)
vinokuma926cb3e2023-03-29 11:41:06 +0530534 // TEMP:
Naveen Sampath04696f72022-06-13 15:19:14 +0530535 vpv.printAssociatedVPVs(false)
536 }
537
Tinoj Josephec742f62022-09-29 19:11:10 +0530538 logger.Infow(ctx, "Associating VPV and Device", log.Fields{"Device": device, "Port": vpv.Port, "SVlan": vpv.SVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530539
540 vpv.Device = device
541 GetApplication().AssociateVpvsToDevice(device, vpv)
vinokuma926cb3e2023-03-29 11:41:06 +0530542 // TEMP:
Naveen Sampath04696f72022-06-13 15:19:14 +0530543 vpv.printAssociatedVPVs(true)
544}
545
vinokuma926cb3e2023-03-29 11:41:06 +0530546// TODO - Nav - Temp
Naveen Sampath04696f72022-06-13 15:19:14 +0530547func (vpv *VoltPortVnet) printAssociatedVPVs(add bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530548 if vMap := GetApplication().GetAssociatedVpvsForDevice(vpv.Device, vpv.SVlan); vMap != nil {
549 vMap.Range(func(key, value interface{}) bool {
550 vpvEntry := key.(*VoltPortVnet)
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530551 logger.Debugw(ctx, "Associated VPVs", log.Fields{"Device": vpv.Device, "Add": add, "SVlan": vpvEntry.SVlan, "CVlan": vpvEntry.CVlan, "UniVlan": vpvEntry.UniVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530552 return true
553 })
554 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530555}
556
557// GetCircuitID : The interface to be satisfied by the VoltPortVnet to be a DHCP relay
558// session is implemented below. The main functions still remain in
559// the service.go file.
560func (vpv *VoltPortVnet) GetCircuitID() []byte {
561 return []byte(vpv.CircuitID)
562}
563
564// GetRemoteID to get remote id
565func (vpv *VoltPortVnet) GetRemoteID() []byte {
566 return []byte(vpv.RemoteID)
567}
568
569// GetDhcpState to get dhcp state
570func (vpv *VoltPortVnet) GetDhcpState() DhcpRelayState {
571 return vpv.RelayState
572}
573
574// SetDhcpState to set the dhcp state
575func (vpv *VoltPortVnet) SetDhcpState(state DhcpRelayState) {
576 vpv.RelayState = state
577}
578
579// GetPppoeIaState to get pppoeia state
580func (vpv *VoltPortVnet) GetPppoeIaState() PppoeIaState {
581 return vpv.PPPoeState
582}
583
584// SetPppoeIaState to set pppoeia state
585func (vpv *VoltPortVnet) SetPppoeIaState(state PppoeIaState) {
586 vpv.PPPoeState = state
587}
588
589// GetDhcpv6State to get dhcpv6 state
590func (vpv *VoltPortVnet) GetDhcpv6State() Dhcpv6RelayState {
591 return vpv.RelayStatev6
592}
593
594// SetDhcpv6State to set dhcpv6 state
595func (vpv *VoltPortVnet) SetDhcpv6State(state Dhcpv6RelayState) {
596 vpv.RelayStatev6 = state
597}
598
599// DhcpResultInd for dhcp result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530600func (vpv *VoltPortVnet) DhcpResultInd(cntx context.Context, res *layers.DHCPv4) {
601 vpv.ProcessDhcpResult(cntx, res)
Naveen Sampath04696f72022-06-13 15:19:14 +0530602}
603
604// Dhcpv6ResultInd for dhcpv6 result indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530605func (vpv *VoltPortVnet) Dhcpv6ResultInd(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
606 vpv.ProcessDhcpv6Result(cntx, ipv6Addr, leaseTime)
Naveen Sampath04696f72022-06-13 15:19:14 +0530607}
608
609// GetNniVlans to get nni vlans
610func (vpv *VoltPortVnet) GetNniVlans() (uint16, uint16) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530611 logger.Debugw(ctx, "Get Nni Vlans", log.Fields{"vpv.VlanControl": vpv.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530612 switch vpv.VlanControl {
613 case ONUCVlanOLTSVlan,
614 OLTCVlanOLTSVlan:
615 return uint16(vpv.SVlan), uint16(vpv.CVlan)
616 case ONUCVlan,
617 None:
618 return uint16(vpv.SVlan), uint16(of.VlanNone)
619 case OLTSVlan:
620 return uint16(vpv.SVlan), uint16(of.VlanNone)
621 }
622 return uint16(of.VlanNone), uint16(of.VlanNone)
623}
624
625// GetService to get service
626func (vpv *VoltPortVnet) GetService(name string) (*VoltService, bool) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530627 logger.Debugw(ctx, "Get Service", log.Fields{"name": name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530628 service, ok := vpv.services.Load(name)
629 if ok {
630 return service.(*VoltService), ok
631 }
632 return nil, ok
633}
634
635// AddService to add service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530636func (vpv *VoltPortVnet) AddService(cntx context.Context, service *VoltService) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530637 logger.Debugw(ctx, "Add Service", log.Fields{"ServiceName": service.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530638 vpv.services.Store(service.Name, service)
639 vpv.servicesCount.Inc()
640 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()})
641}
642
643// DelService to delete service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530644func (vpv *VoltPortVnet) DelService(cntx context.Context, service *VoltService) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530645 logger.Debugw(ctx, "Delete Service", log.Fields{"ServiceName": service.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530646 vpv.services.Delete(service.Name)
647 vpv.servicesCount.Dec()
648
649 // If the only Igmp Enabled service is removed, remove the Igmp trap flow along with it
650 if service.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530651 if err := vpv.DelIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530652 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530653 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
654 }
655
656 vpv.IgmpEnabled = false
657 }
658 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()})
659}
660
661// ProcessDhcpResult to process dhcp results
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530662func (vpv *VoltPortVnet) ProcessDhcpResult(cntx context.Context, res *layers.DHCPv4) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530663 logger.Debug(ctx, "Process Dhcp Result")
Naveen Sampath04696f72022-06-13 15:19:14 +0530664 msgType := DhcpMsgType(res)
mgoudabb017dc2025-10-29 19:53:34 +0530665 switch msgType {
666 case layers.DHCPMsgTypeAck:
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530667 vpv.ProcessDhcpSuccess(cntx, res)
mgoudabb017dc2025-10-29 19:53:34 +0530668 case layers.DHCPMsgTypeNak:
Naveen Sampath04696f72022-06-13 15:19:14 +0530669 vpv.DhcpStatus = DhcpStatusNacked
670 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530671 vpv.WriteToDb(cntx)
672}
673
674// RangeOnServices to call a function on all services on the vpv
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530675func (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 +0530676 vpv.services.Range(func(key, value interface{}) bool {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530677 return callback(cntx, key, value, delFlowsInDevice)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530678 })
Naveen Sampath04696f72022-06-13 15:19:14 +0530679}
680
681// ProcessDhcpSuccess : Learn the IPv4 address allocated to the services and update the
682// the services with the same. This also calls for adding flows
683// for the services as the DHCP procedure is completed
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530684func (vpv *VoltPortVnet) ProcessDhcpSuccess(cntx context.Context, res *layers.DHCPv4) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530685 logger.Info(ctx, "Process Dhcp Success")
Naveen Sampath04696f72022-06-13 15:19:14 +0530686 vpv.DhcpStatus = DhcpStatusAcked
687 vpv.Ipv4Addr, _ = GetIpv4Addr(res)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530688 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 +0530689
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530690 vpv.RangeOnServices(cntx, vpv.updateIPv4AndProvisionFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530691 vpv.ProcessDhcpv4Options(res)
692}
693
694// ProcessDhcpv4Options : Currently we process lease time and store the validity of the
695// IP address allocated.
696func (vpv *VoltPortVnet) ProcessDhcpv4Options(res *layers.DHCPv4) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530697 logger.Debug(ctx, "Process Dhcp v4 Options")
Naveen Sampath04696f72022-06-13 15:19:14 +0530698 for _, o := range res.Options {
699 switch o.Type {
700 case layers.DHCPOptLeaseTime:
701 leasetime := GetIPv4LeaseTime(o)
702 vpv.DhcpExpiryTime = time.Now().Add((time.Duration(leasetime) * time.Second))
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530703 logger.Debugw(ctx, "Lease Expiry Set", log.Fields{"Time": vpv.DhcpExpiryTime})
Naveen Sampath04696f72022-06-13 15:19:14 +0530704 }
705 }
706}
707
708// ProcessDhcpv6Result : Read the IPv6 address allocated to the device and store it on the
709// VNET. The same IPv6 address is also passed to the services. When a
710// service is fetched all the associated information such as MAC address,
711// IPv4 address and IPv6 addresses can be provided.
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530712func (vpv *VoltPortVnet) ProcessDhcpv6Result(cntx context.Context, ipv6Addr net.IP, leaseTime uint32) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530713 logger.Debugw(ctx, "Process Dhcp v6 Result", log.Fields{"ipv6Addr": ipv6Addr, "leaseTime": leaseTime})
Naveen Sampath04696f72022-06-13 15:19:14 +0530714 // TODO: Status based hanlding of flows
715 vpv.Dhcp6ExpiryTime = time.Now().Add((time.Duration(leaseTime) * time.Second))
716 vpv.Ipv6Addr = ipv6Addr
717
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530718 vpv.RangeOnServices(cntx, vpv.updateIPv6AndProvisionFlows, false)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530719 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530720}
721
722// AddSvcUsMeterToDevice to add service upstream meter info to device
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530723func AddSvcUsMeterToDevice(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +0530724 svc := value.(*VoltService)
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530725 logger.Debugw(ctx, "Adding upstream meter profile to device", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530726 if device, _ := GetApplication().GetDeviceFromPort(svc.Port); device != nil {
727 GetApplication().AddMeterToDevice(svc.Port, device.Name, svc.UsMeterID, 0)
728 return true
729 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530730 logger.Warnw(ctx, "Dropping US Meter request: Device not found", log.Fields{"Service": svc})
Naveen Sampath04696f72022-06-13 15:19:14 +0530731 return false
732}
733
734// PushFlowsForPortVnet - triggers flow construction and push for provided VPV
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530735func (vpv *VoltPortVnet) PushFlowsForPortVnet(cntx context.Context, d *VoltDevice) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530736 logger.Debugw(ctx, "Push Flows For Port Vnet", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530737 vp := d.GetPort(vpv.Port)
738
739 //Ignore if UNI port is not found or not UP
740 if vp == nil || vp.State != PortStateUp {
741 logger.Warnw(ctx, "Ignoring Vlan UP Ind for VPV: Port Not Found/Ready", log.Fields{"Port": vp})
742 return
743 }
744
Naveen Sampath04696f72022-06-13 15:19:14 +0530745 //Disable the flag so that flows can be pushed again
746 // vpv.IgmpFlowsApplied = false
747 // vpv.DsFlowsApplied = false
748 // vpv.UsFlowsApplied = false
749 vpv.VpvLock.Lock()
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530750 vpv.PortUpInd(cntx, d, vpv.Port, "")
Naveen Sampath04696f72022-06-13 15:19:14 +0530751 vpv.VpvLock.Unlock()
752}
753
754// PortUpInd : When a port transistions to UP state, the indication is passed
755// on to this module via the application. We read the VNET configuration
756// again here to apply the latest configuration if the configuration
757// changed. Thus, a reboot of ONT forces the new configuration to get
758// applied.
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530759func (vpv *VoltPortVnet) PortUpInd(cntx context.Context, device *VoltDevice, port string, nniPort string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530760 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 +0530761 if vpv.DeleteInProgress {
Akash Sonief452f12024-12-12 18:20:28 +0530762 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 +0530763 return
764 }
765 vpv.setDevice(device.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530766
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530767 if nniPort != "" {
768 err := vpv.ValidateNniPort(device, nniPort)
769 if err != nil {
770 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: NNI is not configured", log.Fields{"Port": vpv.Port, "Device": device.Name, "NNI": nniPort, "Error": err})
771 return
772 }
773 } else {
774 nni, err := GetApplication().GetNniPort(device.Name)
775 if nni == "" {
776 logger.Warnw(ctx, "Ignoring Vnet Port UP indication: Default NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": device.Name, "Error": err})
777 return
Akash Sonia8246972023-01-03 10:37:08 +0530778 }
779 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530780
Naveen Sampath04696f72022-06-13 15:19:14 +0530781 if vpv.Blocked {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530782 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 +0530783 return
784 }
785
786 if vpv.DhcpRelay || vpv.ArpRelay || vpv.PppoeIa {
787 // If MAC Learning is true if no MAC is configured, push DS/US DHCP, US HSIA flows without MAC.
788 // DS HSIA flows are installed after learning the MAC.
789 logger.Infow(ctx, "Port Up - Trap Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530790 // no HSIA flows for multicast service and DPU_MGMT Service
vinokuma926cb3e2023-03-29 11:41:06 +0530791 if !vpv.McastService && vpv.VnetType != DpuMgmtTraffic {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530792 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530793 }
vinokuma926cb3e2023-03-29 11:41:06 +0530794 if vpv.VnetType == DpuMgmtTraffic {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530795 vpv.RangeOnServices(cntx, AddMeterToDevice, false)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530796 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530797 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530798 if vpv.MacLearning == MacLearningNone || NonZeroMacAddress(vpv.MacAddr) {
799 logger.Infow(ctx, "Port Up - DS Flows", log.Fields{"Device": device.Name, "Port": port})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530800 /*In case of DPU_MGMT_TRAFFIC, need to install both US and DS traffic */
vinokuma926cb3e2023-03-29 11:41:06 +0530801 if vpv.VnetType == DpuMgmtTraffic {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530802 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530803 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530804 // US & DS DHCP, US HSIA flows are already installed
805 // install only DS HSIA flow here.
806 // no HSIA flows for multicast service
Akash Soni53da2852023-03-15 00:31:31 +0530807 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530808 vpv.RangeOnServices(cntx, AddDsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530809 }
810 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530811 } else {
812 // DHCP relay is not configured. This implies that the service must use
813 // 1:1 and does not require MAC learning. In a completely uncommon but
814 // plausible case, the MAC address can be learnt from N:1 without DHCP
815 // relay by configuring any unknown MAC address to be reported. This
816 // however is not seen as a real use case.
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530817 logger.Debugw(ctx, "Port Up - Service Flows", log.Fields{"Device": device.Name, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530818 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530819 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530820 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530821 vpv.AddTrapFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530822 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530823 vpv.RangeOnServices(cntx, AddDsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530824 }
825 }
826
827 // Process IGMP proxy - install IGMP trap rules before DHCP trap rules
828 if vpv.IgmpEnabled {
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530829 logger.Debugw(ctx, "Port Up - IGMP Flows", log.Fields{"Device": device.Name, "Port": port})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530830 vpv.RangeOnServices(cntx, AddSvcUsMeterToDevice, false)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530831 if err := vpv.AddIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +0530832 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530833 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
834 }
835
836 if vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530837 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530838 }
839 }
840
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530841 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530842}
843
844// PortDownInd : When the port status changes to down, we delete all configured flows
845// The same indication is also passed to the services enqueued for them
846// to take appropriate actions
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530847// delFlowsInDevice flag indicates that flows should be deleted only in DB/device and should not be forwarded to core
848func (vpv *VoltPortVnet) PortDownInd(cntx context.Context, device string, port string, nbRequest bool, delFlowsInDevice bool) {
Tinoj Joseph4ead4e02023-01-30 03:12:44 +0530849 if !nbRequest && !GetApplication().OltFlowServiceConfig.RemoveFlowsOnDisable {
850 logger.Info(ctx, "VPV Port DOWN Ind, Not deleting flows since RemoveOnDisable is disabled")
851 return
852 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530853 logger.Infow(ctx, "VPV Port DOWN Ind, deleting all flows for services",
Akash Sonief452f12024-12-12 18:20:28 +0530854 log.Fields{"service count": vpv.servicesCount.Load(), "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530855
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530856 //vpv.RangeOnServices(cntx, DelAllFlows)
857 vpv.DelTrapFlows(cntx)
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530858 vpv.DelHsiaFlows(cntx, delFlowsInDevice)
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530859 vpv.WriteToDb(cntx)
860 vpv.ClearServiceCounters(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530861}
862
863// SetMacAddr : The MAC address is set when a MAC address is learnt through the
864// packets received from the network. Currently, DHCP packets are
865// only packets we learn the MAC address from
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530866func (vpv *VoltPortVnet) SetMacAddr(cntx context.Context, addr net.HardwareAddr) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530867 logger.Infow(ctx, "Set Mac Addr", log.Fields{"MAC addr": addr.String(), "Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530868 //Store Learnt MAC address and return if MACLearning is not enabled
869 vpv.LearntMacAddr = addr
870 if vpv.MacLearning == MacLearningNone || !NonZeroMacAddress(addr) ||
871 (NonZeroMacAddress(vpv.MacAddr) && vpv.MacLearning == Learn) {
872 return
873 }
874
875 // Compare the two MAC addresses to see if it is same
876 // If they are same, we just return. If not, we perform
877 // actions to address the change in MAC address
878 //if NonZeroMacAddress(vpv.MacAddr) && !util.MacAddrsMatch(vpv.MacAddr, addr) {
879 if !util.MacAddrsMatch(vpv.MacAddr, addr) {
880 expectedPort := GetApplication().GetMacInPortMap(addr)
881 if expectedPort != "" && expectedPort != vpv.Port {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530882 logger.Warnw(ctx, "mac-learnt-from-different-port-ignoring-setmacaddr",
Naveen Sampath04696f72022-06-13 15:19:14 +0530883 log.Fields{"ExpectedPort": expectedPort, "ReceivedPort": vpv.Port, "LearntMacAdrr": vpv.MacAddr, "NewMacAdrr": addr.String()})
884 return
885 }
886 if NonZeroMacAddress(vpv.MacAddr) {
887 logger.Warnw(ctx, "MAC Address Changed. Remove old flows (if added) and re-add with updated MAC", log.Fields{"UpdatedMAC": addr})
888
889 // The newly learnt MAC address is different than earlier one.
890 // The existing MAC based HSIA flows need to be undone as the device
891 // may have been changed
892 // Atleast one HSIA flow should be present in adapter to retain the TP and GEM
893 // hence delete one after the other
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530894 vpv.RangeOnServices(cntx, DelUsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530895 vpv.MacAddr = addr
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530896 vpv.RangeOnServices(cntx, vpv.setLearntMAC, false)
897 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
898 vpv.RangeOnServices(cntx, DelDsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530899 GetApplication().DeleteMacInPortMap(vpv.MacAddr)
900 } else {
901 vpv.MacAddr = addr
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530902 vpv.RangeOnServices(cntx, vpv.setLearntMAC, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530903 logger.Infow(ctx, "MAC Address learnt from DHCP or ARP", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
904 }
905 GetApplication().UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
906 } else {
907 logger.Infow(ctx, "Leant MAC Address is same", log.Fields{"Learnt MAC": addr.String(), "Port": vpv.Port})
908 }
909
910 _, err := GetApplication().GetDeviceFromPort(vpv.Port)
911 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530912 logger.Errorw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
Akash Sonia8246972023-01-03 10:37:08 +0530913 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530914 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
915 return
916 }
917 // Ds Hsia flows has to be pushed
918 if vpv.FlowsApplied {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530919 // In case of DPU_MGMT_TRAFFIC install both US and DS Flows
vinokuma926cb3e2023-03-29 11:41:06 +0530920 if vpv.VnetType == DpuMgmtTraffic {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530921 vpv.RangeOnServices(cntx, AddUsHsiaFlows, false)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530922 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530923 // no HSIA flows for multicast service
924 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530925 vpv.RangeOnServices(cntx, AddDsHsiaFlows, false)
Naveen Sampath04696f72022-06-13 15:19:14 +0530926 }
927 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530928 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530929}
930
931// MatchesVlans : If the VNET matches both S and C VLANs, return true. Else, return false
932func (vpv *VoltPortVnet) MatchesVlans(svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530933 logger.Debugw(ctx, "Matches Vlans", log.Fields{"Svlan": svlan, "Cvlan": cvlan, "Univlan": univlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530934 if vpv.SVlan != svlan || vpv.CVlan != cvlan || vpv.UniVlan != univlan {
935 return false
936 }
937 return true
938}
939
940// MatchesCvlan : If the VNET matches CVLAN, return true. Else, return false
941func (vpv *VoltPortVnet) MatchesCvlan(cvlan []of.VlanType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530942 logger.Debugw(ctx, "Matches Cvlans", log.Fields{"Cvlan": cvlan})
Naveen Sampath04696f72022-06-13 15:19:14 +0530943 if len(cvlan) != 1 && !vpv.AllowTransparent {
944 return false
945 }
946 if vpv.CVlan != cvlan[0] {
947 return false
948 }
949 return true
950}
951
952// MatchesPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
953func (vpv *VoltPortVnet) MatchesPriority(priority uint8) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530954 logger.Debugw(ctx, "Matches Priority", log.Fields{"Priority": priority})
Naveen Sampath04696f72022-06-13 15:19:14 +0530955 var service *VoltService
956 pbitFound := false
957 matchpbitsFunc := func(key, value interface{}) bool {
958 svc := value.(*VoltService)
959 for _, pbit := range svc.Pbits {
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530960 if uint8(pbit) == priority || uint8(pbit) == uint8(of.PbitMatchAll) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530961 logger.Infow(ctx, "Pbit match found with service",
962 log.Fields{"Pbit": priority, "serviceName": svc.Name})
963 pbitFound = true
964 service = svc
965 return false //Returning false to stop the Range loop
966 }
967 }
968 return true
969 }
970 _ = pbitFound
971 vpv.services.Range(matchpbitsFunc)
972 return service
973}
974
Akash Sonief452f12024-12-12 18:20:28 +0530975func (vpv *VoltPortVnet) GetSvcFromVPV() *VoltService {
976 var service *VoltService
977 vpv.services.Range(func(key, value interface{}) bool {
978 service = value.(*VoltService)
979 logger.Debugw(ctx, "Get Service from VPV", log.Fields{"Service": value})
980 return false
981 })
982 return service
983}
984
Naveen Sampath04696f72022-06-13 15:19:14 +0530985// GetRemarkedPriority : If the VNET matches priority of the incoming packet with any service, return true. Else, return false
986func (vpv *VoltPortVnet) GetRemarkedPriority(priority uint8) uint8 {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530987 logger.Debugw(ctx, "Get Remarked Priority", log.Fields{"Priority": priority})
Naveen Sampath04696f72022-06-13 15:19:14 +0530988 dsPbit := uint8(0)
989 matchpbitsFunc := func(key, value interface{}) bool {
990 svc := value.(*VoltService)
991 if remarkPbit, ok := svc.DsRemarkPbitsMap[int(priority)]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530992 logger.Warnw(ctx, "Pbit match found with service",
Naveen Sampath04696f72022-06-13 15:19:14 +0530993 log.Fields{"Pbit": priority, "serviceName": svc.Name, "remarkPbit": remarkPbit})
994 dsPbit = uint8(remarkPbit)
995 return false //Returning false to stop the Range loop
996 }
997 // When no remarking info is available, remark the incoming pbit
998 // to highest pbit configured for the subscriber (across all subservices associated)
999 svcPbit := uint8(svc.Pbits[0])
1000 if svcPbit > dsPbit {
1001 dsPbit = svcPbit
1002 }
1003 return true
1004 }
1005 vpv.services.Range(matchpbitsFunc)
1006 logger.Debugw(ctx, "Remarked Pbit Value", log.Fields{"Incoming": priority, "Remarked": dsPbit})
1007 return dsPbit
1008}
1009
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301010func (vpv *VoltPortVnet) ValidateNniPort(device *VoltDevice, nniPortName string) error {
1011 devConfig := GetApplication().GetDeviceConfig(device.SerialNum)
1012 if devConfig == nil {
1013 return fmt.Errorf("device config not found for serial number %s", device.SerialNum)
1014 }
1015
1016 var nniPort string
1017 var nniPortID uint32
1018 if nniPortID = device.GetPortIDFromPortName(nniPortName); nniPortID == 0 {
1019 logger.Errorw(ctx, "Port Not Found", log.Fields{"NNI Port": nniPortName})
1020 return errors.New("port not found for service")
1021 }
1022 if !device.IsPortNni(nniPortName) {
1023 logger.Errorw(ctx, "Port Not Found in device", log.Fields{"NNI Port": nniPortName})
1024 return fmt.Errorf("port not found in device")
1025 }
1026
1027 nniPort = strconv.Itoa(int(nniPortID))
1028 if len(devConfig.NniPorts) > 0 {
1029 for _, port := range devConfig.NniPorts {
1030 if port == nniPort {
1031 logger.Debugw(ctx, "NNI port is configured from NB", log.Fields{"NB NniPorts": devConfig.NniPorts, "NniPort": nniPortName})
1032 return nil // Match found
1033 }
1034 }
1035 } else {
1036 if devConfig.UplinkPort == nniPort {
1037 logger.Debugw(ctx, "NNI port is configured as default from NB", log.Fields{"NB NNI Port": devConfig.UplinkPort, "SB NNI Ports": device.NniPort})
1038 return nil // Match found
1039 }
1040 }
1041 return fmt.Errorf("nni port mismatch: NB NNI Port: %s, SB NNI Ports: %v", devConfig.UplinkPort, device.NniPort)
1042}
1043
Naveen Sampath04696f72022-06-13 15:19:14 +05301044// AddSvc adds a service on the VNET on a port. The addition is
1045// triggered when NB requests for service addition
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301046func (vpv *VoltPortVnet) AddSvc(cntx context.Context, svc *VoltService) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301047 logger.Debugw(ctx, "Add Service to VPV", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301048 //vpv.services = append(vpv.services, svc)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301049 vpv.AddService(cntx, svc)
Naveen Sampath04696f72022-06-13 15:19:14 +05301050 logger.Debugw(ctx, "Added Service to VPV", log.Fields{"Num of SVCs": vpv.servicesCount.Load(), "SVC": svc})
1051
1052 // Learn the circuit-id and remote-id from the service
1053 // TODO: There must be a better way of doing this. This
1054 // may be explored
1055 if svc.IgmpEnabled {
1056 vpv.IgmpEnabled = true
1057 }
1058 // first time service activation MacLearning will have default value as None.
1059 // to handle reciliency if anythng other then None we should retain it .
1060 if svc.MacLearning == MacLearningNone {
1061 if !vpv.DhcpRelay && !vpv.ArpRelay {
1062 svc.MacLearning = MacLearningNone
1063 } else if vpv.MacLearning == Learn {
1064 svc.MacLearning = Learn
1065 } else if vpv.MacLearning == ReLearn {
1066 svc.MacLearning = ReLearn
1067 }
1068 }
1069
vinokuma926cb3e2023-03-29 11:41:06 +05301070 // TODO: Temp Change - Need to address MAC Learning flow issues completely
Naveen Sampath04696f72022-06-13 15:19:14 +05301071 if (svc.MacLearning == Learn || svc.MacLearning == ReLearn) && NonZeroMacAddress(vpv.MacAddr) {
1072 svc.MacAddr = vpv.MacAddr
1073 } else if vpv.servicesCount.Load() == 1 {
1074 vpv.MacAddr = svc.MacAddr
1075 }
1076
1077 vpv.MacLearning = svc.MacLearning
1078 vpv.PonPort = svc.PonPort
1079 logger.Debugw(ctx, "Added MAC to VPV", log.Fields{"MacLearning": vpv.MacLearning, "VPV": vpv})
vinokuma926cb3e2023-03-29 11:41:06 +05301080 // Reconfigure Vlans based on Vlan Control type
Naveen Sampath04696f72022-06-13 15:19:14 +05301081 svc.VlanControl = vpv.VlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301082 if svc.McastService {
1083 vpv.McastService = true
1084 vpv.McastTechProfileID = svc.TechProfileID
vinokuma926cb3e2023-03-29 11:41:06 +05301085 // Assumption: Only one Pbit for mcast service
Naveen Sampath04696f72022-06-13 15:19:14 +05301086 vpv.McastPbit = svc.Pbits[0]
1087 vpv.McastUsMeterID = svc.UsMeterID
1088 vpv.SchedID = svc.SchedID
1089 }
1090 svc.ONTEtherTypeClassification = vpv.ONTEtherTypeClassification
1091 svc.AllowTransparent = vpv.AllowTransparent
1092 svc.SVlanTpid = vpv.SVlanTpid
1093
vinokuma926cb3e2023-03-29 11:41:06 +05301094 // Ensure configuring the mvlan profile only once
1095 // One subscriber cannot have multiple mvlan profiles. Only the first configuration is valid
Naveen Sampath04696f72022-06-13 15:19:14 +05301096 if svc.MvlanProfileName != "" {
1097 if vpv.MvlanProfileName == "" {
1098 vpv.MvlanProfileName = svc.MvlanProfileName
1099 } else {
1100 logger.Warnw(ctx, "Mvlan Profile already configured for subscriber. Ignoring new Mvlan", log.Fields{"Existing Mvlan": vpv.MvlanProfileName, "New Mvlan": svc.MvlanProfileName})
1101 }
1102 }
1103
Akash Sonia8246972023-01-03 10:37:08 +05301104 voltDevice, err := GetApplication().GetDeviceFromPort(vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301105 if err != nil {
Akash Sonief452f12024-12-12 18:20:28 +05301106 logger.Errorw(ctx, "Not pushing Service Flows: Error Getting Device", log.Fields{"Reason": err.Error()})
vinokuma926cb3e2023-03-29 11:41:06 +05301107 // statusCode, statusMessage := errorCodes.GetErrorInfo(err)
1108 // TODO-COMM: vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
Naveen Sampath04696f72022-06-13 15:19:14 +05301109 return
1110 }
Tinoj Josephec742f62022-09-29 19:11:10 +05301111 if !svc.IsActivated {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301112 logger.Warnw(ctx, "Not pushing Service Flows: Service Not activated", log.Fields{"ServiceName": svc.Name})
Tinoj Josephec742f62022-09-29 19:11:10 +05301113 return
1114 }
Akash Sonia8246972023-01-03 10:37:08 +05301115
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301116 if svc.NniPort != "" {
1117 err := vpv.ValidateNniPort(voltDevice, svc.NniPort)
1118 if err != nil {
1119 logger.Warnw(ctx, "Not pushing service flows: NNI is not configured", log.Fields{"Port": vpv.Port, "Device": voltDevice.Name, "NNI": svc.NniPort, "Error": err})
1120 return
1121 }
1122 } else {
1123 nni, err := GetApplication().GetNniPort(voltDevice.Name)
1124 if nni == "" {
1125 logger.Warnw(ctx, "Not pushing service flows: Default NNI is unavailable", log.Fields{"Port": vpv.Port, "Device": voltDevice.Name, "Error": err})
1126 return
1127 }
Akash Sonia8246972023-01-03 10:37:08 +05301128 }
vinokuma926cb3e2023-03-29 11:41:06 +05301129 // Push Service Flows if DHCP relay is not configured
1130 // or already DHCP flows are configured for the VPV
1131 // to which the serivce is associated
Naveen Sampath04696f72022-06-13 15:19:14 +05301132 if vpv.FlowsApplied {
1133 if NonZeroMacAddress(vpv.MacAddr) || svc.MacLearning == MacLearningNone {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301134 svc.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301135 } else {
Akash Sonia8246972023-01-03 10:37:08 +05301136 if err := svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301137 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1138 }
1139 }
1140 }
1141
vinokuma926cb3e2023-03-29 11:41:06 +05301142 // Assumption: Igmp will be enabled only for one service and SubMgr ensure the same
Naveen Sampath04696f72022-06-13 15:19:14 +05301143 // When already the port is UP and provisioned a service without igmp, then trap flows for subsequent
1144 // service with Igmp Enabled needs to be installed
1145 if svc.IgmpEnabled && vpv.FlowsApplied {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301146 logger.Debugw(ctx, "Add Service - IGMP Flows", log.Fields{"Device": vpv.Device, "Port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301147 if err := vpv.AddIgmpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301148 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301149 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1150 }
1151
1152 if vpv.McastService {
vinokuma926cb3e2023-03-29 11:41:06 +05301153 // For McastService, send Service Activated indication once IGMP US flow is pushed
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301154 vpv.RangeOnServices(cntx, PostAccessConfigSuccessInd, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301155 }
1156 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301157 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301158}
1159
1160// setLearntMAC to set learnt mac
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301161func (vpv *VoltPortVnet) setLearntMAC(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301162 svc := value.(*VoltService)
1163 svc.SetMacAddr(vpv.MacAddr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301164 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301165 return true
1166}
1167
1168// PostAccessConfigSuccessInd for posting access config success indication
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301169func PostAccessConfigSuccessInd(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301170 return true
1171}
1172
1173// updateIPv4AndProvisionFlows to update ipv4 and provisional flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301174func (vpv *VoltPortVnet) updateIPv4AndProvisionFlows(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301175 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301176 logger.Debugw(ctx, "Updating Ipv4 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301177 svc.SetIpv4Addr(vpv.Ipv4Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301178 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301179
1180 return true
1181}
1182
1183// updateIPv6AndProvisionFlows to update ipv6 and provisional flow
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301184func (vpv *VoltPortVnet) updateIPv6AndProvisionFlows(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301185 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301186 logger.Debugw(ctx, "Updating Ipv6 address for service", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301187 svc.SetIpv6Addr(vpv.Ipv6Addr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301188 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301189
1190 return true
1191}
1192
1193// AddUsHsiaFlows to add upstream hsia flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301194func AddUsHsiaFlows(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301195 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301196 logger.Debugw(ctx, "Add US Hsia Flows", log.Fields{"ServiceName": svc.Name})
Akash Sonia8246972023-01-03 10:37:08 +05301197 if err := svc.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301198 logger.Warnw(ctx, "Add US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1199 }
1200 return true
1201}
1202
1203// AddDsHsiaFlows to add downstream hsia flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301204func AddDsHsiaFlows(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301205 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301206 logger.Debugw(ctx, "Add DS Hsia Flows", log.Fields{"ServiceName": svc.Name})
Akash Sonia8246972023-01-03 10:37:08 +05301207 if err := svc.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301208 logger.Warnw(ctx, "Add DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1209 }
1210 return true
1211}
1212
1213// ClearFlagsInService to clear the flags used in service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301214func ClearFlagsInService(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301215 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301216 logger.Debugw(ctx, "Received Cleared Flow Flags for service", log.Fields{"name": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301217 svc.ServiceLock.Lock()
1218 svc.IgmpFlowsApplied = false
1219 svc.DsDhcpFlowsApplied = false
1220 svc.DsHSIAFlowsApplied = false
1221 svc.Icmpv6FlowsApplied = false
1222 svc.UsHSIAFlowsApplied = false
1223 svc.UsDhcpFlowsApplied = false
1224 svc.PendingFlows = make(map[string]bool)
1225 svc.AssociatedFlows = make(map[string]bool)
1226 svc.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301227 svc.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301228 logger.Debugw(ctx, "Cleared Flow Flags for service", log.Fields{"name": svc.Name})
1229 return true
1230}
1231
1232// DelDsHsiaFlows to delete hsia flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301233// delFlowsInDevice flag indicates that flows should be deleted only in DB/device and should not be forwarded to core
1234func DelDsHsiaFlows(cntx context.Context, key, value interface{}, delFlowsInDevice bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301235 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301236 logger.Debugw(ctx, "Delete DS Hsia Flows", log.Fields{"ServiceName": svc.Name})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301237 if err := svc.DelDsHsiaFlows(cntx, delFlowsInDevice); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301238 logger.Warnw(ctx, "Delete DS hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1239 }
1240 return true
1241}
1242
1243// DelUsHsiaFlows to delete upstream hsia flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301244// delFlowsInDevice flag indicates that flows should be deleted only in DB/device and should not be forwarded to core
1245func DelUsHsiaFlows(cntx context.Context, key, value interface{}, delFlowsInDevice bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301246 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301247 logger.Debugw(ctx, "Delete US Hsia Flows", log.Fields{"ServiceName": svc.Name})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301248 if err := svc.DelUsHsiaFlows(cntx, delFlowsInDevice); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301249 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"service": svc.Name, "Error": err})
1250 }
1251 return true
1252}
1253
1254// ClearServiceCounters to clear the service counters
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301255func ClearServiceCounters(cntx context.Context, key, value interface{}, flag bool) bool {
Naveen Sampath04696f72022-06-13 15:19:14 +05301256 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301257 logger.Debugw(ctx, "Received Clear Service Counters", log.Fields{"ServiceName": svc.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301258 //Delete the per service counter too
1259 GetApplication().ServiceCounters.Delete(svc.Name)
1260 if svc.IgmpEnabled && svc.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301261 _ = db.DelAllServiceChannelCounter(cntx, svc.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301262 }
1263 return true
1264}
1265
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301266// AddMeterToDevice to add meter config to device, used in FTTB case
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301267func AddMeterToDevice(cntx context.Context, key, value interface{}, flag bool) bool {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301268 svc := value.(*VoltService)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301269 logger.Debugw(ctx, "Received Add Meter To Device", log.Fields{"ServiceName": svc.Name})
Akash Soni53da2852023-03-15 00:31:31 +05301270 if err := svc.AddMeterToDevice(cntx); err != nil {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301271 logger.Warnw(ctx, "Add Meter failed", log.Fields{"service": svc.Name, "Error": err})
1272 }
1273 return true
1274}
1275
vinokuma926cb3e2023-03-29 11:41:06 +05301276// AddTrapFlows - Adds US & DS Trap flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301277func (vpv *VoltPortVnet) AddTrapFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301278 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 +05301279 if !vpv.FlowsApplied || vgcRebooted {
1280 if vpv.DhcpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301281 if err := vpv.AddUsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301282 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301283 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1284 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301285 if err := vpv.AddDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301286 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301287 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1288 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301289 logger.Debugw(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
Naveen Sampath04696f72022-06-13 15:19:14 +05301290 log.Fields{"port": vpv.Port})
1291 //vpv.updateICMPv6McGroup(true)
1292 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301293 if err := vpv.AddUsArpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301294 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301295 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1296 }
1297 logger.Info(ctx, "ARP trap rules not added in downstream direction")
Naveen Sampath04696f72022-06-13 15:19:14 +05301298 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301299 if err := vpv.AddUsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301300 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301301 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1302 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301303 if err := vpv.AddDsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301304 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301305 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1306 }
1307 }
1308 vpv.FlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301309 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301310 }
1311}
1312
vinokuma926cb3e2023-03-29 11:41:06 +05301313// DelTrapFlows - Removes all US & DS DHCP, IGMP trap flows.
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301314func (vpv *VoltPortVnet) DelTrapFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301315 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 +05301316 // Delete HSIA & DHCP flows before deleting IGMP flows
1317 if vpv.FlowsApplied || vgcRebooted {
1318 if vpv.DhcpRelay {
Akash Sonia8246972023-01-03 10:37:08 +05301319 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301320 logger.Warnw(ctx, "Delete US hsia flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1321 "UniVlan": vpv.UniVlan, "Error": err})
1322 }
1323 logger.Infow(ctx, "ICMPv6 MC Group modification will not be triggered to rwcore for ",
1324 log.Fields{"port": vpv.Port})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301325 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301326 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301327 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1328 }
1329 //vpv.updateICMPv6McGroup(false)
1330 } else if vpv.ArpRelay {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301331 if err := vpv.DelUsArpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301332 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301333 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1334 }
1335 } else if vpv.PppoeIa {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301336 if err := vpv.DelUsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301337 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301338 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1339 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301340 if err := vpv.DelDsPppoeFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301341 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301342 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1343 }
1344 }
1345 vpv.FlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301346 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301347 }
Akash Sonia8246972023-01-03 10:37:08 +05301348 if err := vpv.DelIgmpFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301349 logger.Warnw(ctx, "Delete igmp flow failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
1350 "UniVlan": vpv.UniVlan, "Error": err})
1351 }
1352}
1353
1354// DelHsiaFlows deletes the service flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301355func (vpv *VoltPortVnet) DelHsiaFlows(cntx context.Context, delFlowsInDevice bool) {
Akash Sonief452f12024-12-12 18:20:28 +05301356 logger.Debugw(ctx, "Received Delete Hsia Flows", log.Fields{"McastService": vpv.McastService})
Naveen Sampath04696f72022-06-13 15:19:14 +05301357 // no HSIA flows for multicast service
1358 if !vpv.McastService {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301359 vpv.RangeOnServices(cntx, DelUsHsiaFlows, delFlowsInDevice)
1360 vpv.RangeOnServices(cntx, DelDsHsiaFlows, delFlowsInDevice)
Naveen Sampath04696f72022-06-13 15:19:14 +05301361 }
1362}
1363
vinokuma926cb3e2023-03-29 11:41:06 +05301364// ClearServiceCounters - Removes all igmp counters for a service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301365func (vpv *VoltPortVnet) ClearServiceCounters(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301366 //send flows deleted indication to submgr
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301367 vpv.RangeOnServices(cntx, ClearServiceCounters, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301368}
1369
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301370// BuildDefaultDhcpTrapFlow to build the downstream dhcp flows
1371func (va *VoltApplication) BuildDefaultDhcpTrapFlow(ctx context.Context, device *VoltDevice, port string) (*of.VoltFlow, error) {
1372 logger.Infow(ctx, "Building NNI DS DHCP flow", log.Fields{"Port": port, "device": device.Name})
1373 flow := &of.VoltFlow{}
1374 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1375 subFlow := of.NewVoltSubFlow()
1376 subFlow.SetTableID(0)
1377
1378 subFlow.SetUdpv4Match()
1379 subFlow.SrcPort = 67
1380 subFlow.DstPort = 68
1381
1382 nniport, err := GetApplication().GetPortID(port)
1383 if err != nil {
1384 return nil, fmt.Errorf("failed to fetch port id %d for nni : %w", nniport, err)
1385 }
1386 subFlow.SetInPort(nniport)
1387 // PortName and PortID to be used for validation of port before flow pushing
1388 flow.PortID = nniport
1389 flow.PortName = port
1390 allowTransparent := 0
1391
1392 ontEtherTypeClass := 0
1393 vlanControl := OLTSVlan
1394 uniVlan := of.VlanNone
1395 cVlan := of.VlanNone
1396
1397 metadata := uint64(allowTransparent)<<56 | uint64(ontEtherTypeClass)<<36 | uint64(vlanControl)<<32 | uint64(uniVlan)<<16 | uint64(cVlan)
1398 subFlow.SetTableMetadata(metadata)
1399 subFlow.Priority = of.DhcpFlowPriority
1400
1401 subFlow.SetReportToController()
1402 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1403 subFlow.Cookie = uint64(cVlan)<<52 | uint64(nniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
1404
1405 flow.SubFlows[subFlow.Cookie] = subFlow
1406 logger.Infow(ctx, "Built NNI DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1407
1408 return flow, nil
1409}
1410
1411// AddDefaultDhcpTrapFlow function pushes the default DHCP flows to the VOLTHA via the controller
1412func (va *VoltApplication) AddDefaultDhcpTrapFlow(cntx context.Context, vd *VoltDevice, p *VoltPort) error {
1413 if vd.GlobalDhcpFlowAdded {
1414 logger.Info(ctx, "Global Dhcp flow already exists")
1415 return nil
1416 }
1417
1418 flows, err := va.BuildDefaultDhcpTrapFlow(cntx, vd, p.Name)
1419 if err == nil {
1420 if err1 := va.PushTrapFlows(cntx, vd, p.Name, flows); err1 != nil {
1421 logger.Errorw(cntx, "Failure pushing nni trap flows", log.Fields{"device": vd.Name, "port": p.Name})
1422 return fmt.Errorf("failed to push trap flow for nni : %s, error : %w", p.Name, err1)
1423 }
1424 } else {
1425 logger.Errorw(cntx, "Failure building nni trap flows", log.Fields{"device": vd.Name, "port": p.Name})
1426 return fmt.Errorf("failed to build trap flow for nni : %s, error : %w", p.Name, err)
1427 }
1428 p.NniDhcpTrapFlowAdded = true
1429 if GetApplication().GetVendorID() != Radisys && va.IsDhcpTrapFlowAdded(cntx, vd) {
1430 logger.Debugw(ctx, "Global DHCP trap flow set", log.Fields{"device": vd.Name})
1431 vd.GlobalDhcpFlowAdded = true
1432 }
1433 return nil
1434}
1435
1436func (va *VoltApplication) IsDhcpTrapFlowAdded(ctx context.Context, vd *VoltDevice) bool {
1437 if len(vd.NniPort) == 0 {
1438 return false
1439 }
1440 flag := true
1441 for _, nniPort := range vd.NniPort {
1442 if p := vd.GetPort(nniPort); p != nil {
1443 if !p.NniDhcpTrapFlowAdded {
1444 flag = false
1445 }
1446 } else {
1447 flag = false
1448 }
1449 }
1450
1451 return flag
1452}
1453
Naveen Sampath04696f72022-06-13 15:19:14 +05301454// AddUsDhcpFlows pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301455func (vpv *VoltPortVnet) AddUsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301456 var vd *VoltDevice
1457 device := vpv.Device
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301458 logger.Debugw(ctx, "Received Add US DHCP Flows", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301459
1460 if vd = GetApplication().GetDevice(device); vd != nil {
1461 if vd.State != controller.DeviceStateUP {
1462 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})
1463 return nil
1464 }
1465 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301466 err := errorCodes.ErrDeviceNotFound
1467 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 +05301468 }
1469
1470 flows, err := vpv.BuildUsDhcpFlows()
1471 if err == nil {
1472 logger.Debugw(ctx, "Adding US DHCP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301473 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
vinokuma926cb3e2023-03-29 11:41:06 +05301474 // push ind here ABHI
Akash Sonia8246972023-01-03 10:37:08 +05301475 statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301476 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1477 }
1478 } else {
1479 logger.Errorw(ctx, "US DHCP Flow Add Failed", log.Fields{"Reason": err.Error(), "Device": device})
vinokuma926cb3e2023-03-29 11:41:06 +05301480 // push ind here ABHI
Akash Sonia8246972023-01-03 10:37:08 +05301481 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301482 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
Naveen Sampath04696f72022-06-13 15:19:14 +05301483 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301484 return nil
1485}
1486
1487// AddDsDhcpFlows function pushes the DHCP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301488func (vpv *VoltPortVnet) AddDsDhcpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301489 var vd *VoltDevice
1490 device := vpv.Device
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301491 logger.Debugw(ctx, "Received Add DS DHCP Flows", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301492
1493 if vd = GetApplication().GetDevice(device); vd != nil {
1494 if vd.State != controller.DeviceStateUP {
1495 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})
1496 return nil
1497 }
1498 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301499 err := errorCodes.ErrDeviceNotFound
1500 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 +05301501 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301502
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301503 if vd.GlobalDhcpFlowAdded {
1504 logger.Info(ctx, "Global Dhcp flow already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301505 return nil
1506 }
1507
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301508 nniPorts := make([]string, 0)
1509 vpv.services.Range(func(key, value interface{}) bool {
1510 svc := value.(*VoltService)
1511 logger.Infow(ctx, "Found service on the vpv", log.Fields{"Name": svc.Name, "NNIPort": svc.NniPort})
1512 nniPorts = append(nniPorts, svc.NniPort)
1513 return true
1514 })
1515
1516 if len(nniPorts) == 0 {
1517 vpv.BuildAndPushDSDhcpFlows(cntx, vd, "")
Naveen Sampath04696f72022-06-13 15:19:14 +05301518 } else {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301519 for _, nniPort := range nniPorts {
1520 vpv.BuildAndPushDSDhcpFlows(cntx, vd, nniPort)
1521 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301522 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301523
Naveen Sampath04696f72022-06-13 15:19:14 +05301524 if GetApplication().GetVendorID() != Radisys {
1525 vd.GlobalDhcpFlowAdded = true
1526 }
1527 return nil
1528}
1529
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301530func (vpv *VoltPortVnet) BuildAndPushDSDhcpFlows(cntx context.Context, device *VoltDevice, nniPort string) {
1531 var err error
1532 var flows *of.VoltFlow
1533 flows, err = vpv.BuildDsDhcpFlows(nniPort)
1534 if err == nil {
1535 if err1 := vpv.PushFlows(cntx, device, flows); err1 != nil {
1536 statusCode, statusMessage := errorCodes.GetErrorInfo(err1)
1537 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1538 }
1539 } else {
1540 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
1541 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1542 }
1543}
1544
Naveen Sampath04696f72022-06-13 15:19:14 +05301545// DelDhcpFlows deletes both US & DS DHCP flows applied for this Vnet instantiated on the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301546func (vpv *VoltPortVnet) DelDhcpFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301547 logger.Info(ctx, "Received Delete DHCP Flows")
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301548 if err := vpv.DelUsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301549 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301550 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1551 }
1552
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301553 if err := vpv.DelDsDhcpFlows(cntx); err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301554 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301555 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1556 }
1557}
1558
1559// DelUsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1560// Write the status of the VPV to the DB once the delete is scheduled
1561// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301562func (vpv *VoltPortVnet) DelUsDhcpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301563 logger.Debugw(ctx, "Received Delete US DHCP Flows", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301564 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1565 if err != nil {
1566 return err
1567 }
1568
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301569 err = vpv.delDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301570 if err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301571 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301572 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1573 }
Akash Sonia8246972023-01-03 10:37:08 +05301574
Naveen Sampath04696f72022-06-13 15:19:14 +05301575 return nil
1576}
1577
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301578func (vpv *VoltPortVnet) delDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301579 logger.Debugw(ctx, "Received US Delete DHCP4 Flows", log.Fields{"DeviceName": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301580 flows, err := vpv.BuildUsDhcpFlows()
1581 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301582 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301583 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301584 return fmt.Errorf("US DHCP Flow Delete Failed : %w", err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301585}
Naveen Sampath04696f72022-06-13 15:19:14 +05301586
1587// DelDsDhcpFlows delete the DHCP flows applied for this Vnet instantiated on the port
1588// Write the status of the VPV to the DB once the delete is scheduled
1589// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301590func (vpv *VoltPortVnet) DelDsDhcpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301591 logger.Debugw(ctx, "Received Delete DS DHCP Flows", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301592 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1593 if err != nil {
1594 return err
1595 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301596 err = vpv.delDsDhcp4Flows(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301597 if err != nil {
Akash Sonia8246972023-01-03 10:37:08 +05301598 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301599 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1600 }
1601 /*
Akash Sonia8246972023-01-03 10:37:08 +05301602 err = vpv.delDsDhcp6Flows(device)
1603 if err != nil {
1604 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
1605 vpv.FlowInstallFailure("VGC processing failure", statusCode, statusMessage)
1606 }*/
Naveen Sampath04696f72022-06-13 15:19:14 +05301607 return nil
1608}
1609
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301610func (vpv *VoltPortVnet) delDsDhcp4Flows(cntx context.Context, device *VoltDevice) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301611 logger.Debugw(ctx, "Received DS Delete DHCP4 Flows", log.Fields{"DeviceName": device.Name})
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301612 nniPorts := make([]string, 0)
1613 vpv.services.Range(func(key, value interface{}) bool {
1614 svc := value.(*VoltService)
1615 logger.Infow(ctx, "Found service on the vpv", log.Fields{"Name": svc.Name, "NNIPort": svc.NniPort})
1616 nniPorts = append(nniPorts, svc.NniPort)
1617 return true
1618 })
1619
1620 if len(nniPorts) == 0 {
1621 if err := vpv.BuildAndRemoveDSDhcpFlows(cntx, device, ""); err != nil {
1622 return err
1623 }
1624 } else {
1625 for _, nniPort := range nniPorts {
1626 if err := vpv.BuildAndRemoveDSDhcpFlows(cntx, device, nniPort); err != nil {
1627 return err
1628 }
1629 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301630 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301631 return nil
1632}
1633
1634func (vpv *VoltPortVnet) BuildAndRemoveDSDhcpFlows(cntx context.Context, device *VoltDevice, nniPort string) error {
1635 var err error
1636 var flows *of.VoltFlow
1637 flows, err = vpv.BuildDsDhcpFlows(nniPort)
1638 if err == nil {
1639 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
1640 logger.Errorw(ctx, "DS DHCP Flow Remove Failed", log.Fields{"Reason": err.Error()})
1641 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)
1642 }
1643 } else {
1644 logger.Errorw(ctx, "DS DHCP Flow Build Failed", log.Fields{"Reason": err.Error()})
1645 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)
1646 }
1647 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301648}
1649
1650/*
1651func (vpv *VoltPortVnet) delDsDhcp6Flows(device *VoltDevice) error {
1652 flows, err := vpv.BuildDsDhcp6Flows()
1653 if err == nil {
1654 return vpv.RemoveFlows(device, flows)
1655 }
1656 logger.Errorw(ctx, "DS DHCP6 Flow Delete Failed", log.Fields{"Reason": err.Error()})
1657 return err
1658}*/
1659
1660// AddUsArpFlows pushes the ARP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301661func (vpv *VoltPortVnet) AddUsArpFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301662 var vd *VoltDevice
1663 device := vpv.Device
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301664 logger.Debugw(ctx, "Received Add US Arp Flows", log.Fields{"DeviceName": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05301665 if vd = GetApplication().GetDevice(device); vd != nil {
1666 if vd.State != controller.DeviceStateUP {
1667 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})
1668 return nil
1669 }
1670 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301671 err := errorCodes.ErrDeviceNotFound
1672 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 +05301673 }
1674
1675 flows, err := vpv.BuildUsArpFlows()
1676 if err == nil {
1677 logger.Debugw(ctx, "Adding US ARP flows", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301678 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301679 return fmt.Errorf("Pushing US ARP Flow Failed : %w", err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301680 }
1681 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301682 return fmt.Errorf("US ARP Flow Add Failed : Device %s : %w", device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301683 }
1684 return nil
1685}
1686
1687// DelUsArpFlows delete the ARP flows applied for this Vnet instantiated on the port
1688// Write the status of the VPV to the DB once the delete is scheduled
1689// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301690func (vpv *VoltPortVnet) DelUsArpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301691 logger.Debugw(ctx, "Delete US ARP Flows", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301692 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1693 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301694 return fmt.Errorf("US ARP Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301695 }
1696 flows, err := vpv.BuildUsArpFlows()
1697 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301698 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301699 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301700 return fmt.Errorf("US ARP Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301701}
1702
1703// AddUsPppoeFlows pushes the PPPoE flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301704func (vpv *VoltPortVnet) AddUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301705 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1706
1707 var vd *VoltDevice
1708 device := vpv.Device
1709
1710 if vd = GetApplication().GetDevice(device); vd != nil {
1711 if vd.State != controller.DeviceStateUP {
1712 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})
1713 return nil
1714 }
1715 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301716 err := errorCodes.ErrDeviceNotFound
1717 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 +05301718 }
1719
1720 if flows, err := vpv.BuildUsPppoeFlows(); err == nil {
1721 logger.Debugw(ctx, "Adding US PPPoE flows", log.Fields{"Device": device})
1722
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301723 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301724 return fmt.Errorf("Pushing US PPPoE Flows Failed : %w", err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301725 }
1726 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301727 return fmt.Errorf("US PPPoE Flow Add Failed : Device %s : %w", device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301728 }
1729 return nil
1730}
1731
1732// AddDsPppoeFlows to add downstream pppoe flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301733func (vpv *VoltPortVnet) AddDsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301734 logger.Debugw(ctx, "Adding DS PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1735 var vd *VoltDevice
1736 device := vpv.Device
1737
1738 if vd = GetApplication().GetDevice(device); vd != nil {
1739 if vd.State != controller.DeviceStateUP {
1740 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})
1741 return nil
1742 }
1743 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301744 err := errorCodes.ErrDeviceNotFound
1745 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 +05301746 }
1747
1748 flows, err := vpv.BuildDsPppoeFlows()
1749 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301750 if err1 := vpv.PushFlows(cntx, vd, flows); err1 != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301751 return fmt.Errorf("Pushing DS PPPoE Flows Failed : %w", err1)
Naveen Sampath04696f72022-06-13 15:19:14 +05301752 }
1753 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301754 return fmt.Errorf("DS PPPoE Flow Add Failed : Device %s : %w", device, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301755 }
1756 return nil
1757}
1758
1759// DelUsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1760// Write the status of the VPV to the DB once the delete is scheduled
1761// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301762func (vpv *VoltPortVnet) DelUsPppoeFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301763 logger.Debugw(ctx, "Deleting US PPPoE flows", log.Fields{"STAG": vpv.SVlan, "CTAG": vpv.CVlan, "Device": vpv.Device})
1764 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1765 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301766 return fmt.Errorf("US PPPoE Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301767 }
1768 flows, err := vpv.BuildUsPppoeFlows()
1769 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301770 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301771 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301772 return fmt.Errorf("US PPPoE Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301773}
1774
1775// DelDsPppoeFlows delete the PPPoE flows applied for this Vnet instantiated on the port
1776// Write the status of the VPV to the DB once the delete is scheduled
1777// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301778func (vpv *VoltPortVnet) DelDsPppoeFlows(cntx context.Context) error {
Akash Sonief452f12024-12-12 18:20:28 +05301779 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 +05301780 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1781 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301782 return fmt.Errorf("DS PPPoE Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301783 }
1784 flows, err := vpv.BuildDsPppoeFlows()
1785 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301786 return vpv.RemoveFlows(cntx, device, flows)
Naveen Sampath04696f72022-06-13 15:19:14 +05301787 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301788 return fmt.Errorf("DS PPPoE Flow Delete Failed : DeviceName %s : %w", device.Name, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301789}
1790
1791// AddIgmpFlows function pushes the IGMP flows to the VOLTHA via the controller
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301792func (vpv *VoltPortVnet) AddIgmpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301793 logger.Debugw(ctx, "Received Add Igmp Flows", log.Fields{"IgmpFlowsApplied": vpv.IgmpFlowsApplied, "VgcRebooted": vgcRebooted})
Naveen Sampath04696f72022-06-13 15:19:14 +05301794 if !vpv.IgmpFlowsApplied || vgcRebooted {
1795 if vpv.MvlanProfileName == "" {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301796 logger.Warn(ctx, "Mvlan Profile not configured. Ignoring Igmp trap flow")
Naveen Sampath04696f72022-06-13 15:19:14 +05301797 return nil
1798 }
1799 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1800 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301801 return fmt.Errorf("Error getting device from port : Port %s : %w", vpv.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301802 } else if device.State != controller.DeviceStateUP {
1803 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})
1804 return nil
1805 }
1806 flows, err := vpv.BuildIgmpFlows()
1807 if err == nil {
1808 for cookie := range flows.SubFlows {
1809 if vd := GetApplication().GetDevice(device.Name); vd != nil {
1810 cookie := strconv.FormatUint(cookie, 10)
1811 fe := &FlowEvent{
1812 eType: EventTypeUsIgmpFlowAdded,
1813 cookie: cookie,
1814 eventData: vpv,
1815 }
1816 vd.RegisterFlowAddEvent(cookie, fe)
1817 }
1818 }
mgoudabb017dc2025-10-29 19:53:34 +05301819 if err1 := controller.GetController().AddFlows(cntx, vpv.Port, device.Name, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301820 return err1
1821 }
1822 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301823 return fmt.Errorf("IGMP Flow Add Failed : %w", err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301824 }
1825 vpv.IgmpFlowsApplied = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301826 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301827 }
1828 return nil
1829}
1830
1831// DelIgmpFlows delete the IGMP flows applied for this Vnet instantiated on the port
1832// Write the status of the VPV to the DB once the delete is scheduled
1833// for dispatch
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301834func (vpv *VoltPortVnet) DelIgmpFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301835 logger.Debugw(ctx, "Received Delete Igmp Flows", log.Fields{"IgmpFlowsApplied": vpv.IgmpFlowsApplied, "VgcRebooted": vgcRebooted})
Naveen Sampath04696f72022-06-13 15:19:14 +05301836 if vpv.IgmpFlowsApplied || vgcRebooted {
1837 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
1838 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301839 return fmt.Errorf("Error getting device from port : Port %s : %w", vpv.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301840 }
1841 flows, err := vpv.BuildIgmpFlows()
1842 if err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301843 if err1 := vpv.RemoveFlows(cntx, device, flows); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301844 return err1
1845 }
1846 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301847 return fmt.Errorf("IGMP Flow Delete Failed : %w", err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301848 }
1849 vpv.IgmpFlowsApplied = false
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301850 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301851 }
1852 return nil
1853}
1854
1855// BuildUsDhcpFlows builds the US DHCP relay flows for a subscriber
1856// The flows included by this function cover US only as the DS is
1857// created either automatically by the VOLTHA or at the device level
1858// earlier
1859func (vpv *VoltPortVnet) BuildUsDhcpFlows() (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301860 logger.Infow(ctx, "Building US DHCP flow", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301861 flow := &of.VoltFlow{}
1862 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1863
Naveen Sampath04696f72022-06-13 15:19:14 +05301864 subFlow := of.NewVoltSubFlow()
1865 subFlow.SetTableID(0)
1866
vinokuma926cb3e2023-03-29 11:41:06 +05301867 if vpv.VnetType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301868 subFlow.SetMatchVlan(vpv.CVlan)
1869 subFlow.SetMatchPbit(vpv.UsPonCTagPriority)
1870 subFlow.SetPcp(vpv.UsPonSTagPriority)
1871 subFlow.SetSetVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301872 } else {
1873 subFlow.SetMatchVlan(vpv.UniVlan)
1874 subFlow.SetSetVlan(vpv.CVlan)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301875 subFlow.SetPcp(vpv.DhcpPbit)
Naveen Sampath04696f72022-06-13 15:19:14 +05301876 }
1877 subFlow.SetUdpv4Match()
Naveen Sampath04696f72022-06-13 15:19:14 +05301878 subFlow.DstPort = 67
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301879 subFlow.SrcPort = 68
Naveen Sampath04696f72022-06-13 15:19:14 +05301880 uniport, err := GetApplication().GetPortID(vpv.Port)
1881 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301882 return nil, fmt.Errorf("failed to fetch uni port %s from vpv : %w", vpv.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301883 }
1884 subFlow.SetInPort(uniport)
1885 // PortName and PortID to be used for validation of port before flow pushing
1886 flow.PortID = uniport
1887 flow.PortName = vpv.Port
1888 subFlow.SetReportToController()
1889
1890 // Set techprofile, meterid of first service
1891 vpv.services.Range(func(key, value interface{}) bool {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301892 vs := value.(*VoltService)
1893 var writemetadata uint64
vinokuma926cb3e2023-03-29 11:41:06 +05301894 if vpv.VnetType == DpuMgmtTraffic {
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +05301895 writemetadata = uint64(vs.TechProfileID)<<32 + uint64(vs.UsMeterID)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301896 } else {
1897 writemetadata = uint64(vs.TechProfileID) << 32
1898 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301899 subFlow.SetWriteMetadata(writemetadata)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301900 subFlow.SetMeterID(vs.UsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301901 return false
1902 })
1903
Naveen Sampath04696f72022-06-13 15:19:14 +05301904 // metadata := uint64(uniport)
1905 // subFlow.SetWriteMetadata(metadata)
1906 allowTransparent := 0
1907 if vpv.AllowTransparent {
1908 allowTransparent = 1
1909 }
vinokuma926cb3e2023-03-29 11:41:06 +05301910 if vpv.VnetType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301911 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1912 subFlow.SetTableMetadata(metadata)
1913 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301914 //| 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
1915 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.UsFlowMask
1916 subFlow.Priority = of.DhcpFlowPriority
1917
1918 flow.SubFlows[subFlow.Cookie] = subFlow
1919 logger.Infow(ctx, "Built US DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
1920 return flow, nil
1921}
1922
1923// BuildDsDhcpFlows to build the downstream dhcp flows
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301924func (vpv *VoltPortVnet) BuildDsDhcpFlows(nniPort string) (*of.VoltFlow, error) {
1925 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 +05301926 flow := &of.VoltFlow{}
1927 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1928 subFlow := of.NewVoltSubFlow()
1929 subFlow.SetTableID(0)
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301930 // match on vlan only for fttb case
vinokuma926cb3e2023-03-29 11:41:06 +05301931 if vpv.VnetType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301932 subFlow.SetMatchVlan(vpv.SVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05301933 }
1934 subFlow.SetUdpv4Match()
1935 subFlow.SrcPort = 67
1936 subFlow.DstPort = 68
1937 uniport, _ := GetApplication().GetPortID(vpv.Port)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301938
1939 device, err := GetApplication().GetDeviceFromPort(vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301940 if err != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301941 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 +05301942 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301943 var inport uint32
1944 if nniPort != "" {
1945 if nniPortID := device.GetPortIDFromPortName(nniPort); nniPortID != 0 {
1946 inport = nniPortID
1947 } else {
1948 return nil, fmt.Errorf("error getting portID for NNI port %s : %w", nniPort, err)
1949 }
1950 } else {
1951 nniPort, err := GetApplication().GetNniPort(device.Name)
1952 if err != nil {
1953 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
1954 return nil, err
1955 }
akashreddykeb418f12025-10-30 10:58:42 +05301956 inport, _ = GetApplication().GetDevicePortID(device.Name, nniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05301957 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05301958
1959 subFlow.SetInPort(inport)
Naveen Sampath04696f72022-06-13 15:19:14 +05301960 // PortName and PortID to be used for validation of port before flow pushing
1961 flow.PortID = uniport
1962 flow.PortName = vpv.Port
1963 // metadata := uint64(uniport)
1964 // subFlow.SetWriteMetadata(metadata)
1965 allowTransparent := 0
1966 if vpv.AllowTransparent {
1967 allowTransparent = 1
1968 }
vinokuma926cb3e2023-03-29 11:41:06 +05301969 if vpv.VnetType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301970 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
1971 subFlow.SetTableMetadata(metadata)
1972 subFlow.Priority = of.DhcpFlowPriority
1973 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301974 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05301975 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05301976 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.DhcpArpFlowMask | of.DsFlowMask
Naveen Sampath04696f72022-06-13 15:19:14 +05301977
1978 flow.SubFlows[subFlow.Cookie] = subFlow
1979 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
1980
1981 return flow, nil
1982}
1983
1984// BuildUsDhcp6Flows to trap the DHCPv6 packets to be reported to the
1985// application.
1986func (vpv *VoltPortVnet) BuildUsDhcp6Flows() (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301987 logger.Infow(ctx, "Building US DHCPv6 flow", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301988 flow := &of.VoltFlow{}
1989 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1990
Naveen Sampath04696f72022-06-13 15:19:14 +05301991 subFlow := of.NewVoltSubFlow()
1992 subFlow.SetTableID(0)
1993
1994 subFlow.SetMatchVlan(vpv.UniVlan)
1995 subFlow.SetSetVlan(vpv.CVlan)
1996 subFlow.SetUdpv6Match()
1997 subFlow.SrcPort = 546
1998 subFlow.DstPort = 547
1999 uniport, err := GetApplication().GetPortID(vpv.Port)
2000 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302001 return nil, fmt.Errorf("failed to fetch uni port %d from vpv : %w", uniport, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05302002 }
2003 // Set techprofile, meterid of first service
2004 vpv.services.Range(func(key, value interface{}) bool {
2005 svc := value.(*VoltService)
2006 writemetadata := uint64(svc.TechProfileID) << 32
2007 subFlow.SetWriteMetadata(writemetadata)
2008 subFlow.SetMeterID(svc.UsMeterID)
2009 return false
2010 })
2011 subFlow.SetInPort(uniport)
2012 // PortName and PortID to be used for validation of port before flow pushing
2013 flow.PortID = uniport
2014 flow.PortName = vpv.Port
vinokuma926cb3e2023-03-29 11:41:06 +05302015 // subFlow.SetMeterId(vpv.UsDhcpMeterId)
Naveen Sampath04696f72022-06-13 15:19:14 +05302016 // metadata := uint64(uniport)
2017 // subFlow.SetWriteMetadata(metadata)
2018 allowTransparent := 0
2019 if vpv.AllowTransparent {
2020 allowTransparent = 1
2021 }
2022 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2023 subFlow.SetTableMetadata(metadata)
2024 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05302025 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302026 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.UsFlowMask
2027 subFlow.Priority = of.DhcpFlowPriority
2028
2029 flow.SubFlows[subFlow.Cookie] = subFlow
2030 logger.Infow(ctx, "Built US DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2031 return flow, nil
2032}
2033
2034// BuildDsDhcp6Flows to trap the DHCPv6 packets to be reported to the
2035// application.
2036func (vpv *VoltPortVnet) BuildDsDhcp6Flows() (*of.VoltFlow, error) {
2037 logger.Infow(ctx, "Building DS DHCPv6 flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
2038
2039 flow := &of.VoltFlow{}
2040 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2041 subFlow := of.NewVoltSubFlow()
2042 subFlow.SetTableID(0)
2043
2044 vpv.setDsMatchVlan(subFlow)
2045 subFlow.SetUdpv6Match()
2046 subFlow.SrcPort = 547
2047 subFlow.DstPort = 547
2048 uniport, _ := GetApplication().GetPortID(vpv.Port)
2049 nni, err := GetApplication().GetNniPort(vpv.Device)
2050 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302051 logger.Errorw(ctx, "Failed to fetch nni port from vpv", log.Fields{"error": err, "device": vpv.Device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302052 return nil, err
2053 }
akashreddykeb418f12025-10-30 10:58:42 +05302054 nniport, err := GetApplication().GetDevicePortID(vpv.Device, nni)
Naveen Sampath04696f72022-06-13 15:19:14 +05302055 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302056 logger.Errorw(ctx, "Failed to fetch port ID for nni", log.Fields{"error": err, "nni": nni})
Naveen Sampath04696f72022-06-13 15:19:14 +05302057 return nil, err
2058 }
2059 subFlow.SetInPort(nniport)
2060 // PortName and PortID to be used for validation of port before flow pushing
2061 flow.PortID = uniport
2062 flow.PortName = vpv.Port
2063 // metadata := uint64(uniport)
2064 // subFlow.SetWriteMetadata(metadata)
2065 allowTransparent := 0
2066 if vpv.AllowTransparent {
2067 allowTransparent = 1
2068 }
2069 metadata := uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2070 subFlow.SetTableMetadata(metadata)
2071 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05302072 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302073 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.Dhcpv6FlowMask | of.DsFlowMask
2074 subFlow.Priority = of.DhcpFlowPriority
2075
2076 flow.SubFlows[subFlow.Cookie] = subFlow
2077 logger.Infow(ctx, "Built DS DHCPv6 flow", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2078 return flow, nil
2079}
2080
2081// BuildUsArpFlows builds the US ARP relay flows for a subscriber
2082// The flows included by this function cover US only as the DS is
2083// created either automatically by the VOLTHA or at the device level
2084// earlier
2085func (vpv *VoltPortVnet) BuildUsArpFlows() (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302086 logger.Infow(ctx, "Building US ARP flow", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05302087 flow := &of.VoltFlow{}
2088 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2089
Naveen Sampath04696f72022-06-13 15:19:14 +05302090 subFlow := of.NewVoltSubFlow()
2091 subFlow.SetTableID(0)
2092
2093 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2094 subFlow.SetMatchSrcMac(vpv.MacAddr)
2095 }
2096
2097 subFlow.SetMatchDstMac(BroadcastMAC)
2098 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2099 return nil, err
2100 }
2101 subFlow.SetArpMatch()
2102 uniport, err := GetApplication().GetPortID(vpv.Port)
2103 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302104 return nil, fmt.Errorf("failed to fetch uni port %d from vpv : %w", uniport, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05302105 }
2106 subFlow.SetInPort(uniport)
2107 // PortName and PortID to be used for validation of port before flow pushing
2108 flow.PortID = uniport
2109 flow.PortName = vpv.Port
2110 subFlow.SetReportToController()
2111 allowTransparent := 0
2112 if vpv.AllowTransparent {
2113 allowTransparent = 1
2114 }
2115 metadata := uint64(uniport)
2116 subFlow.SetWriteMetadata(metadata)
2117 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2118 subFlow.SetTableMetadata(metadata)
2119 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<32 | of.DhcpArpFlowMask | of.UsFlowMask
2120 subFlow.Priority = of.ArpFlowPriority
2121
2122 flow.SubFlows[subFlow.Cookie] = subFlow
2123 logger.Infow(ctx, "Built US ARP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2124 return flow, nil
2125}
2126
2127// setUsMatchVlan to set upstream match vlan
2128func (vpv *VoltPortVnet) setUsMatchVlan(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302129 logger.Debugw(ctx, "Set Us Match Vlan", log.Fields{"Value": vpv.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05302130 switch vpv.VlanControl {
2131 case None:
2132 flow.SetMatchVlan(vpv.SVlan)
2133 case ONUCVlanOLTSVlan:
2134 flow.SetMatchVlan(vpv.CVlan)
2135 case OLTCVlanOLTSVlan:
2136 flow.SetMatchVlan(vpv.UniVlan)
2137 //flow.SetSetVlan(vpv.CVlan)
2138 case ONUCVlan:
2139 flow.SetMatchVlan(vpv.SVlan)
2140 case OLTSVlan:
2141 flow.SetMatchVlan(vpv.UniVlan)
2142 //flow.SetSetVlan(vpv.SVlan)
2143 default:
2144 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2145 return errorCodes.ErrInvalidParamInRequest
2146 }
2147 return nil
2148}
2149
2150// BuildUsPppoeFlows to build upstream pppoe flows
2151func (vpv *VoltPortVnet) BuildUsPppoeFlows() (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302152 logger.Infow(ctx, "Building US PPPoE flow", log.Fields{"Port": vpv.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05302153 flow := &of.VoltFlow{}
2154 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302155 subFlow := of.NewVoltSubFlow()
2156 subFlow.SetTableID(0)
2157
2158 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2159 subFlow.SetMatchSrcMac(vpv.MacAddr)
2160 }
2161
2162 if err := vpv.setUsMatchVlan(subFlow); err != nil {
2163 return nil, err
2164 }
2165 subFlow.SetPppoeDiscoveryMatch()
2166 uniport, err := GetApplication().GetPortID(vpv.Port)
2167 if err != nil {
2168 return nil, err
2169 }
2170 subFlow.SetInPort(uniport)
2171 subFlow.SetReportToController()
2172 // PortName and PortID to be used for validation of port before flow pushing
2173 flow.PortID = uniport
2174 flow.PortName = vpv.Port
2175
2176 allowTransparent := 0
2177 if vpv.AllowTransparent {
2178 allowTransparent = 1
2179 }
2180 metadata := uint64(uniport)
2181 subFlow.SetWriteMetadata(metadata)
2182
2183 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2184 subFlow.SetTableMetadata(metadata)
2185
vinokuma926cb3e2023-03-29 11:41:06 +05302186 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits pppoe mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302187 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.UsFlowMask
2188 subFlow.Priority = of.PppoeFlowPriority
2189
2190 flow.SubFlows[subFlow.Cookie] = subFlow
2191 logger.Infow(ctx, "Built US PPPoE flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2192 return flow, nil
2193}
2194
2195// BuildDsPppoeFlows to build downstream pppoe flows
2196func (vpv *VoltPortVnet) BuildDsPppoeFlows() (*of.VoltFlow, error) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302197 logger.Infow(ctx, "Building DS PPPoE flow", log.Fields{"Port": vpv.Port, "ML": vpv.MacLearning, "Mac": vpv.MacAddr})
2198 flow := &of.VoltFlow{}
2199 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2200 subFlow := of.NewVoltSubFlow()
2201 subFlow.SetTableID(0)
2202
2203 vpv.setDsMatchVlan(subFlow)
2204 subFlow.SetPppoeDiscoveryMatch()
2205
2206 if NonZeroMacAddress(vpv.MacAddr) {
2207 subFlow.SetMatchDstMac(vpv.MacAddr)
2208 }
2209
2210 uniport, _ := GetApplication().GetPortID(vpv.Port)
2211 nni, err := GetApplication().GetNniPort(vpv.Device)
2212 if err != nil {
2213 return nil, err
2214 }
akashreddykeb418f12025-10-30 10:58:42 +05302215 nniport, err := GetApplication().GetDevicePortID(vpv.Device, nni)
Naveen Sampath04696f72022-06-13 15:19:14 +05302216 if err != nil {
2217 return nil, err
2218 }
2219 subFlow.SetInPort(nniport)
2220 // PortName and PortID to be used for validation of port before flow pushing
2221 flow.PortID = uniport
2222 flow.PortName = vpv.Port
2223 metadata := uint64(uniport)
2224 subFlow.SetWriteMetadata(metadata)
2225 allowTransparent := 0
2226 if vpv.AllowTransparent {
2227 allowTransparent = 1
2228 }
2229 metadata = uint64(allowTransparent)<<56 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2230 subFlow.SetTableMetadata(metadata)
2231 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05302232 // | 12-bit cvlan | 4 bits empty | <32-bits uniport>| 16-bits dhcp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302233 subFlow.Cookie = uint64(vpv.CVlan)<<52 | uint64(uniport)<<16 | of.PppoeFlowMask | of.DsFlowMask
2234 subFlow.Priority = of.PppoeFlowPriority
2235
2236 flow.SubFlows[subFlow.Cookie] = subFlow
2237 logger.Infow(ctx, "Built DS DHCP flow ", log.Fields{"cookie": subFlow.Cookie, "Flow": flow})
2238 return flow, nil
2239}
2240
2241// setDsMatchVlan to set downstream match vlan
2242func (vpv *VoltPortVnet) setDsMatchVlan(flow *of.VoltSubFlow) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302243 logger.Debugw(ctx, "Set Ds Match Vlan", log.Fields{"Vlan": vpv.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05302244 switch vpv.VlanControl {
2245 case None:
2246 flow.SetMatchVlan(vpv.SVlan)
2247 case ONUCVlanOLTSVlan,
2248 OLTCVlanOLTSVlan,
2249 ONUCVlan,
2250 OLTSVlan:
2251 flow.SetMatchVlan(vpv.SVlan)
2252 default:
2253 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
2254 }
2255}
2256
2257// BuildIgmpFlows builds the US IGMP flows for a subscriber. IGMP requires flows only
2258// in the US direction.
2259func (vpv *VoltPortVnet) BuildIgmpFlows() (*of.VoltFlow, error) {
2260 logger.Infow(ctx, "Building US IGMP Flow", log.Fields{"Port": vpv.Port})
2261 mvp := GetApplication().GetMvlanProfileByName(vpv.MvlanProfileName)
2262 if mvp == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302263 return nil, errors.New("mvlan profile configured not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05302264 }
2265 mvlan := mvp.GetUsMatchVlan()
2266 flow := &of.VoltFlow{}
2267 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2268 subFlow := of.NewVoltSubFlow()
2269 subFlow.SetTableID(0)
2270
Akash Sonia8246972023-01-03 10:37:08 +05302271 subFlow.SetMatchVlan(vpv.UniVlan)
2272 subFlow.SetSetVlan(vpv.CVlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05302273
2274 uniport, err := GetApplication().GetPortID(vpv.Port)
2275 if err != nil {
2276 return nil, err
2277 }
2278 subFlow.SetInPort(uniport)
2279 // PortName and PortID to be used for validation of port before flow pushing
2280 flow.PortID = uniport
2281 flow.PortName = vpv.Port
2282
2283 if vpv.MacLearning == MacLearningNone && NonZeroMacAddress(vpv.MacAddr) {
2284 subFlow.SetMatchSrcMac(vpv.MacAddr)
2285 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302286 logger.Debugw(ctx, "Mvlan", log.Fields{"mvlan": mvlan})
vinokuma926cb3e2023-03-29 11:41:06 +05302287 // metadata := uint64(mvlan)
Naveen Sampath04696f72022-06-13 15:19:14 +05302288
2289 if vpv.McastService {
2290 metadata := uint64(vpv.McastUsMeterID)
2291 metadata = metadata | uint64(vpv.McastTechProfileID)<<32
2292 subFlow.SetMatchPbit(vpv.McastPbit)
2293 subFlow.SetMeterID(vpv.McastUsMeterID)
2294 subFlow.SetWriteMetadata(metadata)
2295 } else {
2296 // Set techprofile, meterid of first service
2297 vpv.services.Range(func(key, value interface{}) bool {
2298 svc := value.(*VoltService)
2299 writemetadata := uint64(svc.TechProfileID) << 32
2300 subFlow.SetWriteMetadata(writemetadata)
2301 subFlow.SetMeterID(svc.UsMeterID)
2302 return false
2303 })
2304 }
2305
2306 allowTransparent := 0
2307 if vpv.AllowTransparent {
2308 allowTransparent = 1
2309 }
2310 metadata := uint64(allowTransparent)<<56 | uint64(vpv.SchedID)<<40 | uint64(vpv.ONTEtherTypeClassification)<<36 | uint64(vpv.VlanControl)<<32 | uint64(vpv.UniVlan)<<16 | uint64(vpv.CVlan)
2311 subFlow.SetTableMetadata(metadata)
2312 subFlow.SetIgmpMatch()
2313 subFlow.SetReportToController()
vinokuma926cb3e2023-03-29 11:41:06 +05302314 // | 16 bits empty | <32-bits uniport>| 16-bits igmp mask or flow mask |
Naveen Sampath04696f72022-06-13 15:19:14 +05302315 subFlow.Cookie = uint64(uniport)<<16 | of.IgmpFlowMask | of.UsFlowMask
2316 subFlow.Priority = of.IgmpFlowPriority
2317
2318 flow.SubFlows[subFlow.Cookie] = subFlow
2319 logger.Infow(ctx, "Built US IGMP flow ", log.Fields{"cookie": subFlow.Cookie, "flow": flow})
2320 return flow, nil
2321}
2322
2323// WriteToDb for writing to database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302324func (vpv *VoltPortVnet) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302325 if vpv.DeleteInProgress {
2326 logger.Warnw(ctx, "Skipping Redis Update for VPV, VPV delete in progress", log.Fields{"Vnet": vpv.VnetName, "Port": vpv.Port})
2327 return
2328 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302329 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302330}
2331
vinokuma926cb3e2023-03-29 11:41:06 +05302332// ForceWriteToDb force commit a VPV to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302333func (vpv *VoltPortVnet) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302334 vpv.PendingFlowLock.RLock()
2335 defer vpv.PendingFlowLock.RUnlock()
2336 vpv.Version = database.PresentVersionMap[database.VpvPath]
2337 if b, err := json.Marshal(vpv); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302338 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 +05302339 logger.Warnw(ctx, "VPV write to DB failed", log.Fields{"port": vpv.Port, "SVlan": vpv.SVlan, "CVlan": vpv.CVlan,
2340 "UniVlan": vpv.UniVlan, "Error": err})
2341 }
2342 }
2343}
2344
2345// DelFromDb for deleting from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302346func (vpv *VoltPortVnet) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302347 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 +05302348 _ = db.DelVpv(cntx, vpv.Port, uint16(vpv.SVlan), uint16(vpv.CVlan), uint16(vpv.UniVlan))
Naveen Sampath04696f72022-06-13 15:19:14 +05302349}
2350
2351// ClearAllServiceFlags to clear all service flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302352func (vpv *VoltPortVnet) ClearAllServiceFlags(cntx context.Context) {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302353 vpv.RangeOnServices(cntx, ClearFlagsInService, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05302354}
2355
2356// ClearAllVpvFlags to clear all vpv flags
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302357func (vpv *VoltPortVnet) ClearAllVpvFlags(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302358 logger.Debugw(ctx, "Clear All Vpv Flags", log.Fields{"Port": vpv.Port, "Device": vpv.Device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302359 vpv.PendingFlowLock.Lock()
2360 vpv.FlowsApplied = false
2361 vpv.IgmpFlowsApplied = false
2362 vpv.PendingDeleteFlow = make(map[string]bool)
2363 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302364 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302365 logger.Debugw(ctx, "Cleared Flow Flags for VPV",
2366 log.Fields{"device": vpv.Device, "port": vpv.Port,
2367 "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2368}
2369
2370// CreateVpvFromString to create vpv from string
2371func (va *VoltApplication) CreateVpvFromString(b []byte, hash string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302372 logger.Info(ctx, "Create Vpv From String")
Naveen Sampath04696f72022-06-13 15:19:14 +05302373 var vpv VoltPortVnet
2374 if err := json.Unmarshal(b, &vpv); err == nil {
2375 vnetsByPortsSliceIntf, ok := va.VnetsByPort.Load(vpv.Port)
2376 if !ok {
2377 va.VnetsByPort.Store(vpv.Port, []*VoltPortVnet{})
2378 vnetsByPortsSliceIntf = []*VoltPortVnet{}
2379 }
2380 vpv.servicesCount = atomic.NewUint64(0)
2381 vnetsByPortsSlice := vnetsByPortsSliceIntf.([]*VoltPortVnet)
2382 vnetsByPortsSlice = append(vnetsByPortsSlice, &vpv)
2383 va.VnetsByPort.Store(vpv.Port, vnetsByPortsSlice)
2384 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2385 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
2386 vnet.associatePortToVnet(vpv.Port)
2387 }
2388
2389 if vpv.DeleteInProgress {
2390 va.VoltPortVnetsToDelete[&vpv] = true
2391 logger.Warnw(ctx, "VPV (restored) to be deleted", log.Fields{"Port": vpv.Port, "Vnet": vpv.VnetName})
2392 }
2393 logger.Debugw(ctx, "Added VPV from string", log.Fields{"port": vpv.Port, "svlan": vpv.SVlan, "cvlan": vpv.CVlan, "univlan": vpv.UniVlan})
2394 }
2395}
2396
2397// RestoreVpvsFromDb to restore vpvs from database
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302398func (va *VoltApplication) RestoreVpvsFromDb(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302399 logger.Info(ctx, "Restore Vpvs From Db")
Naveen Sampath04696f72022-06-13 15:19:14 +05302400 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302401 vpvs, _ := db.GetVpvs(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302402 for hash, vpv := range vpvs {
2403 b, ok := vpv.Value.([]byte)
2404 if !ok {
2405 logger.Warn(ctx, "The value type is not []byte")
2406 continue
2407 }
2408 va.CreateVpvFromString(b, hash)
2409 }
2410}
2411
2412// GetVnetByPort : VNET related functionality of VOLT Application here on.
2413// Get the VNET from a port. The port identity is passed as device and port identities in string.
2414// The identity of the VNET is the SVLAN and the CVLAN. Only if the both match the VLAN
2415// is assumed to have matched. TODO: 1:1 should be treated differently and needs to be addressed
2416func (va *VoltApplication) GetVnetByPort(port string, svlan of.VlanType, cvlan of.VlanType, univlan of.VlanType) *VoltPortVnet {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302417 logger.Debugw(ctx, "Get Vnet By Port", log.Fields{"port": port, "svlan": svlan, "cvlan": cvlan, "univlan": univlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302418 if _, ok := va.VnetsByPort.Load(port); !ok {
2419 return nil
2420 }
2421 vpvs, _ := va.VnetsByPort.Load(port)
2422 for _, vpv := range vpvs.([]*VoltPortVnet) {
2423 if vpv.MatchesVlans(svlan, cvlan, univlan) {
2424 return vpv
2425 }
2426 }
2427 return nil
2428}
2429
2430// AddVnetToPort to add vnet to port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302431func (va *VoltApplication) AddVnetToPort(cntx context.Context, port string, vvnet *VoltVnet, vs *VoltService) *VoltPortVnet {
Naveen Sampath04696f72022-06-13 15:19:14 +05302432 // The VNET is not on the port and is to be added
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302433 logger.Infow(ctx, "Adding VNET to Port", log.Fields{"Port": port, "VNET": vvnet.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05302434 vpv := NewVoltPortVnet(vvnet)
2435 vpv.MacLearning = vvnet.MacLearning
2436 vpv.Port = port
2437 vvnet.associatePortToVnet(port)
2438 if _, ok := va.VnetsByPort.Load(port); !ok {
2439 va.VnetsByPort.Store(port, []*VoltPortVnet{})
2440 }
2441 vpvsIntf, _ := va.VnetsByPort.Load(port)
2442 vpvs := vpvsIntf.([]*VoltPortVnet)
2443 vpvs = append(vpvs, vpv)
2444 va.VnetsByPort.Store(port, vpvs)
2445 va.UpdateMacInPortMap(vpv.MacAddr, vpv.Port)
2446
2447 vpv.VpvLock.Lock()
2448 defer vpv.VpvLock.Unlock()
2449
2450 // Add the service that is causing the VNET to be added to the port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302451 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05302452
Tinoj Josephec742f62022-09-29 19:11:10 +05302453 if !vs.IsActivated {
2454 logger.Warn(ctx, "Not Checking port state: Service Not activated")
2455 // Process the PORT UP if the port is already up
2456 d, err := va.GetDeviceFromPort(port)
2457 if err == nil {
2458 vpv.setDevice(d.Name)
2459 }
2460 vpv.WriteToDb(cntx)
2461 return vpv
2462 }
2463
Naveen Sampath04696f72022-06-13 15:19:14 +05302464 // Process the PORT UP if the port is already up
2465 d, err := va.GetDeviceFromPort(port)
2466 if err == nil {
2467 vpv.setDevice(d.Name)
2468 p := d.GetPort(port)
2469 if p != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302470 logger.Debugw(ctx, "Checking UNI port state", log.Fields{"State": p.State})
Akash Soni024eb8e2023-04-28 16:25:09 +05302471 if d.State == controller.DeviceStateUP && p.State == PortStateUp {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302472 vpv.PortUpInd(cntx, d, port, vs.NniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05302473 }
2474 }
2475 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302476 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302477 return vpv
2478}
2479
2480// DelVnetFromPort for deleting vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302481func (va *VoltApplication) DelVnetFromPort(cntx context.Context, port string, vpv *VoltPortVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302482 logger.Debugw(ctx, "Delete Vnet From Port", log.Fields{"Port": port, "VNET": vpv.Device})
vinokuma926cb3e2023-03-29 11:41:06 +05302483 // Delete DHCP Session
Naveen Sampath04696f72022-06-13 15:19:14 +05302484 delDhcpSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan, vpv.DHCPv6DUID)
2485
vinokuma926cb3e2023-03-29 11:41:06 +05302486 // Delete PPPoE session
Naveen Sampath04696f72022-06-13 15:19:14 +05302487 delPppoeIaSessions(vpv.LearntMacAddr, vpv.SVlan, vpv.CVlan)
2488
vinokuma926cb3e2023-03-29 11:41:06 +05302489 // Delete Mac from MacPortMap
Naveen Sampath04696f72022-06-13 15:19:14 +05302490 va.DeleteMacInPortMap(vpv.MacAddr)
2491
vinokuma926cb3e2023-03-29 11:41:06 +05302492 // Delete VPV
Naveen Sampath04696f72022-06-13 15:19:14 +05302493 vpvsIntf, ok := va.VnetsByPort.Load(port)
2494 if !ok {
2495 return
2496 }
2497 vpvs := vpvsIntf.([]*VoltPortVnet)
2498 for i, lvpv := range vpvs {
vinokuma04dc9f82023-07-31 15:47:49 +05302499 if reflect.DeepEqual(lvpv, vpv) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302500 logger.Debugw(ctx, "Deleting VPV from port", log.Fields{"Port": vpv.Port, "SVLAN": vpv.SVlan, "CVLAN": vpv.CVlan,
2501 "UNIVLAN": vpv.UniVlan})
2502
2503 vpvs = append(vpvs[0:i], vpvs[i+1:]...)
2504
2505 vpv.DeleteInProgress = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302506 vpv.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302507
2508 va.VnetsByPort.Store(port, vpvs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302509 vpv.DelTrapFlows(cntx)
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302510 vpv.DelHsiaFlows(cntx, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05302511 va.DisassociateVpvsFromDevice(vpv.Device, vpv)
2512 vpv.PendingFlowLock.RLock()
2513 if len(vpv.PendingDeleteFlow) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302514 vpv.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302515 }
2516 if vnet := va.GetVnetByName(vpv.VnetName); vnet != nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302517 vnet.disassociatePortFromVnet(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05302518 }
2519 vpv.PendingFlowLock.RUnlock()
2520 return
2521 }
2522 }
2523}
2524
2525// RestoreVnetsFromDb to restore vnet from port
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302526func (va *VoltApplication) RestoreVnetsFromDb(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302527 logger.Info(ctx, "Restore Vnets From Db")
Naveen Sampath04696f72022-06-13 15:19:14 +05302528 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302529 vnets, _ := db.GetVnets(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05302530 for _, net := range vnets {
2531 b, ok := net.Value.([]byte)
2532 if !ok {
2533 logger.Warn(ctx, "The value type is not []byte")
2534 continue
2535 }
2536 var vnet VoltVnet
2537 err := json.Unmarshal(b, &vnet)
2538 if err != nil {
2539 logger.Warn(ctx, "Unmarshal of VNET failed")
2540 continue
2541 }
2542 logger.Debugw(ctx, "Retrieved VNET", log.Fields{"VNET": vnet.VnetConfig})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302543 if err := va.AddVnet(cntx, vnet.VnetConfig, &vnet.VnetOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302544 logger.Warnw(ctx, "Add Vnet Failed", log.Fields{"Config": vnet.VnetConfig, "Error": err})
2545 }
2546
2547 if vnet.DeleteInProgress {
2548 va.VnetsToDelete[vnet.Name] = true
2549 logger.Warnw(ctx, "Vnet (restored) to be deleted", log.Fields{"Vnet": vnet.Name})
2550 }
Naveen Sampath04696f72022-06-13 15:19:14 +05302551 }
2552}
2553
2554// GetServiceFromCvlan : Locate a service based on the packet received. The packet contains VLANs that
2555// are used as the key to locate the service. If more than one service is on the
2556// same port (essentially a UNI of ONU), the services must be separated by different
2557// CVLANs
2558func (va *VoltApplication) GetServiceFromCvlan(device, port string, vlans []of.VlanType, priority uint8) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302559 logger.Debugw(ctx, "Get Service From Cvlan", log.Fields{"Device": device, "Port": port, "VLANs": vlans, "Priority": priority})
Naveen Sampath04696f72022-06-13 15:19:14 +05302560 // Fetch the device first to make sure the device exists
2561 dIntf, ok := va.DevicesDisc.Load(device)
2562 if !ok {
2563 return nil
2564 }
2565 d := dIntf.(*VoltDevice)
2566
2567 // If the port is NNI port, the services dont exist on it. The svc then
2568 // must be obtained from a different context and is not included here
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302569 if d.IsPortNni(port) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302570 return nil
2571 }
2572
vinokuma926cb3e2023-03-29 11:41:06 +05302573 // To return the matched service
Naveen Sampath04696f72022-06-13 15:19:14 +05302574 var service *VoltService
2575
2576 // This is an access port and the port should have all the associated
2577 // services which can be uniquely identified by the VLANs in the packet
2578 vnets, ok := va.VnetsByPort.Load(port)
2579
2580 if !ok {
2581 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
2582 return nil
2583 }
2584 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2585 for _, vnet := range vnets.([]*VoltPortVnet) {
2586 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2587 switch vnet.VlanControl {
2588 case ONUCVlanOLTSVlan:
2589 service = vnet.MatchesPriority(priority)
2590 if vnet.MatchesCvlan(vlans) && service != nil {
2591 return service
2592 }
2593 case ONUCVlan,
2594 None:
2595 service = vnet.MatchesPriority(priority)
Naveen Sampath04696f72022-06-13 15:19:14 +05302596 // In case of HSIA Flow - cvlan == Svlan
Akash Sonief452f12024-12-12 18:20:28 +05302597 // In case of DHCP flow, match for cvlan as we are setting cvlan for DHCP flows
2598 if len(vlans) == 1 && (vlans[0] == vnet.CVlan || vlans[0] == of.VlanNone) && (service != nil && service.IsActivated) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302599 return service
2600 }
Akash Sonief452f12024-12-12 18:20:28 +05302601 case OLTCVlanOLTSVlan:
Naveen Sampath04696f72022-06-13 15:19:14 +05302602 service = vnet.MatchesPriority(priority)
2603 if len(vlans) == 1 && vlans[0] == vnet.UniVlan && service != nil {
2604 return service
2605 }
Akash Sonief452f12024-12-12 18:20:28 +05302606 case OLTSVlan:
2607 // For OLTSVlan, return only the active service attached to the VPV.
2608 service = vnet.GetSvcFromVPV()
2609 if service != nil && service.IsActivated {
2610 return service
2611 }
Naveen Sampath04696f72022-06-13 15:19:14 +05302612 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302613 logger.Warnw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05302614 }
2615 }
2616 return nil
2617}
2618
2619// GetVnetFromFields : Locate a service based on the packet received. The packet contains VLANs that
2620// are used as the key to locate the service. If more than one service is on the
2621// same port (essentially a UNI of ONU), the services must be separated by different
2622// CVLANs
2623func (va *VoltApplication) GetVnetFromFields(device string, port string, vlans []of.VlanType, priority uint8) (*VoltPortVnet, *VoltService) {
2624 // Fetch the device first to make sure the device exists
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302625 logger.Debugw(ctx, "Get Vnet From Fields", log.Fields{"Device": device, "Port": port, "VLANs": vlans, "Priority": priority})
Naveen Sampath04696f72022-06-13 15:19:14 +05302626 dIntf, ok := va.DevicesDisc.Load(device)
2627 if !ok {
2628 return nil, nil
2629 }
2630 d := dIntf.(*VoltDevice)
2631
2632 // If the port is NNI port, the services dont exist on it. The svc then
2633 // must be obtained from a different context and is not included here
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302634 if d.IsPortNni(port) {
Naveen Sampath04696f72022-06-13 15:19:14 +05302635 return nil, nil
2636 }
2637
2638 //To return the matched service
2639 var service *VoltService
2640
2641 // This is an access port and the port should have all the associated
2642 // services which can be uniquely identified by the VLANs in the packet
2643 if vnets, ok := va.VnetsByPort.Load(port); ok {
2644 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": vlans, "Priority": priority})
2645 for _, vnet := range vnets.([]*VoltPortVnet) {
2646 logger.Infow(ctx, "Vnet", log.Fields{"Vnet": vnet})
2647 switch vnet.VlanControl {
2648 case ONUCVlanOLTSVlan:
2649 service = vnet.MatchesPriority(priority)
2650 if vnet.MatchesCvlan(vlans) && service != nil {
2651 return vnet, service
2652 }
2653 case ONUCVlan,
2654 None:
2655 service = vnet.MatchesPriority(priority)
2656 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.SVlan && service != nil {
2657 return vnet, service
2658 }
2659 case OLTCVlanOLTSVlan,
2660 OLTSVlan:
2661 service = vnet.MatchesPriority(priority)
2662 if (len(vlans) == 1 || vnet.AllowTransparent) && vlans[0] == vnet.UniVlan && service != nil {
2663 return vnet, service
2664 }
2665 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302666 logger.Warnw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vnet.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05302667 }
2668 }
2669 }
2670 return nil, nil
2671}
2672
2673// GetVnetFromPkt : Locate a service based on the packet received. The packet contains VLANs that
2674// are used as the key to locate the service. If more than one service is on the
2675// same port (essentially a UNI of ONU), the services must be separated by different
2676// CVLANs
2677func (va *VoltApplication) GetVnetFromPkt(device string, port string, pkt gopacket.Packet) (*VoltPortVnet, *VoltService) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302678 logger.Debugw(ctx, "Get Vnet From Pkt", log.Fields{"Device": device, "Port": port})
Naveen Sampath04696f72022-06-13 15:19:14 +05302679 vlans := GetVlans(pkt)
2680 priority := GetPriority(pkt)
2681 return va.GetVnetFromFields(device, port, vlans, priority)
2682}
2683
2684// PushDevFlowForVlan to push icmpv6 flows for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302685func (va *VoltApplication) PushDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302686 logger.Debugw(ctx, "PushDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302687 pushflow := func(key interface{}, value interface{}) bool {
2688 device := value.(*VoltDevice)
2689 if !isDeviceInList(device.SerialNum, vnet.DevicesList) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302690 logger.Warnw(ctx, "Device not present in vnet device list", log.Fields{"Device": device.SerialNum})
Naveen Sampath04696f72022-06-13 15:19:14 +05302691 return true
2692 }
2693 if device.State != controller.DeviceStateUP {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302694 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 +05302695 return true
2696 }
2697 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302698 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 +05302699 return true
2700 }
2701
2702 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2703 vnetList := vnetListIntf.(*util.ConcurrentMap)
2704 vnetList.Set(vnet.Name, true)
2705 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302706 logger.Debugw(ctx, "Flow already pushed for these Vlans. Adding profile to list", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan, "vnetList-len": vnetList.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05302707 return true
2708 }
2709 logger.Debugw(ctx, "Configuring Dev Flows Group for device ", log.Fields{"Device": device})
2710 err := ProcessIcmpv6McGroup(device.Name, false)
2711 if err != nil {
2712 logger.Warnw(ctx, "Configuring Dev Flows Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2713 return true
2714 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302715 nniPort, err := GetApplication().GetNniPort(device.Name)
2716 if err != nil {
2717 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2718 return true
2719 }
akashreddykeb418f12025-10-30 10:58:42 +05302720 if portID, err := va.GetDevicePortID(device.Name, nniPort); err == nil {
mgoudabb017dc2025-10-29 19:53:34 +05302721 if state, _ := controller.GetController().GetPortState(device.Name, nniPort); state != controller.PortStateUp {
Naveen Sampath04696f72022-06-13 15:19:14 +05302722 logger.Warnw(ctx, "Skipping Dev Flow Configuration - Port Down", log.Fields{"Device": device})
2723 return true
2724 }
2725
vinokuma926cb3e2023-03-29 11:41:06 +05302726 // Pushing ICMPv6 Flow
Naveen Sampath04696f72022-06-13 15:19:14 +05302727 flow := BuildICMPv6Flow(portID, vnet)
mgoudabb017dc2025-10-29 19:53:34 +05302728 err = controller.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302729 if err != nil {
2730 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2731 return true
2732 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302733 logger.Debugw(ctx, "ICMPv6 Flow Added to Queue", log.Fields{"flow": flow})
Naveen Sampath04696f72022-06-13 15:19:14 +05302734
2735 // Pushing ARP Flow
2736 flow = BuildDSArpFlow(portID, vnet)
mgoudabb017dc2025-10-29 19:53:34 +05302737 err = controller.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302738 if err != nil {
2739 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2740 return true
2741 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302742 logger.Debugw(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
Naveen Sampath04696f72022-06-13 15:19:14 +05302743
2744 vnetList := util.NewConcurrentMap()
2745 vnetList.Set(vnet.Name, true)
2746 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2747 }
2748 return true
2749 }
2750 va.DevicesDisc.Range(pushflow)
2751}
2752
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302753func (va *VoltApplication) PushTrapFlows(cntx context.Context, device *VoltDevice, nniPort string, flow *of.VoltFlow) error {
2754 logger.Debugw(ctx, "Push NNI DHCP Trap Flows", log.Fields{"DeviceName": device.Name, "Flow port": flow.PortID})
mgoudabb017dc2025-10-29 19:53:34 +05302755 return controller.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302756}
2757
Naveen Sampath04696f72022-06-13 15:19:14 +05302758// PushDevFlowForDevice to push icmpv6 flows for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302759func (va *VoltApplication) PushDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302760 logger.Debugw(ctx, "PushDevFlowForDevice", log.Fields{"device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05302761 err := ProcessIcmpv6McGroup(device.Name, false)
2762 if err != nil {
2763 logger.Warnw(ctx, "Configuring ICMPv6 Group for device failed ", log.Fields{"Device": device.Name, "err": err})
2764 return
2765 }
2766 pushicmpv6 := func(key, value interface{}) bool {
2767 vnet := value.(*VoltVnet)
2768 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2769 vnetList := vnetListIntf.(*util.ConcurrentMap)
2770 vnetList.Set(vnet.Name, true)
2771 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2772 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()})
2773 return true
2774 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302775 nniPort, err := GetApplication().GetNniPort(device.Name)
2776 if err != nil {
2777 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2778 return true
2779 }
akashreddykeb418f12025-10-30 10:58:42 +05302780 nniPortID, err := va.GetDevicePortID(device.Name, nniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05302781 if err != nil {
2782 logger.Errorw(ctx, "Push ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2783 }
2784 if applied, ok := device.VlanPortStatus.Load(uint16(vnet.SVlan)); !ok || !applied.(bool) {
2785 logger.Warnw(ctx, "Push ICMPv6 Failed - Vlan not enabled yet", log.Fields{"Port": device.NniPort, "Vlan": vnet.SVlan})
2786 return true
2787 }
2788 flow := BuildICMPv6Flow(nniPortID, vnet)
mgoudabb017dc2025-10-29 19:53:34 +05302789 err = controller.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302790 if err != nil {
2791 logger.Warnw(ctx, "Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2792 return true
2793 }
2794 logger.Infow(ctx, "ICMP Flow Added to Queue", log.Fields{"flow": flow})
2795
2796 flow = BuildDSArpFlow(nniPortID, vnet)
mgoudabb017dc2025-10-29 19:53:34 +05302797 err = controller.GetController().AddFlows(cntx, nniPort, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302798 if err != nil {
2799 logger.Warnw(ctx, "Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2800 return true
2801 }
2802 logger.Infow(ctx, "ARP Flow Added to Queue", log.Fields{"flow": flow})
2803
2804 vnetList := util.NewConcurrentMap()
2805 vnetList.Set(vnet.Name, true)
2806 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2807 return true
2808 }
2809 va.VnetsByName.Range(pushicmpv6)
2810}
2811
2812// DeleteDevFlowForVlan to delete icmpv6 flow for vlan
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302813func (va *VoltApplication) DeleteDevFlowForVlan(cntx context.Context, vnet *VoltVnet) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302814 logger.Debugw(ctx, "DeleteDevFlowForVlan", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302815 delflows := func(key interface{}, value interface{}) bool {
2816 device := value.(*VoltDevice)
2817
2818 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2819 vnetList := vnetListIntf.(*util.ConcurrentMap)
2820 vnetList.Remove(vnet.Name)
2821 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2822 if vnetList.Length() != 0 {
2823 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()})
2824 return true
2825 }
2826 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302827 nniPort, err := GetApplication().GetNniPort(device.Name)
2828 if err != nil {
2829 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2830 return true
2831 }
akashreddykeb418f12025-10-30 10:58:42 +05302832 if portID, err := va.GetDevicePortID(device.Name, nniPort); err == nil {
mgoudabb017dc2025-10-29 19:53:34 +05302833 if state, _ := controller.GetController().GetPortState(device.Name, nniPort); state != controller.PortStateUp {
Naveen Sampath04696f72022-06-13 15:19:14 +05302834 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2835 return true
2836 }
vinokuma926cb3e2023-03-29 11:41:06 +05302837 // Pushing ICMPv6 Flow
Naveen Sampath04696f72022-06-13 15:19:14 +05302838 flow := BuildICMPv6Flow(portID, vnet)
2839 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302840 err := vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302841 if err != nil {
2842 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2843 return true
2844 }
2845 logger.Infow(ctx, "ICMPv6 Flow Delete Added to Queue", log.Fields{"flow": flow})
2846
vinokuma926cb3e2023-03-29 11:41:06 +05302847 // Pushing ARP Flow
Naveen Sampath04696f72022-06-13 15:19:14 +05302848 flow = BuildDSArpFlow(portID, vnet)
2849 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302850 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302851 if err != nil {
2852 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2853 return true
2854 }
2855 logger.Infow(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
2856
2857 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2858 }
2859 return true
2860 }
2861 va.DevicesDisc.Range(delflows)
2862}
2863
2864// DeleteDevFlowForDevice to delete icmpv6 flow for device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302865func (va *VoltApplication) DeleteDevFlowForDevice(cntx context.Context, device *VoltDevice) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302866 logger.Debugw(ctx, "DeleteDevFlowForDevice", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05302867 delicmpv6 := func(key, value interface{}) bool {
2868 vnet := value.(*VoltVnet)
2869 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2870 vnetList := vnetListIntf.(*util.ConcurrentMap)
2871 vnetList.Remove(vnet.Name)
2872 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2873 if vnetList.Length() != 0 {
2874 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()})
2875 return true
2876 }
2877 } else {
2878 logger.Warnw(ctx, "ICMPv6 Flow map entry not found for Vnet", log.Fields{"Vnet": vnet.VnetConfig})
2879 return true
2880 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302881 nniPort, err := GetApplication().GetNniPort(device.Name)
2882 if err != nil {
2883 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2884 return true
2885 }
akashreddykeb418f12025-10-30 10:58:42 +05302886 nniPortID, err := va.GetDevicePortID(device.Name, nniPort)
Naveen Sampath04696f72022-06-13 15:19:14 +05302887 if err != nil {
2888 logger.Errorw(ctx, "Delete ICMPv6 Failed - Failed to get NNI Port Id", log.Fields{"Port": device.NniPort, "Reason": err.Error})
2889 }
2890 flow := BuildICMPv6Flow(nniPortID, vnet)
2891 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302892 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302893 if err != nil {
2894 logger.Warnw(ctx, "De-Configuring ICMPv6 Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2895 return true
2896 }
2897
2898 flow = BuildDSArpFlow(nniPortID, vnet)
2899 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302900 err = vnet.RemoveFlows(cntx, device, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05302901 if err != nil {
2902 logger.Warnw(ctx, "De-Configuring ARP Flow for device failed ", log.Fields{"Device": device.Name, "err": err})
2903 return true
2904 }
2905
2906 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2907 logger.Infow(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
2908 return true
2909 }
2910 va.VnetsByName.Range(delicmpv6)
2911 logger.Debugw(ctx, "De-Configuring ICMPv6 Group for device ", log.Fields{"Device": device.Name})
2912 err := ProcessIcmpv6McGroup(device.Name, true)
2913 if err != nil {
2914 logger.Warnw(ctx, "De-Configuring ICMPv6 Group on device failed ", log.Fields{"Device": device.Name, "err": err})
2915 return
2916 }
2917}
2918
2919// DeleteDevFlowForVlanFromDevice to delete icmpv6 flow for vlan from device
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302920func (va *VoltApplication) DeleteDevFlowForVlanFromDevice(cntx context.Context, vnet *VoltVnet, deviceSerialNum string) {
Akash Sonief452f12024-12-12 18:20:28 +05302921 logger.Infow(ctx, "DeleteDevFlowForVlanFromDevice", log.Fields{"Device-serialNum": deviceSerialNum, "SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302922 delflows := func(key interface{}, value interface{}) bool {
2923 device := value.(*VoltDevice)
2924 if device.SerialNum != deviceSerialNum {
2925 return true
2926 }
2927 if vnetListIntf, ok := device.ConfiguredVlanForDeviceFlows.Get(VnetKey(vnet.SVlan, vnet.CVlan, 0)); ok {
2928 vnetList := vnetListIntf.(*util.ConcurrentMap)
2929 vnetList.Remove(vnet.Name)
2930 device.ConfiguredVlanForDeviceFlows.Set(VnetKey(vnet.SVlan, vnet.CVlan, 0), vnetList)
2931 if vnetList.Length() != 0 {
2932 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()})
2933 return true
2934 }
2935 } else if !vgcRebooted && len(vnet.DevicesList) != 0 {
2936 // Return only in-case of non-reboot/delete scenario. Else, the flows need to be force removed
2937 // DeviceList check is there to avoid dangling flow in-case of pod restart during service de-activation.
2938 // The step will be as follow:
2939 // 1. Deact Service
2940 // 2. Pod Reboot
2941 // 3. Pending Delete Service triggered
2942 // 4. Del Service Ind followed by DelVnet req from NB
2943 // 5. If Vlan status response is awaited, the ConfiguredVlanForDeviceFlows cache will not have flow info
2944 // hence the flow will not be cleared
2945 logger.Warnw(ctx, "Dev Flow map entry not found for Vnet", log.Fields{"PodReboot": vgcRebooted, "VnetDeleteInProgress": vnet.DeleteInProgress})
2946 return true
2947 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302948 nniPort, err := GetApplication().GetNniPort(device.Name)
2949 if err != nil {
2950 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
2951 return true
2952 }
akashreddykeb418f12025-10-30 10:58:42 +05302953 if portID, err := va.GetDevicePortID(device.Name, nniPort); err == nil {
mgoudabb017dc2025-10-29 19:53:34 +05302954 if state, _ := controller.GetController().GetPortState(device.Name, nniPort); state != controller.PortStateUp {
Naveen Sampath04696f72022-06-13 15:19:14 +05302955 logger.Warnw(ctx, "Skipping ICMPv6 Flow Deletion - Port Down", log.Fields{"Device": device})
2956 return false
2957 }
2958 flow := BuildICMPv6Flow(portID, vnet)
2959 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302960 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302961 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2962 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302963 logger.Debugw(ctx, "ICMP Flow Delete Added to Queue", log.Fields{"flow": flow})
Naveen Sampath04696f72022-06-13 15:19:14 +05302964
2965 flow = BuildDSArpFlow(portID, vnet)
2966 flow.ForceAction = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302967 if err := vnet.RemoveFlows(cntx, device, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05302968 logger.Warnw(ctx, "Delete Flow Failed", log.Fields{"Device": device, "Flow": flow, "Error": err})
2969 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302970 logger.Debugw(ctx, "ARP Flow Delete Added to Queue", log.Fields{"flow": flow})
Naveen Sampath04696f72022-06-13 15:19:14 +05302971 device.ConfiguredVlanForDeviceFlows.Remove(VnetKey(vnet.SVlan, vnet.CVlan, 0))
2972 }
2973 return false
2974 }
2975 va.DevicesDisc.Range(delflows)
2976}
2977
2978// BuildICMPv6Flow to Build DS flow for ICMPv6
2979func BuildICMPv6Flow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302980 logger.Debugw(ctx, "Building ICMPv6 MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05302981 flow := &of.VoltFlow{}
2982 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2983 subFlow := of.NewVoltSubFlow()
2984
2985 subFlow.SetICMPv6Match()
2986 subFlow.SetMatchVlan(vnet.SVlan)
2987 subFlow.SetInPort(inport)
2988 subFlow.SetPopVlan()
2989 subFlow.SetOutGroup(ICMPv6ArpGroupID)
2990 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.IgmpFlowMask | of.DsFlowMask
2991 subFlow.Priority = of.McFlowPriority
2992 var metadata uint64
2993 if vnet.VlanControl == None {
2994 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
2995 } else {
2996 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
2997 }
2998 subFlow.SetTableMetadata(metadata)
2999 metadata = uint64(vnet.setPbitRemarking())
3000
3001 logger.Infow(ctx, "ICMPv6 Pbit Remarking", log.Fields{"RemarkPbit": metadata})
3002 subFlow.SetWriteMetadata(metadata)
3003 flow.SubFlows[subFlow.Cookie] = subFlow
3004 return flow
3005}
3006
vinokuma926cb3e2023-03-29 11:41:06 +05303007// BuildDSArpFlow Builds DS flow for ARP
Naveen Sampath04696f72022-06-13 15:19:14 +05303008func BuildDSArpFlow(inport uint32, vnet *VoltVnet) *of.VoltFlow {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303009 logger.Debugw(ctx, "Building ARP MC Flow", log.Fields{"SVlan": vnet.SVlan, "CVlan": vnet.CVlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05303010
3011 flow := &of.VoltFlow{}
3012 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3013 subFlow := of.NewVoltSubFlow()
3014
3015 BcastMAC, _ := net.ParseMAC("FF:FF:FF:FF:FF:FF")
3016 subFlow.SetArpMatch()
3017 subFlow.SetMatchDstMac(BcastMAC)
3018 subFlow.SetMatchVlan(vnet.SVlan)
3019 subFlow.SetInPort(inport)
3020 subFlow.SetPopVlan()
3021 subFlow.SetOutGroup(ICMPv6ArpGroupID)
3022
3023 subFlow.Cookie = uint64(vnet.CVlan)<<48 | uint64(vnet.SVlan)<<32 | of.DsArpFlowMask | of.DsFlowMask
3024 subFlow.Priority = of.McFlowPriority
3025
3026 var metadata uint64
3027 if vnet.VlanControl == None {
3028 metadata = uint64(ONUCVlan)<<32 | uint64(vnet.CVlan)
3029 } else {
3030 metadata = uint64(vnet.VlanControl)<<32 | uint64(vnet.CVlan)
3031 }
3032 subFlow.SetTableMetadata(metadata)
3033 metadata = uint64(vnet.setPbitRemarking())
3034 subFlow.SetWriteMetadata(metadata)
3035
3036 flow.SubFlows[subFlow.Cookie] = subFlow
3037 logger.Infow(ctx, "ARP Pbit Remarking", log.Fields{"RemarkPbit": metadata})
3038 return flow
3039}
3040
3041// setPbitRemarking to set Pbit remarking
3042func (vv *VoltVnet) setPbitRemarking() uint32 {
Naveen Sampath04696f72022-06-13 15:19:14 +05303043 // Remarkable
3044 // Remarked Pbit Pbit
3045 // |-----------------------------| |------|
3046 // |7| |6| |5| |4| |3| |2| |1| |0| 76543210
3047 // 000 000 000 000 000 000 000 000 00000000
3048
3049 // Eg:
3050 // For 6:3 & 7:1
3051 // 001 011 000 000 000 000 000 000 11000000
3052
3053 var remarkable uint8
3054 var remarked uint32
3055 for refPbit, remarkPbit := range vv.CtrlPktPbitRemark {
3056 remarkable = remarkable | 1<<refPbit
3057 remarked = remarked | uint32(remarkPbit)<<(refPbit*3)
3058 }
3059 return remarked<<8 | uint32(remarkable)
3060}
3061
3062// ProcessIcmpv6McGroup to add icmpv6 multicast group
3063func ProcessIcmpv6McGroup(device string, delete bool) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05303064 logger.Info(ctx, "Creating ICMPv6 MC Group")
3065 va := GetApplication()
3066 vd := va.GetDevice(device)
3067 group := &of.Group{}
3068 group.GroupID = ICMPv6ArpGroupID
3069 group.Device = device
3070 if delete {
3071 if !vd.icmpv6GroupAdded {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303072 logger.Debug(ctx, "ICMPv6 MC Group is already deleted. Ignoring icmpv6 group Delete")
Naveen Sampath04696f72022-06-13 15:19:14 +05303073 return nil //TODO
3074 }
3075 vd.icmpv6GroupAdded = false
3076 group.Command = of.GroupCommandDel
3077 group.ForceAction = true
3078 } else {
3079 if vd.icmpv6GroupAdded {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303080 logger.Debug(ctx, "ICMPv6 MC Group is already added. Ignoring icmpv6 group Add")
Naveen Sampath04696f72022-06-13 15:19:14 +05303081 return nil //TODO
3082 }
3083 vd.icmpv6GroupAdded = true
3084 group.Command = of.GroupCommandAdd
3085 receivers := GetApplication().GetIcmpv6Receivers(device)
3086 group.Buckets = append(group.Buckets, receivers...)
3087 }
3088 logger.Infow(ctx, "ICMPv6 MC Group Action", log.Fields{"Device": device, "Delete": delete})
3089 port, _ := GetApplication().GetNniPort(device)
mgoudabb017dc2025-10-29 19:53:34 +05303090 err := controller.GetController().GroupUpdate(port, device, group)
Naveen Sampath04696f72022-06-13 15:19:14 +05303091 return err
3092}
3093
vinokuma926cb3e2023-03-29 11:41:06 +05303094// isVlanMatching - checks is vlans matches with vpv based on vlan control
Naveen Sampath04696f72022-06-13 15:19:14 +05303095func (vpv *VoltPortVnet) isVlanMatching(cvlan of.VlanType, svlan of.VlanType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303096 logger.Debugw(ctx, "Is Vlan Matching", log.Fields{"cvlan": cvlan, "svlan": svlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05303097 switch vpv.VlanControl {
3098 case ONUCVlanOLTSVlan,
3099 OLTCVlanOLTSVlan:
3100 if vpv.SVlan == svlan && vpv.CVlan == cvlan {
3101 return true
3102 }
3103 case ONUCVlan,
3104 OLTSVlan,
3105 None:
3106 if vpv.SVlan == svlan {
3107 return true
3108 }
3109 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303110 logger.Warnw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vpv.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05303111 }
3112 return false
3113}
3114
vinokuma926cb3e2023-03-29 11:41:06 +05303115// PushFlows - Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303116func (vpv *VoltPortVnet) PushFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303117 logger.Debugw(ctx, "Push Flows", log.Fields{"DeviceName": device.Name, "Flow port": flow.PortID})
Naveen Sampath04696f72022-06-13 15:19:14 +05303118 for cookie := range flow.SubFlows {
3119 cookie := strconv.FormatUint(cookie, 10)
3120 fe := &FlowEvent{
3121 eType: EventTypeControlFlowAdded,
3122 cookie: cookie,
3123 eventData: vpv,
3124 }
3125 device.RegisterFlowAddEvent(cookie, fe)
3126 }
mgoudabb017dc2025-10-29 19:53:34 +05303127 return controller.GetController().AddFlows(cntx, vpv.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05303128}
3129
vinokuma926cb3e2023-03-29 11:41:06 +05303130// FlowInstallFailure - Process flow failure indication and triggers HSIA failure for all associated services
Naveen Sampath04696f72022-06-13 15:19:14 +05303131func (vpv *VoltPortVnet) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303132 logger.Debugw(ctx, "Flow Install Failure", log.Fields{"Cookie": cookie, "ErrorCode": errorCode, "ErrReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05303133 sendFlowFailureInd := func(key, value interface{}) bool {
3134 //svc := value.(*VoltService)
3135 //TODO-COMM: svc.triggerServiceFailureInd(errorCode, errReason)
3136 return true
3137 }
3138 logger.Errorw(ctx, "Control Flow Add Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3139 vpv.services.Range(sendFlowFailureInd)
3140}
3141
vinokuma926cb3e2023-03-29 11:41:06 +05303142// RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303143func (vpv *VoltPortVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303144 logger.Debugw(ctx, "Remove Flows", log.Fields{"DeviceName": device.Name, "Flow port": flow.PortID})
Naveen Sampath04696f72022-06-13 15:19:14 +05303145 vpv.PendingFlowLock.Lock()
3146 defer vpv.PendingFlowLock.Unlock()
3147
3148 for cookie := range flow.SubFlows {
3149 cookie := strconv.FormatUint(cookie, 10)
3150 fe := &FlowEvent{
3151 eType: EventTypeControlFlowRemoved,
3152 device: device.Name,
3153 cookie: cookie,
3154 eventData: vpv,
3155 }
3156 device.RegisterFlowDelEvent(cookie, fe)
3157 vpv.PendingDeleteFlow[cookie] = true
3158 }
mgoudabb017dc2025-10-29 19:53:34 +05303159 return controller.GetController().DelFlows(cntx, vpv.Port, device.Name, flow, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05303160}
3161
vinokuma926cb3e2023-03-29 11:41:06 +05303162// CheckAndDeleteVpv - remove VPV from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303163func (vpv *VoltPortVnet) CheckAndDeleteVpv(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303164 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 +05303165 vpv.PendingFlowLock.RLock()
3166 defer vpv.PendingFlowLock.RUnlock()
3167 if !vpv.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303168 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 +05303169 return
3170 }
3171 if len(vpv.PendingDeleteFlow) == 0 && !vpv.FlowsApplied {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303172 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 +05303173 vpv.DelFromDb(cntx)
balaji.nagarajan182b64f2025-09-04 11:25:17 +05303174 logger.Debugw(ctx, "Deleted VPV from DB/Cache successfully", log.Fields{"VPV Port": vpv.Port, "Device": vpv.Device, "Vnet": vpv.VnetName})
Naveen Sampath04696f72022-06-13 15:19:14 +05303175 }
3176}
3177
vinokuma926cb3e2023-03-29 11:41:06 +05303178// FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303179func (vpv *VoltPortVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303180 vpv.PendingFlowLock.Lock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303181 logger.Debugw(ctx, "VPV Flow Remove Success Notification", log.Fields{"Port": vpv.Port, "Cookie": cookie, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303182
3183 delete(vpv.PendingDeleteFlow, cookie)
3184 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303185 vpv.CheckAndDeleteVpv(cntx)
3186 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303187}
3188
vinokuma926cb3e2023-03-29 11:41:06 +05303189// FlowRemoveFailure - Process flow failure indication and triggers Del HSIA failure for all associated services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303190func (vpv *VoltPortVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303191 vpv.PendingFlowLock.Lock()
3192
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303193 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 +05303194
3195 sendFlowFailureInd := func(key, value interface{}) bool {
3196 svc := value.(*VoltService)
3197 svc.triggerServiceFailureInd(errorCode, errReason)
3198 return true
3199 }
3200 logger.Errorw(ctx, "Control Flow Del Failure Notification", log.Fields{"uniPort": vpv.Port, "Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
3201 vpv.services.Range(sendFlowFailureInd)
3202
3203 if vpv.DeleteInProgress {
3204 delete(vpv.PendingDeleteFlow, cookie)
3205 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303206 vpv.CheckAndDeleteVpv(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303207 } else {
3208 vpv.PendingFlowLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303209 vpv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303210 }
3211}
3212
vinokuma926cb3e2023-03-29 11:41:06 +05303213// RemoveFlows - Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303214func (vv *VoltVnet) RemoveFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303215 logger.Debugw(ctx, "Remove Flows", log.Fields{"PortName": flow.PortName, "DeviceName": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05303216 vv.VnetLock.Lock()
3217 defer vv.VnetLock.Unlock()
3218
3219 var flowMap map[string]bool
3220 var ok bool
3221
3222 for cookie := range flow.SubFlows {
3223 cookie := strconv.FormatUint(cookie, 10)
3224 fe := &FlowEvent{
3225 eType: EventTypeDeviceFlowRemoved,
3226 device: device.Name,
3227 cookie: cookie,
3228 eventData: vv,
3229 }
3230 device.RegisterFlowDelEvent(cookie, fe)
3231 if flowMap, ok = vv.PendingDeleteFlow[device.Name]; !ok {
3232 flowMap = make(map[string]bool)
3233 }
3234 flowMap[cookie] = true
3235 vv.PendingDeleteFlow[device.Name] = flowMap
3236 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303237 vv.WriteToDb(cntx)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303238 nniPort, err := GetApplication().GetNniPort(device.Name)
3239 if err != nil {
3240 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
3241 return err
3242 }
mgoudabb017dc2025-10-29 19:53:34 +05303243 return controller.GetController().DelFlows(cntx, nniPort, device.Name, flow, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05303244}
3245
vinokuma926cb3e2023-03-29 11:41:06 +05303246// CheckAndDeleteVnet - remove Vnet from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303247func (vv *VoltVnet) CheckAndDeleteVnet(cntx context.Context, device string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303248 logger.Debugw(ctx, "Check And Delete Vnet", log.Fields{"Device": device, "Vnet": vv.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05303249 if !vv.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303250 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 +05303251 return
3252 }
3253 vv.VnetPortLock.RLock()
3254 if len(vv.PendingDeleteFlow[device]) == 0 && !vv.isAssociatedPortsPresent() {
3255 logger.Warnw(ctx, "Deleting Vnet : All flows removed", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "Device": device})
3256 GetApplication().deleteVnetConfig(vv)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303257 _ = db.DelVnet(cntx, vv.Name)
balaji.nagarajan182b64f2025-09-04 11:25:17 +05303258 logger.Debugw(ctx, "Deleted Vnet from DB/Cache successfully", log.Fields{"Device": device, "Vnet": vv.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05303259 } else {
3260 logger.Warnw(ctx, "Skipping Del Vnet", log.Fields{"Name": vv.Name, "AssociatedPorts": vv.AssociatedPorts, "PendingDelFlows": vv.PendingDeleteFlow[device]})
3261 }
3262 vv.VnetPortLock.RUnlock()
3263}
3264
vinokuma926cb3e2023-03-29 11:41:06 +05303265// FlowRemoveSuccess - Process flow success indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303266func (vv *VoltVnet) FlowRemoveSuccess(cntx context.Context, cookie string, device string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303267 vv.VnetLock.Lock()
3268 defer vv.VnetLock.Unlock()
3269
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303270 logger.Debugw(ctx, "Vnet Flow Remove Success Notification", log.Fields{"VnetProfile": vv.Name, "Cookie": cookie, "Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303271
3272 if _, ok := vv.PendingDeleteFlow[device]; ok {
3273 delete(vv.PendingDeleteFlow[device], cookie)
3274 }
3275
3276 //Check and update success for pending disable request
3277 if d := GetApplication().GetDevice(device); d != nil {
3278 _, present := d.ConfiguredVlanForDeviceFlows.Get(VnetKey(vv.SVlan, vv.CVlan, 0))
3279 if !present && len(vv.PendingDeleteFlow[device]) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303280 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303281 }
3282 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303283 vv.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05303284}
3285
vinokuma926cb3e2023-03-29 11:41:06 +05303286// FlowRemoveFailure - Process flow failure indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303287func (vv *VoltVnet) FlowRemoveFailure(cntx context.Context, cookie string, device string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303288 vv.VnetLock.Lock()
3289 defer vv.VnetLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303290 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 +05303291
3292 if flowMap, ok := vv.PendingDeleteFlow[device]; ok {
3293 if _, ok := flowMap[cookie]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303294 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 +05303295
3296 if vv.DeleteInProgress {
3297 delete(vv.PendingDeleteFlow[device], cookie)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303298 vv.CheckAndDeleteVnet(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05303299 }
3300 return
3301 }
3302 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303303 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 +05303304}
3305
vinokuma926cb3e2023-03-29 11:41:06 +05303306// IgmpFlowInstallFailure - Process flow failure indication and triggers HSIA failure for Igmp enabled services
Naveen Sampath04696f72022-06-13 15:19:14 +05303307func (vpv *VoltPortVnet) IgmpFlowInstallFailure(cookie string, errorCode uint32, errReason string) {
vinokuma926cb3e2023-03-29 11:41:06 +05303308 // Note: Current implementation supports only for single service with Igmp Enabled for a subscriber
3309 // When multiple Igmp-suported service enabled, comment "return false"
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303310 logger.Debugw(ctx, "Igmp Flow Install Failure", log.Fields{"Cookie": cookie, "ErrorCode": errorCode, "ErrorReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05303311
3312 sendFlowFailureInd := func(key, value interface{}) bool {
3313 svc := value.(*VoltService)
3314 if svc.IgmpEnabled {
3315 svc.triggerServiceFailureInd(errorCode, errReason)
3316 return false
3317 }
3318 return true
3319 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303320 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 +05303321 vpv.services.Range(sendFlowFailureInd)
3322}
3323
3324// GetMatchingMcastService to get matching multicast service
3325func (va *VoltApplication) GetMatchingMcastService(port string, device string, cvlan of.VlanType) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303326 logger.Debugw(ctx, "Get Matching Mcast Service", log.Fields{"Port": port, "Device": device, "Cvlan": cvlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05303327 var service *VoltService
3328 dIntf, ok := va.DevicesDisc.Load(device)
3329 if !ok {
3330 return nil
3331 }
3332 d := dIntf.(*VoltDevice)
3333
3334 // If the port is NNI port, the services dont exist on it. The svc then
3335 // must be obtained from a different context and is not included here
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303336 if d.IsPortNni(port) {
Naveen Sampath04696f72022-06-13 15:19:14 +05303337 return nil
3338 }
3339
3340 // This is an access port and the port should have all the associated
3341 // services which can be uniquely identified by the VLANs in the packet
3342 vnets, ok := va.VnetsByPort.Load(port)
3343
3344 if !ok {
3345 logger.Debugw(ctx, "No Vnets for port", log.Fields{"Port": port})
3346 return nil
3347 }
3348 logger.Debugw(ctx, "Matching for VLANs", log.Fields{"VLANs": cvlan})
3349 getMcastService := func(key, value interface{}) bool {
3350 srv := value.(*VoltService)
3351 if srv.IgmpEnabled {
3352 service = srv
3353
3354 //TODO: Current implementation supports only for single service with Igmp Enabled
3355 //FIX-ME: When multiple service suports Igmp, update of logic required
3356 return false
3357 }
3358 return true
3359 }
3360
3361 for _, vpv := range vnets.([]*VoltPortVnet) {
3362 if vpv.CVlan == cvlan {
3363 vpv.services.Range(getMcastService)
3364 if service != nil {
3365 break
3366 }
3367 }
3368 }
3369 return service
3370}
3371
vinokuma926cb3e2023-03-29 11:41:06 +05303372// TriggerAssociatedFlowDelete - Re-trigger delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303373func (vv *VoltVnet) TriggerAssociatedFlowDelete(cntx context.Context, device string) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303374 logger.Infow(ctx, "Trigger Associated Flow Delete", log.Fields{"Device": device})
Naveen Sampath04696f72022-06-13 15:19:14 +05303375 vv.VnetLock.Lock()
3376 cookieList := []uint64{}
3377 flowMap := vv.PendingDeleteFlow[device]
3378
3379 for cookie := range flowMap {
3380 cookieList = append(cookieList, convertToUInt64(cookie))
3381 }
3382 vv.VnetLock.Unlock()
3383
3384 if len(cookieList) == 0 {
3385 return false
3386 }
3387
3388 for _, cookie := range cookieList {
3389 if vd := GetApplication().GetDevice(device); vd != nil {
3390 flow := &of.VoltFlow{}
3391 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
3392 subFlow := of.NewVoltSubFlow()
3393 subFlow.Cookie = cookie
3394 flow.SubFlows[cookie] = subFlow
3395 logger.Infow(ctx, "Retriggering Vnet Delete Flow", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05303396 if err := vv.RemoveFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05303397 logger.Warnw(ctx, "Vnet Delete Flow Failed", log.Fields{"Device": device, "Vnet": vv.Name, "Cookie": cookie, "Error": err})
3398 }
3399 }
3400 }
3401 return true
3402}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303403
vinokuma926cb3e2023-03-29 11:41:06 +05303404// JSONMarshal wrapper function for json Marshal VoltVnet
3405func (vv *VoltVnet) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303406 return json.Marshal(VoltVnet{
3407 VnetConfig: vv.VnetConfig,
Akash Sonia8246972023-01-03 10:37:08 +05303408 Version: vv.Version,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303409 VnetOper: VnetOper{
3410 PendingDeleteFlow: vv.VnetOper.PendingDeleteFlow,
3411 DeleteInProgress: vv.VnetOper.DeleteInProgress,
3412 PendingDeviceToDelete: vv.VnetOper.PendingDeviceToDelete,
3413 },
3414 })
3415}
3416
vinokuma926cb3e2023-03-29 11:41:06 +05303417// JSONMarshal wrapper function for json Marshal VoltPortVnet
3418func (vpv *VoltPortVnet) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303419 return json.Marshal(VoltPortVnet{
3420 Device: vpv.Device,
3421 Port: vpv.Port,
3422 PonPort: vpv.PonPort,
3423 VnetName: vpv.VnetName,
3424 SVlan: vpv.SVlan,
3425 CVlan: vpv.CVlan,
3426 UniVlan: vpv.UniVlan,
3427 SVlanTpid: vpv.SVlanTpid,
3428 DhcpRelay: vpv.DhcpRelay,
3429 ArpRelay: vpv.ArpRelay,
3430 PppoeIa: vpv.PppoeIa,
3431 MacLearning: vpv.MacLearning,
3432 DhcpStatus: vpv.DhcpStatus,
3433 DhcpExpiryTime: vpv.DhcpExpiryTime,
3434 Dhcp6ExpiryTime: vpv.Dhcp6ExpiryTime,
3435 FlowsApplied: vpv.FlowsApplied,
3436 Ipv4Addr: vpv.Ipv4Addr,
3437 Ipv6Addr: vpv.Ipv6Addr,
3438 MacAddr: vpv.MacAddr,
3439 LearntMacAddr: vpv.LearntMacAddr,
3440 CircuitID: vpv.CircuitID,
3441 RemoteID: vpv.RemoteID,
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05303442 IsOption82Enabled: vpv.IsOption82Enabled,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05303443 RelayState: vpv.RelayState,
3444 PPPoeState: vpv.PPPoeState,
3445 RelayStatev6: vpv.RelayStatev6,
3446 IgmpEnabled: vpv.IgmpEnabled,
3447 IgmpFlowsApplied: vpv.IgmpFlowsApplied,
3448 McastService: vpv.McastService,
3449 ONTEtherTypeClassification: vpv.ONTEtherTypeClassification,
3450 VlanControl: vpv.VlanControl,
3451 MvlanProfileName: vpv.MvlanProfileName,
3452 Version: vpv.Version,
3453 McastTechProfileID: vpv.McastTechProfileID,
3454 McastPbit: vpv.McastPbit,
3455 McastUsMeterID: vpv.McastUsMeterID,
3456 AllowTransparent: vpv.AllowTransparent,
3457 SchedID: vpv.SchedID,
3458 DHCPv6DUID: vpv.DHCPv6DUID,
3459 PendingDeleteFlow: vpv.PendingDeleteFlow,
3460 DeleteInProgress: vpv.DeleteInProgress,
3461 Blocked: vpv.Blocked,
3462 DhcpPbit: vpv.DhcpPbit,
3463 })
3464}
Tinoj Josephec742f62022-09-29 19:11:10 +05303465
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303466func (vpv *VoltPortVnet) IsServiceActivated(cntx context.Context) (bool, string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05303467 logger.Debugw(ctx, "Is Service Activated", log.Fields{"Name": vpv.Port})
Tinoj Josephec742f62022-09-29 19:11:10 +05303468 isActivated := false
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303469 nniPort := ""
Tinoj Josephec742f62022-09-29 19:11:10 +05303470 vpv.services.Range(func(key, value interface{}) bool {
3471 svc := value.(*VoltService)
3472 if svc.IsActivated {
3473 logger.Infow(ctx, "Found activated service on the vpv", log.Fields{"Name": svc.Name})
3474 isActivated = true
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303475 nniPort = svc.NniPort
Tinoj Josephec742f62022-09-29 19:11:10 +05303476 return false //to exit loop
3477 }
3478 return true
3479 })
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05303480 return isActivated, nniPort
Tinoj Josephec742f62022-09-29 19:11:10 +05303481}