blob: ec10fb3ee4386a43aa1133442a38a7e63c1fd5de [file] [log] [blame]
Joey Armstrongaca03cf2024-04-23 09:29:52 -04001/* -----------------------------------------------------------------------
2 * Copyright 2022-2024 Open Networking Foundation Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 * -----------------------------------------------------------------------
16 * SPDX-FileCopyrightText: 2022-2024 Open Networking Foundation Contributors
17 * SPDX-License-Identifier: Apache-2.0
18 * -----------------------------------------------------------------------
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053019 */
Naveen Sampath04696f72022-06-13 15:19:14 +053020
21package application
22
23import (
24 "bytes"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053025 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053026 "encoding/json"
27 "errors"
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +053028 "fmt"
Naveen Sampath04696f72022-06-13 15:19:14 +053029 "net"
30 "reflect"
Naveen Sampath04696f72022-06-13 15:19:14 +053031 "sort"
32 "strconv"
33 "strings"
34 "sync"
35
36 "github.com/google/gopacket/layers"
37
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053038 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053039 "voltha-go-controller/internal/pkg/controller"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053040 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053041 "voltha-go-controller/internal/pkg/of"
42 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053043 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053044)
45
46const (
47 // DSLAttrEnabled constant
48 DSLAttrEnabled string = "ENABLED"
Tinoj Josephec742f62022-09-29 19:11:10 +053049 // DeviceAny constant
50 DeviceAny string = "DEVICE-ANY"
Akash Soni634d9bf2023-07-10 12:11:10 +053051
52 ALL_FLOWS_PROVISIONED string = "ALL_FLOWS_PROVISIONED"
53
54 NO_FLOWS_PROVISIONED string = "NO_FLOWS_PROVISIONED"
55
56 FLOWS_PROVISIONED_PARTIALLY string = "FLOWS_PROVISIONED_PARTIALLY"
57
58 SUBSCRIBER_DISABLED_IN_CONTROLLER string = "DISABLED_IN_CONTROLLER"
59
60 SUBSCRIBER_NOT_IN_CONTROLLER string = "NOT_IN_CONTROLLER"
61
62 ONT_FLOWS_PROVISION_STATE_UNUSED string = "ONT_FLOWS_PROVISION_STATE_UNUSED"
Naveen Sampath04696f72022-06-13 15:19:14 +053063)
64
65// VoltServiceCfg structure
66// Name - Uniquely identifies a service across the entire application
67// UniVlan - The VLAN of the packets entering the UNI of ONU
68// CVlan - The VLAN to transalate to/from on the PON link
69// SVlan - The outer VLAN to be used on the NNI of OLT.
vinokuma926cb3e2023-03-29 11:41:06 +053070// - In general, 4096 is used as NO VLAN for all the above
71// SVlanTpid - SVlan Tag Protocol Identifier
Naveen Sampath04696f72022-06-13 15:19:14 +053072// Pbits - Each bit of uint8 represents one p-bit. MSB is pbit 7
73// DhcpRelay - Whether it is turned on/off
74// CircuitId - The circuit id to be used with DHCP relay. Unused otherwise
75// RemoveId - Same as above
76// Port - The access port for the service. Each service has a single access
vinokuma926cb3e2023-03-29 11:41:06 +053077// port. The converse is not always true
Naveen Sampath04696f72022-06-13 15:19:14 +053078// MacLearning - If MAC learning is turned on, the MAC address learned from the
vinokuma926cb3e2023-03-29 11:41:06 +053079// the service activation is used in programming flows
Naveen Sampath04696f72022-06-13 15:19:14 +053080// MacAddress - The MAC hardware address learnt on the UNI interface
81// MacAddresses - Not yet implemented. To be used to learn more MAC addresses
82type VoltServiceCfg struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053083 FlowPushCount map[string]int64 // Tracks the number of flow install/delete failure attempts per cookie in order to throttle flow auditing
84 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
vinokuma926cb3e2023-03-29 11:41:06 +053085 Name string
Naveen Sampath04696f72022-06-13 15:19:14 +053086 CircuitID string
Naveen Sampath04696f72022-06-13 15:19:14 +053087 Port string
Sridhar Ravindrab76eb162025-07-02 01:25:10 +053088 NniPort string
Naveen Sampath04696f72022-06-13 15:19:14 +053089 UsMeterProfile string
90 DsMeterProfile string
91 AggDsMeterProfile string
92 VnetID string
93 MvlanProfileName string
94 RemoteIDType string
Naveen Sampath04696f72022-06-13 15:19:14 +053095 DataRateAttr string
vinokuma926cb3e2023-03-29 11:41:06 +053096 ServiceType string
Akash Sonief452f12024-12-12 18:20:28 +053097 Pbits []of.PbitType
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053098 RemoteID []byte
99 MacAddr net.HardwareAddr
vinokuma926cb3e2023-03-29 11:41:06 +0530100 Trigger ServiceTrigger
101 MacLearning MacLearningType
Akash Sonief452f12024-12-12 18:20:28 +0530102 ONTEtherTypeClassification int
103 SchedID int
vinokuma926cb3e2023-03-29 11:41:06 +0530104 PonPort uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530105 MinDataRateUs uint32
106 MinDataRateDs uint32
107 MaxDataRateUs uint32
108 MaxDataRateDs uint32
vinokuma926cb3e2023-03-29 11:41:06 +0530109 SVlanTpid layers.EthernetType
Akash Sonief452f12024-12-12 18:20:28 +0530110 TechProfileID uint16
vinokuma926cb3e2023-03-29 11:41:06 +0530111 UniVlan of.VlanType
112 CVlan of.VlanType
113 SVlan of.VlanType
114 UsPonCTagPriority of.PbitType
115 UsPonSTagPriority of.PbitType
116 DsPonSTagPriority of.PbitType
117 DsPonCTagPriority of.PbitType
Akash Sonief452f12024-12-12 18:20:28 +0530118 ServiceDeactivateReason SvcDeactivateReason // Mentions why the service was deactivated
vinokuma926cb3e2023-03-29 11:41:06 +0530119 VlanControl VlanControl
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530120 IsOption82Enabled bool
vinokuma926cb3e2023-03-29 11:41:06 +0530121 IgmpEnabled bool
122 McastService bool
123 AllowTransparent bool
124 EnableMulticastKPI bool
Tinoj Josephec742f62022-09-29 19:11:10 +0530125 IsActivated bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530126}
127
128// VoltServiceOper structure
129type VoltServiceOper struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530130 Metadata interface{}
131 PendingFlows map[string]bool
132 AssociatedFlows map[string]bool
133 BwAvailInfo string
Naveen Sampath04696f72022-06-13 15:19:14 +0530134 //MacLearning bool
135 //MacAddr net.HardwareAddr
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530136 Device string
137 Ipv4Addr net.IP
138 Ipv6Addr net.IP
139 ServiceLock sync.RWMutex `json:"-"`
140 UsMeterID uint32
141 DsMeterID uint32
142 AggDsMeterID uint32
143 UpdateInProgress bool
144 DeleteInProgress bool
145 DeactivateInProgress bool
146 ForceDelete bool
vinokuma926cb3e2023-03-29 11:41:06 +0530147 // Multiservice-Fix
Naveen Sampath04696f72022-06-13 15:19:14 +0530148 UsHSIAFlowsApplied bool
149 DsHSIAFlowsApplied bool
150 UsDhcpFlowsApplied bool
151 DsDhcpFlowsApplied bool
152 IgmpFlowsApplied bool
153 Icmpv6FlowsApplied bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530154}
155
156// VoltService structure
157type VoltService struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530158 Version string
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530159 VoltServiceOper
vinokuma926cb3e2023-03-29 11:41:06 +0530160 VoltServiceCfg
Naveen Sampath04696f72022-06-13 15:19:14 +0530161}
162
vinokuma926cb3e2023-03-29 11:41:06 +0530163// ServiceTrigger - Service activation trigger
Naveen Sampath04696f72022-06-13 15:19:14 +0530164type ServiceTrigger int
165
166const (
vinokuma926cb3e2023-03-29 11:41:06 +0530167 // NBActivate - Service added due to NB Action
Naveen Sampath04696f72022-06-13 15:19:14 +0530168 NBActivate ServiceTrigger = 0
vinokuma926cb3e2023-03-29 11:41:06 +0530169 // ServiceVlanUpdate - Service added due to Svlan Update
Naveen Sampath04696f72022-06-13 15:19:14 +0530170 ServiceVlanUpdate ServiceTrigger = 1
171)
172
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530173// SvcDeactivateReason - Reason for service deactivation
174type SvcDeactivateReason uint8
175
176const (
177 // Service deactivated reason - none
178 SvcDeacRsn_None SvcDeactivateReason = 0
179 // Service deactivate reason - NB
180 SvcDeacRsn_NB SvcDeactivateReason = 1
181 // Service deactivate reason - Controller
182 SvcDeacRsn_Controller SvcDeactivateReason = 2
183)
184
Naveen Sampath04696f72022-06-13 15:19:14 +0530185// AppMutexes structure
186type AppMutexes struct {
187 ServiceDataMutex sync.Mutex `json:"-"`
188 VnetMutex sync.Mutex `json:"-"`
189}
190
vinokuma926cb3e2023-03-29 11:41:06 +0530191// MigrateServiceMetadata - migrate services request metadata
Naveen Sampath04696f72022-06-13 15:19:14 +0530192type MigrateServiceMetadata struct {
193 NewVnetID string
194 RequestID string
195}
196
197// AppMutex variable
198var AppMutex AppMutexes
199
200// NewVoltService for constructor for volt service
201func NewVoltService(cfg *VoltServiceCfg) *VoltService {
202 var vs VoltService
203 vs.VoltServiceCfg = *cfg
204 vs.UsHSIAFlowsApplied = false
205 vs.DsHSIAFlowsApplied = false
206 vs.DeleteInProgress = false
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530207 vs.DeactivateInProgress = false
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530208 vs.ServiceDeactivateReason = SvcDeacRsn_None
Naveen Sampath04696f72022-06-13 15:19:14 +0530209 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530210
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530211 vs.IsOption82Enabled = cfg.IsOption82Enabled
Naveen Sampath04696f72022-06-13 15:19:14 +0530212 vs.MacAddr = cfg.MacAddr
213 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
214 vs.Ipv6Addr = net.ParseIP("::")
215 vs.PendingFlows = make(map[string]bool)
216 vs.AssociatedFlows = make(map[string]bool)
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530217 vs.FlowPushCount = make(map[string]int64)
Naveen Sampath04696f72022-06-13 15:19:14 +0530218 return &vs
219}
220
221// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530222func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530223 vs.ServiceLock.RLock()
224 defer vs.ServiceLock.RUnlock()
225
226 if vs.DeleteInProgress {
227 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
228 return
229 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530230 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530231}
232
vinokuma926cb3e2023-03-29 11:41:06 +0530233// ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530234func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530235 b, err := json.Marshal(vs)
236
237 if err != nil {
238 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
239 return
240 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530241 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530242 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
243 }
244}
245
246// isDataRateAttrPresent to check if data attribute is present
247func (vs *VoltService) isDataRateAttrPresent() bool {
248 return vs.DataRateAttr == DSLAttrEnabled
249}
250
251// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530252func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530253 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
vinokuma926cb3e2023-03-29 11:41:06 +0530254 // TODO - Need to understand and delete the second call
255 // Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530256 _ = db.DelService(cntx, vs.Name)
257 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530258}
259
260// MatchesVlans find the service that matches the VLANs. In this case it is
261// purely based on CVLAN. The CVLAN can sufficiently be used to
262// match a service
263func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
264 if len(vlans) != 1 {
265 return false
266 }
267
268 if vlans[0] == vs.CVlan {
269 return true
270 }
271 return false
272}
273
274// MatchesPbits allows matching a service to a pbit. This is used
275// to search for a service matching the pbits, typically to identify
276// attributes for other flows such as DHCP, IGMP, etc.
277func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
278 for _, pbit := range pbits {
279 for _, pb := range vs.Pbits {
280 if pb == pbit {
281 return true
282 }
283 }
284 }
285 return false
286}
287
288// IsPbitExist allows matching a service to a pbit. This is used
289// to search for a service matching the pbit
290func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530291 logger.Debugw(ctx, "Request for IsPbitExist", log.Fields{"pbit": pbit})
Naveen Sampath04696f72022-06-13 15:19:14 +0530292 for _, pb := range vs.Pbits {
293 if pb == pbit {
294 return true
295 }
296 }
297 return false
298}
299
300// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530301func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530302 logger.Debugw(ctx, "Add US & DS HSIA Flows for the service", log.Fields{"ServiceName": vs.Name})
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530303 if err := vs.AddUsHsiaFlows(cntx, false); err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530304 logger.Errorw(ctx, "Error adding US HSIA Flows", log.Fields{"Service": vs.Name, "Port": vs.Port, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530305 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530306 vs.triggerServiceFailureInd(statusCode, statusMessage)
307 }
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530308 if err := vs.AddDsHsiaFlows(cntx, false); err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530309 logger.Errorw(ctx, "Error adding DS HSIA Flows", log.Fields{"Service": vs.Name, "Port": vs.Port, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530310 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530311 vs.triggerServiceFailureInd(statusCode, statusMessage)
312 }
313}
314
vinokuma926cb3e2023-03-29 11:41:06 +0530315// DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530316func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530317 logger.Debugw(ctx, "Delete US & DS HSIA Flows for the service", log.Fields{"ServiceName": vs.Name})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530318 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530319 logger.Errorw(ctx, "Error deleting US HSIA Flows", log.Fields{"Service": vs.Name, "Port": vs.Port, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530320 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530321 vs.triggerServiceFailureInd(statusCode, statusMessage)
322 }
323
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530324 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530325 logger.Errorw(ctx, "Error deleting DS HSIA Flows", log.Fields{"Service": vs.Name, "Port": vs.Port, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530326 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530327 vs.triggerServiceFailureInd(statusCode, statusMessage)
328 }
329}
330
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530331func (vs *VoltService) AddMeterToDevice(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530332 logger.Debugw(ctx, "Add Meter To Device for the service", log.Fields{"ServiceName": vs.Name})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530333 if vs.DeleteInProgress || vs.UpdateInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530334 logger.Warnw(ctx, "Ignoring Meter Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530335 }
336 va := GetApplication()
337 logger.Infow(ctx, "Configuring Meters for FTTB", log.Fields{"ServiceName": vs.Name})
338 device, err := va.GetDeviceFromPort(vs.Port)
339 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530340 return fmt.Errorf("Error during Getting Device from Port %s for service %s : %w", vs.Port, vs.Name, err)
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530341 } else if device.State != controller.DeviceStateUP {
342 logger.Warnw(ctx, "Device state Down. Ignoring Meter Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
343 return nil
344 }
345 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
346 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
347 return nil
348}
349
Naveen Sampath04696f72022-06-13 15:19:14 +0530350// AddUsHsiaFlows - Add US HSIA Flows for the service
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530351func (vs *VoltService) AddUsHsiaFlows(cntx context.Context, skipFlowPushToVoltha bool) error {
Akash Sonief452f12024-12-12 18:20:28 +0530352 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Port": vs.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530353 if vs.DeleteInProgress || vs.UpdateInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530354 logger.Warnw(ctx, "Ignoring US HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530355 return nil
356 }
357
358 va := GetApplication()
Naveen Sampath04696f72022-06-13 15:19:14 +0530359 if !vs.UsHSIAFlowsApplied || vgcRebooted {
360 device, err := va.GetDeviceFromPort(vs.Port)
361 if err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530362 logger.Errorw(ctx, "Error Getting Device for Service and Port", log.Fields{"Service": vs.Name, "Port": vs.Port, "Error": err})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530363 return fmt.Errorf("Error Getting Device for Service %s and Port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530364 } else if device.State != controller.DeviceStateUP {
365 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
366 return nil
367 }
368
369 vs.Device = device.Name
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530370 /* In case of DPU_MGMT_TRAFFIC the meters will be configured before US flow creation*/
vinokuma926cb3e2023-03-29 11:41:06 +0530371 if vs.ServiceType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530372 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
373 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
374 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530375 pBits := vs.Pbits
376
vinokuma926cb3e2023-03-29 11:41:06 +0530377 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530378 if len(vs.Pbits) == 0 {
379 pBits = append(pBits, PbitMatchNone)
380 }
381 for _, pbits := range pBits {
382 usflows, err := vs.BuildUsHsiaFlows(pbits)
383 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530384 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530385 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530386 vs.triggerServiceFailureInd(statusCode, statusMessage)
387 continue
388 }
389 usflows.MigrateCookie = vgcRebooted
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530390 if err := vs.AddFlows(cntx, device, usflows, skipFlowPushToVoltha); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530391 logger.Errorw(ctx, "Error adding HSIA US flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530392 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530393 vs.triggerServiceFailureInd(statusCode, statusMessage)
394 }
395 }
396 vs.UsHSIAFlowsApplied = true
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530397 logger.Debugw(ctx, "Pushed US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530398 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530399 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530400 return nil
401}
402
403// AddDsHsiaFlows - Add DS HSIA Flows for the service
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530404func (vs *VoltService) AddDsHsiaFlows(cntx context.Context, skipFlowPushToVoltha bool) error {
Akash Sonief452f12024-12-12 18:20:28 +0530405 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Port": vs.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530406 if vs.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530407 logger.Warnw(ctx, "Ignoring DS HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530408 return nil
409 }
410
411 va := GetApplication()
Naveen Sampath04696f72022-06-13 15:19:14 +0530412 if !vs.DsHSIAFlowsApplied || vgcRebooted {
413 device, err := va.GetDeviceFromPort(vs.Port)
414 if err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530415 logger.Errorw(ctx, "Error Getting Device for Service and Port", log.Fields{"Service": vs.Name, "Port": vs.Port, "Error": err})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530416 return fmt.Errorf("Error Getting Device for Service %s and Port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530417 } else if device.State != controller.DeviceStateUP {
418 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
419 return nil
420 }
421
422 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530423
424 //If no pbits configured for service, hence add PbitNone for flows
425 if len(vs.DsRemarkPbitsMap) == 0 {
426 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
427 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530428 return fmt.Errorf("Error Building HSIA DS flows for Service %s and Port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530429 }
430 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530431 if err = vs.AddFlows(cntx, device, dsflows, skipFlowPushToVoltha); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530432 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err})
mgoudabb017dc2025-10-29 19:53:34 +0530433 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530434 vs.triggerServiceFailureInd(statusCode, statusMessage)
435 }
436 } else {
437 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
438 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
439 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
440 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530441 return fmt.Errorf("Error Building HSIA DS flows for Service %s and Port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530442 }
443 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
444 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530445 if err := vs.AddFlows(cntx, device, dsflows, skipFlowPushToVoltha); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530446 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err})
mgoudabb017dc2025-10-29 19:53:34 +0530447 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530448 vs.triggerServiceFailureInd(statusCode, statusMessage)
449 }
450 } else {
451 for matchPbit := range vs.DsRemarkPbitsMap {
452 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
453 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530454 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530455 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530456 vs.triggerServiceFailureInd(statusCode, statusMessage)
457 continue
458 }
459 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +0530460 if err := vs.AddFlows(cntx, device, dsflows, skipFlowPushToVoltha); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530461 logger.Errorw(ctx, "Failed to Add HSIA DS flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err})
mgoudabb017dc2025-10-29 19:53:34 +0530462 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530463 vs.triggerServiceFailureInd(statusCode, statusMessage)
464 }
465 }
466 }
467 }
468 vs.DsHSIAFlowsApplied = true
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530469 logger.Debugw(ctx, "Pushed DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530470 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530471 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530472 return nil
473}
474
475// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530476func (vs *VoltService) DelUsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530477 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530478 if vs.UsHSIAFlowsApplied || vgcRebooted {
479 device, err := GetApplication().GetDeviceFromPort(vs.Port)
480 if err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530481 logger.Errorw(ctx, "Error Getting Device for Servic and Port", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530482 return fmt.Errorf("Error Getting Device for Service %s and Port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530483 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530484 pBits := vs.Pbits
485
vinokuma926cb3e2023-03-29 11:41:06 +0530486 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530487 if len(vs.Pbits) == 0 {
488 pBits = append(pBits, PbitMatchNone)
489 }
490 for _, pbits := range pBits {
491 usflows, err := vs.BuildUsHsiaFlows(pbits)
492 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530493 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530494 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530495 vs.triggerServiceFailureInd(statusCode, statusMessage)
496 continue
497 }
498 usflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530499 if err = vs.DelFlows(cntx, device, usflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530500 logger.Errorw(ctx, "Error Deleting HSIA US flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530501 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530502 vs.triggerServiceFailureInd(statusCode, statusMessage)
503 }
504 }
505 vs.UsHSIAFlowsApplied = false
506 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530507 logger.Debugw(ctx, "Deleted HSIA US flows from DB successfully", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530508 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530509 return nil
510}
511
512// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530513func (vs *VoltService) DelDsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530514 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530515 if vs.DsHSIAFlowsApplied || vgcRebooted {
516 device, err := GetApplication().GetDeviceFromPort(vs.Port)
517 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530518 return fmt.Errorf("Error Getting Device for Service %s and Port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530519 }
520
Naveen Sampath04696f72022-06-13 15:19:14 +0530521 var matchPbit int
vinokuma926cb3e2023-03-29 11:41:06 +0530522 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530523 if len(vs.DsRemarkPbitsMap) == 0 {
524 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
525 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530526 return fmt.Errorf("Error Building HSIA DS flows for Service %s and Port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530527 }
528 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530529 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530530 logger.Errorw(ctx, "Error Deleting HSIA DS flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530531 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530532 vs.triggerServiceFailureInd(statusCode, statusMessage)
533 }
534 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
535 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
536 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530537 return fmt.Errorf("Error Building HSIA DS flows for Service %s and Port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530538 }
539 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530540 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530541 logger.Errorw(ctx, "Error Deleting HSIA DS flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530542 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530543 vs.triggerServiceFailureInd(statusCode, statusMessage)
544 }
545 } else {
546 for matchPbit = range vs.DsRemarkPbitsMap {
547 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
548 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530549 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530550 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530551 vs.triggerServiceFailureInd(statusCode, statusMessage)
552 continue
553 }
554 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530555 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530556 logger.Errorw(ctx, "Error Deleting HSIA DS flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
mgoudabb017dc2025-10-29 19:53:34 +0530557 statusCode, statusMessage := errorCodes.GetErrorInfo(err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530558 vs.triggerServiceFailureInd(statusCode, statusMessage)
559 }
560 }
561 }
562 vs.DsHSIAFlowsApplied = false
563 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530564 logger.Debugw(ctx, "Deleted HSIA DS flows from DB successfully", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530565 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530566 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530567 return nil
568}
569
570// BuildDsHsiaFlows build the DS HSIA flows
571// Called for add/delete HSIA flows
572func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530573 logger.Debugw(ctx, "Building DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530574 flow := &of.VoltFlow{}
575 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
576
Naveen Sampath04696f72022-06-13 15:19:14 +0530577 device, err := GetApplication().GetDeviceFromPort(vs.Port)
578 if err != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530579 return nil, fmt.Errorf("error getting device for service %s and port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530580 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530581 // inport will be obtained from nniPort of service else we'll use the default nni port
582 var inport uint32
583 // Get the out and in ports for the flows
584 if vs.NniPort != "" {
585 if nniPortID := device.GetPortIDFromPortName(vs.NniPort); nniPortID != 0 {
586 inport = nniPortID
587 } else {
588 return nil, fmt.Errorf("error getting portID for NNI port %s of Service %s", vs.NniPort, vs.Name)
589 }
590 } else {
591 nniPort, err1 := GetApplication().GetNniPort(device.Name)
592 if err != nil {
593 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err1})
594 return nil, err1
595 }
akashreddykeb418f12025-10-30 10:58:42 +0530596 inport, _ = GetApplication().GetDevicePortID(device.Name, nniPort)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530597 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530598 outport, _ := GetApplication().GetPortID(vs.Port)
599 // PortName and PortID to be used for validation of port before flow pushing
600 flow.PortID = outport
601 flow.PortName = vs.Port
602 allowTransparent := 0
603 if vs.AllowTransparent {
604 allowTransparent = 1
605 }
606
607 // initialized actnPbit to 0 for cookie genration backward compatibility.
608 var actnPbit of.PbitType
609 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
610
611 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530612 // | 12-bit cvlan/UniVlan | 4 bits action pbit | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
Naveen Sampath04696f72022-06-13 15:19:14 +0530613 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
614 cookie = cookie | of.DsFlowMask
615 cookie = cookie + (valToShift << 4) + uint64(pbits)
616 return cookie
617 }
618
619 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
620 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530621 return nil, fmt.Errorf("DS HSIA flow push failed: Invalid SvlanTpid for Service %s and SvlanTpid %s : %w", vs.SVlanTpid, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530622 }
623
624 // Add Table-0 flow that deals with the outer VLAN in pOLT
625 {
626 subflow1 := of.NewVoltSubFlow()
627 subflow1.SetTableID(0)
628 subflow1.SetGoToTable(1)
629 subflow1.SetInPort(inport)
630
631 if pbits != PbitMatchNone {
632 subflow1.SetMatchPbit(pbits)
633 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530634 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
635 subflow1.SetPcp(of.PbitType(remarkPbit))
636 // match & action pbits are different, set remark-pbit action
637 actnPbit = of.PbitType(remarkPbit)
638 // mask remark p-bit to 4bits
639 actnPbit = actnPbit & 0x0F
640 }
641
642 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
643 return nil, err
644 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530645 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530646 if NonZeroMacAddress(vs.MacAddr) {
647 subflow1.SetMatchDstMac(vs.MacAddr)
648 }
649 subflow1.Priority = of.HsiaFlowPriority
650 subflow1.SetMeterID(vs.DsMeterID)
651
652 /* WriteMetaData 8 Byte(uint64) usage:
653 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
654 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
655 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530656 if vs.ServiceType == FttbSubscriberTraffic {
657 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
658 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530659 subflow1.SetWriteMetadata(metadata)
660
661 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
662 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
663 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
664 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
665
666 //TODO-COMM:
667 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
668 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
669 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
670 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
671
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530672 if vs.ServiceType != FttbSubscriberTraffic {
673 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
674 subflow1.SetTableMetadata(metadata)
675 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530676 // TODO - We are using cookie as key and must come up with better cookie
677 // allocation algorithm
678 /**
679 * Cokies may clash when -
680 * on same uni-port we have two sub-service
681 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
682 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
683 * However, this p-bit re-use will not be allowed by sub-mgr.
684 */
685 if vs.VlanControl == OLTCVlanOLTSVlan {
686 /**
687 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
688 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
689 * use old cookie.
690 */
691 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
692 if vgcRebooted {
693 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
694 }
695 } else {
696 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
697 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
698 }
699
700 flow.SubFlows[subflow1.Cookie] = subflow1
701 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
702 "subflow": subflow1})
703 }
704
vinokuma926cb3e2023-03-29 11:41:06 +0530705 // Add Table-1 flow that deals with inner VLAN at the ONU
Naveen Sampath04696f72022-06-13 15:19:14 +0530706 {
707 subflow2 := of.NewVoltSubFlow()
708 subflow2.SetTableID(1)
709 subflow2.SetInPort(inport)
710 if NonZeroMacAddress(vs.MacAddr) {
711 subflow2.SetMatchDstMac(vs.MacAddr)
712 }
713
714 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
715 return nil, err
716 }
717 if pbits != PbitMatchNone {
718 subflow2.SetMatchPbit(pbits)
719 }
720
721 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
722 subflow2.SetPcp(of.PbitType(remarkPbit))
723 }
724
725 subflow2.SetOutPort(outport)
726 subflow2.SetMeterID(vs.DsMeterID)
727
728 // refer Table-0 flow generation for byte information
729 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530730 if vs.ServiceType == FttbSubscriberTraffic {
731 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
732 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530733 subflow2.SetWriteMetadata(metadata)
734
735 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
736 if util.IsNniPort(inport) {
737 metadata = uint64(outport)
738 } else {
739 // refer Table-0 flow generation for byte information
740 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
741 }
742 subflow2.SetTableMetadata(metadata)
743 // Setting of Cookie - TODO - Improve the allocation algorithm
744 if vs.VlanControl == OLTCVlanOLTSVlan {
745 /**
746 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
747 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
748 * use old cookie.
749 */
750 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
751 if vgcRebooted {
752 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
753 }
754 } else {
755 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
756 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
757 }
758
759 subflow2.Priority = of.HsiaFlowPriority
760 flow.SubFlows[subflow2.Cookie] = subflow2
761 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
762 "subflow": subflow2})
763 }
764
765 return flow, nil
766}
767
768// BuildUsHsiaFlows build the US HSIA flows
769// Called for add/delete HSIA flows
770func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Akash Sonief452f12024-12-12 18:20:28 +0530771 logger.Debugw(ctx, "Building US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Port": vs.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +0530772 flow := &of.VoltFlow{}
773 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
774
Naveen Sampath04696f72022-06-13 15:19:14 +0530775 device, err := GetApplication().GetDeviceFromPort(vs.Port)
776 if err != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530777 return nil, fmt.Errorf("error getting device for service %s and port %s : %w", vs.Name, vs.Port, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530778 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530779 // outport will be obtained from nniPort of service else we'll use the default nni port
780 var outport uint32
781 // Get the out and in ports for the flows
782 if vs.NniPort != "" {
783 if nniPortID := device.GetPortIDFromPortName(vs.NniPort); nniPortID != 0 {
784 outport = nniPortID
785 } else {
786 return nil, fmt.Errorf("error getting portID for NNI port %s of Service %s : %w", vs.NniPort, vs.Name, err)
787 }
788 } else {
789 nniPort, err := GetApplication().GetNniPort(device.Name)
790 if err != nil {
791 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
792 return nil, err
793 }
akashreddykeb418f12025-10-30 10:58:42 +0530794 outport, _ = GetApplication().GetDevicePortID(device.Name, nniPort)
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530795 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530796 inport, _ := GetApplication().GetPortID(vs.Port)
797 // PortName and PortID to be used for validation of port before flow pushing
798 flow.PortID = inport
799 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530800
801 // Add Table-0 flow that deals with the inner VLAN in ONU
802 {
803 subflow1 := of.NewVoltSubFlow()
804 subflow1.SetTableID(0)
805 subflow1.SetGoToTable(1)
806 subflow1.SetInPort(inport)
807
mgoudabb017dc2025-10-29 19:53:34 +0530808 switch vs.ServiceType {
809 case DpuMgmtTraffic:
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530810 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
811 subflow1.SetPcp(vs.UsPonSTagPriority)
mgoudabb017dc2025-10-29 19:53:34 +0530812 case DpuAncpTraffic:
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530813 subflow1.SetPcp(vs.UsPonSTagPriority)
814 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530815 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
816 return nil, err
817 }
818 subflow1.SetMeterID(vs.UsMeterID)
819
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530820 /* WriteMetaData 8 Byte(uint64) usage:
821 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
822 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
823 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
824 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530825 if vs.ServiceType == FttbSubscriberTraffic {
826 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
827 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530828 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530829
Naveen Sampath04696f72022-06-13 15:19:14 +0530830 if vs.VlanControl == OLTCVlanOLTSVlan {
831 /**
832 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
833 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
834 * use old cookie.
835 */
836 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
837 if vgcRebooted {
838 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
839 }
840 } else {
841 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
842 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
843 }
844 subflow1.Priority = of.HsiaFlowPriority
845 flow.SubFlows[subflow1.Cookie] = subflow1
846 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
847 }
848
vinokuma926cb3e2023-03-29 11:41:06 +0530849 // Add Table-1 flow that deals with the outer vlan in pOLT
Naveen Sampath04696f72022-06-13 15:19:14 +0530850 {
851 subflow2 := of.NewVoltSubFlow()
852 subflow2.SetTableID(1)
853 subflow2.SetInPort(inport)
854
Naveen Sampath04696f72022-06-13 15:19:14 +0530855 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
856 return nil, err
857 }
vinokuma926cb3e2023-03-29 11:41:06 +0530858 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530859 subflow2.SetMatchSrcMac(vs.MacAddr)
860 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530861 subflow2.SetInPort(inport)
862 subflow2.SetOutPort(outport)
863 subflow2.SetMeterID(vs.UsMeterID)
864
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530865 // refer Table-0 flow generation for byte information
866 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530867 if vs.ServiceType == FttbSubscriberTraffic {
868 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
869 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530870 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530871
Naveen Sampath04696f72022-06-13 15:19:14 +0530872 if vs.VlanControl == OLTCVlanOLTSVlan {
873 /**
874 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
875 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
876 * use old cookie.
877 */
878 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
879 if vgcRebooted {
880 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
881 }
882 } else {
883 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
884 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
885 }
886 subflow2.Priority = of.HsiaFlowPriority
887
888 flow.SubFlows[subflow2.Cookie] = subflow2
889 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
890 }
891
892 return flow, nil
893}
894
895func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530896 // | 12-bit cvlan/UniVlan | 4 bits empty | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530897 logger.Debugw(ctx, "Generate US Cookie", log.Fields{"Vlan": vlan, "ValToShift": vlan, "Inport": inport, "Pbits": pbits})
Naveen Sampath04696f72022-06-13 15:19:14 +0530898 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
899 cookie = cookie | of.UsFlowMask
900 cookie = cookie + (valToShift << 4) + uint64(pbits)
901 return cookie
902}
903
904// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
905// based on different Vlan Controls
906func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530907 logger.Debugw(ctx, "Set US Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530908 switch vs.VlanControl {
909 case None:
910 flow.SetMatchVlan(vs.SVlan)
911 case ONUCVlanOLTSVlan:
912 flow.SetMatchVlan(vs.CVlan)
913 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
914 case OLTCVlanOLTSVlan:
915 flow.SetMatchVlan(vs.UniVlan)
916 flow.SetSetVlan(vs.CVlan)
917 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
918 case ONUCVlan:
919 flow.SetMatchVlan(vs.SVlan)
920 case OLTSVlan:
921 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
922 flow.SetMatchVlan(vs.UniVlan)
923 flow.SetSetVlan(vs.SVlan)
924 } else if vs.UniVlan != of.VlanNone {
925 flow.SetMatchVlan(vs.UniVlan)
926 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
927 } else {
928 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
929 }
930 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530931 err := errorCodes.ErrInvalidParamInRequest
932 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530933 }
934 return nil
935}
936
937// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
938// based on different Vlan Controls
939func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530940 logger.Debugw(ctx, "Set DS Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530941 switch vs.VlanControl {
942 case None:
943 flow.SetMatchVlan(vs.SVlan)
944 case ONUCVlanOLTSVlan:
945 flow.SetMatchVlan(vs.SVlan)
946 flow.SetPopVlan()
947 case OLTCVlanOLTSVlan:
948 flow.SetMatchVlan(vs.SVlan)
949 flow.SetPopVlan()
950 flow.SetSetVlan(vs.UniVlan)
951 case ONUCVlan:
952 flow.SetMatchVlan(vs.SVlan)
953 case OLTSVlan:
954 flow.SetMatchVlan(vs.SVlan)
955 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
956 flow.SetSetVlan(vs.UniVlan)
957 } else {
958 flow.SetPopVlan()
959 }
960 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530961 err := errorCodes.ErrInvalidParamInRequest
962 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530963 }
964 return nil
965}
966
967// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
968// based on different Vlan Controls
969func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530970 logger.Debugw(ctx, "Set US Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530971 switch vs.VlanControl {
972 case None:
973 flow.SetMatchVlan(vs.SVlan)
974 case ONUCVlanOLTSVlan:
975 if vs.UniVlan != of.VlanNone {
976 flow.SetMatchVlan(vs.UniVlan)
977 flow.SetSetVlan(vs.CVlan)
978 } else {
979 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
980 }
981 case OLTCVlanOLTSVlan:
982 flow.SetMatchVlan(vs.UniVlan)
983 case ONUCVlan:
984 if vs.UniVlan != of.VlanNone {
985 flow.SetMatchVlan(vs.UniVlan)
986 flow.SetSetVlan(vs.SVlan)
987 } else {
988 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
989 }
990 case OLTSVlan:
991 flow.SetMatchVlan(vs.UniVlan)
992 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530993 err := errorCodes.ErrInvalidParamInRequest
994 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530995 }
996 return nil
997}
998
999// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
1000// based on different Vlan Controls
1001func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301002 logger.Debugw(ctx, "Set DS Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05301003 switch vs.VlanControl {
1004 case None:
1005 flow.SetMatchVlan(vs.SVlan)
1006 case ONUCVlanOLTSVlan:
1007 flow.SetMatchVlan(vs.CVlan)
1008 if vs.UniVlan != of.VlanNone {
1009 flow.SetSetVlan(vs.UniVlan)
1010 } else {
1011 flow.SetPopVlan()
1012 }
1013 case OLTCVlanOLTSVlan:
1014 flow.SetMatchVlan(vs.UniVlan)
1015 case ONUCVlan:
1016 flow.SetMatchVlan(vs.SVlan)
1017 if vs.UniVlan != of.VlanNone {
1018 flow.SetSetVlan(vs.UniVlan)
1019 } else {
1020 flow.SetPopVlan()
1021 }
1022 case OLTSVlan:
1023 flow.SetMatchVlan(vs.UniVlan)
1024 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301025 err := errorCodes.ErrInvalidParamInRequest
1026 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301027 }
1028 return nil
1029}
1030
1031// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301032func (vs *VoltService) SvcUpInd(cntx context.Context) {
1033 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301034}
1035
1036// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301037func (vs *VoltService) SvcDownInd(cntx context.Context) {
1038 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301039}
1040
1041// SetIpv4Addr to set ipv4 address
1042func (vs *VoltService) SetIpv4Addr(addr net.IP) {
1043 vs.Ipv4Addr = addr
1044}
1045
1046// SetIpv6Addr to set ipv6 address
1047func (vs *VoltService) SetIpv6Addr(addr net.IP) {
1048 vs.Ipv6Addr = addr
1049}
1050
1051// SetMacAddr to set mac address
1052func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
1053 vs.MacAddr = addr
1054}
1055
1056// ----------------------------------------------
1057// VOLT Application - Related to services
1058// ---------------------------------------------
1059// ---------------------------------------------------------------
1060// Service CRUD functions. These are exposed to the overall binary
1061// to be invoked from the point where the CRUD operations are received
1062// from the external entities
1063
1064// AddService : A service in the context of VOLT is a subscriber or service of a
1065// subscriber which is uniquely identified by a combination of MAC
1066// address, VLAN tags, 802.1p bits. However, in the context of the
1067// current implementation, a service is an entity that is identified by a
1068// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
1069// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301070func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301071 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
Naveen Sampath04696f72022-06-13 15:19:14 +05301072 var mmUs, mmDs *VoltMeter
1073 var err error
1074
vinokuma926cb3e2023-03-29 11:41:06 +05301075 // Take the Device lock only in case of NB add request.
Naveen Sampath04696f72022-06-13 15:19:14 +05301076 // Allow internal adds since internal add happen only under
1077 // 1. Restore Service from DB
1078 // 2. Service Migration
1079 if oper == nil {
1080 if svc := va.GetService(cfg.Name); svc != nil {
1081 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301082 return errors.New("service already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301083 }
1084 }
1085
Naveen Sampath04696f72022-06-13 15:19:14 +05301086 // Service doesn't exist. So create it and add to the port
1087 vs := NewVoltService(&cfg)
1088 if oper != nil {
1089 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1090 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1091 vs.Ipv4Addr = oper.Ipv4Addr
1092 vs.Ipv6Addr = oper.Ipv6Addr
1093 vs.MacLearning = cfg.MacLearning
1094 vs.PendingFlows = oper.PendingFlows
1095 vs.AssociatedFlows = oper.AssociatedFlows
1096 vs.DeleteInProgress = oper.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301097 vs.DeactivateInProgress = oper.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301098 vs.BwAvailInfo = oper.BwAvailInfo
1099 vs.Device = oper.Device
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301100 vs.ServiceDeactivateReason = cfg.ServiceDeactivateReason
Naveen Sampath04696f72022-06-13 15:19:14 +05301101 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301102 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301103 sort.Slice(vs.Pbits, func(i, j int) bool {
1104 return vs.Pbits[i] > vs.Pbits[j]
1105 })
Akash Sonief452f12024-12-12 18:20:28 +05301106 logger.Debugw(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
Naveen Sampath04696f72022-06-13 15:19:14 +05301107 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301108 logger.Debugw(ctx, "VolthService...", log.Fields{"vs": vs})
Naveen Sampath04696f72022-06-13 15:19:14 +05301109
1110 // The bandwidth and shaper profile combined into meter
1111 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1112 vs.DsMeterID = mmDs.ID
1113 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301114 return errors.New("downStream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301115 }
1116
1117 // The aggregated downstream meter profile
1118 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1119 // vs.AggDsMeterID = mmAg.ID
1120 // } else {
1121 // return errors.New("Aggregated meter profile not found")
1122 // }
1123
1124 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1125 // vs.UsMeterID = mmAg.ID
1126 // } else {
1127 // The bandwidth and shaper profile combined into meter
1128 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1129 vs.UsMeterID = mmUs.ID
1130 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301131 return errors.New("upstream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301132 }
1133 //}
1134
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +05301135 // The global ServiceDataMutex lock is redundant here and
1136 // can be safely removed to avoid unnecessary contention and improve performance.
1137 // AppMutex.ServiceDataMutex.Lock()
1138 // defer AppMutex.ServiceDataMutex.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301139
1140 // Add the service to the VNET
1141 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1142 if vnet != nil {
1143 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1144 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301145 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301146 vpv.VpvLock.Unlock()
1147 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301148 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301149 }
1150 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301151 logger.Warnw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
1152 return errors.New("vnet doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301153 }
1154
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301155 // If the device is already discovered, update the device name in service
1156 d, err := va.GetDeviceFromPort(vs.Port)
1157 if err == nil {
1158 vs.Device = d.Name
1159 }
1160
Naveen Sampath04696f72022-06-13 15:19:14 +05301161 vs.Version = database.PresentVersionMap[database.ServicePath]
1162 // Add the service to the volt application
1163 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301164 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301165
1166 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301167 if !vs.UsHSIAFlowsApplied {
1168 vs.triggerServiceInProgressInd()
1169 }
1170
vinokuma926cb3e2023-03-29 11:41:06 +05301171 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301172 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301173 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301174 if mmUs != nil {
1175 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301176 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301177 }
1178 //mmAg.AssociatedServices++
1179 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301180 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301181 }
1182
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301183 logger.Debugw(ctx, "Added Service to DB", log.Fields{"Name": vs.Name, "Port": (vs.Port), "ML": vs.MacLearning})
Naveen Sampath04696f72022-06-13 15:19:14 +05301184 return nil
1185}
1186
vinokuma926cb3e2023-03-29 11:41:06 +05301187// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301188// Added for DT/TT usecase with sadis replica interface
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301189func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) error {
Akash Sonief452f12024-12-12 18:20:28 +05301190 logger.Debugw(ctx, "Delete Service With provided Prefix", log.Fields{"Prefix": prefix})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301191 var isServiceExist bool
Naveen Sampath04696f72022-06-13 15:19:14 +05301192 va.ServiceByName.Range(func(key, value interface{}) bool {
1193 srvName := key.(string)
1194 vs := value.(*VoltService)
1195 if strings.Contains(srvName, prefix) {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301196 isServiceExist = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301197 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301198
1199 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1200 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1201 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1202
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301203 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301204 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1205 }
1206 }
1207 return true
1208 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301209
1210 if !isServiceExist {
1211 return errorCodes.ErrServiceNotFound
1212 }
1213 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301214}
1215
1216// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301217func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301218 AppMutex.ServiceDataMutex.Lock()
1219 defer AppMutex.ServiceDataMutex.Unlock()
1220
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301221 logger.Infow(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
Naveen Sampath04696f72022-06-13 15:19:14 +05301222 var noFlowsPresent bool
1223
1224 vsIntf, ok := va.ServiceByName.Load(name)
1225 if !ok {
1226 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1227 return
1228 }
1229 vs := vsIntf.(*VoltService)
1230 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1231 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301232 logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301233 return
1234 }
1235
vinokuma926cb3e2023-03-29 11:41:06 +05301236 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301237 vs.DeleteInProgress = true
1238 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301239 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301240
Akash Sonief452f12024-12-12 18:20:28 +05301241 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301242 if len(vs.AssociatedFlows) == 0 {
1243 noFlowsPresent = true
1244 }
Akash Sonief452f12024-12-12 18:20:28 +05301245 vs.ServiceLock.RUnlock()
1246
Naveen Sampath04696f72022-06-13 15:19:14 +05301247 vpv.VpvLock.Lock()
1248 defer vpv.VpvLock.Unlock()
1249
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301250 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301251
1252 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301253 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301254 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301255 logger.Debugw(ctx, "Delete Service from VPV", log.Fields{"VPV_Port": vpv.Port, "VPV_SVlan": vpv.SVlan, "VPV_CVlan": vpv.CVlan, "VPV_UniVlan": vpv.UniVlan, "ServiceName": name})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301256 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301257 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301258 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301259 }
1260
1261 // Delete the service immediately in case of Force Delete
1262 // This will be enabled when profile reconciliation happens after restore
1263 // of backedup data
1264 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301265 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301266 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301267 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301268 }
1269
Naveen Sampath04696f72022-06-13 15:19:14 +05301270 if nil != newSvc {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301271 logger.Debugw(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1272 logger.Debugw(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
Naveen Sampath04696f72022-06-13 15:19:14 +05301273 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301274
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301275 logger.Debugw(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301276
1277 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1278 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301279 if aggMeter.AssociatedServices > 0 {
1280 aggMeter.AssociatedServices--
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301281 logger.Debugw(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
vinokuma926cb3e2023-03-29 11:41:06 +05301282 va.UpdateMeterProf(cntx, *aggMeter)
1283 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301284 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301285 }
1286 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301287 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1288 if dsMeter.AssociatedServices > 0 {
1289 dsMeter.AssociatedServices--
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301290 logger.Debugw(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
vinokuma926cb3e2023-03-29 11:41:06 +05301291 va.UpdateMeterProf(cntx, *dsMeter)
1292 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301293 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301294 }
1295 if vs.AggDsMeterID != vs.UsMeterID {
1296 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301297 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1298 if usMeter.AssociatedServices > 0 {
1299 usMeter.AssociatedServices--
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301300 logger.Debugw(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
vinokuma926cb3e2023-03-29 11:41:06 +05301301 va.UpdateMeterProf(cntx, *usMeter)
1302 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301303 }
1304 }
1305 }
1306
1307 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301308 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301309 }
1310
vinokuma926cb3e2023-03-29 11:41:06 +05301311 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301312 va.ServiceCounters.Delete(name)
1313 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301314 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301315 }
1316}
1317
vinokuma926cb3e2023-03-29 11:41:06 +05301318// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301319// Triggers flow addition after registering for flow indication event
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +05301320func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow, skipFlowPushToVoltha bool) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301321 // Using locks instead of concurrent map for PendingFlows to avoid
1322 // race condition during flow response indication processing
1323 vs.ServiceLock.Lock()
1324 defer vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301325 logger.Debugw(ctx, "Adds the flow to the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301326
1327 for cookie := range flow.SubFlows {
1328 cookie := strconv.FormatUint(cookie, 10)
1329 fe := &FlowEvent{
1330 eType: EventTypeServiceFlowAdded,
1331 device: device.Name,
1332 cookie: cookie,
1333 eventData: vs,
1334 }
1335 device.RegisterFlowAddEvent(cookie, fe)
1336 vs.PendingFlows[cookie] = true
1337 }
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +05301338 return controller.GetController().AddFlows(cntx, vs.Port, device.Name, flow, skipFlowPushToVoltha)
Naveen Sampath04696f72022-06-13 15:19:14 +05301339}
1340
vinokuma926cb3e2023-03-29 11:41:06 +05301341// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301342// If no more pending flows, HSIA indication wil be triggered
Akash Sonief452f12024-12-12 18:20:28 +05301343func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301344 logger.Debugw(ctx, "Flow Add Success Notification", log.Fields{"Cookie": cookie, "bwAvailInfo": bwAvailInfo, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301345 if vs.DeleteInProgress {
1346 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1347 return
1348 }
1349 vs.ServiceLock.Lock()
1350
1351 if _, ok := vs.PendingFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301352 logger.Warnw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301353 vs.ServiceLock.Unlock()
1354 return
1355 }
1356
1357 delete(vs.PendingFlows, cookie)
1358 vs.AssociatedFlows[cookie] = true
1359 vs.ServiceLock.Unlock()
1360 var prevBwAvail, presentBwAvail string
1361 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1362 prevBwAvail = bwAvailInfo.PrevBw
1363 presentBwAvail = bwAvailInfo.PresentBw
1364 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301365 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301366 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301367 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301368
Akash Sonief452f12024-12-12 18:20:28 +05301369 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301370 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Akash Sonief452f12024-12-12 18:20:28 +05301371 vs.ServiceLock.RUnlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301372 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1373 if err != nil {
1374 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1375 return
1376 } else if device.State != controller.DeviceStateUP {
1377 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1378 return
1379 }
1380
1381 if vs.Trigger == ServiceVlanUpdate {
1382 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301383 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301384 }
1385 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1386 return
1387 }
Akash Sonief452f12024-12-12 18:20:28 +05301388 vs.ServiceLock.RUnlock()
1389 logger.Debugw(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301390}
1391
vinokuma926cb3e2023-03-29 11:41:06 +05301392// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301393// Trigger service failure indication to NB
Akash Sonief452f12024-12-12 18:20:28 +05301394func (vs *VoltService) FlowInstallFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301395 logger.Debugw(ctx, "Service flow installation failure", log.Fields{"Service": vs.Name, "Cookie": cookie, "errorCode": errorCode, "errReason": errReason})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301396 vs.ServiceLock.RLock()
Akash Sonief452f12024-12-12 18:20:28 +05301397
Naveen Sampath04696f72022-06-13 15:19:14 +05301398 if _, ok := vs.PendingFlows[cookie]; !ok {
1399 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1400 vs.ServiceLock.RUnlock()
1401 return
1402 }
1403 vs.ServiceLock.RUnlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301404 logger.Debugw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05301405 vs.triggerServiceFailureInd(errorCode, errReason)
1406}
1407
vinokuma926cb3e2023-03-29 11:41:06 +05301408// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301409// Triggers flow deletion after registering for flow indication event
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301410func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow, delFlowsInDevice bool) error {
Akash Sonief452f12024-12-12 18:20:28 +05301411 logger.Infow(ctx, "Delete the flow from the service", log.Fields{"Port": vs.Port, "Device": device.Name, "cookie": flow.MigrateCookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301412 if !vs.ForceDelete {
1413 // Using locks instead of concurrent map for AssociatedFlows to avoid
1414 // race condition during flow response indication processing
1415 vs.ServiceLock.Lock()
1416 defer vs.ServiceLock.Unlock()
1417
1418 for cookie := range flow.SubFlows {
1419 cookie := strconv.FormatUint(cookie, 10)
1420 fe := &FlowEvent{
1421 eType: EventTypeServiceFlowRemoved,
1422 cookie: cookie,
1423 eventData: vs,
1424 }
1425 device.RegisterFlowDelEvent(cookie, fe)
1426 }
1427 }
mgoudabb017dc2025-10-29 19:53:34 +05301428 return controller.GetController().DelFlows(cntx, vs.Port, device.Name, flow, delFlowsInDevice)
Naveen Sampath04696f72022-06-13 15:19:14 +05301429}
1430
vinokuma926cb3e2023-03-29 11:41:06 +05301431// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301432func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301433 logger.Debugw(ctx, "Delete service from DB/Cache", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301434 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301435 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301436 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301437 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301438 }
1439}
1440
vinokuma926cb3e2023-03-29 11:41:06 +05301441// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301442// If no more associated flows, DelHSIA indication wil be triggered
Akash Sonief452f12024-12-12 18:20:28 +05301443func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301444 // if vs.DeleteInProgress {
1445 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1446 // return
1447 // }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301448
Naveen Sampath04696f72022-06-13 15:19:14 +05301449 vs.ServiceLock.Lock()
Akash Sonief452f12024-12-12 18:20:28 +05301450 logger.Debugw(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301451
1452 if _, ok := vs.AssociatedFlows[cookie]; ok {
1453 delete(vs.AssociatedFlows, cookie)
1454 } else if _, ok := vs.PendingFlows[cookie]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301455 logger.Debugw(ctx, "Service Flow Remove: Cookie Present in Pending Flow list. No Action", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
Naveen Sampath04696f72022-06-13 15:19:14 +05301456 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301457 logger.Debugw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
Naveen Sampath04696f72022-06-13 15:19:14 +05301458 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301459 vs.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301460 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301461
Akash Sonief452f12024-12-12 18:20:28 +05301462 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301463 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Akash Sonief452f12024-12-12 18:20:28 +05301464 vs.ServiceLock.RUnlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301465 device := GetApplication().GetDevice(vs.Device)
1466 if device == nil {
1467 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1468 return
1469 } else if device.State != controller.DeviceStateUP {
1470 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1471 return
1472 }
1473
1474 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301475 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301476 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301477 return
1478 }
1479 logger.Infow(ctx, "All Flows removed for Service. Triggering Service De-activation Success indication to NB", log.Fields{"Service": vs.Name, "DeleteFlag": vs.DeleteInProgress})
Akash Sonief452f12024-12-12 18:20:28 +05301480 // Get the service from application before proceeding to delete, as the service might have been activated
1481 // by the time the flow removal response is received from SB
1482 svc := GetApplication().GetService(vs.Name)
1483 if svc != nil {
1484 svc.CheckAndDeleteService(cntx)
1485 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301486
1487 return
1488 }
Akash Sonief452f12024-12-12 18:20:28 +05301489 vs.ServiceLock.RUnlock()
1490 logger.Debugw(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301491}
1492
vinokuma926cb3e2023-03-29 11:41:06 +05301493// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301494// Trigger service failure indication to NB
Akash Sonief452f12024-12-12 18:20:28 +05301495func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301496 vs.ServiceLock.Lock()
Akash Sonief452f12024-12-12 18:20:28 +05301497 logger.Debugw(ctx, "Processing Service Flow Remove Failure Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301498
1499 if _, ok := vs.AssociatedFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301500 logger.Warnw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301501 vs.ServiceLock.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301502 return
1503 }
1504 if vs.DeleteInProgress {
1505 delete(vs.AssociatedFlows, cookie)
1506 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301507 vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301508 logger.Debugw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05301509
1510 vs.triggerServiceFailureInd(errorCode, errReason)
Akash Sonief452f12024-12-12 18:20:28 +05301511 // Get the service from application before proceeding to delete, as the service might have been activated
1512 // by the time the flow removal response is received from SB
1513 svc := GetApplication().GetService(vs.Name)
1514 if svc != nil {
1515 svc.CheckAndDeleteService(cntx)
1516 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301517}
1518
1519func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301520 logger.Debugw(ctx, "Trigger Service Failure Ind", log.Fields{"Service": vs.Name, "Port": vs.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301521 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1522 if err != nil {
1523 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1524 return
1525 } else if device.State != controller.DeviceStateUP {
1526 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1527 return
1528 }
1529}
1530
1531// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301532func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301533 // VNETS must be learnt first
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301534 logger.Debug(ctx, "Restore Svcs From Db")
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301535 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301536 for _, vs := range vss {
1537 b, ok := vs.Value.([]byte)
1538 if !ok {
1539 logger.Warn(ctx, "The value type is not []byte")
1540 continue
1541 }
1542 var vvs VoltService
1543 err := json.Unmarshal(b, &vvs)
1544 if err != nil {
1545 logger.Warn(ctx, "Unmarshal of VNET failed")
1546 continue
1547 }
1548 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301549 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301550 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1551 }
1552
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301553 if vvs.VoltServiceOper.DeactivateInProgress {
Akash Sonief452f12024-12-12 18:20:28 +05301554 va.ServicesToDeactivate.Store(vvs.VoltServiceCfg.Name, true)
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301555 logger.Warnw(ctx, "Service (restored) to be deactivated", log.Fields{"Service": vvs.Name})
1556 }
1557
Naveen Sampath04696f72022-06-13 15:19:14 +05301558 if vvs.VoltServiceOper.DeleteInProgress {
Akash Sonief452f12024-12-12 18:20:28 +05301559 va.ServicesToDelete.Store(vvs.VoltServiceCfg.Name, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301560 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1561 }
1562 }
1563}
1564
1565// GetService to get service
1566func (va *VoltApplication) GetService(name string) *VoltService {
1567 if vs, ok := va.ServiceByName.Load(name); ok {
1568 return vs.(*VoltService)
1569 }
1570 return nil
1571}
1572
1573// GetCircuitID to get circuit id
1574func (vs *VoltService) GetCircuitID() []byte {
1575 return []byte(vs.CircuitID)
1576}
1577
1578// GetRemoteID to get remote id
1579func (vs *VoltService) GetRemoteID() []byte {
1580 return []byte(vs.RemoteID)
1581}
1582
1583// IPAssigned to check if ip is assigned
1584func (vs *VoltService) IPAssigned() bool {
1585 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1586 return true
1587 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1588 return true
1589 }
1590 return false
1591}
1592
1593// GetServiceNameFromCookie to get service name from cookie
1594func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301595 logger.Debugw(ctx, "Get Service Name From Cookie", log.Fields{"Cookie": cookie, "PortName": portName, "Pbit": pbit, "Device": device, "TableMetadata": tableMetadata})
Naveen Sampath04696f72022-06-13 15:19:14 +05301596 var vlan uint64
1597 vlanControl := (tableMetadata >> 32) & 0xF
1598
1599 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1600 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1601 vlan = (tableMetadata >> 16) & 0xFFFF
1602 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301603 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301604 vlan = cookie >> 52
1605 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301606 logger.Debugw(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301607 var vlans []of.VlanType
1608 vlans = append(vlans, of.VlanType(vlan))
1609 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1610 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301611 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301612 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301613 logger.Warnw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05301614 }
1615 return service
1616}
1617
vinokuma926cb3e2023-03-29 11:41:06 +05301618// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301619type MigrateServicesReqStatus string
1620
1621const (
vinokuma926cb3e2023-03-29 11:41:06 +05301622 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301623 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301624 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301625 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301626 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301627 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1628)
1629
vinokuma926cb3e2023-03-29 11:41:06 +05301630// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301631type MigrateServicesRequest struct {
1632 ID string
1633 OldVnetID string
1634 NewVnetID string
1635 ServicesList map[string]bool
1636 DeviceID string
1637 Status MigrateServicesReqStatus
1638 MigrateServicesLock sync.RWMutex
1639}
1640
1641func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301642 var msr MigrateServicesRequest
1643 msr.OldVnetID = oldVnetID
1644 msr.NewVnetID = newVnetID
1645 msr.ID = id
1646 msr.ServicesList = serviceMap
1647 msr.DeviceID = deviceID
1648 msr.Status = MigrateSrvsReqInit
1649 return &msr
1650}
1651
vinokuma926cb3e2023-03-29 11:41:06 +05301652// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301653func (msr *MigrateServicesRequest) GetMsrKey() string {
1654 return msr.OldVnetID + "-" + msr.ID
1655}
1656
1657// //isRequestComplete - return if all request has been processed and completed
1658// // RequestProcessed indicates that all the profile de-activation has been triggered
1659// // And the associated profiles indicates the profiles awaiting results
1660// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1661// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1662// return (len(edr.AssociatedProfiles) == 0)
1663// }
1664
vinokuma926cb3e2023-03-29 11:41:06 +05301665// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301666func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301667 logger.Debugw(ctx, "Adding Migrate Service Request to DB", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID, "Device": msr.DeviceID, "RequestID": msr.ID, "ServiceCount": len(msr.ServicesList)})
1668 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301669 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301670 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301671 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301672 }
1673 }
1674}
1675
vinokuma926cb3e2023-03-29 11:41:06 +05301676// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301677func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301678 logger.Debugw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
Naveen Sampath04696f72022-06-13 15:19:14 +05301679 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301680 return errors.New("old vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301681 }
1682 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301683 return errors.New("new vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301684 }
1685
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301686 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301687 if d == nil {
1688 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1689 return errorCodes.ErrDeviceNotFound
1690 }
1691
1692 serviceMap := make(map[string]bool)
1693
1694 for _, service := range serviceList {
1695 serviceMap[service] = false
1696 }
1697 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301698 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301699
1700 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301701 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301702 return nil
1703}
1704
vinokuma926cb3e2023-03-29 11:41:06 +05301705// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301706func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301707 logger.Debug(ctx, "Process Migrate Services Prof Request")
Naveen Sampath04696f72022-06-13 15:19:14 +05301708 va := GetApplication()
1709 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301710 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301711 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301712 va.DelService(cntx, srv, true, nil, true)
1713 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301714 continue
1715 }
1716
1717 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1718 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1719 vs := vsIntf.(*VoltService)
1720 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1721 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301722 logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301723 continue
1724 }
1725 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1726 vpv.Blocked = true
1727
1728 // setDeactTrigger := func(key, value interface{}) bool {
1729 // vs := value.(*VoltService)
1730 vs.ServiceLock.Lock()
1731 vs.UpdateInProgress = true
1732 metadata := &MigrateServiceMetadata{
1733 NewVnetID: msr.NewVnetID,
1734 RequestID: msr.ID,
1735 }
1736 vs.Metadata = metadata
1737 vs.ServiceLock.Unlock()
1738
vinokuma926cb3e2023-03-29 11:41:06 +05301739 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301740 // new vpv flows will be installed when new service is added
1741 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301742 vpv.DelTrapFlows(cntx)
1743 vs.DelHsiaFlows(cntx)
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301744 logger.Debugw(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301745 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301746 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301747 }
1748 } else {
1749 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1750 }
1751 }
1752}
1753
vinokuma926cb3e2023-03-29 11:41:06 +05301754// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301755func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301756 logger.Infow(ctx, "Add Migrating Services", log.Fields{"Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301757 var msrMap *util.ConcurrentMap
1758 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1759 msrMap = util.NewConcurrentMap()
1760 } else {
1761 msrMap = msrMapIntf.(*util.ConcurrentMap)
1762 }
1763
1764 msrMap.Set(msr.ID, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301765 logger.Debugw(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301766
1767 d.MigratingServices.Set(msr.OldVnetID, msrMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301768 logger.Debugw(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301769}
1770
vinokuma926cb3e2023-03-29 11:41:06 +05301771// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301772func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301773 logger.Debugw(ctx, "Get Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301774 if vd := va.GetDevice(deviceID); vd != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301775 logger.Debugw(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301776 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1777 msrList := msrListIntf.(*util.ConcurrentMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301778 logger.Debugw(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301779 if msrObj, ok := msrList.Get(requestID); ok {
1780 return msrObj.(*MigrateServicesRequest)
1781 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301782 }
1783 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301784 logger.Warnw(ctx, "Device Not Found", log.Fields{"DeviceID": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301785 return nil
1786}
1787
vinokuma926cb3e2023-03-29 11:41:06 +05301788// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301789func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301790 logger.Debugw(ctx, "Update Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301791 if vd := va.GetDevice(deviceID); vd != nil {
1792 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1793 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1794 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1795 }
1796 }
1797 }
1798}
1799
vinokuma926cb3e2023-03-29 11:41:06 +05301800// updateVnetProfile - Called on flow process completion
1801// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301802func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301803 logger.Debugw(ctx, "Update Vnet Profile Triggering", log.Fields{"Service": vs.Name, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301804
1805 nvs := VoltService{}
1806 nvs.VoltServiceCfg = vs.VoltServiceCfg
1807 nvs.Device = vs.Device
1808 nvs.Ipv4Addr = vs.Ipv4Addr
1809 nvs.Ipv6Addr = vs.Ipv6Addr
1810 nvs.UsMeterID = vs.UsMeterID
1811 nvs.DsMeterID = vs.DsMeterID
1812 nvs.AggDsMeterID = vs.AggDsMeterID
1813 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1814 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1815 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1816 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1817 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1818 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1819 nvs.PendingFlows = vs.PendingFlows
1820 nvs.AssociatedFlows = vs.AssociatedFlows
1821 nvs.DeleteInProgress = vs.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301822 nvs.DeactivateInProgress = vs.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301823 nvs.ForceDelete = vs.ForceDelete
1824 nvs.BwAvailInfo = vs.BwAvailInfo
1825 nvs.UpdateInProgress = vs.UpdateInProgress
1826
1827 if nvs.DeleteInProgress {
1828 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1829 return
1830 }
1831
1832 metadata := vs.Metadata.(*MigrateServiceMetadata)
1833 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301834 oldSrvName := vs.Name
1835
1836 if metadata == nil || metadata.NewVnetID == "" {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301837 logger.Warnw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301838 return
1839 }
1840
vinokuma926cb3e2023-03-29 11:41:06 +05301841 nvs.VnetID = metadata.NewVnetID
1842 id := metadata.RequestID
1843
1844 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301845 // Since if post del service in case of pod crash or reboot, the service data will be lost
1846 va := GetApplication()
1847 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1848 vnets := strings.Split(metadata.NewVnetID, "-")
1849 svlan, _ := strconv.Atoi(vnets[0])
1850 nvs.SVlan = of.VlanType(svlan)
1851 nvs.UpdateInProgress = false
1852 nvs.Metadata = nil
1853 nvs.Trigger = ServiceVlanUpdate
1854
1855 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1856 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1857 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1858
vinokuma926cb3e2023-03-29 11:41:06 +05301859 // TODO:Nav Pass a copy, not the pointer
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301860 logger.Debugw(ctx, "Add New Service Triggering", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301861 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301862 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1863 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301864 logger.Debugw(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
Naveen Sampath04696f72022-06-13 15:19:14 +05301865
1866 msr.ServicesList[oldSrvName] = true
1867 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301868 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301869
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301870 logger.Debugw(ctx, "Del Old Service Triggering", log.Fields{"Service": oldSrvName, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied, "DelFlag": vs.DeleteInProgress})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301871 va.DelService(cntx, oldSrvName, true, nil, true)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301872 logger.Debugw(ctx, "Del Old Service Triggered", log.Fields{"Service": oldSrvName, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied, "DelFlag": vs.DeleteInProgress})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301873 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301874}
1875
vinokuma926cb3e2023-03-29 11:41:06 +05301876// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301877// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301878func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301879 logger.Infow(ctx, "Service Migrated", log.Fields{"ServiceName": serviceName})
Naveen Sampath04696f72022-06-13 15:19:14 +05301880 msr.MigrateServicesLock.Lock()
1881 defer msr.MigrateServicesLock.Unlock()
1882
1883 delete(msr.ServicesList, serviceName)
1884
1885 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301886 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301887 return
1888 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301889 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301890 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301891}
1892
vinokuma926cb3e2023-03-29 11:41:06 +05301893// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301894func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1895 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301896}
1897
vinokuma926cb3e2023-03-29 11:41:06 +05301898// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301899func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301900 logger.Debugw(ctx, "Fetch all pending migrate services req from DB and process based on provided func", log.Fields{"Device": device})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301901 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301902 for _, msr := range msrList {
1903 b, ok := msr.Value.([]byte)
1904 if !ok {
1905 logger.Warn(ctx, "The value type is not []byte")
1906 continue
1907 }
1908 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301909 msrAction(cntx, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301910 logger.Debugw(ctx, "Triggering Pending Migrate Services Req", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID, "Device": device, "PendingProfiles": len(msr.ServicesList)})
Naveen Sampath04696f72022-06-13 15:19:14 +05301911 }
1912}
1913
1914// createMigrateServicesFromString to create Service from string
1915func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301916 logger.Info(ctx, "Create Migrate Services From String")
Naveen Sampath04696f72022-06-13 15:19:14 +05301917 var msr MigrateServicesRequest
1918 if err := json.Unmarshal(b, &msr); err == nil {
1919 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301920 } else {
1921 logger.Warn(ctx, "Unmarshal failed")
1922 }
1923 return &msr
1924}
1925
vinokuma926cb3e2023-03-29 11:41:06 +05301926// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301927func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301928 logger.Infow(ctx, "Store And Process Migrate Srv Request", log.Fields{"MsrID": msr.DeviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301929 d := GetApplication().GetDevice(msr.DeviceID)
1930 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301931 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301932}
1933
vinokuma926cb3e2023-03-29 11:41:06 +05301934// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301935func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301936 logger.Infow(ctx, "Force udpate services with new vnet profile", log.Fields{"MsrID": msr.NewVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301937 for srv := range msr.ServicesList {
1938 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301939 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301940 }
1941 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301942 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301943}
1944
vinokuma926cb3e2023-03-29 11:41:06 +05301945// nolint: gocyclo
1946// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301947func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1948 if nvs.Name != evs.Name {
1949 return false
1950 }
1951 if nvs.UniVlan != evs.UniVlan {
1952 return false
1953 }
1954 if nvs.CVlan != evs.CVlan {
1955 return false
1956 }
1957 if nvs.SVlan != evs.SVlan {
1958 return false
1959 }
1960 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1961 return false
1962 }
1963 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1964 return false
1965 }
1966 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1967 return false
1968 }
1969 if nvs.TechProfileID != evs.TechProfileID {
1970 return false
1971 }
1972 if nvs.CircuitID != evs.CircuitID {
1973 return false
1974 }
1975 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1976 return false
1977 }
1978 if nvs.Port != evs.Port {
1979 return false
1980 }
1981 if nvs.PonPort != evs.PonPort {
1982 return false
1983 }
1984 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1985 return false
1986 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301987 if nvs.IsOption82Enabled != evs.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +05301988 return false
1989 }
1990 if nvs.IgmpEnabled != evs.IgmpEnabled {
1991 return false
1992 }
1993 if nvs.McastService != evs.McastService {
1994 return false
1995 }
1996 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1997 return false
1998 }
1999 if nvs.UsMeterProfile != evs.UsMeterProfile {
2000 return false
2001 }
2002 if nvs.DsMeterProfile != evs.DsMeterProfile {
2003 return false
2004 }
2005 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
2006 return false
2007 }
2008 if nvs.VnetID != evs.VnetID {
2009 return false
2010 }
2011 if nvs.MvlanProfileName != evs.MvlanProfileName {
2012 return false
2013 }
2014 if nvs.RemoteIDType != evs.RemoteIDType {
2015 return false
2016 }
2017 if nvs.SchedID != evs.SchedID {
2018 return false
2019 }
2020 if nvs.AllowTransparent != evs.AllowTransparent {
2021 return false
2022 }
2023 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
2024 return false
2025 }
2026 if nvs.DataRateAttr != evs.DataRateAttr {
2027 return false
2028 }
2029 if nvs.MinDataRateUs != evs.MinDataRateUs {
2030 return false
2031 }
2032 if nvs.MinDataRateDs != evs.MinDataRateDs {
2033 return false
2034 }
2035 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
2036 return false
2037 }
2038 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
2039 return false
2040 }
2041
2042 return true
2043}
2044
vinokuma926cb3e2023-03-29 11:41:06 +05302045// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302046func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05302047 // Clear the Flows flag if already set
2048 // This case happens only in case of some race condition
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302049 logger.Infow(ctx, "Trigger Associated Flow Delete", log.Fields{"Device": vs.Device, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05302050 if vs.UsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302051 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302052 logger.Warnw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302053 }
2054 }
2055
2056 if vs.DsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302057 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302058 logger.Warnw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302059 }
2060 }
2061
2062 vs.ServiceLock.Lock()
2063 cookieList := []uint64{}
2064 for cookie := range vs.AssociatedFlows {
2065 cookieList = append(cookieList, convertToUInt64(cookie))
2066 }
2067 vs.ServiceLock.Unlock()
2068
2069 if len(cookieList) == 0 {
2070 return false
2071 }
2072
vinokuma926cb3e2023-03-29 11:41:06 +05302073 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05302074 for _, cookie := range cookieList {
2075 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
2076 flow := &of.VoltFlow{}
2077 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2078 subFlow := of.NewVoltSubFlow()
2079 subFlow.Cookie = cookie
2080 flow.SubFlows[cookie] = subFlow
2081 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302082 if err := vs.DelFlows(cntx, vd, flow, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302083 logger.Warnw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302084 }
2085 }
2086 }
2087 return true
2088}
2089
vinokuma926cb3e2023-03-29 11:41:06 +05302090// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05302091func (vs *VoltService) triggerServiceInProgressInd() {
2092}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302093
vinokuma926cb3e2023-03-29 11:41:06 +05302094// JSONMarshal wrapper function for json Marshal VoltService
2095func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302096 return json.Marshal(VoltService{
2097 VoltServiceCfg: vs.VoltServiceCfg,
2098 VoltServiceOper: VoltServiceOper{
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302099 Device: vs.VoltServiceOper.Device,
2100 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
2101 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
2102 UsMeterID: vs.VoltServiceOper.UsMeterID,
2103 DsMeterID: vs.VoltServiceOper.DsMeterID,
2104 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
2105 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
2106 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
2107 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
2108 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
2109 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
2110 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
2111 PendingFlows: vs.VoltServiceOper.PendingFlows,
2112 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2113 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2114 DeactivateInProgress: vs.VoltServiceOper.DeactivateInProgress,
2115 ForceDelete: vs.VoltServiceOper.ForceDelete,
2116 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2117 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2118 Metadata: vs.VoltServiceOper.Metadata,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302119 },
2120 })
2121}
Tinoj Josephec742f62022-09-29 19:11:10 +05302122
2123// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302124func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302125 var svcList []*VoltService
2126 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2127 va.ServiceByName.Range(func(key, value interface{}) bool {
2128 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302129 if len(deviceID) > 0 {
2130 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302131 if deviceID == vs.Device && portNo == vs.Port {
2132 svcList = append(svcList, vs)
2133 }
2134 } else {
2135 if deviceID == vs.Device {
2136 svcList = append(svcList, vs)
2137 }
2138 }
2139 } else {
2140 svcList = append(svcList, vs)
2141 }
2142 return true
2143 })
2144 return svcList, nil
2145}
2146
Akash Soni634d9bf2023-07-10 12:11:10 +05302147type FlowProvisionStatus struct {
2148 FlowProvisionStatus string
2149}
2150
2151// GetFlowProvisionStatus to get status of the subscriber and flow provisioned in controller
Akash Soni3c391e72023-08-16 12:21:33 +05302152func (va *VoltApplication) GetFlowProvisionStatus(portNo string) FlowProvisionStatus {
Akash Soni634d9bf2023-07-10 12:11:10 +05302153 logger.Infow(ctx, "GetFlowProvisionStatus Request ", log.Fields{"Port": portNo})
2154 flowProvisionStatus := FlowProvisionStatus{}
Akash Soni3c391e72023-08-16 12:21:33 +05302155 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_NOT_IN_CONTROLLER
Akash Soni634d9bf2023-07-10 12:11:10 +05302156 va.ServiceByName.Range(func(key, value interface{}) bool {
2157 vs := value.(*VoltService)
2158 logger.Debugw(ctx, "Volt Service ", log.Fields{"VS": vs})
Akash Soni3c391e72023-08-16 12:21:33 +05302159 if portNo == vs.Port {
2160 if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() == 0 {
2161 flowProvisionStatus.FlowProvisionStatus = ALL_FLOWS_PROVISIONED
2162 return false
2163 } else if !vs.IsActivated {
2164 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_DISABLED_IN_CONTROLLER
2165 return false
2166 } else if !vs.DsHSIAFlowsApplied && !vs.UsHSIAFlowsApplied {
2167 flowProvisionStatus.FlowProvisionStatus = NO_FLOWS_PROVISIONED
2168 return false
Akash Soni230e6212023-10-16 10:46:07 +05302169 } else if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() > 0 {
Akash Soni3c391e72023-08-16 12:21:33 +05302170 flowProvisionStatus.FlowProvisionStatus = FLOWS_PROVISIONED_PARTIALLY
2171 return false
Akash Soni634d9bf2023-07-10 12:11:10 +05302172 }
2173 }
2174 return true
2175 })
Akash Soni634d9bf2023-07-10 12:11:10 +05302176 return flowProvisionStatus
2177}
2178
2179func (vs *VoltService) LenOfPendingFlows() int {
2180 vs.ServiceLock.RLock()
2181 lth := len(vs.PendingFlows)
2182 vs.ServiceLock.RUnlock()
2183 return lth
2184}
2185
Tinoj Josephec742f62022-09-29 19:11:10 +05302186// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302187func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302188 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo, "Svaln": sVlan, "Cvlan": cVlan, "TpID": tpID})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302189 device, err := va.GetDeviceFromPort(portNo)
2190 if err != nil {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302191 // Lets activate the service even though port was not found. We will push the flows once the port is added by voltha
2192 logger.Warnw(ctx, "Couldn't get device for port, continuing with service activation", log.Fields{"Reason": err.Error(), "Port": portNo})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302193 }
2194 // If device id is not provided check only port number
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302195 if device != nil {
2196 if deviceID == DeviceAny {
2197 deviceID = device.Name
2198 } else if deviceID != device.Name {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302199 err := errorCodes.ErrDeviceNotFound
2200 return fmt.Errorf("wrong device id %s : %w", deviceID, err)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302201 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302202 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302203 va.ServiceByName.Range(func(key, value interface{}) bool {
2204 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302205 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302206 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302207 logger.Debugw(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302208 return true
2209 }
2210 if portNo == vs.Port && !vs.IsActivated {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302211 // Mark the service as activated, so that we can push the flows later when the port is added by voltha
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302212 logger.Debugw(ctx, "Service Activate", log.Fields{"Name": vs.Name})
Tinoj Josephec742f62022-09-29 19:11:10 +05302213 vs.IsActivated = true
2214 va.ServiceByName.Store(vs.Name, vs)
2215 vs.WriteToDb(cntx)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302216
2217 // Push the flows only if the port is already added and we have a valid device
2218 if device != nil {
2219 p := device.GetPort(vs.Port)
2220 if p == nil {
2221 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2222 return true
2223 }
2224 // If port is already up send indication to vpv
2225 if p.State == PortStateUp {
2226 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2227 // PortUp call initiates flow addition
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302228 // The flow generation and pushing the flow can be done in a go routine,
2229 // VGC once service is activated remembers and pushes the flows again
2230 // if there was a restart in VGC during the execution of the go routine.
2231 // Making it as a go routine will not impact anything
Sridhar Ravindra64b19ca2026-01-26 22:19:07 +05302232 go vpv.PortUpInd(cntx, device, portNo, vs.NniPort, false)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302233 } else {
2234 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2235 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302236 }
2237 }
2238 }
2239 return true
2240 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302241 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302242}
2243
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302244func (vs *VoltService) SetSvcDeactivationFlags(deactivateRsn SvcDeactivateReason) {
2245 vs.DeactivateInProgress = true
2246 vs.IsActivated = false
2247 vs.ServiceDeactivateReason = deactivateRsn
2248}
2249
Tinoj Josephec742f62022-09-29 19:11:10 +05302250// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302251func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302252 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo, "Svaln": sVlan, "Cvlan": cVlan, "TpID": tpID})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302253
Tinoj Josephec742f62022-09-29 19:11:10 +05302254 va.ServiceByName.Range(func(key, value interface{}) bool {
2255 vs := value.(*VoltService)
2256 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302257 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302258 logger.Warnw(ctx, "condition not matched", log.Fields{"Device": deviceID, "Port": portNo, "sVlan": sVlan, "cVlan": cVlan, "tpID": tpID})
Tinoj Josephec742f62022-09-29 19:11:10 +05302259 return true
2260 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302261 if portNo == vs.Port && vs.IsActivated {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302262 vs.SetSvcDeactivationFlags(SvcDeacRsn_NB)
Tinoj Josephec742f62022-09-29 19:11:10 +05302263 va.ServiceByName.Store(vs.Name, vs)
2264 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302265 device, err := va.GetDeviceFromPort(portNo)
2266 if err != nil {
2267 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2268 // So no error is returned
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302269 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302270 return true
2271 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302272 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302273 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302274 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2275 // Port down call internally deletes all the flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302276 vpv.PortDownInd(cntx, deviceID, portNo, true, false)
Tinoj Josephec742f62022-09-29 19:11:10 +05302277 if vpv.IgmpEnabled {
2278 va.ReceiverDownInd(cntx, deviceID, portNo)
2279 }
2280 } else {
2281 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2282 }
2283 }
Akash Sonief452f12024-12-12 18:20:28 +05302284 vs.DeactivateInProgress = false
2285 va.ServiceByName.Store(vs.Name, vs)
2286 vs.WriteToDb(cntx)
Tinoj Josephec742f62022-09-29 19:11:10 +05302287 }
2288 return true
2289 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302290 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302291}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302292
vinokuma926cb3e2023-03-29 11:41:06 +05302293// GetServicePbit to get first set bit in the pbit map
2294// returns -1 : If configured to match on all pbits
2295// returns 8 : If no pbits are configured
2296// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302297func (vs *VoltService) GetServicePbit() int {
2298 if vs.IsPbitExist(of.PbitMatchAll) {
2299 return -1
2300 }
vinokuma926cb3e2023-03-29 11:41:06 +05302301 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302302 if vs.IsPbitExist(of.PbitType(pbit)) {
2303 return pbit
2304 }
2305 }
2306 return int(of.PbitMatchNone)
2307}