blob: 9a771f993f7a4b78fa12f6c71e8b4f17883461a4 [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 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530509 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530510 return nil
511}
512
513// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530514func (vs *VoltService) DelDsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530515 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530516 if vs.DsHSIAFlowsApplied || vgcRebooted {
517 device, err := GetApplication().GetDeviceFromPort(vs.Port)
518 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530519 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 +0530520 }
521
Naveen Sampath04696f72022-06-13 15:19:14 +0530522 var matchPbit int
vinokuma926cb3e2023-03-29 11:41:06 +0530523 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530524 if len(vs.DsRemarkPbitsMap) == 0 {
525 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
526 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530527 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 +0530528 }
529 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530530 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530531 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 +0530532 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
533 vs.triggerServiceFailureInd(statusCode, statusMessage)
534 }
535 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
536 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
537 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530538 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 +0530539 }
540 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530541 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530542 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 +0530543 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
544 vs.triggerServiceFailureInd(statusCode, statusMessage)
545 }
546 } else {
547 for matchPbit = range vs.DsRemarkPbitsMap {
548 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
549 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530550 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 +0530551 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
552 vs.triggerServiceFailureInd(statusCode, statusMessage)
553 continue
554 }
555 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530556 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530557 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 +0530558 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
559 vs.triggerServiceFailureInd(statusCode, statusMessage)
560 }
561 }
562 }
563 vs.DsHSIAFlowsApplied = false
564 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530565 logger.Infow(ctx, "Deleted HSIA DS flows from DB successfully", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530566 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530567 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530568 return nil
569}
570
571// BuildDsHsiaFlows build the DS HSIA flows
572// Called for add/delete HSIA flows
573func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530574 logger.Debugw(ctx, "Building DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530575 flow := &of.VoltFlow{}
576 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
577
Naveen Sampath04696f72022-06-13 15:19:14 +0530578 device, err := GetApplication().GetDeviceFromPort(vs.Port)
579 if err != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530580 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 +0530581 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530582 // inport will be obtained from nniPort of service else we'll use the default nni port
583 var inport uint32
584 // Get the out and in ports for the flows
585 if vs.NniPort != "" {
586 if nniPortID := device.GetPortIDFromPortName(vs.NniPort); nniPortID != 0 {
587 inport = nniPortID
588 } else {
589 return nil, fmt.Errorf("error getting portID for NNI port %s of Service %s", vs.NniPort, vs.Name)
590 }
591 } else {
592 nniPort, err1 := GetApplication().GetNniPort(device.Name)
593 if err != nil {
594 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err1})
595 return nil, err1
596 }
597 inport, _ = GetApplication().GetPortID(nniPort)
598 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530599 outport, _ := GetApplication().GetPortID(vs.Port)
600 // PortName and PortID to be used for validation of port before flow pushing
601 flow.PortID = outport
602 flow.PortName = vs.Port
603 allowTransparent := 0
604 if vs.AllowTransparent {
605 allowTransparent = 1
606 }
607
608 // initialized actnPbit to 0 for cookie genration backward compatibility.
609 var actnPbit of.PbitType
610 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
611
612 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530613 // | 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 +0530614 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
615 cookie = cookie | of.DsFlowMask
616 cookie = cookie + (valToShift << 4) + uint64(pbits)
617 return cookie
618 }
619
620 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
621 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530622 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 +0530623 }
624
625 // Add Table-0 flow that deals with the outer VLAN in pOLT
626 {
627 subflow1 := of.NewVoltSubFlow()
628 subflow1.SetTableID(0)
629 subflow1.SetGoToTable(1)
630 subflow1.SetInPort(inport)
631
632 if pbits != PbitMatchNone {
633 subflow1.SetMatchPbit(pbits)
634 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530635 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
636 subflow1.SetPcp(of.PbitType(remarkPbit))
637 // match & action pbits are different, set remark-pbit action
638 actnPbit = of.PbitType(remarkPbit)
639 // mask remark p-bit to 4bits
640 actnPbit = actnPbit & 0x0F
641 }
642
643 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
644 return nil, err
645 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530646 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530647 if NonZeroMacAddress(vs.MacAddr) {
648 subflow1.SetMatchDstMac(vs.MacAddr)
649 }
650 subflow1.Priority = of.HsiaFlowPriority
651 subflow1.SetMeterID(vs.DsMeterID)
652
653 /* WriteMetaData 8 Byte(uint64) usage:
654 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
655 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
656 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530657 if vs.ServiceType == FttbSubscriberTraffic {
658 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
659 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530660 subflow1.SetWriteMetadata(metadata)
661
662 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
663 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
664 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
665 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
666
667 //TODO-COMM:
668 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
669 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
670 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
671 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
672
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530673 if vs.ServiceType != FttbSubscriberTraffic {
674 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
675 subflow1.SetTableMetadata(metadata)
676 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530677 // TODO - We are using cookie as key and must come up with better cookie
678 // allocation algorithm
679 /**
680 * Cokies may clash when -
681 * on same uni-port we have two sub-service
682 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
683 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
684 * However, this p-bit re-use will not be allowed by sub-mgr.
685 */
686 if vs.VlanControl == OLTCVlanOLTSVlan {
687 /**
688 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
689 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
690 * use old cookie.
691 */
692 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
693 if vgcRebooted {
694 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
695 }
696 } else {
697 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
698 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
699 }
700
701 flow.SubFlows[subflow1.Cookie] = subflow1
702 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
703 "subflow": subflow1})
704 }
705
vinokuma926cb3e2023-03-29 11:41:06 +0530706 // Add Table-1 flow that deals with inner VLAN at the ONU
Naveen Sampath04696f72022-06-13 15:19:14 +0530707 {
708 subflow2 := of.NewVoltSubFlow()
709 subflow2.SetTableID(1)
710 subflow2.SetInPort(inport)
711 if NonZeroMacAddress(vs.MacAddr) {
712 subflow2.SetMatchDstMac(vs.MacAddr)
713 }
714
715 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
716 return nil, err
717 }
718 if pbits != PbitMatchNone {
719 subflow2.SetMatchPbit(pbits)
720 }
721
722 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
723 subflow2.SetPcp(of.PbitType(remarkPbit))
724 }
725
726 subflow2.SetOutPort(outport)
727 subflow2.SetMeterID(vs.DsMeterID)
728
729 // refer Table-0 flow generation for byte information
730 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530731 if vs.ServiceType == FttbSubscriberTraffic {
732 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
733 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530734 subflow2.SetWriteMetadata(metadata)
735
736 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
737 if util.IsNniPort(inport) {
738 metadata = uint64(outport)
739 } else {
740 // refer Table-0 flow generation for byte information
741 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
742 }
743 subflow2.SetTableMetadata(metadata)
744 // Setting of Cookie - TODO - Improve the allocation algorithm
745 if vs.VlanControl == OLTCVlanOLTSVlan {
746 /**
747 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
748 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
749 * use old cookie.
750 */
751 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
752 if vgcRebooted {
753 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
754 }
755 } else {
756 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
757 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
758 }
759
760 subflow2.Priority = of.HsiaFlowPriority
761 flow.SubFlows[subflow2.Cookie] = subflow2
762 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
763 "subflow": subflow2})
764 }
765
766 return flow, nil
767}
768
769// BuildUsHsiaFlows build the US HSIA flows
770// Called for add/delete HSIA flows
771func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Akash Sonief452f12024-12-12 18:20:28 +0530772 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 +0530773 flow := &of.VoltFlow{}
774 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
775
Naveen Sampath04696f72022-06-13 15:19:14 +0530776 device, err := GetApplication().GetDeviceFromPort(vs.Port)
777 if err != nil {
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530778 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 +0530779 }
Sridhar Ravindrab76eb162025-07-02 01:25:10 +0530780 // outport will be obtained from nniPort of service else we'll use the default nni port
781 var outport uint32
782 // Get the out and in ports for the flows
783 if vs.NniPort != "" {
784 if nniPortID := device.GetPortIDFromPortName(vs.NniPort); nniPortID != 0 {
785 outport = nniPortID
786 } else {
787 return nil, fmt.Errorf("error getting portID for NNI port %s of Service %s : %w", vs.NniPort, vs.Name, err)
788 }
789 } else {
790 nniPort, err := GetApplication().GetNniPort(device.Name)
791 if err != nil {
792 logger.Errorw(ctx, "Error getting NNI port", log.Fields{"Error": err})
793 return nil, err
794 }
795 outport, _ = GetApplication().GetPortID(nniPort)
796 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530797 inport, _ := GetApplication().GetPortID(vs.Port)
798 // PortName and PortID to be used for validation of port before flow pushing
799 flow.PortID = inport
800 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530801
802 // Add Table-0 flow that deals with the inner VLAN in ONU
803 {
804 subflow1 := of.NewVoltSubFlow()
805 subflow1.SetTableID(0)
806 subflow1.SetGoToTable(1)
807 subflow1.SetInPort(inport)
808
vinokuma926cb3e2023-03-29 11:41:06 +0530809 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530810 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
811 subflow1.SetPcp(vs.UsPonSTagPriority)
vinokuma926cb3e2023-03-29 11:41:06 +0530812 } else if vs.ServiceType == DpuAncpTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530813 subflow1.SetPcp(vs.UsPonSTagPriority)
814 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530815 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
816 return nil, err
817 }
818 subflow1.SetMeterID(vs.UsMeterID)
819
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530820 /* WriteMetaData 8 Byte(uint64) usage:
821 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
822 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
823 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
824 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530825 if vs.ServiceType == FttbSubscriberTraffic {
826 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
827 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530828 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530829
Naveen Sampath04696f72022-06-13 15:19:14 +0530830 if vs.VlanControl == OLTCVlanOLTSVlan {
831 /**
832 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
833 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
834 * use old cookie.
835 */
836 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
837 if vgcRebooted {
838 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
839 }
840 } else {
841 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
842 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
843 }
844 subflow1.Priority = of.HsiaFlowPriority
845 flow.SubFlows[subflow1.Cookie] = subflow1
846 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
847 }
848
vinokuma926cb3e2023-03-29 11:41:06 +0530849 // Add Table-1 flow that deals with the outer vlan in pOLT
Naveen Sampath04696f72022-06-13 15:19:14 +0530850 {
851 subflow2 := of.NewVoltSubFlow()
852 subflow2.SetTableID(1)
853 subflow2.SetInPort(inport)
854
Naveen Sampath04696f72022-06-13 15:19:14 +0530855 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
856 return nil, err
857 }
vinokuma926cb3e2023-03-29 11:41:06 +0530858 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530859 subflow2.SetMatchSrcMac(vs.MacAddr)
860 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530861 subflow2.SetInPort(inport)
862 subflow2.SetOutPort(outport)
863 subflow2.SetMeterID(vs.UsMeterID)
864
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530865 // refer Table-0 flow generation for byte information
866 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530867 if vs.ServiceType == FttbSubscriberTraffic {
868 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
869 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530870 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530871
Naveen Sampath04696f72022-06-13 15:19:14 +0530872 if vs.VlanControl == OLTCVlanOLTSVlan {
873 /**
874 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
875 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
876 * use old cookie.
877 */
878 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
879 if vgcRebooted {
880 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
881 }
882 } else {
883 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
884 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
885 }
886 subflow2.Priority = of.HsiaFlowPriority
887
888 flow.SubFlows[subflow2.Cookie] = subflow2
889 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
890 }
891
892 return flow, nil
893}
894
895func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530896 // | 12-bit cvlan/UniVlan | 4 bits empty | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530897 logger.Debugw(ctx, "Generate US Cookie", log.Fields{"Vlan": vlan, "ValToShift": vlan, "Inport": inport, "Pbits": pbits})
Naveen Sampath04696f72022-06-13 15:19:14 +0530898 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
899 cookie = cookie | of.UsFlowMask
900 cookie = cookie + (valToShift << 4) + uint64(pbits)
901 return cookie
902}
903
904// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
905// based on different Vlan Controls
906func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530907 logger.Debugw(ctx, "Set US Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530908 switch vs.VlanControl {
909 case None:
910 flow.SetMatchVlan(vs.SVlan)
911 case ONUCVlanOLTSVlan:
912 flow.SetMatchVlan(vs.CVlan)
913 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
914 case OLTCVlanOLTSVlan:
915 flow.SetMatchVlan(vs.UniVlan)
916 flow.SetSetVlan(vs.CVlan)
917 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
918 case ONUCVlan:
919 flow.SetMatchVlan(vs.SVlan)
920 case OLTSVlan:
921 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
922 flow.SetMatchVlan(vs.UniVlan)
923 flow.SetSetVlan(vs.SVlan)
924 } else if vs.UniVlan != of.VlanNone {
925 flow.SetMatchVlan(vs.UniVlan)
926 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
927 } else {
928 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
929 }
930 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530931 err := errorCodes.ErrInvalidParamInRequest
932 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530933 }
934 return nil
935}
936
937// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
938// based on different Vlan Controls
939func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530940 logger.Debugw(ctx, "Set DS Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530941 switch vs.VlanControl {
942 case None:
943 flow.SetMatchVlan(vs.SVlan)
944 case ONUCVlanOLTSVlan:
945 flow.SetMatchVlan(vs.SVlan)
946 flow.SetPopVlan()
947 case OLTCVlanOLTSVlan:
948 flow.SetMatchVlan(vs.SVlan)
949 flow.SetPopVlan()
950 flow.SetSetVlan(vs.UniVlan)
951 case ONUCVlan:
952 flow.SetMatchVlan(vs.SVlan)
953 case OLTSVlan:
954 flow.SetMatchVlan(vs.SVlan)
955 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
956 flow.SetSetVlan(vs.UniVlan)
957 } else {
958 flow.SetPopVlan()
959 }
960 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530961 err := errorCodes.ErrInvalidParamInRequest
962 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530963 }
964 return nil
965}
966
967// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
968// based on different Vlan Controls
969func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530970 logger.Debugw(ctx, "Set US Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530971 switch vs.VlanControl {
972 case None:
973 flow.SetMatchVlan(vs.SVlan)
974 case ONUCVlanOLTSVlan:
975 if vs.UniVlan != of.VlanNone {
976 flow.SetMatchVlan(vs.UniVlan)
977 flow.SetSetVlan(vs.CVlan)
978 } else {
979 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
980 }
981 case OLTCVlanOLTSVlan:
982 flow.SetMatchVlan(vs.UniVlan)
983 case ONUCVlan:
984 if vs.UniVlan != of.VlanNone {
985 flow.SetMatchVlan(vs.UniVlan)
986 flow.SetSetVlan(vs.SVlan)
987 } else {
988 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
989 }
990 case OLTSVlan:
991 flow.SetMatchVlan(vs.UniVlan)
992 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530993 err := errorCodes.ErrInvalidParamInRequest
994 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530995 }
996 return nil
997}
998
999// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
1000// based on different Vlan Controls
1001func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301002 logger.Debugw(ctx, "Set DS Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +05301003 switch vs.VlanControl {
1004 case None:
1005 flow.SetMatchVlan(vs.SVlan)
1006 case ONUCVlanOLTSVlan:
1007 flow.SetMatchVlan(vs.CVlan)
1008 if vs.UniVlan != of.VlanNone {
1009 flow.SetSetVlan(vs.UniVlan)
1010 } else {
1011 flow.SetPopVlan()
1012 }
1013 case OLTCVlanOLTSVlan:
1014 flow.SetMatchVlan(vs.UniVlan)
1015 case ONUCVlan:
1016 flow.SetMatchVlan(vs.SVlan)
1017 if vs.UniVlan != of.VlanNone {
1018 flow.SetSetVlan(vs.UniVlan)
1019 } else {
1020 flow.SetPopVlan()
1021 }
1022 case OLTSVlan:
1023 flow.SetMatchVlan(vs.UniVlan)
1024 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301025 err := errorCodes.ErrInvalidParamInRequest
1026 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +05301027 }
1028 return nil
1029}
1030
1031// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301032func (vs *VoltService) SvcUpInd(cntx context.Context) {
1033 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301034}
1035
1036// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301037func (vs *VoltService) SvcDownInd(cntx context.Context) {
1038 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301039}
1040
1041// SetIpv4Addr to set ipv4 address
1042func (vs *VoltService) SetIpv4Addr(addr net.IP) {
1043 vs.Ipv4Addr = addr
1044}
1045
1046// SetIpv6Addr to set ipv6 address
1047func (vs *VoltService) SetIpv6Addr(addr net.IP) {
1048 vs.Ipv6Addr = addr
1049}
1050
1051// SetMacAddr to set mac address
1052func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
1053 vs.MacAddr = addr
1054}
1055
1056// ----------------------------------------------
1057// VOLT Application - Related to services
1058// ---------------------------------------------
1059// ---------------------------------------------------------------
1060// Service CRUD functions. These are exposed to the overall binary
1061// to be invoked from the point where the CRUD operations are received
1062// from the external entities
1063
1064// AddService : A service in the context of VOLT is a subscriber or service of a
1065// subscriber which is uniquely identified by a combination of MAC
1066// address, VLAN tags, 802.1p bits. However, in the context of the
1067// current implementation, a service is an entity that is identified by a
1068// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
1069// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301070func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301071 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
Naveen Sampath04696f72022-06-13 15:19:14 +05301072 var mmUs, mmDs *VoltMeter
1073 var err error
1074
vinokuma926cb3e2023-03-29 11:41:06 +05301075 // Take the Device lock only in case of NB add request.
Naveen Sampath04696f72022-06-13 15:19:14 +05301076 // Allow internal adds since internal add happen only under
1077 // 1. Restore Service from DB
1078 // 2. Service Migration
1079 if oper == nil {
1080 if svc := va.GetService(cfg.Name); svc != nil {
1081 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301082 return errors.New("service already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301083 }
1084 }
1085
Naveen Sampath04696f72022-06-13 15:19:14 +05301086 // Service doesn't exist. So create it and add to the port
1087 vs := NewVoltService(&cfg)
1088 if oper != nil {
1089 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1090 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1091 vs.Ipv4Addr = oper.Ipv4Addr
1092 vs.Ipv6Addr = oper.Ipv6Addr
1093 vs.MacLearning = cfg.MacLearning
1094 vs.PendingFlows = oper.PendingFlows
1095 vs.AssociatedFlows = oper.AssociatedFlows
1096 vs.DeleteInProgress = oper.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301097 vs.DeactivateInProgress = oper.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301098 vs.BwAvailInfo = oper.BwAvailInfo
1099 vs.Device = oper.Device
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301100 vs.ServiceDeactivateReason = cfg.ServiceDeactivateReason
Naveen Sampath04696f72022-06-13 15:19:14 +05301101 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301102 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301103 sort.Slice(vs.Pbits, func(i, j int) bool {
1104 return vs.Pbits[i] > vs.Pbits[j]
1105 })
Akash Sonief452f12024-12-12 18:20:28 +05301106 logger.Debugw(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
Naveen Sampath04696f72022-06-13 15:19:14 +05301107 }
1108 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1109
1110 // The bandwidth and shaper profile combined into meter
1111 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1112 vs.DsMeterID = mmDs.ID
1113 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301114 return errors.New("downStream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301115 }
1116
1117 // The aggregated downstream meter profile
1118 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1119 // vs.AggDsMeterID = mmAg.ID
1120 // } else {
1121 // return errors.New("Aggregated meter profile not found")
1122 // }
1123
1124 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1125 // vs.UsMeterID = mmAg.ID
1126 // } else {
1127 // The bandwidth and shaper profile combined into meter
1128 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1129 vs.UsMeterID = mmUs.ID
1130 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301131 return errors.New("upstream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301132 }
1133 //}
1134
1135 AppMutex.ServiceDataMutex.Lock()
1136 defer AppMutex.ServiceDataMutex.Unlock()
1137
1138 // Add the service to the VNET
1139 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1140 if vnet != nil {
1141 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1142 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301143 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301144 vpv.VpvLock.Unlock()
1145 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301146 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301147 }
1148 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301149 logger.Warnw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
1150 return errors.New("vnet doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301151 }
1152
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301153 // If the device is already discovered, update the device name in service
1154 d, err := va.GetDeviceFromPort(vs.Port)
1155 if err == nil {
1156 vs.Device = d.Name
1157 }
1158
Naveen Sampath04696f72022-06-13 15:19:14 +05301159 vs.Version = database.PresentVersionMap[database.ServicePath]
1160 // Add the service to the volt application
1161 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301162 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301163
1164 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301165 if !vs.UsHSIAFlowsApplied {
1166 vs.triggerServiceInProgressInd()
1167 }
1168
vinokuma926cb3e2023-03-29 11:41:06 +05301169 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301170 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301171 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301172 if mmUs != nil {
1173 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301174 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301175 }
1176 //mmAg.AssociatedServices++
1177 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301178 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301179 }
1180
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301181 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 +05301182 return nil
1183}
1184
vinokuma926cb3e2023-03-29 11:41:06 +05301185// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301186// Added for DT/TT usecase with sadis replica interface
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301187func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) error {
Akash Sonief452f12024-12-12 18:20:28 +05301188 logger.Debugw(ctx, "Delete Service With provided Prefix", log.Fields{"Prefix": prefix})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301189 var isServiceExist bool
Naveen Sampath04696f72022-06-13 15:19:14 +05301190 va.ServiceByName.Range(func(key, value interface{}) bool {
1191 srvName := key.(string)
1192 vs := value.(*VoltService)
1193 if strings.Contains(srvName, prefix) {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301194 isServiceExist = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301195 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301196
1197 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1198 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1199 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1200
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301201 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301202 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1203 }
1204 }
1205 return true
1206 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301207
1208 if !isServiceExist {
1209 return errorCodes.ErrServiceNotFound
1210 }
1211 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301212}
1213
1214// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301215func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301216 AppMutex.ServiceDataMutex.Lock()
1217 defer AppMutex.ServiceDataMutex.Unlock()
1218
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301219 logger.Infow(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
Naveen Sampath04696f72022-06-13 15:19:14 +05301220 var noFlowsPresent bool
1221
1222 vsIntf, ok := va.ServiceByName.Load(name)
1223 if !ok {
1224 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1225 return
1226 }
1227 vs := vsIntf.(*VoltService)
1228 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1229 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301230 logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301231 return
1232 }
1233
vinokuma926cb3e2023-03-29 11:41:06 +05301234 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301235 vs.DeleteInProgress = true
1236 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301237 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301238
Akash Sonief452f12024-12-12 18:20:28 +05301239 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301240 if len(vs.AssociatedFlows) == 0 {
1241 noFlowsPresent = true
1242 }
Akash Sonief452f12024-12-12 18:20:28 +05301243 vs.ServiceLock.RUnlock()
1244
Naveen Sampath04696f72022-06-13 15:19:14 +05301245 vpv.VpvLock.Lock()
1246 defer vpv.VpvLock.Unlock()
1247
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301248 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301249
1250 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301251 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301252 }
1253 logger.Infow(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 +05301254 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301255 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301256 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301257 }
1258
1259 // Delete the service immediately in case of Force Delete
1260 // This will be enabled when profile reconciliation happens after restore
1261 // of backedup data
1262 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301263 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301264 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301265 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301266 }
1267
Naveen Sampath04696f72022-06-13 15:19:14 +05301268 if nil != newSvc {
1269 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1270 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1271 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301272
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301273 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1274
1275 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1276 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301277 if aggMeter.AssociatedServices > 0 {
1278 aggMeter.AssociatedServices--
1279 logger.Infow(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
1280 va.UpdateMeterProf(cntx, *aggMeter)
1281 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301282 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301283 }
1284 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301285 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1286 if dsMeter.AssociatedServices > 0 {
1287 dsMeter.AssociatedServices--
1288 logger.Infow(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
1289 va.UpdateMeterProf(cntx, *dsMeter)
1290 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301291 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301292 }
1293 if vs.AggDsMeterID != vs.UsMeterID {
1294 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301295 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1296 if usMeter.AssociatedServices > 0 {
1297 usMeter.AssociatedServices--
1298 logger.Infow(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
1299 va.UpdateMeterProf(cntx, *usMeter)
1300 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301301 }
1302 }
1303 }
1304
1305 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301306 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301307 }
1308
vinokuma926cb3e2023-03-29 11:41:06 +05301309 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301310 va.ServiceCounters.Delete(name)
1311 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301312 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301313 }
1314}
1315
vinokuma926cb3e2023-03-29 11:41:06 +05301316// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301317// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301318func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301319 // Using locks instead of concurrent map for PendingFlows to avoid
1320 // race condition during flow response indication processing
1321 vs.ServiceLock.Lock()
1322 defer vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301323 logger.Debugw(ctx, "Adds the flow to the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301324
1325 for cookie := range flow.SubFlows {
1326 cookie := strconv.FormatUint(cookie, 10)
1327 fe := &FlowEvent{
1328 eType: EventTypeServiceFlowAdded,
1329 device: device.Name,
1330 cookie: cookie,
1331 eventData: vs,
1332 }
1333 device.RegisterFlowAddEvent(cookie, fe)
1334 vs.PendingFlows[cookie] = true
1335 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301336 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301337}
1338
vinokuma926cb3e2023-03-29 11:41:06 +05301339// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301340// If no more pending flows, HSIA indication wil be triggered
Akash Sonief452f12024-12-12 18:20:28 +05301341func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301342 logger.Debugw(ctx, "Flow Add Success Notification", log.Fields{"Cookie": cookie, "bwAvailInfo": bwAvailInfo, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301343 if vs.DeleteInProgress {
1344 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1345 return
1346 }
1347 vs.ServiceLock.Lock()
1348
1349 if _, ok := vs.PendingFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301350 logger.Warnw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301351 vs.ServiceLock.Unlock()
1352 return
1353 }
1354
1355 delete(vs.PendingFlows, cookie)
1356 vs.AssociatedFlows[cookie] = true
1357 vs.ServiceLock.Unlock()
1358 var prevBwAvail, presentBwAvail string
1359 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1360 prevBwAvail = bwAvailInfo.PrevBw
1361 presentBwAvail = bwAvailInfo.PresentBw
1362 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301363 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301364 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301365 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301366
Akash Sonief452f12024-12-12 18:20:28 +05301367 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301368 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Akash Sonief452f12024-12-12 18:20:28 +05301369 vs.ServiceLock.RUnlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301370 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1371 if err != nil {
1372 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1373 return
1374 } else if device.State != controller.DeviceStateUP {
1375 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1376 return
1377 }
1378
1379 if vs.Trigger == ServiceVlanUpdate {
1380 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301381 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301382 }
1383 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1384 return
1385 }
Akash Sonief452f12024-12-12 18:20:28 +05301386 vs.ServiceLock.RUnlock()
1387 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 +05301388}
1389
vinokuma926cb3e2023-03-29 11:41:06 +05301390// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301391// Trigger service failure indication to NB
Akash Sonief452f12024-12-12 18:20:28 +05301392func (vs *VoltService) FlowInstallFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301393 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 +05301394 vs.ServiceLock.RLock()
Akash Sonief452f12024-12-12 18:20:28 +05301395
Naveen Sampath04696f72022-06-13 15:19:14 +05301396 if _, ok := vs.PendingFlows[cookie]; !ok {
1397 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1398 vs.ServiceLock.RUnlock()
1399 return
1400 }
1401 vs.ServiceLock.RUnlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301402 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 +05301403 vs.triggerServiceFailureInd(errorCode, errReason)
1404}
1405
vinokuma926cb3e2023-03-29 11:41:06 +05301406// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301407// Triggers flow deletion after registering for flow indication event
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301408func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow, delFlowsInDevice bool) error {
Akash Sonief452f12024-12-12 18:20:28 +05301409 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 +05301410 if !vs.ForceDelete {
1411 // Using locks instead of concurrent map for AssociatedFlows to avoid
1412 // race condition during flow response indication processing
1413 vs.ServiceLock.Lock()
1414 defer vs.ServiceLock.Unlock()
1415
1416 for cookie := range flow.SubFlows {
1417 cookie := strconv.FormatUint(cookie, 10)
1418 fe := &FlowEvent{
1419 eType: EventTypeServiceFlowRemoved,
1420 cookie: cookie,
1421 eventData: vs,
1422 }
1423 device.RegisterFlowDelEvent(cookie, fe)
1424 }
1425 }
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301426 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow, delFlowsInDevice)
Naveen Sampath04696f72022-06-13 15:19:14 +05301427}
1428
vinokuma926cb3e2023-03-29 11:41:06 +05301429// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301430func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301431 logger.Debugw(ctx, "Delete service from DB/Cache", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301432 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301433 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301434 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301435 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301436 }
1437}
1438
vinokuma926cb3e2023-03-29 11:41:06 +05301439// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301440// If no more associated flows, DelHSIA indication wil be triggered
Akash Sonief452f12024-12-12 18:20:28 +05301441func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301442 // if vs.DeleteInProgress {
1443 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1444 // return
1445 // }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301446
Naveen Sampath04696f72022-06-13 15:19:14 +05301447 vs.ServiceLock.Lock()
Akash Sonief452f12024-12-12 18:20:28 +05301448 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 +05301449
1450 if _, ok := vs.AssociatedFlows[cookie]; ok {
1451 delete(vs.AssociatedFlows, cookie)
1452 } else if _, ok := vs.PendingFlows[cookie]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301453 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 +05301454 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301455 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 +05301456 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301457 vs.ServiceLock.Unlock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301458 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301459
Akash Sonief452f12024-12-12 18:20:28 +05301460 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301461 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Akash Sonief452f12024-12-12 18:20:28 +05301462 vs.ServiceLock.RUnlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301463 device := GetApplication().GetDevice(vs.Device)
1464 if device == nil {
1465 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1466 return
1467 } else if device.State != controller.DeviceStateUP {
1468 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1469 return
1470 }
1471
1472 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301473 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301474 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301475 return
1476 }
1477 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 +05301478 // Get the service from application before proceeding to delete, as the service might have been activated
1479 // by the time the flow removal response is received from SB
1480 svc := GetApplication().GetService(vs.Name)
1481 if svc != nil {
1482 svc.CheckAndDeleteService(cntx)
1483 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301484
1485 return
1486 }
Akash Sonief452f12024-12-12 18:20:28 +05301487 vs.ServiceLock.RUnlock()
1488 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 +05301489}
1490
vinokuma926cb3e2023-03-29 11:41:06 +05301491// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301492// Trigger service failure indication to NB
Akash Sonief452f12024-12-12 18:20:28 +05301493func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301494 vs.ServiceLock.Lock()
Akash Sonief452f12024-12-12 18:20:28 +05301495 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 +05301496
1497 if _, ok := vs.AssociatedFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301498 logger.Warnw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301499 vs.ServiceLock.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301500 return
1501 }
1502 if vs.DeleteInProgress {
1503 delete(vs.AssociatedFlows, cookie)
1504 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301505 vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301506 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 +05301507
1508 vs.triggerServiceFailureInd(errorCode, errReason)
Akash Sonief452f12024-12-12 18:20:28 +05301509 // Get the service from application before proceeding to delete, as the service might have been activated
1510 // by the time the flow removal response is received from SB
1511 svc := GetApplication().GetService(vs.Name)
1512 if svc != nil {
1513 svc.CheckAndDeleteService(cntx)
1514 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301515}
1516
1517func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301518 logger.Debugw(ctx, "Trigger Service Failure Ind", log.Fields{"Service": vs.Name, "Port": vs.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301519 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1520 if err != nil {
1521 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1522 return
1523 } else if device.State != controller.DeviceStateUP {
1524 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1525 return
1526 }
1527}
1528
1529// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301530func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301531 // VNETS must be learnt first
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301532 logger.Debug(ctx, "Restore Svcs From Db")
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301533 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301534 for _, vs := range vss {
1535 b, ok := vs.Value.([]byte)
1536 if !ok {
1537 logger.Warn(ctx, "The value type is not []byte")
1538 continue
1539 }
1540 var vvs VoltService
1541 err := json.Unmarshal(b, &vvs)
1542 if err != nil {
1543 logger.Warn(ctx, "Unmarshal of VNET failed")
1544 continue
1545 }
1546 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301547 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301548 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1549 }
1550
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301551 if vvs.VoltServiceOper.DeactivateInProgress {
Akash Sonief452f12024-12-12 18:20:28 +05301552 va.ServicesToDeactivate.Store(vvs.VoltServiceCfg.Name, true)
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301553 logger.Warnw(ctx, "Service (restored) to be deactivated", log.Fields{"Service": vvs.Name})
1554 }
1555
Naveen Sampath04696f72022-06-13 15:19:14 +05301556 if vvs.VoltServiceOper.DeleteInProgress {
Akash Sonief452f12024-12-12 18:20:28 +05301557 va.ServicesToDelete.Store(vvs.VoltServiceCfg.Name, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301558 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1559 }
1560 }
1561}
1562
1563// GetService to get service
1564func (va *VoltApplication) GetService(name string) *VoltService {
1565 if vs, ok := va.ServiceByName.Load(name); ok {
1566 return vs.(*VoltService)
1567 }
1568 return nil
1569}
1570
1571// GetCircuitID to get circuit id
1572func (vs *VoltService) GetCircuitID() []byte {
1573 return []byte(vs.CircuitID)
1574}
1575
1576// GetRemoteID to get remote id
1577func (vs *VoltService) GetRemoteID() []byte {
1578 return []byte(vs.RemoteID)
1579}
1580
1581// IPAssigned to check if ip is assigned
1582func (vs *VoltService) IPAssigned() bool {
1583 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1584 return true
1585 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1586 return true
1587 }
1588 return false
1589}
1590
1591// GetServiceNameFromCookie to get service name from cookie
1592func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301593 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 +05301594 var vlan uint64
1595 vlanControl := (tableMetadata >> 32) & 0xF
1596
1597 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1598 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1599 vlan = (tableMetadata >> 16) & 0xFFFF
1600 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301601 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301602 vlan = cookie >> 52
1603 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301604 logger.Debugw(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301605 var vlans []of.VlanType
1606 vlans = append(vlans, of.VlanType(vlan))
1607 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1608 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301609 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301610 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301611 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 +05301612 }
1613 return service
1614}
1615
vinokuma926cb3e2023-03-29 11:41:06 +05301616// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301617type MigrateServicesReqStatus string
1618
1619const (
vinokuma926cb3e2023-03-29 11:41:06 +05301620 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301621 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301622 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301623 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301624 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301625 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1626)
1627
vinokuma926cb3e2023-03-29 11:41:06 +05301628// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301629type MigrateServicesRequest struct {
1630 ID string
1631 OldVnetID string
1632 NewVnetID string
1633 ServicesList map[string]bool
1634 DeviceID string
1635 Status MigrateServicesReqStatus
1636 MigrateServicesLock sync.RWMutex
1637}
1638
1639func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301640 var msr MigrateServicesRequest
1641 msr.OldVnetID = oldVnetID
1642 msr.NewVnetID = newVnetID
1643 msr.ID = id
1644 msr.ServicesList = serviceMap
1645 msr.DeviceID = deviceID
1646 msr.Status = MigrateSrvsReqInit
1647 return &msr
1648}
1649
vinokuma926cb3e2023-03-29 11:41:06 +05301650// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301651func (msr *MigrateServicesRequest) GetMsrKey() string {
1652 return msr.OldVnetID + "-" + msr.ID
1653}
1654
1655// //isRequestComplete - return if all request has been processed and completed
1656// // RequestProcessed indicates that all the profile de-activation has been triggered
1657// // And the associated profiles indicates the profiles awaiting results
1658// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1659// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1660// return (len(edr.AssociatedProfiles) == 0)
1661// }
1662
vinokuma926cb3e2023-03-29 11:41:06 +05301663// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301664func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301665 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)})
1666 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301667 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301668 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301669 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301670 }
1671 }
1672}
1673
vinokuma926cb3e2023-03-29 11:41:06 +05301674// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301675func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301676 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 +05301677 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301678 return errors.New("old vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301679 }
1680 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301681 return errors.New("new vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301682 }
1683
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301684 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301685 if d == nil {
1686 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1687 return errorCodes.ErrDeviceNotFound
1688 }
1689
1690 serviceMap := make(map[string]bool)
1691
1692 for _, service := range serviceList {
1693 serviceMap[service] = false
1694 }
1695 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301696 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301697
1698 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301699 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301700 return nil
1701}
1702
vinokuma926cb3e2023-03-29 11:41:06 +05301703// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301704func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301705 logger.Debug(ctx, "Process Migrate Services Prof Request")
Naveen Sampath04696f72022-06-13 15:19:14 +05301706 va := GetApplication()
1707 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301708 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301709 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301710 va.DelService(cntx, srv, true, nil, true)
1711 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301712 continue
1713 }
1714
1715 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1716 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1717 vs := vsIntf.(*VoltService)
1718 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1719 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301720 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 +05301721 continue
1722 }
1723 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1724 vpv.Blocked = true
1725
1726 // setDeactTrigger := func(key, value interface{}) bool {
1727 // vs := value.(*VoltService)
1728 vs.ServiceLock.Lock()
1729 vs.UpdateInProgress = true
1730 metadata := &MigrateServiceMetadata{
1731 NewVnetID: msr.NewVnetID,
1732 RequestID: msr.ID,
1733 }
1734 vs.Metadata = metadata
1735 vs.ServiceLock.Unlock()
1736
vinokuma926cb3e2023-03-29 11:41:06 +05301737 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301738 // new vpv flows will be installed when new service is added
1739 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301740 vpv.DelTrapFlows(cntx)
1741 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301742 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301743 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301744 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301745 }
1746 } else {
1747 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1748 }
1749 }
1750}
1751
vinokuma926cb3e2023-03-29 11:41:06 +05301752// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301753func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301754 logger.Infow(ctx, "Add Migrating Services", log.Fields{"Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301755 var msrMap *util.ConcurrentMap
1756 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1757 msrMap = util.NewConcurrentMap()
1758 } else {
1759 msrMap = msrMapIntf.(*util.ConcurrentMap)
1760 }
1761
1762 msrMap.Set(msr.ID, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301763 logger.Debugw(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301764
1765 d.MigratingServices.Set(msr.OldVnetID, msrMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301766 logger.Debugw(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301767}
1768
vinokuma926cb3e2023-03-29 11:41:06 +05301769// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301770func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301771 logger.Debugw(ctx, "Get Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301772 if vd := va.GetDevice(deviceID); vd != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301773 logger.Debugw(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301774 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1775 msrList := msrListIntf.(*util.ConcurrentMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301776 logger.Debugw(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301777 if msrObj, ok := msrList.Get(requestID); ok {
1778 return msrObj.(*MigrateServicesRequest)
1779 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301780 }
1781 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301782 logger.Warnw(ctx, "Device Not Found", log.Fields{"DeviceID": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301783 return nil
1784}
1785
vinokuma926cb3e2023-03-29 11:41:06 +05301786// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301787func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301788 logger.Debugw(ctx, "Update Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301789 if vd := va.GetDevice(deviceID); vd != nil {
1790 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1791 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1792 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1793 }
1794 }
1795 }
1796}
1797
vinokuma926cb3e2023-03-29 11:41:06 +05301798// updateVnetProfile - Called on flow process completion
1799// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301800func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301801 logger.Infow(ctx, "Update Vnet Profile Triggering", log.Fields{"Service": vs.Name, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301802
1803 nvs := VoltService{}
1804 nvs.VoltServiceCfg = vs.VoltServiceCfg
1805 nvs.Device = vs.Device
1806 nvs.Ipv4Addr = vs.Ipv4Addr
1807 nvs.Ipv6Addr = vs.Ipv6Addr
1808 nvs.UsMeterID = vs.UsMeterID
1809 nvs.DsMeterID = vs.DsMeterID
1810 nvs.AggDsMeterID = vs.AggDsMeterID
1811 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1812 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1813 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1814 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1815 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1816 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1817 nvs.PendingFlows = vs.PendingFlows
1818 nvs.AssociatedFlows = vs.AssociatedFlows
1819 nvs.DeleteInProgress = vs.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301820 nvs.DeactivateInProgress = vs.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301821 nvs.ForceDelete = vs.ForceDelete
1822 nvs.BwAvailInfo = vs.BwAvailInfo
1823 nvs.UpdateInProgress = vs.UpdateInProgress
1824
1825 if nvs.DeleteInProgress {
1826 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1827 return
1828 }
1829
1830 metadata := vs.Metadata.(*MigrateServiceMetadata)
1831 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301832 oldSrvName := vs.Name
1833
1834 if metadata == nil || metadata.NewVnetID == "" {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301835 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 +05301836 return
1837 }
1838
vinokuma926cb3e2023-03-29 11:41:06 +05301839 nvs.VnetID = metadata.NewVnetID
1840 id := metadata.RequestID
1841
1842 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301843 // Since if post del service in case of pod crash or reboot, the service data will be lost
1844 va := GetApplication()
1845 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1846 vnets := strings.Split(metadata.NewVnetID, "-")
1847 svlan, _ := strconv.Atoi(vnets[0])
1848 nvs.SVlan = of.VlanType(svlan)
1849 nvs.UpdateInProgress = false
1850 nvs.Metadata = nil
1851 nvs.Trigger = ServiceVlanUpdate
1852
1853 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1854 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1855 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1856
vinokuma926cb3e2023-03-29 11:41:06 +05301857 // TODO:Nav Pass a copy, not the pointer
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301858 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 +05301859 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301860 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1861 }
1862 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1863
1864 msr.ServicesList[oldSrvName] = true
1865 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301866 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301867
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301868 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 +05301869 va.DelService(cntx, oldSrvName, true, nil, true)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301870 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 +05301871 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301872}
1873
vinokuma926cb3e2023-03-29 11:41:06 +05301874// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301875// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301876func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301877 logger.Infow(ctx, "Service Migrated", log.Fields{"ServiceName": serviceName})
Naveen Sampath04696f72022-06-13 15:19:14 +05301878 msr.MigrateServicesLock.Lock()
1879 defer msr.MigrateServicesLock.Unlock()
1880
1881 delete(msr.ServicesList, serviceName)
1882
1883 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301884 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301885 return
1886 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301887 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301888 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301889}
1890
vinokuma926cb3e2023-03-29 11:41:06 +05301891// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301892func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1893 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301894}
1895
vinokuma926cb3e2023-03-29 11:41:06 +05301896// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301897func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301898 logger.Infow(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 +05301899 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301900 for _, msr := range msrList {
1901 b, ok := msr.Value.([]byte)
1902 if !ok {
1903 logger.Warn(ctx, "The value type is not []byte")
1904 continue
1905 }
1906 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301907 msrAction(cntx, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301908 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 +05301909 }
1910}
1911
1912// createMigrateServicesFromString to create Service from string
1913func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301914 logger.Info(ctx, "Create Migrate Services From String")
Naveen Sampath04696f72022-06-13 15:19:14 +05301915 var msr MigrateServicesRequest
1916 if err := json.Unmarshal(b, &msr); err == nil {
1917 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301918 } else {
1919 logger.Warn(ctx, "Unmarshal failed")
1920 }
1921 return &msr
1922}
1923
vinokuma926cb3e2023-03-29 11:41:06 +05301924// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301925func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301926 logger.Infow(ctx, "Store And Process Migrate Srv Request", log.Fields{"MsrID": msr.DeviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301927 d := GetApplication().GetDevice(msr.DeviceID)
1928 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301929 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301930}
1931
vinokuma926cb3e2023-03-29 11:41:06 +05301932// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301933func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301934 logger.Infow(ctx, "Force udpate services with new vnet profile", log.Fields{"MsrID": msr.NewVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301935 for srv := range msr.ServicesList {
1936 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301937 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301938 }
1939 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301940 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301941}
1942
vinokuma926cb3e2023-03-29 11:41:06 +05301943// nolint: gocyclo
1944// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301945func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1946 if nvs.Name != evs.Name {
1947 return false
1948 }
1949 if nvs.UniVlan != evs.UniVlan {
1950 return false
1951 }
1952 if nvs.CVlan != evs.CVlan {
1953 return false
1954 }
1955 if nvs.SVlan != evs.SVlan {
1956 return false
1957 }
1958 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1959 return false
1960 }
1961 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1962 return false
1963 }
1964 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1965 return false
1966 }
1967 if nvs.TechProfileID != evs.TechProfileID {
1968 return false
1969 }
1970 if nvs.CircuitID != evs.CircuitID {
1971 return false
1972 }
1973 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1974 return false
1975 }
1976 if nvs.Port != evs.Port {
1977 return false
1978 }
1979 if nvs.PonPort != evs.PonPort {
1980 return false
1981 }
1982 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1983 return false
1984 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301985 if nvs.IsOption82Enabled != evs.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +05301986 return false
1987 }
1988 if nvs.IgmpEnabled != evs.IgmpEnabled {
1989 return false
1990 }
1991 if nvs.McastService != evs.McastService {
1992 return false
1993 }
1994 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1995 return false
1996 }
1997 if nvs.UsMeterProfile != evs.UsMeterProfile {
1998 return false
1999 }
2000 if nvs.DsMeterProfile != evs.DsMeterProfile {
2001 return false
2002 }
2003 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
2004 return false
2005 }
2006 if nvs.VnetID != evs.VnetID {
2007 return false
2008 }
2009 if nvs.MvlanProfileName != evs.MvlanProfileName {
2010 return false
2011 }
2012 if nvs.RemoteIDType != evs.RemoteIDType {
2013 return false
2014 }
2015 if nvs.SchedID != evs.SchedID {
2016 return false
2017 }
2018 if nvs.AllowTransparent != evs.AllowTransparent {
2019 return false
2020 }
2021 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
2022 return false
2023 }
2024 if nvs.DataRateAttr != evs.DataRateAttr {
2025 return false
2026 }
2027 if nvs.MinDataRateUs != evs.MinDataRateUs {
2028 return false
2029 }
2030 if nvs.MinDataRateDs != evs.MinDataRateDs {
2031 return false
2032 }
2033 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
2034 return false
2035 }
2036 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
2037 return false
2038 }
2039
2040 return true
2041}
2042
vinokuma926cb3e2023-03-29 11:41:06 +05302043// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302044func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05302045 // Clear the Flows flag if already set
2046 // This case happens only in case of some race condition
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302047 logger.Infow(ctx, "Trigger Associated Flow Delete", log.Fields{"Device": vs.Device, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05302048 if vs.UsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302049 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302050 logger.Warnw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302051 }
2052 }
2053
2054 if vs.DsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302055 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302056 logger.Warnw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302057 }
2058 }
2059
2060 vs.ServiceLock.Lock()
2061 cookieList := []uint64{}
2062 for cookie := range vs.AssociatedFlows {
2063 cookieList = append(cookieList, convertToUInt64(cookie))
2064 }
2065 vs.ServiceLock.Unlock()
2066
2067 if len(cookieList) == 0 {
2068 return false
2069 }
2070
vinokuma926cb3e2023-03-29 11:41:06 +05302071 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05302072 for _, cookie := range cookieList {
2073 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
2074 flow := &of.VoltFlow{}
2075 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2076 subFlow := of.NewVoltSubFlow()
2077 subFlow.Cookie = cookie
2078 flow.SubFlows[cookie] = subFlow
2079 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302080 if err := vs.DelFlows(cntx, vd, flow, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302081 logger.Warnw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302082 }
2083 }
2084 }
2085 return true
2086}
2087
vinokuma926cb3e2023-03-29 11:41:06 +05302088// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05302089func (vs *VoltService) triggerServiceInProgressInd() {
2090}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302091
vinokuma926cb3e2023-03-29 11:41:06 +05302092// JSONMarshal wrapper function for json Marshal VoltService
2093func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302094 return json.Marshal(VoltService{
2095 VoltServiceCfg: vs.VoltServiceCfg,
2096 VoltServiceOper: VoltServiceOper{
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302097 Device: vs.VoltServiceOper.Device,
2098 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
2099 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
2100 UsMeterID: vs.VoltServiceOper.UsMeterID,
2101 DsMeterID: vs.VoltServiceOper.DsMeterID,
2102 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
2103 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
2104 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
2105 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
2106 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
2107 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
2108 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
2109 PendingFlows: vs.VoltServiceOper.PendingFlows,
2110 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2111 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2112 DeactivateInProgress: vs.VoltServiceOper.DeactivateInProgress,
2113 ForceDelete: vs.VoltServiceOper.ForceDelete,
2114 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2115 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2116 Metadata: vs.VoltServiceOper.Metadata,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302117 },
2118 })
2119}
Tinoj Josephec742f62022-09-29 19:11:10 +05302120
2121// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302122func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302123 var svcList []*VoltService
2124 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2125 va.ServiceByName.Range(func(key, value interface{}) bool {
2126 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302127 if len(deviceID) > 0 {
2128 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302129 if deviceID == vs.Device && portNo == vs.Port {
2130 svcList = append(svcList, vs)
2131 }
2132 } else {
2133 if deviceID == vs.Device {
2134 svcList = append(svcList, vs)
2135 }
2136 }
2137 } else {
2138 svcList = append(svcList, vs)
2139 }
2140 return true
2141 })
2142 return svcList, nil
2143}
2144
Akash Soni634d9bf2023-07-10 12:11:10 +05302145type FlowProvisionStatus struct {
2146 FlowProvisionStatus string
2147}
2148
2149// GetFlowProvisionStatus to get status of the subscriber and flow provisioned in controller
Akash Soni3c391e72023-08-16 12:21:33 +05302150func (va *VoltApplication) GetFlowProvisionStatus(portNo string) FlowProvisionStatus {
Akash Soni634d9bf2023-07-10 12:11:10 +05302151 logger.Infow(ctx, "GetFlowProvisionStatus Request ", log.Fields{"Port": portNo})
2152 flowProvisionStatus := FlowProvisionStatus{}
Akash Soni3c391e72023-08-16 12:21:33 +05302153 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_NOT_IN_CONTROLLER
Akash Soni634d9bf2023-07-10 12:11:10 +05302154 va.ServiceByName.Range(func(key, value interface{}) bool {
2155 vs := value.(*VoltService)
2156 logger.Debugw(ctx, "Volt Service ", log.Fields{"VS": vs})
Akash Soni3c391e72023-08-16 12:21:33 +05302157 if portNo == vs.Port {
2158 if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() == 0 {
2159 flowProvisionStatus.FlowProvisionStatus = ALL_FLOWS_PROVISIONED
2160 return false
2161 } else if !vs.IsActivated {
2162 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_DISABLED_IN_CONTROLLER
2163 return false
2164 } else if !vs.DsHSIAFlowsApplied && !vs.UsHSIAFlowsApplied {
2165 flowProvisionStatus.FlowProvisionStatus = NO_FLOWS_PROVISIONED
2166 return false
Akash Soni230e6212023-10-16 10:46:07 +05302167 } else if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() > 0 {
Akash Soni3c391e72023-08-16 12:21:33 +05302168 flowProvisionStatus.FlowProvisionStatus = FLOWS_PROVISIONED_PARTIALLY
2169 return false
Akash Soni634d9bf2023-07-10 12:11:10 +05302170 }
2171 }
2172 return true
2173 })
Akash Soni634d9bf2023-07-10 12:11:10 +05302174 return flowProvisionStatus
2175}
2176
2177func (vs *VoltService) LenOfPendingFlows() int {
2178 vs.ServiceLock.RLock()
2179 lth := len(vs.PendingFlows)
2180 vs.ServiceLock.RUnlock()
2181 return lth
2182}
2183
Tinoj Josephec742f62022-09-29 19:11:10 +05302184// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302185func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302186 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 +05302187 device, err := va.GetDeviceFromPort(portNo)
2188 if err != nil {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302189 // Lets activate the service even though port was not found. We will push the flows once the port is added by voltha
2190 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 +05302191 }
2192 // If device id is not provided check only port number
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302193 if device != nil {
2194 if deviceID == DeviceAny {
2195 deviceID = device.Name
2196 } else if deviceID != device.Name {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302197 err := errorCodes.ErrDeviceNotFound
2198 return fmt.Errorf("wrong device id %s : %w", deviceID, err)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302199 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302200 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302201 va.ServiceByName.Range(func(key, value interface{}) bool {
2202 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302203 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302204 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302205 logger.Warnw(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302206 return true
2207 }
2208 if portNo == vs.Port && !vs.IsActivated {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302209 // 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 +05302210 logger.Debugw(ctx, "Service Activate", log.Fields{"Name": vs.Name})
Tinoj Josephec742f62022-09-29 19:11:10 +05302211 vs.IsActivated = true
2212 va.ServiceByName.Store(vs.Name, vs)
2213 vs.WriteToDb(cntx)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302214
2215 // Push the flows only if the port is already added and we have a valid device
2216 if device != nil {
2217 p := device.GetPort(vs.Port)
2218 if p == nil {
2219 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2220 return true
2221 }
2222 // If port is already up send indication to vpv
2223 if p.State == PortStateUp {
2224 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2225 // PortUp call initiates flow addition
Sridhar Ravindrab76eb162025-07-02 01:25:10 +05302226 // The flow generation and pushing the flow can be done in a go routine,
2227 // VGC once service is activated remembers and pushes the flows again
2228 // if there was a restart in VGC during the execution of the go routine.
2229 // Making it as a go routine will not impact anything
2230 go vpv.PortUpInd(cntx, device, portNo, vs.NniPort)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302231 } else {
2232 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2233 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302234 }
2235 }
2236 }
2237 return true
2238 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302239 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302240}
2241
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302242func (vs *VoltService) SetSvcDeactivationFlags(deactivateRsn SvcDeactivateReason) {
2243 vs.DeactivateInProgress = true
2244 vs.IsActivated = false
2245 vs.ServiceDeactivateReason = deactivateRsn
2246}
2247
Tinoj Josephec742f62022-09-29 19:11:10 +05302248// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302249func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Akash Sonief452f12024-12-12 18:20:28 +05302250 logger.Debugw(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo, "Svaln": sVlan, "Cvlan": cVlan, "TpID": tpID})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302251
Tinoj Josephec742f62022-09-29 19:11:10 +05302252 va.ServiceByName.Range(func(key, value interface{}) bool {
2253 vs := value.(*VoltService)
2254 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302255 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302256 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 +05302257 return true
2258 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302259 if portNo == vs.Port && vs.IsActivated {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302260 vs.SetSvcDeactivationFlags(SvcDeacRsn_NB)
Tinoj Josephec742f62022-09-29 19:11:10 +05302261 va.ServiceByName.Store(vs.Name, vs)
2262 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302263 device, err := va.GetDeviceFromPort(portNo)
2264 if err != nil {
2265 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2266 // So no error is returned
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302267 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302268 return true
2269 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302270 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302271 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302272 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2273 // Port down call internally deletes all the flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302274 vpv.PortDownInd(cntx, deviceID, portNo, true, false)
Tinoj Josephec742f62022-09-29 19:11:10 +05302275 if vpv.IgmpEnabled {
2276 va.ReceiverDownInd(cntx, deviceID, portNo)
2277 }
2278 } else {
2279 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2280 }
2281 }
Akash Sonief452f12024-12-12 18:20:28 +05302282 vs.DeactivateInProgress = false
2283 va.ServiceByName.Store(vs.Name, vs)
2284 vs.WriteToDb(cntx)
Tinoj Josephec742f62022-09-29 19:11:10 +05302285 }
2286 return true
2287 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302288 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302289}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302290
vinokuma926cb3e2023-03-29 11:41:06 +05302291// GetServicePbit to get first set bit in the pbit map
2292// returns -1 : If configured to match on all pbits
2293// returns 8 : If no pbits are configured
2294// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302295func (vs *VoltService) GetServicePbit() int {
2296 if vs.IsPbitExist(of.PbitMatchAll) {
2297 return -1
2298 }
vinokuma926cb3e2023-03-29 11:41:06 +05302299 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302300 if vs.IsPbitExist(of.PbitType(pbit)) {
2301 return pbit
2302 }
2303 }
2304 return int(of.PbitMatchNone)
2305}