blob: 3fd1a4e957a0639eeef3316d5654c4481bdc03a3 [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"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053035 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053036
37 "github.com/google/gopacket/layers"
38
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053039 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053040 "voltha-go-controller/internal/pkg/controller"
41 cntlr "voltha-go-controller/internal/pkg/controller"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053042 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053043 "voltha-go-controller/internal/pkg/of"
44 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053045 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053046)
47
48const (
49 // DSLAttrEnabled constant
50 DSLAttrEnabled string = "ENABLED"
Tinoj Josephec742f62022-09-29 19:11:10 +053051 // DeviceAny constant
52 DeviceAny string = "DEVICE-ANY"
Akash Soni634d9bf2023-07-10 12:11:10 +053053
54 ALL_FLOWS_PROVISIONED string = "ALL_FLOWS_PROVISIONED"
55
56 NO_FLOWS_PROVISIONED string = "NO_FLOWS_PROVISIONED"
57
58 FLOWS_PROVISIONED_PARTIALLY string = "FLOWS_PROVISIONED_PARTIALLY"
59
60 SUBSCRIBER_DISABLED_IN_CONTROLLER string = "DISABLED_IN_CONTROLLER"
61
62 SUBSCRIBER_NOT_IN_CONTROLLER string = "NOT_IN_CONTROLLER"
63
64 ONT_FLOWS_PROVISION_STATE_UNUSED string = "ONT_FLOWS_PROVISION_STATE_UNUSED"
Naveen Sampath04696f72022-06-13 15:19:14 +053065)
66
67// VoltServiceCfg structure
68// Name - Uniquely identifies a service across the entire application
69// UniVlan - The VLAN of the packets entering the UNI of ONU
70// CVlan - The VLAN to transalate to/from on the PON link
71// SVlan - The outer VLAN to be used on the NNI of OLT.
vinokuma926cb3e2023-03-29 11:41:06 +053072// - In general, 4096 is used as NO VLAN for all the above
73// SVlanTpid - SVlan Tag Protocol Identifier
Naveen Sampath04696f72022-06-13 15:19:14 +053074// Pbits - Each bit of uint8 represents one p-bit. MSB is pbit 7
75// DhcpRelay - Whether it is turned on/off
76// CircuitId - The circuit id to be used with DHCP relay. Unused otherwise
77// RemoveId - Same as above
78// Port - The access port for the service. Each service has a single access
vinokuma926cb3e2023-03-29 11:41:06 +053079// port. The converse is not always true
Naveen Sampath04696f72022-06-13 15:19:14 +053080// MacLearning - If MAC learning is turned on, the MAC address learned from the
vinokuma926cb3e2023-03-29 11:41:06 +053081// the service activation is used in programming flows
Naveen Sampath04696f72022-06-13 15:19:14 +053082// MacAddress - The MAC hardware address learnt on the UNI interface
83// MacAddresses - Not yet implemented. To be used to learn more MAC addresses
84type VoltServiceCfg struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053085 FlowPushCount map[string]int64 // Tracks the number of flow install/delete failure attempts per cookie in order to throttle flow auditing
86 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
vinokuma926cb3e2023-03-29 11:41:06 +053087 Name string
Naveen Sampath04696f72022-06-13 15:19:14 +053088 CircuitID string
Naveen Sampath04696f72022-06-13 15:19:14 +053089 Port string
Sridhar Ravindrab76eb162025-07-02 01:25:10 +053090 NniPort string
Naveen Sampath04696f72022-06-13 15:19:14 +053091 UsMeterProfile string
92 DsMeterProfile string
93 AggDsMeterProfile string
94 VnetID string
95 MvlanProfileName string
96 RemoteIDType string
Naveen Sampath04696f72022-06-13 15:19:14 +053097 DataRateAttr string
vinokuma926cb3e2023-03-29 11:41:06 +053098 ServiceType string
Akash Sonief452f12024-12-12 18:20:28 +053099 Pbits []of.PbitType
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530100 RemoteID []byte
101 MacAddr net.HardwareAddr
vinokuma926cb3e2023-03-29 11:41:06 +0530102 Trigger ServiceTrigger
103 MacLearning MacLearningType
Akash Sonief452f12024-12-12 18:20:28 +0530104 ONTEtherTypeClassification int
105 SchedID int
vinokuma926cb3e2023-03-29 11:41:06 +0530106 PonPort uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530107 MinDataRateUs uint32
108 MinDataRateDs uint32
109 MaxDataRateUs uint32
110 MaxDataRateDs uint32
vinokuma926cb3e2023-03-29 11:41:06 +0530111 SVlanTpid layers.EthernetType
Akash Sonief452f12024-12-12 18:20:28 +0530112 TechProfileID uint16
vinokuma926cb3e2023-03-29 11:41:06 +0530113 UniVlan of.VlanType
114 CVlan of.VlanType
115 SVlan of.VlanType
116 UsPonCTagPriority of.PbitType
117 UsPonSTagPriority of.PbitType
118 DsPonSTagPriority of.PbitType
119 DsPonCTagPriority of.PbitType
Akash Sonief452f12024-12-12 18:20:28 +0530120 ServiceDeactivateReason SvcDeactivateReason // Mentions why the service was deactivated
vinokuma926cb3e2023-03-29 11:41:06 +0530121 VlanControl VlanControl
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530122 IsOption82Enabled bool
vinokuma926cb3e2023-03-29 11:41:06 +0530123 IgmpEnabled bool
124 McastService bool
125 AllowTransparent bool
126 EnableMulticastKPI bool
Tinoj Josephec742f62022-09-29 19:11:10 +0530127 IsActivated bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530128}
129
130// VoltServiceOper structure
131type VoltServiceOper struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530132 Metadata interface{}
133 PendingFlows map[string]bool
134 AssociatedFlows map[string]bool
135 BwAvailInfo string
Naveen Sampath04696f72022-06-13 15:19:14 +0530136 //MacLearning bool
137 //MacAddr net.HardwareAddr
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530138 Device string
139 Ipv4Addr net.IP
140 Ipv6Addr net.IP
141 ServiceLock sync.RWMutex `json:"-"`
142 UsMeterID uint32
143 DsMeterID uint32
144 AggDsMeterID uint32
145 UpdateInProgress bool
146 DeleteInProgress bool
147 DeactivateInProgress bool
148 ForceDelete bool
vinokuma926cb3e2023-03-29 11:41:06 +0530149 // Multiservice-Fix
Naveen Sampath04696f72022-06-13 15:19:14 +0530150 UsHSIAFlowsApplied bool
151 DsHSIAFlowsApplied bool
152 UsDhcpFlowsApplied bool
153 DsDhcpFlowsApplied bool
154 IgmpFlowsApplied bool
155 Icmpv6FlowsApplied bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530156}
157
158// VoltService structure
159type VoltService struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530160 Version string
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530161 VoltServiceOper
vinokuma926cb3e2023-03-29 11:41:06 +0530162 VoltServiceCfg
Naveen Sampath04696f72022-06-13 15:19:14 +0530163}
164
vinokuma926cb3e2023-03-29 11:41:06 +0530165// ServiceTrigger - Service activation trigger
Naveen Sampath04696f72022-06-13 15:19:14 +0530166type ServiceTrigger int
167
168const (
vinokuma926cb3e2023-03-29 11:41:06 +0530169 // NBActivate - Service added due to NB Action
Naveen Sampath04696f72022-06-13 15:19:14 +0530170 NBActivate ServiceTrigger = 0
vinokuma926cb3e2023-03-29 11:41:06 +0530171 // ServiceVlanUpdate - Service added due to Svlan Update
Naveen Sampath04696f72022-06-13 15:19:14 +0530172 ServiceVlanUpdate ServiceTrigger = 1
173)
174
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530175// SvcDeactivateReason - Reason for service deactivation
176type SvcDeactivateReason uint8
177
178const (
179 // Service deactivated reason - none
180 SvcDeacRsn_None SvcDeactivateReason = 0
181 // Service deactivate reason - NB
182 SvcDeacRsn_NB SvcDeactivateReason = 1
183 // Service deactivate reason - Controller
184 SvcDeacRsn_Controller SvcDeactivateReason = 2
185)
186
Naveen Sampath04696f72022-06-13 15:19:14 +0530187// AppMutexes structure
188type AppMutexes struct {
189 ServiceDataMutex sync.Mutex `json:"-"`
190 VnetMutex sync.Mutex `json:"-"`
191}
192
vinokuma926cb3e2023-03-29 11:41:06 +0530193// MigrateServiceMetadata - migrate services request metadata
Naveen Sampath04696f72022-06-13 15:19:14 +0530194type MigrateServiceMetadata struct {
195 NewVnetID string
196 RequestID string
197}
198
199// AppMutex variable
200var AppMutex AppMutexes
201
202// NewVoltService for constructor for volt service
203func NewVoltService(cfg *VoltServiceCfg) *VoltService {
204 var vs VoltService
205 vs.VoltServiceCfg = *cfg
206 vs.UsHSIAFlowsApplied = false
207 vs.DsHSIAFlowsApplied = false
208 vs.DeleteInProgress = false
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530209 vs.DeactivateInProgress = false
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530210 vs.ServiceDeactivateReason = SvcDeacRsn_None
Naveen Sampath04696f72022-06-13 15:19:14 +0530211 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530212
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530213 vs.IsOption82Enabled = cfg.IsOption82Enabled
Naveen Sampath04696f72022-06-13 15:19:14 +0530214 vs.MacAddr = cfg.MacAddr
215 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
216 vs.Ipv6Addr = net.ParseIP("::")
217 vs.PendingFlows = make(map[string]bool)
218 vs.AssociatedFlows = make(map[string]bool)
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530219 vs.FlowPushCount = make(map[string]int64)
Naveen Sampath04696f72022-06-13 15:19:14 +0530220 return &vs
221}
222
223// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530224func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530225 vs.ServiceLock.RLock()
226 defer vs.ServiceLock.RUnlock()
227
228 if vs.DeleteInProgress {
229 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
230 return
231 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530232 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530233}
234
vinokuma926cb3e2023-03-29 11:41:06 +0530235// ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530236func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530237 b, err := json.Marshal(vs)
238
239 if err != nil {
240 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
241 return
242 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530243 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530244 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
245 }
246}
247
248// isDataRateAttrPresent to check if data attribute is present
249func (vs *VoltService) isDataRateAttrPresent() bool {
250 return vs.DataRateAttr == DSLAttrEnabled
251}
252
253// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530254func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530255 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
vinokuma926cb3e2023-03-29 11:41:06 +0530256 // TODO - Need to understand and delete the second call
257 // Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530258 _ = db.DelService(cntx, vs.Name)
259 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530260}
261
262// MatchesVlans find the service that matches the VLANs. In this case it is
263// purely based on CVLAN. The CVLAN can sufficiently be used to
264// match a service
265func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
266 if len(vlans) != 1 {
267 return false
268 }
269
270 if vlans[0] == vs.CVlan {
271 return true
272 }
273 return false
274}
275
276// MatchesPbits allows matching a service to a pbit. This is used
277// to search for a service matching the pbits, typically to identify
278// attributes for other flows such as DHCP, IGMP, etc.
279func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
280 for _, pbit := range pbits {
281 for _, pb := range vs.Pbits {
282 if pb == pbit {
283 return true
284 }
285 }
286 }
287 return false
288}
289
290// IsPbitExist allows matching a service to a pbit. This is used
291// to search for a service matching the pbit
292func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530293 logger.Debugw(ctx, "Request for IsPbitExist", log.Fields{"pbit": pbit})
Naveen Sampath04696f72022-06-13 15:19:14 +0530294 for _, pb := range vs.Pbits {
295 if pb == pbit {
296 return true
297 }
298 }
299 return false
300}
301
302// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530303func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530304 logger.Debugw(ctx, "Add US & DS HSIA Flows for the service", log.Fields{"ServiceName": vs.Name})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530305 if err := vs.AddUsHsiaFlows(cntx); err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530306 logger.Errorw(ctx, "Error adding US HSIA Flows", log.Fields{"Service": vs.Name, "Port": vs.Port, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530307 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
308 vs.triggerServiceFailureInd(statusCode, statusMessage)
309 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530310 if err := vs.AddDsHsiaFlows(cntx); err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530311 logger.Errorw(ctx, "Error adding DS HSIA Flows", log.Fields{"Service": vs.Name, "Port": vs.Port, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530312 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
313 vs.triggerServiceFailureInd(statusCode, statusMessage)
314 }
315}
316
vinokuma926cb3e2023-03-29 11:41:06 +0530317// DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530318func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530319 logger.Debugw(ctx, "Delete US & DS HSIA Flows for the service", log.Fields{"ServiceName": vs.Name})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530320 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530321 logger.Errorw(ctx, "Error deleting US HSIA Flows", log.Fields{"Service": vs.Name, "Port": vs.Port, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530322 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
323 vs.triggerServiceFailureInd(statusCode, statusMessage)
324 }
325
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530326 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530327 logger.Errorw(ctx, "Error deleting DS HSIA Flows", log.Fields{"Service": vs.Name, "Port": vs.Port, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530328 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
329 vs.triggerServiceFailureInd(statusCode, statusMessage)
330 }
331}
332
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530333func (vs *VoltService) AddMeterToDevice(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530334 logger.Debugw(ctx, "Add Meter To Device for the service", log.Fields{"ServiceName": vs.Name})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530335 if vs.DeleteInProgress || vs.UpdateInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530336 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 +0530337 }
338 va := GetApplication()
339 logger.Infow(ctx, "Configuring Meters for FTTB", log.Fields{"ServiceName": vs.Name})
340 device, err := va.GetDeviceFromPort(vs.Port)
341 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530342 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 +0530343 } else if device.State != controller.DeviceStateUP {
344 logger.Warnw(ctx, "Device state Down. Ignoring Meter Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
345 return nil
346 }
347 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
348 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
349 return nil
350}
351
Naveen Sampath04696f72022-06-13 15:19:14 +0530352// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530353func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Akash Sonief452f12024-12-12 18:20:28 +0530354 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 +0530355 if vs.DeleteInProgress || vs.UpdateInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530356 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 +0530357 return nil
358 }
359
360 va := GetApplication()
Naveen Sampath04696f72022-06-13 15:19:14 +0530361 if !vs.UsHSIAFlowsApplied || vgcRebooted {
362 device, err := va.GetDeviceFromPort(vs.Port)
363 if err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530364 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 +0530365 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 +0530366 } else if device.State != controller.DeviceStateUP {
367 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
368 return nil
369 }
370
371 vs.Device = device.Name
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530372 /* In case of DPU_MGMT_TRAFFIC the meters will be configured before US flow creation*/
vinokuma926cb3e2023-03-29 11:41:06 +0530373 if vs.ServiceType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530374 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
375 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
376 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530377 pBits := vs.Pbits
378
vinokuma926cb3e2023-03-29 11:41:06 +0530379 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530380 if len(vs.Pbits) == 0 {
381 pBits = append(pBits, PbitMatchNone)
382 }
383 for _, pbits := range pBits {
384 usflows, err := vs.BuildUsHsiaFlows(pbits)
385 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530386 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530387 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
388 vs.triggerServiceFailureInd(statusCode, statusMessage)
389 continue
390 }
391 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530392 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530393 logger.Errorw(ctx, "Error adding HSIA US flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530394 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
395 vs.triggerServiceFailureInd(statusCode, statusMessage)
396 }
397 }
398 vs.UsHSIAFlowsApplied = true
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530399 logger.Debugw(ctx, "Pushed US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530400 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530401 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530402 return nil
403}
404
405// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530406func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Akash Sonief452f12024-12-12 18:20:28 +0530407 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 +0530408 if vs.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530409 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 +0530410 return nil
411 }
412
413 va := GetApplication()
Naveen Sampath04696f72022-06-13 15:19:14 +0530414 if !vs.DsHSIAFlowsApplied || vgcRebooted {
415 device, err := va.GetDeviceFromPort(vs.Port)
416 if err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530417 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 +0530418 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 +0530419 } else if device.State != controller.DeviceStateUP {
420 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
421 return nil
422 }
423
424 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530425
426 //If no pbits configured for service, hence add PbitNone for flows
427 if len(vs.DsRemarkPbitsMap) == 0 {
428 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
429 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530430 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 +0530431 }
432 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530433 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530434 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530435 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
436 vs.triggerServiceFailureInd(statusCode, statusMessage)
437 }
438 } else {
439 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
440 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
441 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
442 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530443 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 +0530444 }
445 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
446 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530447 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530448 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530449 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
450 vs.triggerServiceFailureInd(statusCode, statusMessage)
451 }
452 } else {
453 for matchPbit := range vs.DsRemarkPbitsMap {
454 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
455 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530456 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530457 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
458 vs.triggerServiceFailureInd(statusCode, statusMessage)
459 continue
460 }
461 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530462 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530463 logger.Errorw(ctx, "Failed to Add HSIA DS flows", log.Fields{"Device": vs.Device, "Service": vs.Name, "Reason": err})
Naveen Sampath04696f72022-06-13 15:19:14 +0530464 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
465 vs.triggerServiceFailureInd(statusCode, statusMessage)
466 }
467 }
468 }
469 }
470 vs.DsHSIAFlowsApplied = true
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530471 logger.Debugw(ctx, "Pushed DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530472 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530473 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530474 return nil
475}
476
477// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530478func (vs *VoltService) DelUsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530479 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530480 if vs.UsHSIAFlowsApplied || vgcRebooted {
481 device, err := GetApplication().GetDeviceFromPort(vs.Port)
482 if err != nil {
Akash Sonief452f12024-12-12 18:20:28 +0530483 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 +0530484 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 +0530485 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530486 pBits := vs.Pbits
487
vinokuma926cb3e2023-03-29 11:41:06 +0530488 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530489 if len(vs.Pbits) == 0 {
490 pBits = append(pBits, PbitMatchNone)
491 }
492 for _, pbits := range pBits {
493 usflows, err := vs.BuildUsHsiaFlows(pbits)
494 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530495 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530496 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
497 vs.triggerServiceFailureInd(statusCode, statusMessage)
498 continue
499 }
500 usflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530501 if err = vs.DelFlows(cntx, device, usflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530502 logger.Errorw(ctx, "Error Deleting HSIA US flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530503 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
504 vs.triggerServiceFailureInd(statusCode, statusMessage)
505 }
506 }
507 vs.UsHSIAFlowsApplied = false
508 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530509 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 +0530510 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530511 return nil
512}
513
514// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530515func (vs *VoltService) DelDsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530516 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530517 if vs.DsHSIAFlowsApplied || vgcRebooted {
518 device, err := GetApplication().GetDeviceFromPort(vs.Port)
519 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530520 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 +0530521 }
522
Naveen Sampath04696f72022-06-13 15:19:14 +0530523 var matchPbit int
vinokuma926cb3e2023-03-29 11:41:06 +0530524 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530525 if len(vs.DsRemarkPbitsMap) == 0 {
526 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
527 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530528 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 +0530529 }
530 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530531 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530532 logger.Errorw(ctx, "Error Deleting HSIA DS flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530533 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
534 vs.triggerServiceFailureInd(statusCode, statusMessage)
535 }
536 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
537 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
538 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530539 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 +0530540 }
541 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530542 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530543 logger.Errorw(ctx, "Error Deleting HSIA DS flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530544 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
545 vs.triggerServiceFailureInd(statusCode, statusMessage)
546 }
547 } else {
548 for matchPbit = range vs.DsRemarkPbitsMap {
549 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
550 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530551 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530552 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
553 vs.triggerServiceFailureInd(statusCode, statusMessage)
554 continue
555 }
556 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530557 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530558 logger.Errorw(ctx, "Error Deleting HSIA DS flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name, "Reason": err.Error()})
Naveen Sampath04696f72022-06-13 15:19:14 +0530559 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
560 vs.triggerServiceFailureInd(statusCode, statusMessage)
561 }
562 }
563 }
564 vs.DsHSIAFlowsApplied = false
565 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +0530566 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 +0530567 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530568 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530569 return nil
570}
571
572// BuildDsHsiaFlows build the DS HSIA flows
573// Called for add/delete HSIA flows
574func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530575 logger.Debugw(ctx, "Building DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530576 flow := &of.VoltFlow{}
577 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
578
Naveen Sampath04696f72022-06-13 15:19:14 +0530579 device, err := GetApplication().GetDeviceFromPort(vs.Port)
580 if err != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530581 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 +0530582 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530583 // inport will be obtained from nniPort of service else we'll use the default nni port
584 var inport uint32
585 // Get the out and in ports for the flows
586 if vs.NniPort != "" {
587 if nniPortID := device.GetPortIDFromPortName(vs.NniPort); nniPortID != 0 {
588 inport = nniPortID
589 } else {
590 return nil, fmt.Errorf("error getting portID for NNI port %s of Service %s", vs.NniPort, vs.Name)
591 }
592 } else {
593 nniPort, err1 := GetApplication().GetNniPort(device.Name)
594 if err != nil {
595 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err1})
596 return nil, err1
597 }
598 inport, _ = GetApplication().GetPortID(nniPort)
599 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530600 outport, _ := GetApplication().GetPortID(vs.Port)
601 // PortName and PortID to be used for validation of port before flow pushing
602 flow.PortID = outport
603 flow.PortName = vs.Port
604 allowTransparent := 0
605 if vs.AllowTransparent {
606 allowTransparent = 1
607 }
608
609 // initialized actnPbit to 0 for cookie genration backward compatibility.
610 var actnPbit of.PbitType
611 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
612
613 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530614 // | 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 +0530615 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
616 cookie = cookie | of.DsFlowMask
617 cookie = cookie + (valToShift << 4) + uint64(pbits)
618 return cookie
619 }
620
621 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
622 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530623 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 +0530624 }
625
626 // Add Table-0 flow that deals with the outer VLAN in pOLT
627 {
628 subflow1 := of.NewVoltSubFlow()
629 subflow1.SetTableID(0)
630 subflow1.SetGoToTable(1)
631 subflow1.SetInPort(inport)
632
633 if pbits != PbitMatchNone {
634 subflow1.SetMatchPbit(pbits)
635 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530636 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
637 subflow1.SetPcp(of.PbitType(remarkPbit))
638 // match & action pbits are different, set remark-pbit action
639 actnPbit = of.PbitType(remarkPbit)
640 // mask remark p-bit to 4bits
641 actnPbit = actnPbit & 0x0F
642 }
643
644 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
645 return nil, err
646 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530647 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530648 if NonZeroMacAddress(vs.MacAddr) {
649 subflow1.SetMatchDstMac(vs.MacAddr)
650 }
651 subflow1.Priority = of.HsiaFlowPriority
652 subflow1.SetMeterID(vs.DsMeterID)
653
654 /* WriteMetaData 8 Byte(uint64) usage:
655 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
656 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
657 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530658 if vs.ServiceType == FttbSubscriberTraffic {
659 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
660 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530661 subflow1.SetWriteMetadata(metadata)
662
663 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
664 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
665 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
666 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
667
668 //TODO-COMM:
669 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
670 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
671 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
672 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
673
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530674 if vs.ServiceType != FttbSubscriberTraffic {
675 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
676 subflow1.SetTableMetadata(metadata)
677 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530678 // TODO - We are using cookie as key and must come up with better cookie
679 // allocation algorithm
680 /**
681 * Cokies may clash when -
682 * on same uni-port we have two sub-service
683 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
684 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
685 * However, this p-bit re-use will not be allowed by sub-mgr.
686 */
687 if vs.VlanControl == OLTCVlanOLTSVlan {
688 /**
689 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
690 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
691 * use old cookie.
692 */
693 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
694 if vgcRebooted {
695 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
696 }
697 } else {
698 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
699 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
700 }
701
702 flow.SubFlows[subflow1.Cookie] = subflow1
703 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
704 "subflow": subflow1})
705 }
706
vinokuma926cb3e2023-03-29 11:41:06 +0530707 // Add Table-1 flow that deals with inner VLAN at the ONU
Naveen Sampath04696f72022-06-13 15:19:14 +0530708 {
709 subflow2 := of.NewVoltSubFlow()
710 subflow2.SetTableID(1)
711 subflow2.SetInPort(inport)
712 if NonZeroMacAddress(vs.MacAddr) {
713 subflow2.SetMatchDstMac(vs.MacAddr)
714 }
715
716 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
717 return nil, err
718 }
719 if pbits != PbitMatchNone {
720 subflow2.SetMatchPbit(pbits)
721 }
722
723 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
724 subflow2.SetPcp(of.PbitType(remarkPbit))
725 }
726
727 subflow2.SetOutPort(outport)
728 subflow2.SetMeterID(vs.DsMeterID)
729
730 // refer Table-0 flow generation for byte information
731 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530732 if vs.ServiceType == FttbSubscriberTraffic {
733 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
734 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530735 subflow2.SetWriteMetadata(metadata)
736
737 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
738 if util.IsNniPort(inport) {
739 metadata = uint64(outport)
740 } else {
741 // refer Table-0 flow generation for byte information
742 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
743 }
744 subflow2.SetTableMetadata(metadata)
745 // Setting of Cookie - TODO - Improve the allocation algorithm
746 if vs.VlanControl == OLTCVlanOLTSVlan {
747 /**
748 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
749 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
750 * use old cookie.
751 */
752 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
753 if vgcRebooted {
754 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
755 }
756 } else {
757 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
758 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
759 }
760
761 subflow2.Priority = of.HsiaFlowPriority
762 flow.SubFlows[subflow2.Cookie] = subflow2
763 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
764 "subflow": subflow2})
765 }
766
767 return flow, nil
768}
769
770// BuildUsHsiaFlows build the US HSIA flows
771// Called for add/delete HSIA flows
772func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Akash Sonief452f12024-12-12 18:20:28 +0530773 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 +0530774 flow := &of.VoltFlow{}
775 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
776
Naveen Sampath04696f72022-06-13 15:19:14 +0530777 device, err := GetApplication().GetDeviceFromPort(vs.Port)
778 if err != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530779 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 +0530780 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530781 // outport will be obtained from nniPort of service else we'll use the default nni port
782 var outport uint32
783 // Get the out and in ports for the flows
784 if vs.NniPort != "" {
785 if nniPortID := device.GetPortIDFromPortName(vs.NniPort); nniPortID != 0 {
786 outport = nniPortID
787 } else {
788 return nil, fmt.Errorf("error getting portID for NNI port %s of Service %s : %w", vs.NniPort, vs.Name, err)
789 }
790 } else {
791 nniPort, err := GetApplication().GetNniPort(device.Name)
792 if err != nil {
793 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
794 return nil, err
795 }
796 outport, _ = GetApplication().GetPortID(nniPort)
797 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530798 inport, _ := GetApplication().GetPortID(vs.Port)
799 // PortName and PortID to be used for validation of port before flow pushing
800 flow.PortID = inport
801 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530802
803 // Add Table-0 flow that deals with the inner VLAN in ONU
804 {
805 subflow1 := of.NewVoltSubFlow()
806 subflow1.SetTableID(0)
807 subflow1.SetGoToTable(1)
808 subflow1.SetInPort(inport)
809
vinokuma926cb3e2023-03-29 11:41:06 +0530810 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530811 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
812 subflow1.SetPcp(vs.UsPonSTagPriority)
vinokuma926cb3e2023-03-29 11:41:06 +0530813 } else if vs.ServiceType == DpuAncpTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530814 subflow1.SetPcp(vs.UsPonSTagPriority)
815 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530816 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
817 return nil, err
818 }
819 subflow1.SetMeterID(vs.UsMeterID)
820
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530821 /* WriteMetaData 8 Byte(uint64) usage:
822 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
823 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
824 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
825 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530826 if vs.ServiceType == FttbSubscriberTraffic {
827 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
828 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530829 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530830
Naveen Sampath04696f72022-06-13 15:19:14 +0530831 if vs.VlanControl == OLTCVlanOLTSVlan {
832 /**
833 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
834 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
835 * use old cookie.
836 */
837 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
838 if vgcRebooted {
839 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
840 }
841 } else {
842 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
843 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
844 }
845 subflow1.Priority = of.HsiaFlowPriority
846 flow.SubFlows[subflow1.Cookie] = subflow1
847 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
848 }
849
vinokuma926cb3e2023-03-29 11:41:06 +0530850 // Add Table-1 flow that deals with the outer vlan in pOLT
Naveen Sampath04696f72022-06-13 15:19:14 +0530851 {
852 subflow2 := of.NewVoltSubFlow()
853 subflow2.SetTableID(1)
854 subflow2.SetInPort(inport)
855
Naveen Sampath04696f72022-06-13 15:19:14 +0530856 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
857 return nil, err
858 }
vinokuma926cb3e2023-03-29 11:41:06 +0530859 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530860 subflow2.SetMatchSrcMac(vs.MacAddr)
861 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530862 subflow2.SetInPort(inport)
863 subflow2.SetOutPort(outport)
864 subflow2.SetMeterID(vs.UsMeterID)
865
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530866 // refer Table-0 flow generation for byte information
867 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530868 if vs.ServiceType == FttbSubscriberTraffic {
869 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
870 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530871 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530872
Naveen Sampath04696f72022-06-13 15:19:14 +0530873 if vs.VlanControl == OLTCVlanOLTSVlan {
874 /**
875 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
876 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
877 * use old cookie.
878 */
879 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
880 if vgcRebooted {
881 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
882 }
883 } else {
884 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
885 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
886 }
887 subflow2.Priority = of.HsiaFlowPriority
888
889 flow.SubFlows[subflow2.Cookie] = subflow2
890 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
891 }
892
893 return flow, nil
894}
895
896func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530897 // | 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 +0530898 logger.Debugw(ctx, "Generate US Cookie", log.Fields{"Vlan": vlan, "ValToShift": vlan, "Inport": inport, "Pbits": pbits})
Naveen Sampath04696f72022-06-13 15:19:14 +0530899 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
900 cookie = cookie | of.UsFlowMask
901 cookie = cookie + (valToShift << 4) + uint64(pbits)
902 return cookie
903}
904
905// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
906// based on different Vlan Controls
907func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530908 logger.Debugw(ctx, "Set US Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530909 switch vs.VlanControl {
910 case None:
911 flow.SetMatchVlan(vs.SVlan)
912 case ONUCVlanOLTSVlan:
913 flow.SetMatchVlan(vs.CVlan)
914 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
915 case OLTCVlanOLTSVlan:
916 flow.SetMatchVlan(vs.UniVlan)
917 flow.SetSetVlan(vs.CVlan)
918 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
919 case ONUCVlan:
920 flow.SetMatchVlan(vs.SVlan)
921 case OLTSVlan:
922 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
923 flow.SetMatchVlan(vs.UniVlan)
924 flow.SetSetVlan(vs.SVlan)
925 } else if vs.UniVlan != of.VlanNone {
926 flow.SetMatchVlan(vs.UniVlan)
927 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
928 } else {
929 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
930 }
931 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530932 err := errorCodes.ErrInvalidParamInRequest
933 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530934 }
935 return nil
936}
937
938// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
939// based on different Vlan Controls
940func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530941 logger.Debugw(ctx, "Set DS Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530942 switch vs.VlanControl {
943 case None:
944 flow.SetMatchVlan(vs.SVlan)
945 case ONUCVlanOLTSVlan:
946 flow.SetMatchVlan(vs.SVlan)
947 flow.SetPopVlan()
948 case OLTCVlanOLTSVlan:
949 flow.SetMatchVlan(vs.SVlan)
950 flow.SetPopVlan()
951 flow.SetSetVlan(vs.UniVlan)
952 case ONUCVlan:
953 flow.SetMatchVlan(vs.SVlan)
954 case OLTSVlan:
955 flow.SetMatchVlan(vs.SVlan)
956 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
957 flow.SetSetVlan(vs.UniVlan)
958 } else {
959 flow.SetPopVlan()
960 }
961 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530962 err := errorCodes.ErrInvalidParamInRequest
963 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530964 }
965 return nil
966}
967
968// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
969// based on different Vlan Controls
970func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530971 logger.Debugw(ctx, "Set US Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530972 switch vs.VlanControl {
973 case None:
974 flow.SetMatchVlan(vs.SVlan)
975 case ONUCVlanOLTSVlan:
976 if vs.UniVlan != of.VlanNone {
977 flow.SetMatchVlan(vs.UniVlan)
978 flow.SetSetVlan(vs.CVlan)
979 } else {
980 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
981 }
982 case OLTCVlanOLTSVlan:
983 flow.SetMatchVlan(vs.UniVlan)
984 case ONUCVlan:
985 if vs.UniVlan != of.VlanNone {
986 flow.SetMatchVlan(vs.UniVlan)
987 flow.SetSetVlan(vs.SVlan)
988 } else {
989 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
990 }
991 case OLTSVlan:
992 flow.SetMatchVlan(vs.UniVlan)
993 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530994 err := errorCodes.ErrInvalidParamInRequest
995 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530996 }
997 return nil
998}
999
1000// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
1001// based on different Vlan Controls
1002func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301003 logger.Debugw(ctx, "Set DS Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05301004 switch vs.VlanControl {
1005 case None:
1006 flow.SetMatchVlan(vs.SVlan)
1007 case ONUCVlanOLTSVlan:
1008 flow.SetMatchVlan(vs.CVlan)
1009 if vs.UniVlan != of.VlanNone {
1010 flow.SetSetVlan(vs.UniVlan)
1011 } else {
1012 flow.SetPopVlan()
1013 }
1014 case OLTCVlanOLTSVlan:
1015 flow.SetMatchVlan(vs.UniVlan)
1016 case ONUCVlan:
1017 flow.SetMatchVlan(vs.SVlan)
1018 if vs.UniVlan != of.VlanNone {
1019 flow.SetSetVlan(vs.UniVlan)
1020 } else {
1021 flow.SetPopVlan()
1022 }
1023 case OLTSVlan:
1024 flow.SetMatchVlan(vs.UniVlan)
1025 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301026 err := errorCodes.ErrInvalidParamInRequest
1027 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301028 }
1029 return nil
1030}
1031
1032// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301033func (vs *VoltService) SvcUpInd(cntx context.Context) {
1034 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301035}
1036
1037// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301038func (vs *VoltService) SvcDownInd(cntx context.Context) {
1039 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301040}
1041
1042// SetIpv4Addr to set ipv4 address
1043func (vs *VoltService) SetIpv4Addr(addr net.IP) {
1044 vs.Ipv4Addr = addr
1045}
1046
1047// SetIpv6Addr to set ipv6 address
1048func (vs *VoltService) SetIpv6Addr(addr net.IP) {
1049 vs.Ipv6Addr = addr
1050}
1051
1052// SetMacAddr to set mac address
1053func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
1054 vs.MacAddr = addr
1055}
1056
1057// ----------------------------------------------
1058// VOLT Application - Related to services
1059// ---------------------------------------------
1060// ---------------------------------------------------------------
1061// Service CRUD functions. These are exposed to the overall binary
1062// to be invoked from the point where the CRUD operations are received
1063// from the external entities
1064
1065// AddService : A service in the context of VOLT is a subscriber or service of a
1066// subscriber which is uniquely identified by a combination of MAC
1067// address, VLAN tags, 802.1p bits. However, in the context of the
1068// current implementation, a service is an entity that is identified by a
1069// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
1070// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301071func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301072 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
Naveen Sampath04696f72022-06-13 15:19:14 +05301073 var mmUs, mmDs *VoltMeter
1074 var err error
1075
vinokuma926cb3e2023-03-29 11:41:06 +05301076 // Take the Device lock only in case of NB add request.
Naveen Sampath04696f72022-06-13 15:19:14 +05301077 // Allow internal adds since internal add happen only under
1078 // 1. Restore Service from DB
1079 // 2. Service Migration
1080 if oper == nil {
1081 if svc := va.GetService(cfg.Name); svc != nil {
1082 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301083 return errors.New("service already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301084 }
1085 }
1086
Naveen Sampath04696f72022-06-13 15:19:14 +05301087 // Service doesn't exist. So create it and add to the port
1088 vs := NewVoltService(&cfg)
1089 if oper != nil {
1090 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1091 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1092 vs.Ipv4Addr = oper.Ipv4Addr
1093 vs.Ipv6Addr = oper.Ipv6Addr
1094 vs.MacLearning = cfg.MacLearning
1095 vs.PendingFlows = oper.PendingFlows
1096 vs.AssociatedFlows = oper.AssociatedFlows
1097 vs.DeleteInProgress = oper.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301098 vs.DeactivateInProgress = oper.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301099 vs.BwAvailInfo = oper.BwAvailInfo
1100 vs.Device = oper.Device
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301101 vs.ServiceDeactivateReason = cfg.ServiceDeactivateReason
Naveen Sampath04696f72022-06-13 15:19:14 +05301102 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301103 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301104 sort.Slice(vs.Pbits, func(i, j int) bool {
1105 return vs.Pbits[i] > vs.Pbits[j]
1106 })
Akash Sonief452f12024-12-12 18:20:28 +05301107 logger.Debugw(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
Naveen Sampath04696f72022-06-13 15:19:14 +05301108 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301109 logger.Debugw(ctx, "VolthService...", log.Fields{"vs": vs})
Naveen Sampath04696f72022-06-13 15:19:14 +05301110
1111 // The bandwidth and shaper profile combined into meter
1112 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1113 vs.DsMeterID = mmDs.ID
1114 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301115 return errors.New("downStream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301116 }
1117
1118 // The aggregated downstream meter profile
1119 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1120 // vs.AggDsMeterID = mmAg.ID
1121 // } else {
1122 // return errors.New("Aggregated meter profile not found")
1123 // }
1124
1125 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1126 // vs.UsMeterID = mmAg.ID
1127 // } else {
1128 // The bandwidth and shaper profile combined into meter
1129 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1130 vs.UsMeterID = mmUs.ID
1131 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301132 return errors.New("upstream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301133 }
1134 //}
1135
1136 AppMutex.ServiceDataMutex.Lock()
1137 defer AppMutex.ServiceDataMutex.Unlock()
1138
1139 // Add the service to the VNET
1140 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1141 if vnet != nil {
1142 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1143 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301144 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301145 vpv.VpvLock.Unlock()
1146 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301147 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301148 }
1149 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301150 logger.Warnw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
1151 return errors.New("vnet doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301152 }
1153
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301154 // If the device is already discovered, update the device name in service
1155 d, err := va.GetDeviceFromPort(vs.Port)
1156 if err == nil {
1157 vs.Device = d.Name
1158 }
1159
Naveen Sampath04696f72022-06-13 15:19:14 +05301160 vs.Version = database.PresentVersionMap[database.ServicePath]
1161 // Add the service to the volt application
1162 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301163 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301164
1165 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301166 if !vs.UsHSIAFlowsApplied {
1167 vs.triggerServiceInProgressInd()
1168 }
1169
vinokuma926cb3e2023-03-29 11:41:06 +05301170 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301171 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301172 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301173 if mmUs != nil {
1174 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301175 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301176 }
1177 //mmAg.AssociatedServices++
1178 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301179 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301180 }
1181
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301182 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 +05301183 return nil
1184}
1185
vinokuma926cb3e2023-03-29 11:41:06 +05301186// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301187// Added for DT/TT usecase with sadis replica interface
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301188func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) error {
Akash Sonief452f12024-12-12 18:20:28 +05301189 logger.Debugw(ctx, "Delete Service With provided Prefix", log.Fields{"Prefix": prefix})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301190 var isServiceExist bool
Naveen Sampath04696f72022-06-13 15:19:14 +05301191 va.ServiceByName.Range(func(key, value interface{}) bool {
1192 srvName := key.(string)
1193 vs := value.(*VoltService)
1194 if strings.Contains(srvName, prefix) {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301195 isServiceExist = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301196 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301197
1198 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1199 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1200 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1201
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301202 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301203 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1204 }
1205 }
1206 return true
1207 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301208
1209 if !isServiceExist {
1210 return errorCodes.ErrServiceNotFound
1211 }
1212 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301213}
1214
1215// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301216func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301217 AppMutex.ServiceDataMutex.Lock()
1218 defer AppMutex.ServiceDataMutex.Unlock()
1219
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301220 logger.Infow(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
Naveen Sampath04696f72022-06-13 15:19:14 +05301221 var noFlowsPresent bool
1222
1223 vsIntf, ok := va.ServiceByName.Load(name)
1224 if !ok {
1225 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1226 return
1227 }
1228 vs := vsIntf.(*VoltService)
1229 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1230 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301231 logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301232 return
1233 }
1234
vinokuma926cb3e2023-03-29 11:41:06 +05301235 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301236 vs.DeleteInProgress = true
1237 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301238 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301239
Akash Sonief452f12024-12-12 18:20:28 +05301240 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301241 if len(vs.AssociatedFlows) == 0 {
1242 noFlowsPresent = true
1243 }
Akash Sonief452f12024-12-12 18:20:28 +05301244 vs.ServiceLock.RUnlock()
1245
Naveen Sampath04696f72022-06-13 15:19:14 +05301246 vpv.VpvLock.Lock()
1247 defer vpv.VpvLock.Unlock()
1248
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301249 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301250
1251 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301252 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301253 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301254 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 +05301255 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301256 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301257 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301258 }
1259
1260 // Delete the service immediately in case of Force Delete
1261 // This will be enabled when profile reconciliation happens after restore
1262 // of backedup data
1263 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301264 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301265 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301266 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301267 }
1268
Naveen Sampath04696f72022-06-13 15:19:14 +05301269 if nil != newSvc {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301270 logger.Debugw(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1271 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 +05301272 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301273
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301274 logger.Debugw(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301275
1276 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1277 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301278 if aggMeter.AssociatedServices > 0 {
1279 aggMeter.AssociatedServices--
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301280 logger.Debugw(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
vinokuma926cb3e2023-03-29 11:41:06 +05301281 va.UpdateMeterProf(cntx, *aggMeter)
1282 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301283 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301284 }
1285 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301286 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1287 if dsMeter.AssociatedServices > 0 {
1288 dsMeter.AssociatedServices--
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301289 logger.Debugw(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
vinokuma926cb3e2023-03-29 11:41:06 +05301290 va.UpdateMeterProf(cntx, *dsMeter)
1291 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301292 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301293 }
1294 if vs.AggDsMeterID != vs.UsMeterID {
1295 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301296 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1297 if usMeter.AssociatedServices > 0 {
1298 usMeter.AssociatedServices--
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301299 logger.Debugw(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
vinokuma926cb3e2023-03-29 11:41:06 +05301300 va.UpdateMeterProf(cntx, *usMeter)
1301 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301302 }
1303 }
1304 }
1305
1306 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301307 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301308 }
1309
vinokuma926cb3e2023-03-29 11:41:06 +05301310 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301311 va.ServiceCounters.Delete(name)
1312 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301313 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301314 }
1315}
1316
vinokuma926cb3e2023-03-29 11:41:06 +05301317// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301318// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301319func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301320 // Using locks instead of concurrent map for PendingFlows to avoid
1321 // race condition during flow response indication processing
1322 vs.ServiceLock.Lock()
1323 defer vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301324 logger.Debugw(ctx, "Adds the flow to the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301325
1326 for cookie := range flow.SubFlows {
1327 cookie := strconv.FormatUint(cookie, 10)
1328 fe := &FlowEvent{
1329 eType: EventTypeServiceFlowAdded,
1330 device: device.Name,
1331 cookie: cookie,
1332 eventData: vs,
1333 }
1334 device.RegisterFlowAddEvent(cookie, fe)
1335 vs.PendingFlows[cookie] = true
1336 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301337 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301338}
1339
vinokuma926cb3e2023-03-29 11:41:06 +05301340// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301341// If no more pending flows, HSIA indication wil be triggered
Akash Sonief452f12024-12-12 18:20:28 +05301342func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301343 logger.Debugw(ctx, "Flow Add Success Notification", log.Fields{"Cookie": cookie, "bwAvailInfo": bwAvailInfo, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301344 if vs.DeleteInProgress {
1345 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1346 return
1347 }
1348 vs.ServiceLock.Lock()
1349
1350 if _, ok := vs.PendingFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301351 logger.Warnw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301352 vs.ServiceLock.Unlock()
1353 return
1354 }
1355
1356 delete(vs.PendingFlows, cookie)
1357 vs.AssociatedFlows[cookie] = true
1358 vs.ServiceLock.Unlock()
1359 var prevBwAvail, presentBwAvail string
1360 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1361 prevBwAvail = bwAvailInfo.PrevBw
1362 presentBwAvail = bwAvailInfo.PresentBw
1363 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301364 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301365 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301366 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301367
Akash Sonief452f12024-12-12 18:20:28 +05301368 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301369 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Akash Sonief452f12024-12-12 18:20:28 +05301370 vs.ServiceLock.RUnlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301371 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1372 if err != nil {
1373 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1374 return
1375 } else if device.State != controller.DeviceStateUP {
1376 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1377 return
1378 }
1379
1380 if vs.Trigger == ServiceVlanUpdate {
1381 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301382 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301383 }
1384 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1385 return
1386 }
Akash Sonief452f12024-12-12 18:20:28 +05301387 vs.ServiceLock.RUnlock()
1388 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 +05301389}
1390
vinokuma926cb3e2023-03-29 11:41:06 +05301391// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301392// Trigger service failure indication to NB
Akash Sonief452f12024-12-12 18:20:28 +05301393func (vs *VoltService) FlowInstallFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301394 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 +05301395 vs.ServiceLock.RLock()
Akash Sonief452f12024-12-12 18:20:28 +05301396
Naveen Sampath04696f72022-06-13 15:19:14 +05301397 if _, ok := vs.PendingFlows[cookie]; !ok {
1398 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1399 vs.ServiceLock.RUnlock()
1400 return
1401 }
1402 vs.ServiceLock.RUnlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301403 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 +05301404 vs.triggerServiceFailureInd(errorCode, errReason)
1405}
1406
vinokuma926cb3e2023-03-29 11:41:06 +05301407// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301408// Triggers flow deletion after registering for flow indication event
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301409func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow, delFlowsInDevice bool) error {
Akash Sonief452f12024-12-12 18:20:28 +05301410 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 +05301411 if !vs.ForceDelete {
1412 // Using locks instead of concurrent map for AssociatedFlows to avoid
1413 // race condition during flow response indication processing
1414 vs.ServiceLock.Lock()
1415 defer vs.ServiceLock.Unlock()
1416
1417 for cookie := range flow.SubFlows {
1418 cookie := strconv.FormatUint(cookie, 10)
1419 fe := &FlowEvent{
1420 eType: EventTypeServiceFlowRemoved,
1421 cookie: cookie,
1422 eventData: vs,
1423 }
1424 device.RegisterFlowDelEvent(cookie, fe)
1425 }
1426 }
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301427 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow, delFlowsInDevice)
Naveen Sampath04696f72022-06-13 15:19:14 +05301428}
1429
vinokuma926cb3e2023-03-29 11:41:06 +05301430// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301431func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301432 logger.Debugw(ctx, "Delete service from DB/Cache", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301433 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301434 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301435 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301436 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301437 }
1438}
1439
vinokuma926cb3e2023-03-29 11:41:06 +05301440// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301441// If no more associated flows, DelHSIA indication wil be triggered
Akash Sonief452f12024-12-12 18:20:28 +05301442func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301443 // if vs.DeleteInProgress {
1444 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1445 // return
1446 // }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301447
Naveen Sampath04696f72022-06-13 15:19:14 +05301448 vs.ServiceLock.Lock()
Akash Sonief452f12024-12-12 18:20:28 +05301449 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 +05301450
1451 if _, ok := vs.AssociatedFlows[cookie]; ok {
1452 delete(vs.AssociatedFlows, cookie)
1453 } else if _, ok := vs.PendingFlows[cookie]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301454 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 +05301455 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301456 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 +05301457 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301458 vs.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301459 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301460
Akash Sonief452f12024-12-12 18:20:28 +05301461 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301462 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Akash Sonief452f12024-12-12 18:20:28 +05301463 vs.ServiceLock.RUnlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301464 device := GetApplication().GetDevice(vs.Device)
1465 if device == nil {
1466 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1467 return
1468 } else if device.State != controller.DeviceStateUP {
1469 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1470 return
1471 }
1472
1473 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301474 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301475 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301476 return
1477 }
1478 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 +05301479 // Get the service from application before proceeding to delete, as the service might have been activated
1480 // by the time the flow removal response is received from SB
1481 svc := GetApplication().GetService(vs.Name)
1482 if svc != nil {
1483 svc.CheckAndDeleteService(cntx)
1484 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301485
1486 return
1487 }
Akash Sonief452f12024-12-12 18:20:28 +05301488 vs.ServiceLock.RUnlock()
1489 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 +05301490}
1491
vinokuma926cb3e2023-03-29 11:41:06 +05301492// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301493// Trigger service failure indication to NB
Akash Sonief452f12024-12-12 18:20:28 +05301494func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301495 vs.ServiceLock.Lock()
Akash Sonief452f12024-12-12 18:20:28 +05301496 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 +05301497
1498 if _, ok := vs.AssociatedFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301499 logger.Warnw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301500 vs.ServiceLock.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301501 return
1502 }
1503 if vs.DeleteInProgress {
1504 delete(vs.AssociatedFlows, cookie)
1505 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301506 vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301507 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 +05301508
1509 vs.triggerServiceFailureInd(errorCode, errReason)
Akash Sonief452f12024-12-12 18:20:28 +05301510 // Get the service from application before proceeding to delete, as the service might have been activated
1511 // by the time the flow removal response is received from SB
1512 svc := GetApplication().GetService(vs.Name)
1513 if svc != nil {
1514 svc.CheckAndDeleteService(cntx)
1515 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301516}
1517
1518func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301519 logger.Debugw(ctx, "Trigger Service Failure Ind", log.Fields{"Service": vs.Name, "Port": vs.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301520 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1521 if err != nil {
1522 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1523 return
1524 } else if device.State != controller.DeviceStateUP {
1525 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1526 return
1527 }
1528}
1529
1530// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301531func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301532 // VNETS must be learnt first
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301533 logger.Debug(ctx, "Restore Svcs From Db")
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301534 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301535 for _, vs := range vss {
1536 b, ok := vs.Value.([]byte)
1537 if !ok {
1538 logger.Warn(ctx, "The value type is not []byte")
1539 continue
1540 }
1541 var vvs VoltService
1542 err := json.Unmarshal(b, &vvs)
1543 if err != nil {
1544 logger.Warn(ctx, "Unmarshal of VNET failed")
1545 continue
1546 }
1547 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301548 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301549 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1550 }
1551
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301552 if vvs.VoltServiceOper.DeactivateInProgress {
Akash Sonief452f12024-12-12 18:20:28 +05301553 va.ServicesToDeactivate.Store(vvs.VoltServiceCfg.Name, true)
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301554 logger.Warnw(ctx, "Service (restored) to be deactivated", log.Fields{"Service": vvs.Name})
1555 }
1556
Naveen Sampath04696f72022-06-13 15:19:14 +05301557 if vvs.VoltServiceOper.DeleteInProgress {
Akash Sonief452f12024-12-12 18:20:28 +05301558 va.ServicesToDelete.Store(vvs.VoltServiceCfg.Name, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301559 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1560 }
1561 }
1562}
1563
1564// GetService to get service
1565func (va *VoltApplication) GetService(name string) *VoltService {
1566 if vs, ok := va.ServiceByName.Load(name); ok {
1567 return vs.(*VoltService)
1568 }
1569 return nil
1570}
1571
1572// GetCircuitID to get circuit id
1573func (vs *VoltService) GetCircuitID() []byte {
1574 return []byte(vs.CircuitID)
1575}
1576
1577// GetRemoteID to get remote id
1578func (vs *VoltService) GetRemoteID() []byte {
1579 return []byte(vs.RemoteID)
1580}
1581
1582// IPAssigned to check if ip is assigned
1583func (vs *VoltService) IPAssigned() bool {
1584 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1585 return true
1586 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1587 return true
1588 }
1589 return false
1590}
1591
1592// GetServiceNameFromCookie to get service name from cookie
1593func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301594 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 +05301595 var vlan uint64
1596 vlanControl := (tableMetadata >> 32) & 0xF
1597
1598 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1599 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1600 vlan = (tableMetadata >> 16) & 0xFFFF
1601 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301602 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301603 vlan = cookie >> 52
1604 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301605 logger.Debugw(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301606 var vlans []of.VlanType
1607 vlans = append(vlans, of.VlanType(vlan))
1608 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1609 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301610 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301611 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301612 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 +05301613 }
1614 return service
1615}
1616
vinokuma926cb3e2023-03-29 11:41:06 +05301617// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301618type MigrateServicesReqStatus string
1619
1620const (
vinokuma926cb3e2023-03-29 11:41:06 +05301621 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301622 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301623 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301624 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301625 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301626 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1627)
1628
vinokuma926cb3e2023-03-29 11:41:06 +05301629// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301630type MigrateServicesRequest struct {
1631 ID string
1632 OldVnetID string
1633 NewVnetID string
1634 ServicesList map[string]bool
1635 DeviceID string
1636 Status MigrateServicesReqStatus
1637 MigrateServicesLock sync.RWMutex
1638}
1639
1640func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301641 var msr MigrateServicesRequest
1642 msr.OldVnetID = oldVnetID
1643 msr.NewVnetID = newVnetID
1644 msr.ID = id
1645 msr.ServicesList = serviceMap
1646 msr.DeviceID = deviceID
1647 msr.Status = MigrateSrvsReqInit
1648 return &msr
1649}
1650
vinokuma926cb3e2023-03-29 11:41:06 +05301651// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301652func (msr *MigrateServicesRequest) GetMsrKey() string {
1653 return msr.OldVnetID + "-" + msr.ID
1654}
1655
1656// //isRequestComplete - return if all request has been processed and completed
1657// // RequestProcessed indicates that all the profile de-activation has been triggered
1658// // And the associated profiles indicates the profiles awaiting results
1659// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1660// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1661// return (len(edr.AssociatedProfiles) == 0)
1662// }
1663
vinokuma926cb3e2023-03-29 11:41:06 +05301664// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301665func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301666 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)})
1667 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301668 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301669 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301670 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301671 }
1672 }
1673}
1674
vinokuma926cb3e2023-03-29 11:41:06 +05301675// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301676func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301677 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 +05301678 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301679 return errors.New("old vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301680 }
1681 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301682 return errors.New("new vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301683 }
1684
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301685 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301686 if d == nil {
1687 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1688 return errorCodes.ErrDeviceNotFound
1689 }
1690
1691 serviceMap := make(map[string]bool)
1692
1693 for _, service := range serviceList {
1694 serviceMap[service] = false
1695 }
1696 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301697 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301698
1699 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301700 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301701 return nil
1702}
1703
vinokuma926cb3e2023-03-29 11:41:06 +05301704// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301705func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301706 logger.Debug(ctx, "Process Migrate Services Prof Request")
Naveen Sampath04696f72022-06-13 15:19:14 +05301707 va := GetApplication()
1708 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301709 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301710 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301711 va.DelService(cntx, srv, true, nil, true)
1712 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301713 continue
1714 }
1715
1716 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1717 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1718 vs := vsIntf.(*VoltService)
1719 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1720 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301721 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 +05301722 continue
1723 }
1724 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1725 vpv.Blocked = true
1726
1727 // setDeactTrigger := func(key, value interface{}) bool {
1728 // vs := value.(*VoltService)
1729 vs.ServiceLock.Lock()
1730 vs.UpdateInProgress = true
1731 metadata := &MigrateServiceMetadata{
1732 NewVnetID: msr.NewVnetID,
1733 RequestID: msr.ID,
1734 }
1735 vs.Metadata = metadata
1736 vs.ServiceLock.Unlock()
1737
vinokuma926cb3e2023-03-29 11:41:06 +05301738 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301739 // new vpv flows will be installed when new service is added
1740 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301741 vpv.DelTrapFlows(cntx)
1742 vs.DelHsiaFlows(cntx)
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301743 logger.Debugw(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301744 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301745 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301746 }
1747 } else {
1748 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1749 }
1750 }
1751}
1752
vinokuma926cb3e2023-03-29 11:41:06 +05301753// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301754func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301755 logger.Infow(ctx, "Add Migrating Services", log.Fields{"Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301756 var msrMap *util.ConcurrentMap
1757 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1758 msrMap = util.NewConcurrentMap()
1759 } else {
1760 msrMap = msrMapIntf.(*util.ConcurrentMap)
1761 }
1762
1763 msrMap.Set(msr.ID, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301764 logger.Debugw(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301765
1766 d.MigratingServices.Set(msr.OldVnetID, msrMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301767 logger.Debugw(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301768}
1769
vinokuma926cb3e2023-03-29 11:41:06 +05301770// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301771func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301772 logger.Debugw(ctx, "Get Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301773 if vd := va.GetDevice(deviceID); vd != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301774 logger.Debugw(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301775 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1776 msrList := msrListIntf.(*util.ConcurrentMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301777 logger.Debugw(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301778 if msrObj, ok := msrList.Get(requestID); ok {
1779 return msrObj.(*MigrateServicesRequest)
1780 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301781 }
1782 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301783 logger.Warnw(ctx, "Device Not Found", log.Fields{"DeviceID": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301784 return nil
1785}
1786
vinokuma926cb3e2023-03-29 11:41:06 +05301787// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301788func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301789 logger.Debugw(ctx, "Update Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301790 if vd := va.GetDevice(deviceID); vd != nil {
1791 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1792 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1793 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1794 }
1795 }
1796 }
1797}
1798
vinokuma926cb3e2023-03-29 11:41:06 +05301799// updateVnetProfile - Called on flow process completion
1800// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301801func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301802 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 +05301803
1804 nvs := VoltService{}
1805 nvs.VoltServiceCfg = vs.VoltServiceCfg
1806 nvs.Device = vs.Device
1807 nvs.Ipv4Addr = vs.Ipv4Addr
1808 nvs.Ipv6Addr = vs.Ipv6Addr
1809 nvs.UsMeterID = vs.UsMeterID
1810 nvs.DsMeterID = vs.DsMeterID
1811 nvs.AggDsMeterID = vs.AggDsMeterID
1812 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1813 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1814 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1815 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1816 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1817 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1818 nvs.PendingFlows = vs.PendingFlows
1819 nvs.AssociatedFlows = vs.AssociatedFlows
1820 nvs.DeleteInProgress = vs.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301821 nvs.DeactivateInProgress = vs.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301822 nvs.ForceDelete = vs.ForceDelete
1823 nvs.BwAvailInfo = vs.BwAvailInfo
1824 nvs.UpdateInProgress = vs.UpdateInProgress
1825
1826 if nvs.DeleteInProgress {
1827 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1828 return
1829 }
1830
1831 metadata := vs.Metadata.(*MigrateServiceMetadata)
1832 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301833 oldSrvName := vs.Name
1834
1835 if metadata == nil || metadata.NewVnetID == "" {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301836 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 +05301837 return
1838 }
1839
vinokuma926cb3e2023-03-29 11:41:06 +05301840 nvs.VnetID = metadata.NewVnetID
1841 id := metadata.RequestID
1842
1843 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301844 // Since if post del service in case of pod crash or reboot, the service data will be lost
1845 va := GetApplication()
1846 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1847 vnets := strings.Split(metadata.NewVnetID, "-")
1848 svlan, _ := strconv.Atoi(vnets[0])
1849 nvs.SVlan = of.VlanType(svlan)
1850 nvs.UpdateInProgress = false
1851 nvs.Metadata = nil
1852 nvs.Trigger = ServiceVlanUpdate
1853
1854 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1855 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1856 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1857
vinokuma926cb3e2023-03-29 11:41:06 +05301858 // TODO:Nav Pass a copy, not the pointer
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301859 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 +05301860 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301861 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1862 }
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301863 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 +05301864
1865 msr.ServicesList[oldSrvName] = true
1866 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301867 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301868
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301869 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 +05301870 va.DelService(cntx, oldSrvName, true, nil, true)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301871 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 +05301872 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301873}
1874
vinokuma926cb3e2023-03-29 11:41:06 +05301875// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301876// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301877func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301878 logger.Infow(ctx, "Service Migrated", log.Fields{"ServiceName": serviceName})
Naveen Sampath04696f72022-06-13 15:19:14 +05301879 msr.MigrateServicesLock.Lock()
1880 defer msr.MigrateServicesLock.Unlock()
1881
1882 delete(msr.ServicesList, serviceName)
1883
1884 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301885 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301886 return
1887 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301888 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301889 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301890}
1891
vinokuma926cb3e2023-03-29 11:41:06 +05301892// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301893func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1894 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301895}
1896
vinokuma926cb3e2023-03-29 11:41:06 +05301897// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301898func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05301899 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 +05301900 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301901 for _, msr := range msrList {
1902 b, ok := msr.Value.([]byte)
1903 if !ok {
1904 logger.Warn(ctx, "The value type is not []byte")
1905 continue
1906 }
1907 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301908 msrAction(cntx, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301909 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 +05301910 }
1911}
1912
1913// createMigrateServicesFromString to create Service from string
1914func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301915 logger.Info(ctx, "Create Migrate Services From String")
Naveen Sampath04696f72022-06-13 15:19:14 +05301916 var msr MigrateServicesRequest
1917 if err := json.Unmarshal(b, &msr); err == nil {
1918 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301919 } else {
1920 logger.Warn(ctx, "Unmarshal failed")
1921 }
1922 return &msr
1923}
1924
vinokuma926cb3e2023-03-29 11:41:06 +05301925// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301926func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301927 logger.Infow(ctx, "Store And Process Migrate Srv Request", log.Fields{"MsrID": msr.DeviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301928 d := GetApplication().GetDevice(msr.DeviceID)
1929 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301930 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301931}
1932
vinokuma926cb3e2023-03-29 11:41:06 +05301933// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301934func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301935 logger.Infow(ctx, "Force udpate services with new vnet profile", log.Fields{"MsrID": msr.NewVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301936 for srv := range msr.ServicesList {
1937 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301938 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301939 }
1940 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301941 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301942}
1943
vinokuma926cb3e2023-03-29 11:41:06 +05301944// nolint: gocyclo
1945// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301946func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1947 if nvs.Name != evs.Name {
1948 return false
1949 }
1950 if nvs.UniVlan != evs.UniVlan {
1951 return false
1952 }
1953 if nvs.CVlan != evs.CVlan {
1954 return false
1955 }
1956 if nvs.SVlan != evs.SVlan {
1957 return false
1958 }
1959 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1960 return false
1961 }
1962 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1963 return false
1964 }
1965 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1966 return false
1967 }
1968 if nvs.TechProfileID != evs.TechProfileID {
1969 return false
1970 }
1971 if nvs.CircuitID != evs.CircuitID {
1972 return false
1973 }
1974 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1975 return false
1976 }
1977 if nvs.Port != evs.Port {
1978 return false
1979 }
1980 if nvs.PonPort != evs.PonPort {
1981 return false
1982 }
1983 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1984 return false
1985 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301986 if nvs.IsOption82Enabled != evs.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +05301987 return false
1988 }
1989 if nvs.IgmpEnabled != evs.IgmpEnabled {
1990 return false
1991 }
1992 if nvs.McastService != evs.McastService {
1993 return false
1994 }
1995 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1996 return false
1997 }
1998 if nvs.UsMeterProfile != evs.UsMeterProfile {
1999 return false
2000 }
2001 if nvs.DsMeterProfile != evs.DsMeterProfile {
2002 return false
2003 }
2004 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
2005 return false
2006 }
2007 if nvs.VnetID != evs.VnetID {
2008 return false
2009 }
2010 if nvs.MvlanProfileName != evs.MvlanProfileName {
2011 return false
2012 }
2013 if nvs.RemoteIDType != evs.RemoteIDType {
2014 return false
2015 }
2016 if nvs.SchedID != evs.SchedID {
2017 return false
2018 }
2019 if nvs.AllowTransparent != evs.AllowTransparent {
2020 return false
2021 }
2022 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
2023 return false
2024 }
2025 if nvs.DataRateAttr != evs.DataRateAttr {
2026 return false
2027 }
2028 if nvs.MinDataRateUs != evs.MinDataRateUs {
2029 return false
2030 }
2031 if nvs.MinDataRateDs != evs.MinDataRateDs {
2032 return false
2033 }
2034 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
2035 return false
2036 }
2037 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
2038 return false
2039 }
2040
2041 return true
2042}
2043
vinokuma926cb3e2023-03-29 11:41:06 +05302044// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302045func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05302046 // Clear the Flows flag if already set
2047 // This case happens only in case of some race condition
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302048 logger.Infow(ctx, "Trigger Associated Flow Delete", log.Fields{"Device": vs.Device, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05302049 if vs.UsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302050 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302051 logger.Warnw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302052 }
2053 }
2054
2055 if vs.DsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302056 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302057 logger.Warnw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302058 }
2059 }
2060
2061 vs.ServiceLock.Lock()
2062 cookieList := []uint64{}
2063 for cookie := range vs.AssociatedFlows {
2064 cookieList = append(cookieList, convertToUInt64(cookie))
2065 }
2066 vs.ServiceLock.Unlock()
2067
2068 if len(cookieList) == 0 {
2069 return false
2070 }
2071
vinokuma926cb3e2023-03-29 11:41:06 +05302072 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05302073 for _, cookie := range cookieList {
2074 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
2075 flow := &of.VoltFlow{}
2076 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2077 subFlow := of.NewVoltSubFlow()
2078 subFlow.Cookie = cookie
2079 flow.SubFlows[cookie] = subFlow
2080 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302081 if err := vs.DelFlows(cntx, vd, flow, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302082 logger.Warnw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302083 }
2084 }
2085 }
2086 return true
2087}
2088
vinokuma926cb3e2023-03-29 11:41:06 +05302089// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05302090func (vs *VoltService) triggerServiceInProgressInd() {
2091}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302092
vinokuma926cb3e2023-03-29 11:41:06 +05302093// JSONMarshal wrapper function for json Marshal VoltService
2094func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302095 return json.Marshal(VoltService{
2096 VoltServiceCfg: vs.VoltServiceCfg,
2097 VoltServiceOper: VoltServiceOper{
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302098 Device: vs.VoltServiceOper.Device,
2099 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
2100 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
2101 UsMeterID: vs.VoltServiceOper.UsMeterID,
2102 DsMeterID: vs.VoltServiceOper.DsMeterID,
2103 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
2104 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
2105 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
2106 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
2107 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
2108 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
2109 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
2110 PendingFlows: vs.VoltServiceOper.PendingFlows,
2111 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2112 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2113 DeactivateInProgress: vs.VoltServiceOper.DeactivateInProgress,
2114 ForceDelete: vs.VoltServiceOper.ForceDelete,
2115 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2116 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2117 Metadata: vs.VoltServiceOper.Metadata,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302118 },
2119 })
2120}
Tinoj Josephec742f62022-09-29 19:11:10 +05302121
2122// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302123func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302124 var svcList []*VoltService
2125 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2126 va.ServiceByName.Range(func(key, value interface{}) bool {
2127 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302128 if len(deviceID) > 0 {
2129 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302130 if deviceID == vs.Device && portNo == vs.Port {
2131 svcList = append(svcList, vs)
2132 }
2133 } else {
2134 if deviceID == vs.Device {
2135 svcList = append(svcList, vs)
2136 }
2137 }
2138 } else {
2139 svcList = append(svcList, vs)
2140 }
2141 return true
2142 })
2143 return svcList, nil
2144}
2145
Akash Soni634d9bf2023-07-10 12:11:10 +05302146type FlowProvisionStatus struct {
2147 FlowProvisionStatus string
2148}
2149
2150// GetFlowProvisionStatus to get status of the subscriber and flow provisioned in controller
Akash Soni3c391e72023-08-16 12:21:33 +05302151func (va *VoltApplication) GetFlowProvisionStatus(portNo string) FlowProvisionStatus {
Akash Soni634d9bf2023-07-10 12:11:10 +05302152 logger.Infow(ctx, "GetFlowProvisionStatus Request ", log.Fields{"Port": portNo})
2153 flowProvisionStatus := FlowProvisionStatus{}
Akash Soni3c391e72023-08-16 12:21:33 +05302154 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_NOT_IN_CONTROLLER
Akash Soni634d9bf2023-07-10 12:11:10 +05302155 va.ServiceByName.Range(func(key, value interface{}) bool {
2156 vs := value.(*VoltService)
2157 logger.Debugw(ctx, "Volt Service ", log.Fields{"VS": vs})
Akash Soni3c391e72023-08-16 12:21:33 +05302158 if portNo == vs.Port {
2159 if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() == 0 {
2160 flowProvisionStatus.FlowProvisionStatus = ALL_FLOWS_PROVISIONED
2161 return false
2162 } else if !vs.IsActivated {
2163 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_DISABLED_IN_CONTROLLER
2164 return false
2165 } else if !vs.DsHSIAFlowsApplied && !vs.UsHSIAFlowsApplied {
2166 flowProvisionStatus.FlowProvisionStatus = NO_FLOWS_PROVISIONED
2167 return false
Akash Soni230e6212023-10-16 10:46:07 +05302168 } else if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() > 0 {
Akash Soni3c391e72023-08-16 12:21:33 +05302169 flowProvisionStatus.FlowProvisionStatus = FLOWS_PROVISIONED_PARTIALLY
2170 return false
Akash Soni634d9bf2023-07-10 12:11:10 +05302171 }
2172 }
2173 return true
2174 })
Akash Soni634d9bf2023-07-10 12:11:10 +05302175 return flowProvisionStatus
2176}
2177
2178func (vs *VoltService) LenOfPendingFlows() int {
2179 vs.ServiceLock.RLock()
2180 lth := len(vs.PendingFlows)
2181 vs.ServiceLock.RUnlock()
2182 return lth
2183}
2184
Tinoj Josephec742f62022-09-29 19:11:10 +05302185// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302186func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302187 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 +05302188 device, err := va.GetDeviceFromPort(portNo)
2189 if err != nil {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302190 // Lets activate the service even though port was not found. We will push the flows once the port is added by voltha
2191 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 +05302192 }
2193 // If device id is not provided check only port number
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302194 if device != nil {
2195 if deviceID == DeviceAny {
2196 deviceID = device.Name
2197 } else if deviceID != device.Name {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302198 err := errorCodes.ErrDeviceNotFound
2199 return fmt.Errorf("wrong device id %s : %w", deviceID, err)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302200 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302201 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302202 va.ServiceByName.Range(func(key, value interface{}) bool {
2203 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302204 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302205 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302206 logger.Debugw(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302207 return true
2208 }
2209 if portNo == vs.Port && !vs.IsActivated {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302210 // 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 +05302211 logger.Debugw(ctx, "Service Activate", log.Fields{"Name": vs.Name})
Tinoj Josephec742f62022-09-29 19:11:10 +05302212 vs.IsActivated = true
2213 va.ServiceByName.Store(vs.Name, vs)
2214 vs.WriteToDb(cntx)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302215
2216 // Push the flows only if the port is already added and we have a valid device
2217 if device != nil {
2218 p := device.GetPort(vs.Port)
2219 if p == nil {
2220 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2221 return true
2222 }
2223 // If port is already up send indication to vpv
2224 if p.State == PortStateUp {
2225 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2226 // PortUp call initiates flow addition
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302227 // The flow generation and pushing the flow can be done in a go routine,
2228 // VGC once service is activated remembers and pushes the flows again
2229 // if there was a restart in VGC during the execution of the go routine.
2230 // Making it as a go routine will not impact anything
2231 go vpv.PortUpInd(cntx, device, portNo, vs.NniPort)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302232 } else {
2233 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2234 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302235 }
2236 }
2237 }
2238 return true
2239 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302240 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302241}
2242
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302243func (vs *VoltService) SetSvcDeactivationFlags(deactivateRsn SvcDeactivateReason) {
2244 vs.DeactivateInProgress = true
2245 vs.IsActivated = false
2246 vs.ServiceDeactivateReason = deactivateRsn
2247}
2248
Tinoj Josephec742f62022-09-29 19:11:10 +05302249// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302250func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
balaji.nagarajan182b64f2025-09-04 11:25:17 +05302251 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 +05302252
Tinoj Josephec742f62022-09-29 19:11:10 +05302253 va.ServiceByName.Range(func(key, value interface{}) bool {
2254 vs := value.(*VoltService)
2255 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302256 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302257 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 +05302258 return true
2259 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302260 if portNo == vs.Port && vs.IsActivated {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302261 vs.SetSvcDeactivationFlags(SvcDeacRsn_NB)
Tinoj Josephec742f62022-09-29 19:11:10 +05302262 va.ServiceByName.Store(vs.Name, vs)
2263 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302264 device, err := va.GetDeviceFromPort(portNo)
2265 if err != nil {
2266 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2267 // So no error is returned
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302268 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302269 return true
2270 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302271 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302272 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302273 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2274 // Port down call internally deletes all the flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302275 vpv.PortDownInd(cntx, deviceID, portNo, true, false)
Tinoj Josephec742f62022-09-29 19:11:10 +05302276 if vpv.IgmpEnabled {
2277 va.ReceiverDownInd(cntx, deviceID, portNo)
2278 }
2279 } else {
2280 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2281 }
2282 }
Akash Sonief452f12024-12-12 18:20:28 +05302283 vs.DeactivateInProgress = false
2284 va.ServiceByName.Store(vs.Name, vs)
2285 vs.WriteToDb(cntx)
Tinoj Josephec742f62022-09-29 19:11:10 +05302286 }
2287 return true
2288 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302289 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302290}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302291
vinokuma926cb3e2023-03-29 11:41:06 +05302292// GetServicePbit to get first set bit in the pbit map
2293// returns -1 : If configured to match on all pbits
2294// returns 8 : If no pbits are configured
2295// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302296func (vs *VoltService) GetServicePbit() int {
2297 if vs.IsPbitExist(of.PbitMatchAll) {
2298 return -1
2299 }
vinokuma926cb3e2023-03-29 11:41:06 +05302300 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302301 if vs.IsPbitExist(of.PbitType(pbit)) {
2302 return pbit
2303 }
2304 }
2305 return int(of.PbitMatchNone)
2306}