blob: 2c16f294301ffda111725b616e5bbc84f064b24c [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053014 */
Naveen Sampath04696f72022-06-13 15:19:14 +053015
16package application
17
18import (
19 "bytes"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053020 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053021 "encoding/json"
22 "errors"
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +053023 "fmt"
Naveen Sampath04696f72022-06-13 15:19:14 +053024 "net"
25 "reflect"
Naveen Sampath04696f72022-06-13 15:19:14 +053026 "sort"
27 "strconv"
28 "strings"
29 "sync"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053030 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053031
32 "github.com/google/gopacket/layers"
33
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053034 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053035 "voltha-go-controller/internal/pkg/controller"
36 cntlr "voltha-go-controller/internal/pkg/controller"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053037 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053038 "voltha-go-controller/internal/pkg/of"
39 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053040 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053041)
42
43const (
44 // DSLAttrEnabled constant
45 DSLAttrEnabled string = "ENABLED"
Tinoj Josephec742f62022-09-29 19:11:10 +053046 // DeviceAny constant
47 DeviceAny string = "DEVICE-ANY"
Akash Soni634d9bf2023-07-10 12:11:10 +053048
49 ALL_FLOWS_PROVISIONED string = "ALL_FLOWS_PROVISIONED"
50
51 NO_FLOWS_PROVISIONED string = "NO_FLOWS_PROVISIONED"
52
53 FLOWS_PROVISIONED_PARTIALLY string = "FLOWS_PROVISIONED_PARTIALLY"
54
55 SUBSCRIBER_DISABLED_IN_CONTROLLER string = "DISABLED_IN_CONTROLLER"
56
57 SUBSCRIBER_NOT_IN_CONTROLLER string = "NOT_IN_CONTROLLER"
58
59 ONT_FLOWS_PROVISION_STATE_UNUSED string = "ONT_FLOWS_PROVISION_STATE_UNUSED"
Naveen Sampath04696f72022-06-13 15:19:14 +053060)
61
62// VoltServiceCfg structure
63// Name - Uniquely identifies a service across the entire application
64// UniVlan - The VLAN of the packets entering the UNI of ONU
65// CVlan - The VLAN to transalate to/from on the PON link
66// SVlan - The outer VLAN to be used on the NNI of OLT.
vinokuma926cb3e2023-03-29 11:41:06 +053067// - In general, 4096 is used as NO VLAN for all the above
68// SVlanTpid - SVlan Tag Protocol Identifier
Naveen Sampath04696f72022-06-13 15:19:14 +053069// Pbits - Each bit of uint8 represents one p-bit. MSB is pbit 7
70// DhcpRelay - Whether it is turned on/off
71// CircuitId - The circuit id to be used with DHCP relay. Unused otherwise
72// RemoveId - Same as above
73// Port - The access port for the service. Each service has a single access
vinokuma926cb3e2023-03-29 11:41:06 +053074// port. The converse is not always true
Naveen Sampath04696f72022-06-13 15:19:14 +053075// MacLearning - If MAC learning is turned on, the MAC address learned from the
vinokuma926cb3e2023-03-29 11:41:06 +053076// the service activation is used in programming flows
Naveen Sampath04696f72022-06-13 15:19:14 +053077// MacAddress - The MAC hardware address learnt on the UNI interface
78// MacAddresses - Not yet implemented. To be used to learn more MAC addresses
79type VoltServiceCfg struct {
Naveen Sampath04696f72022-06-13 15:19:14 +053080 Pbits []of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +053081 Name string
Naveen Sampath04696f72022-06-13 15:19:14 +053082 CircuitID string
Naveen Sampath04696f72022-06-13 15:19:14 +053083 Port string
Naveen Sampath04696f72022-06-13 15:19:14 +053084 UsMeterProfile string
85 DsMeterProfile string
86 AggDsMeterProfile string
87 VnetID string
88 MvlanProfileName string
89 RemoteIDType string
Naveen Sampath04696f72022-06-13 15:19:14 +053090 DataRateAttr string
vinokuma926cb3e2023-03-29 11:41:06 +053091 ServiceType string
92 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
93 RemoteID []byte
94 MacAddr net.HardwareAddr
95 ONTEtherTypeClassification int
96 SchedID int
97 Trigger ServiceTrigger
98 MacLearning MacLearningType
99 PonPort uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530100 MinDataRateUs uint32
101 MinDataRateDs uint32
102 MaxDataRateUs uint32
103 MaxDataRateDs uint32
vinokuma926cb3e2023-03-29 11:41:06 +0530104 TechProfileID uint16
105 SVlanTpid layers.EthernetType
106 UniVlan of.VlanType
107 CVlan of.VlanType
108 SVlan of.VlanType
109 UsPonCTagPriority of.PbitType
110 UsPonSTagPriority of.PbitType
111 DsPonSTagPriority of.PbitType
112 DsPonCTagPriority of.PbitType
113 VlanControl VlanControl
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530114 IsOption82Enabled bool
vinokuma926cb3e2023-03-29 11:41:06 +0530115 IgmpEnabled bool
116 McastService bool
117 AllowTransparent bool
118 EnableMulticastKPI bool
Tinoj Josephec742f62022-09-29 19:11:10 +0530119 IsActivated bool
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530120 FlowPushCount map[string]uint32 // Tracks the number of flow install/delete failure attempts per cookie in order to throttle flow auditing
121 ServiceDeactivateReason SvcDeactivateReason // Mentions why the service was deactivated
Naveen Sampath04696f72022-06-13 15:19:14 +0530122}
123
124// VoltServiceOper structure
125type VoltServiceOper struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530126 Metadata interface{}
127 PendingFlows map[string]bool
128 AssociatedFlows map[string]bool
129 BwAvailInfo string
Naveen Sampath04696f72022-06-13 15:19:14 +0530130 //MacLearning bool
131 //MacAddr net.HardwareAddr
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530132 Device string
133 Ipv4Addr net.IP
134 Ipv6Addr net.IP
135 ServiceLock sync.RWMutex `json:"-"`
136 UsMeterID uint32
137 DsMeterID uint32
138 AggDsMeterID uint32
139 UpdateInProgress bool
140 DeleteInProgress bool
141 DeactivateInProgress bool
142 ForceDelete bool
vinokuma926cb3e2023-03-29 11:41:06 +0530143 // Multiservice-Fix
Naveen Sampath04696f72022-06-13 15:19:14 +0530144 UsHSIAFlowsApplied bool
145 DsHSIAFlowsApplied bool
146 UsDhcpFlowsApplied bool
147 DsDhcpFlowsApplied bool
148 IgmpFlowsApplied bool
149 Icmpv6FlowsApplied bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530150}
151
152// VoltService structure
153type VoltService struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530154 VoltServiceOper
155 Version string
vinokuma926cb3e2023-03-29 11:41:06 +0530156 VoltServiceCfg
Naveen Sampath04696f72022-06-13 15:19:14 +0530157}
158
vinokuma926cb3e2023-03-29 11:41:06 +0530159// ServiceTrigger - Service activation trigger
Naveen Sampath04696f72022-06-13 15:19:14 +0530160type ServiceTrigger int
161
162const (
vinokuma926cb3e2023-03-29 11:41:06 +0530163 // NBActivate - Service added due to NB Action
Naveen Sampath04696f72022-06-13 15:19:14 +0530164 NBActivate ServiceTrigger = 0
vinokuma926cb3e2023-03-29 11:41:06 +0530165 // ServiceVlanUpdate - Service added due to Svlan Update
Naveen Sampath04696f72022-06-13 15:19:14 +0530166 ServiceVlanUpdate ServiceTrigger = 1
167)
168
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530169// SvcDeactivateReason - Reason for service deactivation
170type SvcDeactivateReason uint8
171
172const (
173 // Service deactivated reason - none
174 SvcDeacRsn_None SvcDeactivateReason = 0
175 // Service deactivate reason - NB
176 SvcDeacRsn_NB SvcDeactivateReason = 1
177 // Service deactivate reason - Controller
178 SvcDeacRsn_Controller SvcDeactivateReason = 2
179)
180
Naveen Sampath04696f72022-06-13 15:19:14 +0530181// AppMutexes structure
182type AppMutexes struct {
183 ServiceDataMutex sync.Mutex `json:"-"`
184 VnetMutex sync.Mutex `json:"-"`
185}
186
vinokuma926cb3e2023-03-29 11:41:06 +0530187// MigrateServiceMetadata - migrate services request metadata
Naveen Sampath04696f72022-06-13 15:19:14 +0530188type MigrateServiceMetadata struct {
189 NewVnetID string
190 RequestID string
191}
192
193// AppMutex variable
194var AppMutex AppMutexes
195
196// NewVoltService for constructor for volt service
197func NewVoltService(cfg *VoltServiceCfg) *VoltService {
198 var vs VoltService
199 vs.VoltServiceCfg = *cfg
200 vs.UsHSIAFlowsApplied = false
201 vs.DsHSIAFlowsApplied = false
202 vs.DeleteInProgress = false
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530203 vs.DeactivateInProgress = false
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530204 vs.ServiceDeactivateReason = SvcDeacRsn_None
Naveen Sampath04696f72022-06-13 15:19:14 +0530205 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530206
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530207 vs.IsOption82Enabled = cfg.IsOption82Enabled
Naveen Sampath04696f72022-06-13 15:19:14 +0530208 vs.MacAddr = cfg.MacAddr
209 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
210 vs.Ipv6Addr = net.ParseIP("::")
211 vs.PendingFlows = make(map[string]bool)
212 vs.AssociatedFlows = make(map[string]bool)
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530213 vs.FlowPushCount = make(map[string]uint32)
Naveen Sampath04696f72022-06-13 15:19:14 +0530214 return &vs
215}
216
217// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530218func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530219 vs.ServiceLock.RLock()
220 defer vs.ServiceLock.RUnlock()
221
222 if vs.DeleteInProgress {
223 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
224 return
225 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530226 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530227}
228
vinokuma926cb3e2023-03-29 11:41:06 +0530229// ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530230func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530231 b, err := json.Marshal(vs)
232
233 if err != nil {
234 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
235 return
236 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530237 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530238 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
239 }
240}
241
242// isDataRateAttrPresent to check if data attribute is present
243func (vs *VoltService) isDataRateAttrPresent() bool {
244 return vs.DataRateAttr == DSLAttrEnabled
245}
246
247// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530248func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530249 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
vinokuma926cb3e2023-03-29 11:41:06 +0530250 // TODO - Need to understand and delete the second call
251 // Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530252 _ = db.DelService(cntx, vs.Name)
253 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530254}
255
256// MatchesVlans find the service that matches the VLANs. In this case it is
257// purely based on CVLAN. The CVLAN can sufficiently be used to
258// match a service
259func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
260 if len(vlans) != 1 {
261 return false
262 }
263
264 if vlans[0] == vs.CVlan {
265 return true
266 }
267 return false
268}
269
270// MatchesPbits allows matching a service to a pbit. This is used
271// to search for a service matching the pbits, typically to identify
272// attributes for other flows such as DHCP, IGMP, etc.
273func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
274 for _, pbit := range pbits {
275 for _, pb := range vs.Pbits {
276 if pb == pbit {
277 return true
278 }
279 }
280 }
281 return false
282}
283
284// IsPbitExist allows matching a service to a pbit. This is used
285// to search for a service matching the pbit
286func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530287 logger.Debugw(ctx, "Request for IsPbitExist", log.Fields{"pbit": pbit})
Naveen Sampath04696f72022-06-13 15:19:14 +0530288 for _, pb := range vs.Pbits {
289 if pb == pbit {
290 return true
291 }
292 }
293 return false
294}
295
296// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530297func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530298 logger.Debugw(ctx, "Add US & DS HSIA Flows for the service", log.Fields{"ServiceName": vs.Name})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530299 if err := vs.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530300 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
301 vs.triggerServiceFailureInd(statusCode, statusMessage)
302 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530303 if err := vs.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530304 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
305 vs.triggerServiceFailureInd(statusCode, statusMessage)
306 }
307}
308
vinokuma926cb3e2023-03-29 11:41:06 +0530309// DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530310func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530311 logger.Debugw(ctx, "Delete US & DS HSIA Flows for the service", log.Fields{"ServiceName": vs.Name})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530312 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530313 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
314 vs.triggerServiceFailureInd(statusCode, statusMessage)
315 }
316
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530317 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530318 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
319 vs.triggerServiceFailureInd(statusCode, statusMessage)
320 }
321}
322
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530323func (vs *VoltService) AddMeterToDevice(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530324 logger.Debugw(ctx, "Add Meter To Device for the service", log.Fields{"ServiceName": vs.Name})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530325 if vs.DeleteInProgress || vs.UpdateInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530326 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 +0530327 }
328 va := GetApplication()
329 logger.Infow(ctx, "Configuring Meters for FTTB", log.Fields{"ServiceName": vs.Name})
330 device, err := va.GetDeviceFromPort(vs.Port)
331 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530332 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 +0530333 } else if device.State != controller.DeviceStateUP {
334 logger.Warnw(ctx, "Device state Down. Ignoring Meter Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
335 return nil
336 }
337 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
338 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
339 return nil
340}
341
Naveen Sampath04696f72022-06-13 15:19:14 +0530342// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530343func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530344 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530345 if vs.DeleteInProgress || vs.UpdateInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530346 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 +0530347 return nil
348 }
349
350 va := GetApplication()
Naveen Sampath04696f72022-06-13 15:19:14 +0530351 if !vs.UsHSIAFlowsApplied || vgcRebooted {
352 device, err := va.GetDeviceFromPort(vs.Port)
353 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530354 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 +0530355 } else if device.State != controller.DeviceStateUP {
356 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
357 return nil
358 }
359
360 vs.Device = device.Name
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530361 /* In case of DPU_MGMT_TRAFFIC the meters will be configured before US flow creation*/
vinokuma926cb3e2023-03-29 11:41:06 +0530362 if vs.ServiceType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530363 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
364 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
365 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530366 pBits := vs.Pbits
367
vinokuma926cb3e2023-03-29 11:41:06 +0530368 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530369 if len(vs.Pbits) == 0 {
370 pBits = append(pBits, PbitMatchNone)
371 }
372 for _, pbits := range pBits {
373 usflows, err := vs.BuildUsHsiaFlows(pbits)
374 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530375 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 +0530376 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
377 vs.triggerServiceFailureInd(statusCode, statusMessage)
378 continue
379 }
380 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530381 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530382 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 +0530383 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
384 vs.triggerServiceFailureInd(statusCode, statusMessage)
385 }
386 }
387 vs.UsHSIAFlowsApplied = true
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530388 logger.Debugw(ctx, "Pushed US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530389 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530390 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530391 return nil
392}
393
394// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530395func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530396 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530397 if vs.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530398 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 +0530399 return nil
400 }
401
402 va := GetApplication()
Naveen Sampath04696f72022-06-13 15:19:14 +0530403 if !vs.DsHSIAFlowsApplied || vgcRebooted {
404 device, err := va.GetDeviceFromPort(vs.Port)
405 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530406 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 +0530407 } else if device.State != controller.DeviceStateUP {
408 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
409 return nil
410 }
411
412 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530413
414 //If no pbits configured for service, hence add PbitNone for flows
415 if len(vs.DsRemarkPbitsMap) == 0 {
416 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
417 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530418 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 +0530419 }
420 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530421 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530422 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 +0530423 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
424 vs.triggerServiceFailureInd(statusCode, statusMessage)
425 }
426 } else {
427 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
428 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
429 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
430 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530431 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 +0530432 }
433 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
434 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530435 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530436 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 +0530437 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
438 vs.triggerServiceFailureInd(statusCode, statusMessage)
439 }
440 } else {
441 for matchPbit := range vs.DsRemarkPbitsMap {
442 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
443 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530444 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 +0530445 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
446 vs.triggerServiceFailureInd(statusCode, statusMessage)
447 continue
448 }
449 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530450 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530451 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 +0530452 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
453 vs.triggerServiceFailureInd(statusCode, statusMessage)
454 }
455 }
456 }
457 }
458 vs.DsHSIAFlowsApplied = true
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530459 logger.Debugw(ctx, "Pushed DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530460 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530461 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530462 return nil
463}
464
465// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530466func (vs *VoltService) DelUsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530467 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530468 if vs.UsHSIAFlowsApplied || vgcRebooted {
469 device, err := GetApplication().GetDeviceFromPort(vs.Port)
470 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530471 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 +0530472 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530473 pBits := vs.Pbits
474
vinokuma926cb3e2023-03-29 11:41:06 +0530475 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530476 if len(vs.Pbits) == 0 {
477 pBits = append(pBits, PbitMatchNone)
478 }
479 for _, pbits := range pBits {
480 usflows, err := vs.BuildUsHsiaFlows(pbits)
481 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530482 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 +0530483 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
484 vs.triggerServiceFailureInd(statusCode, statusMessage)
485 continue
486 }
487 usflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530488 if err = vs.DelFlows(cntx, device, usflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530489 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 +0530490 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
491 vs.triggerServiceFailureInd(statusCode, statusMessage)
492 }
493 }
494 vs.UsHSIAFlowsApplied = false
495 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530496 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530497 return nil
498}
499
500// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530501func (vs *VoltService) DelDsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530502 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530503 if vs.DsHSIAFlowsApplied || vgcRebooted {
504 device, err := GetApplication().GetDeviceFromPort(vs.Port)
505 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530506 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 +0530507 }
508
Naveen Sampath04696f72022-06-13 15:19:14 +0530509 var matchPbit int
vinokuma926cb3e2023-03-29 11:41:06 +0530510 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530511 if len(vs.DsRemarkPbitsMap) == 0 {
512 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
513 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530514 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 +0530515 }
516 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530517 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530518 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 +0530519 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
520 vs.triggerServiceFailureInd(statusCode, statusMessage)
521 }
522 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
523 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
524 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530525 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 +0530526 }
527 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530528 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530529 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 +0530530 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
531 vs.triggerServiceFailureInd(statusCode, statusMessage)
532 }
533 } else {
534 for matchPbit = range vs.DsRemarkPbitsMap {
535 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
536 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530537 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 +0530538 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
539 vs.triggerServiceFailureInd(statusCode, statusMessage)
540 continue
541 }
542 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530543 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530544 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 +0530545 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
546 vs.triggerServiceFailureInd(statusCode, statusMessage)
547 }
548 }
549 }
550 vs.DsHSIAFlowsApplied = false
551 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530552 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 +0530553 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530554 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530555 return nil
556}
557
558// BuildDsHsiaFlows build the DS HSIA flows
559// Called for add/delete HSIA flows
560func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530561 logger.Debugw(ctx, "Building DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530562 flow := &of.VoltFlow{}
563 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
564
565 // Get the out and in ports for the flows
566 device, err := GetApplication().GetDeviceFromPort(vs.Port)
567 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530568 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 +0530569 }
570 inport, _ := GetApplication().GetPortID(device.NniPort)
571 outport, _ := GetApplication().GetPortID(vs.Port)
572 // PortName and PortID to be used for validation of port before flow pushing
573 flow.PortID = outport
574 flow.PortName = vs.Port
575 allowTransparent := 0
576 if vs.AllowTransparent {
577 allowTransparent = 1
578 }
579
580 // initialized actnPbit to 0 for cookie genration backward compatibility.
581 var actnPbit of.PbitType
582 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
583
584 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530585 // | 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 +0530586 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
587 cookie = cookie | of.DsFlowMask
588 cookie = cookie + (valToShift << 4) + uint64(pbits)
589 return cookie
590 }
591
592 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
593 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530594 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 +0530595 }
596
597 // Add Table-0 flow that deals with the outer VLAN in pOLT
598 {
599 subflow1 := of.NewVoltSubFlow()
600 subflow1.SetTableID(0)
601 subflow1.SetGoToTable(1)
602 subflow1.SetInPort(inport)
603
604 if pbits != PbitMatchNone {
605 subflow1.SetMatchPbit(pbits)
606 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530607 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
608 subflow1.SetPcp(of.PbitType(remarkPbit))
609 // match & action pbits are different, set remark-pbit action
610 actnPbit = of.PbitType(remarkPbit)
611 // mask remark p-bit to 4bits
612 actnPbit = actnPbit & 0x0F
613 }
614
615 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
616 return nil, err
617 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530618 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530619 if NonZeroMacAddress(vs.MacAddr) {
620 subflow1.SetMatchDstMac(vs.MacAddr)
621 }
622 subflow1.Priority = of.HsiaFlowPriority
623 subflow1.SetMeterID(vs.DsMeterID)
624
625 /* WriteMetaData 8 Byte(uint64) usage:
626 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
627 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
628 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530629 if vs.ServiceType == FttbSubscriberTraffic {
630 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
631 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530632 subflow1.SetWriteMetadata(metadata)
633
634 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
635 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
636 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
637 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
638
639 //TODO-COMM:
640 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
641 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
642 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
643 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
644
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530645 if vs.ServiceType != FttbSubscriberTraffic {
646 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
647 subflow1.SetTableMetadata(metadata)
648 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530649 // TODO - We are using cookie as key and must come up with better cookie
650 // allocation algorithm
651 /**
652 * Cokies may clash when -
653 * on same uni-port we have two sub-service
654 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
655 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
656 * However, this p-bit re-use will not be allowed by sub-mgr.
657 */
658 if vs.VlanControl == OLTCVlanOLTSVlan {
659 /**
660 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
661 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
662 * use old cookie.
663 */
664 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
665 if vgcRebooted {
666 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
667 }
668 } else {
669 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
670 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
671 }
672
673 flow.SubFlows[subflow1.Cookie] = subflow1
674 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
675 "subflow": subflow1})
676 }
677
vinokuma926cb3e2023-03-29 11:41:06 +0530678 // Add Table-1 flow that deals with inner VLAN at the ONU
Naveen Sampath04696f72022-06-13 15:19:14 +0530679 {
680 subflow2 := of.NewVoltSubFlow()
681 subflow2.SetTableID(1)
682 subflow2.SetInPort(inport)
683 if NonZeroMacAddress(vs.MacAddr) {
684 subflow2.SetMatchDstMac(vs.MacAddr)
685 }
686
687 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
688 return nil, err
689 }
690 if pbits != PbitMatchNone {
691 subflow2.SetMatchPbit(pbits)
692 }
693
694 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
695 subflow2.SetPcp(of.PbitType(remarkPbit))
696 }
697
698 subflow2.SetOutPort(outport)
699 subflow2.SetMeterID(vs.DsMeterID)
700
701 // refer Table-0 flow generation for byte information
702 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530703 if vs.ServiceType == FttbSubscriberTraffic {
704 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
705 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530706 subflow2.SetWriteMetadata(metadata)
707
708 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
709 if util.IsNniPort(inport) {
710 metadata = uint64(outport)
711 } else {
712 // refer Table-0 flow generation for byte information
713 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
714 }
715 subflow2.SetTableMetadata(metadata)
716 // Setting of Cookie - TODO - Improve the allocation algorithm
717 if vs.VlanControl == OLTCVlanOLTSVlan {
718 /**
719 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
720 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
721 * use old cookie.
722 */
723 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
724 if vgcRebooted {
725 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
726 }
727 } else {
728 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
729 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
730 }
731
732 subflow2.Priority = of.HsiaFlowPriority
733 flow.SubFlows[subflow2.Cookie] = subflow2
734 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
735 "subflow": subflow2})
736 }
737
738 return flow, nil
739}
740
741// BuildUsHsiaFlows build the US HSIA flows
742// Called for add/delete HSIA flows
743func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530744 logger.Debugw(ctx, "Building US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530745 flow := &of.VoltFlow{}
746 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
747
748 // Get the out and in ports for the flows
749 device, err := GetApplication().GetDeviceFromPort(vs.Port)
750 if err != nil {
751 return nil, errorCodes.ErrDeviceNotFound
752 }
753 outport, _ := GetApplication().GetPortID(device.NniPort)
754 inport, _ := GetApplication().GetPortID(vs.Port)
755 // PortName and PortID to be used for validation of port before flow pushing
756 flow.PortID = inport
757 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530758
759 // Add Table-0 flow that deals with the inner VLAN in ONU
760 {
761 subflow1 := of.NewVoltSubFlow()
762 subflow1.SetTableID(0)
763 subflow1.SetGoToTable(1)
764 subflow1.SetInPort(inport)
765
vinokuma926cb3e2023-03-29 11:41:06 +0530766 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530767 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
768 subflow1.SetPcp(vs.UsPonSTagPriority)
vinokuma926cb3e2023-03-29 11:41:06 +0530769 } else if vs.ServiceType == DpuAncpTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530770 subflow1.SetPcp(vs.UsPonSTagPriority)
771 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530772 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
773 return nil, err
774 }
775 subflow1.SetMeterID(vs.UsMeterID)
776
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530777 /* WriteMetaData 8 Byte(uint64) usage:
778 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
779 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
780 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
781 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530782 if vs.ServiceType == FttbSubscriberTraffic {
783 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
784 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530785 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530786
Naveen Sampath04696f72022-06-13 15:19:14 +0530787 if vs.VlanControl == OLTCVlanOLTSVlan {
788 /**
789 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
790 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
791 * use old cookie.
792 */
793 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
794 if vgcRebooted {
795 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
796 }
797 } else {
798 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
799 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
800 }
801 subflow1.Priority = of.HsiaFlowPriority
802 flow.SubFlows[subflow1.Cookie] = subflow1
803 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
804 }
805
vinokuma926cb3e2023-03-29 11:41:06 +0530806 // Add Table-1 flow that deals with the outer vlan in pOLT
Naveen Sampath04696f72022-06-13 15:19:14 +0530807 {
808 subflow2 := of.NewVoltSubFlow()
809 subflow2.SetTableID(1)
810 subflow2.SetInPort(inport)
811
Naveen Sampath04696f72022-06-13 15:19:14 +0530812 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
813 return nil, err
814 }
vinokuma926cb3e2023-03-29 11:41:06 +0530815 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530816 subflow2.SetMatchSrcMac(vs.MacAddr)
817 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530818 subflow2.SetInPort(inport)
819 subflow2.SetOutPort(outport)
820 subflow2.SetMeterID(vs.UsMeterID)
821
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530822 // refer Table-0 flow generation for byte information
823 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530824 if vs.ServiceType == FttbSubscriberTraffic {
825 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
826 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530827 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530828
Naveen Sampath04696f72022-06-13 15:19:14 +0530829 if vs.VlanControl == OLTCVlanOLTSVlan {
830 /**
831 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
832 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
833 * use old cookie.
834 */
835 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
836 if vgcRebooted {
837 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
838 }
839 } else {
840 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
841 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
842 }
843 subflow2.Priority = of.HsiaFlowPriority
844
845 flow.SubFlows[subflow2.Cookie] = subflow2
846 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
847 }
848
849 return flow, nil
850}
851
852func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530853 // | 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 +0530854 logger.Debugw(ctx, "Generate US Cookie", log.Fields{"Vlan": vlan, "ValToShift": vlan, "Inport": inport, "Pbits": pbits})
Naveen Sampath04696f72022-06-13 15:19:14 +0530855 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
856 cookie = cookie | of.UsFlowMask
857 cookie = cookie + (valToShift << 4) + uint64(pbits)
858 return cookie
859}
860
861// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
862// based on different Vlan Controls
863func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530864 logger.Debugw(ctx, "Set US Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530865 switch vs.VlanControl {
866 case None:
867 flow.SetMatchVlan(vs.SVlan)
868 case ONUCVlanOLTSVlan:
869 flow.SetMatchVlan(vs.CVlan)
870 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
871 case OLTCVlanOLTSVlan:
872 flow.SetMatchVlan(vs.UniVlan)
873 flow.SetSetVlan(vs.CVlan)
874 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
875 case ONUCVlan:
876 flow.SetMatchVlan(vs.SVlan)
877 case OLTSVlan:
878 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
879 flow.SetMatchVlan(vs.UniVlan)
880 flow.SetSetVlan(vs.SVlan)
881 } else if vs.UniVlan != of.VlanNone {
882 flow.SetMatchVlan(vs.UniVlan)
883 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
884 } else {
885 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
886 }
887 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530888 err := errorCodes.ErrInvalidParamInRequest
889 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530890 }
891 return nil
892}
893
894// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
895// based on different Vlan Controls
896func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530897 logger.Debugw(ctx, "Set DS Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530898 switch vs.VlanControl {
899 case None:
900 flow.SetMatchVlan(vs.SVlan)
901 case ONUCVlanOLTSVlan:
902 flow.SetMatchVlan(vs.SVlan)
903 flow.SetPopVlan()
904 case OLTCVlanOLTSVlan:
905 flow.SetMatchVlan(vs.SVlan)
906 flow.SetPopVlan()
907 flow.SetSetVlan(vs.UniVlan)
908 case ONUCVlan:
909 flow.SetMatchVlan(vs.SVlan)
910 case OLTSVlan:
911 flow.SetMatchVlan(vs.SVlan)
912 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
913 flow.SetSetVlan(vs.UniVlan)
914 } else {
915 flow.SetPopVlan()
916 }
917 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530918 err := errorCodes.ErrInvalidParamInRequest
919 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530920 }
921 return nil
922}
923
924// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
925// based on different Vlan Controls
926func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530927 logger.Debugw(ctx, "Set US Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530928 switch vs.VlanControl {
929 case None:
930 flow.SetMatchVlan(vs.SVlan)
931 case ONUCVlanOLTSVlan:
932 if vs.UniVlan != of.VlanNone {
933 flow.SetMatchVlan(vs.UniVlan)
934 flow.SetSetVlan(vs.CVlan)
935 } else {
936 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
937 }
938 case OLTCVlanOLTSVlan:
939 flow.SetMatchVlan(vs.UniVlan)
940 case ONUCVlan:
941 if vs.UniVlan != of.VlanNone {
942 flow.SetMatchVlan(vs.UniVlan)
943 flow.SetSetVlan(vs.SVlan)
944 } else {
945 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
946 }
947 case OLTSVlan:
948 flow.SetMatchVlan(vs.UniVlan)
949 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530950 err := errorCodes.ErrInvalidParamInRequest
951 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530952 }
953 return nil
954}
955
956// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
957// based on different Vlan Controls
958func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530959 logger.Debugw(ctx, "Set DS Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530960 switch vs.VlanControl {
961 case None:
962 flow.SetMatchVlan(vs.SVlan)
963 case ONUCVlanOLTSVlan:
964 flow.SetMatchVlan(vs.CVlan)
965 if vs.UniVlan != of.VlanNone {
966 flow.SetSetVlan(vs.UniVlan)
967 } else {
968 flow.SetPopVlan()
969 }
970 case OLTCVlanOLTSVlan:
971 flow.SetMatchVlan(vs.UniVlan)
972 case ONUCVlan:
973 flow.SetMatchVlan(vs.SVlan)
974 if vs.UniVlan != of.VlanNone {
975 flow.SetSetVlan(vs.UniVlan)
976 } else {
977 flow.SetPopVlan()
978 }
979 case OLTSVlan:
980 flow.SetMatchVlan(vs.UniVlan)
981 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530982 err := errorCodes.ErrInvalidParamInRequest
983 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530984 }
985 return nil
986}
987
988// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530989func (vs *VoltService) SvcUpInd(cntx context.Context) {
990 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530991}
992
993// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530994func (vs *VoltService) SvcDownInd(cntx context.Context) {
995 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530996}
997
998// SetIpv4Addr to set ipv4 address
999func (vs *VoltService) SetIpv4Addr(addr net.IP) {
1000 vs.Ipv4Addr = addr
1001}
1002
1003// SetIpv6Addr to set ipv6 address
1004func (vs *VoltService) SetIpv6Addr(addr net.IP) {
1005 vs.Ipv6Addr = addr
1006}
1007
1008// SetMacAddr to set mac address
1009func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
1010 vs.MacAddr = addr
1011}
1012
1013// ----------------------------------------------
1014// VOLT Application - Related to services
1015// ---------------------------------------------
1016// ---------------------------------------------------------------
1017// Service CRUD functions. These are exposed to the overall binary
1018// to be invoked from the point where the CRUD operations are received
1019// from the external entities
1020
1021// AddService : A service in the context of VOLT is a subscriber or service of a
1022// subscriber which is uniquely identified by a combination of MAC
1023// address, VLAN tags, 802.1p bits. However, in the context of the
1024// current implementation, a service is an entity that is identified by a
1025// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
1026// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301027func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301028 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
Naveen Sampath04696f72022-06-13 15:19:14 +05301029 var mmUs, mmDs *VoltMeter
1030 var err error
1031
vinokuma926cb3e2023-03-29 11:41:06 +05301032 // Take the Device lock only in case of NB add request.
Naveen Sampath04696f72022-06-13 15:19:14 +05301033 // Allow internal adds since internal add happen only under
1034 // 1. Restore Service from DB
1035 // 2. Service Migration
1036 if oper == nil {
1037 if svc := va.GetService(cfg.Name); svc != nil {
1038 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301039 return errors.New("service already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301040 }
1041 }
1042
Naveen Sampath04696f72022-06-13 15:19:14 +05301043 // Service doesn't exist. So create it and add to the port
1044 vs := NewVoltService(&cfg)
1045 if oper != nil {
1046 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1047 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1048 vs.Ipv4Addr = oper.Ipv4Addr
1049 vs.Ipv6Addr = oper.Ipv6Addr
1050 vs.MacLearning = cfg.MacLearning
1051 vs.PendingFlows = oper.PendingFlows
1052 vs.AssociatedFlows = oper.AssociatedFlows
1053 vs.DeleteInProgress = oper.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301054 vs.DeactivateInProgress = oper.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301055 vs.BwAvailInfo = oper.BwAvailInfo
1056 vs.Device = oper.Device
Sridhar Ravindra45589a72024-01-04 17:57:35 +05301057 // FlowPushCount is newly introduced map and it can be nil when VGC is upgraded. Hence adding a nil check to handle backward compatibility
1058 if cfg.FlowPushCount != nil {
1059 vs.FlowPushCount = cfg.FlowPushCount
1060 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301061 vs.ServiceDeactivateReason = cfg.ServiceDeactivateReason
Naveen Sampath04696f72022-06-13 15:19:14 +05301062 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301063 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301064 sort.Slice(vs.Pbits, func(i, j int) bool {
1065 return vs.Pbits[i] > vs.Pbits[j]
1066 })
1067 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1068 }
1069 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1070
1071 // The bandwidth and shaper profile combined into meter
1072 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1073 vs.DsMeterID = mmDs.ID
1074 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301075 return errors.New("downStream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301076 }
1077
1078 // The aggregated downstream meter profile
1079 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1080 // vs.AggDsMeterID = mmAg.ID
1081 // } else {
1082 // return errors.New("Aggregated meter profile not found")
1083 // }
1084
1085 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1086 // vs.UsMeterID = mmAg.ID
1087 // } else {
1088 // The bandwidth and shaper profile combined into meter
1089 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1090 vs.UsMeterID = mmUs.ID
1091 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301092 return errors.New("upstream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301093 }
1094 //}
1095
1096 AppMutex.ServiceDataMutex.Lock()
1097 defer AppMutex.ServiceDataMutex.Unlock()
1098
1099 // Add the service to the VNET
1100 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1101 if vnet != nil {
1102 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1103 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301104 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301105 vpv.VpvLock.Unlock()
1106 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301107 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301108 }
1109 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301110 logger.Warnw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
1111 return errors.New("vnet doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301112 }
1113
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301114 // If the device is already discovered, update the device name in service
1115 d, err := va.GetDeviceFromPort(vs.Port)
1116 if err == nil {
1117 vs.Device = d.Name
1118 }
1119
Naveen Sampath04696f72022-06-13 15:19:14 +05301120 vs.Version = database.PresentVersionMap[database.ServicePath]
1121 // Add the service to the volt application
1122 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301123 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301124
1125 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301126 if !vs.UsHSIAFlowsApplied {
1127 vs.triggerServiceInProgressInd()
1128 }
1129
vinokuma926cb3e2023-03-29 11:41:06 +05301130 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301131 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301132 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301133 if mmUs != nil {
1134 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301135 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301136 }
1137 //mmAg.AssociatedServices++
1138 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301139 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301140 }
1141
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301142 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 +05301143 return nil
1144}
1145
vinokuma926cb3e2023-03-29 11:41:06 +05301146// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301147// Added for DT/TT usecase with sadis replica interface
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301148func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301149 logger.Infow(ctx, "Delete Service With provided Prefix", log.Fields{"Prefix": prefix})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301150 var isServiceExist bool
Naveen Sampath04696f72022-06-13 15:19:14 +05301151 va.ServiceByName.Range(func(key, value interface{}) bool {
1152 srvName := key.(string)
1153 vs := value.(*VoltService)
1154 if strings.Contains(srvName, prefix) {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301155 isServiceExist = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301156 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301157
1158 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1159 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1160 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1161
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301162 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301163 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1164 }
1165 }
1166 return true
1167 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301168
1169 if !isServiceExist {
1170 return errorCodes.ErrServiceNotFound
1171 }
1172 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301173}
1174
1175// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301176func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301177 AppMutex.ServiceDataMutex.Lock()
1178 defer AppMutex.ServiceDataMutex.Unlock()
1179
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301180 logger.Infow(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
Naveen Sampath04696f72022-06-13 15:19:14 +05301181 var noFlowsPresent bool
1182
1183 vsIntf, ok := va.ServiceByName.Load(name)
1184 if !ok {
1185 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1186 return
1187 }
1188 vs := vsIntf.(*VoltService)
1189 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1190 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301191 logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301192 return
1193 }
1194
vinokuma926cb3e2023-03-29 11:41:06 +05301195 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301196 vs.DeleteInProgress = true
1197 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301198 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301199
1200 if len(vs.AssociatedFlows) == 0 {
1201 noFlowsPresent = true
1202 }
1203 vpv.VpvLock.Lock()
1204 defer vpv.VpvLock.Unlock()
1205
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301206 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301207
1208 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301209 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301210 }
1211 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 +05301212 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301213 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301214 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301215 }
1216
1217 // Delete the service immediately in case of Force Delete
1218 // This will be enabled when profile reconciliation happens after restore
1219 // of backedup data
1220 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301221 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301222 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301223 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301224 }
1225
Naveen Sampath04696f72022-06-13 15:19:14 +05301226 if nil != newSvc {
1227 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1228 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1229 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301230
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301231 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1232
1233 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1234 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301235 if aggMeter.AssociatedServices > 0 {
1236 aggMeter.AssociatedServices--
1237 logger.Infow(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
1238 va.UpdateMeterProf(cntx, *aggMeter)
1239 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301240 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301241 }
1242 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301243 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1244 if dsMeter.AssociatedServices > 0 {
1245 dsMeter.AssociatedServices--
1246 logger.Infow(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
1247 va.UpdateMeterProf(cntx, *dsMeter)
1248 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301249 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301250 }
1251 if vs.AggDsMeterID != vs.UsMeterID {
1252 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301253 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1254 if usMeter.AssociatedServices > 0 {
1255 usMeter.AssociatedServices--
1256 logger.Infow(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
1257 va.UpdateMeterProf(cntx, *usMeter)
1258 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301259 }
1260 }
1261 }
1262
1263 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301264 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301265 }
1266
vinokuma926cb3e2023-03-29 11:41:06 +05301267 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301268 va.ServiceCounters.Delete(name)
1269 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301270 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301271 }
1272}
1273
vinokuma926cb3e2023-03-29 11:41:06 +05301274// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301275// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301276func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301277 // Using locks instead of concurrent map for PendingFlows to avoid
1278 // race condition during flow response indication processing
1279 vs.ServiceLock.Lock()
1280 defer vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301281 logger.Debugw(ctx, "Adds the flow to the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301282
1283 for cookie := range flow.SubFlows {
1284 cookie := strconv.FormatUint(cookie, 10)
1285 fe := &FlowEvent{
1286 eType: EventTypeServiceFlowAdded,
1287 device: device.Name,
1288 cookie: cookie,
1289 eventData: vs,
1290 }
1291 device.RegisterFlowAddEvent(cookie, fe)
1292 vs.PendingFlows[cookie] = true
1293 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301294 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301295}
1296
vinokuma926cb3e2023-03-29 11:41:06 +05301297// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301298// If no more pending flows, HSIA indication wil be triggered
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301299func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails, flowEventMap *util.ConcurrentMap) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301300 logger.Debugw(ctx, "Flow Add Success Notification", log.Fields{"Cookie": cookie, "bwAvailInfo": bwAvailInfo, "Service": vs.Name})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301301 flowEventMap.MapLock.Lock()
1302 flowEventMap.Remove(cookie)
1303 flowEventMap.MapLock.Unlock()
1304
Naveen Sampath04696f72022-06-13 15:19:14 +05301305 if vs.DeleteInProgress {
1306 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1307 return
1308 }
1309 vs.ServiceLock.Lock()
1310
1311 if _, ok := vs.PendingFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301312 logger.Warnw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301313 vs.ServiceLock.Unlock()
1314 return
1315 }
1316
1317 delete(vs.PendingFlows, cookie)
1318 vs.AssociatedFlows[cookie] = true
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301319 vs.FlowPushCount[cookie] = 0
Naveen Sampath04696f72022-06-13 15:19:14 +05301320 vs.ServiceLock.Unlock()
1321 var prevBwAvail, presentBwAvail string
1322 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1323 prevBwAvail = bwAvailInfo.PrevBw
1324 presentBwAvail = bwAvailInfo.PresentBw
1325 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301326 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301327 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301328 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301329
1330 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301331 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1332 if err != nil {
1333 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1334 return
1335 } else if device.State != controller.DeviceStateUP {
1336 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1337 return
1338 }
1339
1340 if vs.Trigger == ServiceVlanUpdate {
1341 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301342 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301343 }
1344 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1345 return
1346 }
1347 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1348}
1349
vinokuma926cb3e2023-03-29 11:41:06 +05301350// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301351// Trigger service failure indication to NB
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301352func (vs *VoltService) FlowInstallFailure(cntx context.Context, cookie string, errorCode uint32, errReason string, flowEventMap *util.ConcurrentMap) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301353 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 +05301354
1355 isServiceDeactivated := vs.CheckAndDeactivateService(cntx, cookie)
1356 if isServiceDeactivated {
1357 flowEventMap.MapLock.Lock()
1358 for ck := range vs.PendingFlows {
1359 flowEventMap.Remove(ck)
1360 }
1361 flowEventMap.MapLock.Unlock()
1362 }
1363
1364 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301365 if _, ok := vs.PendingFlows[cookie]; !ok {
1366 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1367 vs.ServiceLock.RUnlock()
1368 return
1369 }
1370 vs.ServiceLock.RUnlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301371 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 +05301372 vs.triggerServiceFailureInd(errorCode, errReason)
1373}
1374
vinokuma926cb3e2023-03-29 11:41:06 +05301375// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301376// Triggers flow deletion after registering for flow indication event
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301377func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301378 logger.Debugw(ctx, "Delete the flow from the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301379 if !vs.ForceDelete {
1380 // Using locks instead of concurrent map for AssociatedFlows to avoid
1381 // race condition during flow response indication processing
1382 vs.ServiceLock.Lock()
1383 defer vs.ServiceLock.Unlock()
1384
1385 for cookie := range flow.SubFlows {
1386 cookie := strconv.FormatUint(cookie, 10)
1387 fe := &FlowEvent{
1388 eType: EventTypeServiceFlowRemoved,
1389 cookie: cookie,
1390 eventData: vs,
1391 }
1392 device.RegisterFlowDelEvent(cookie, fe)
1393 }
1394 }
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301395 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow, delFlowsInDevice)
Naveen Sampath04696f72022-06-13 15:19:14 +05301396}
1397
vinokuma926cb3e2023-03-29 11:41:06 +05301398// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301399func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301400 logger.Debugw(ctx, "Delete service from DB/Cache", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301401 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301402 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301403 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301404 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301405 }
1406}
1407
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301408// CheckAndDeactivateService - deactivate service and remove flows from DB, if the max flows retry attempt has reached
1409func (vs *VoltService) CheckAndDeactivateService(cntx context.Context, cookie string) bool {
1410 vs.ServiceLock.Lock()
1411 logger.Debugw(ctx, "Check and Deactivate service if flow install threshold is reached and remove flows from DB/Device", log.Fields{"serviceName": vs.Name, "FlowPushCount": vs.FlowPushCount[cookie]})
1412 vs.FlowPushCount[cookie]++
1413 if vs.FlowPushCount[cookie] == controller.GetController().GetMaxFlowRetryAttempt() {
1414 if vs.IsActivated {
1415 vs.ServiceLock.Unlock()
1416 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1417 if err != nil {
1418 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
1419 // So no error is returned
1420 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": vs.Port})
1421 return false
1422 }
1423 vs.SetSvcDeactivationFlags(SvcDeacRsn_Controller)
1424 GetApplication().ServiceByName.Store(vs.Name, vs)
1425 p := device.GetPort(vs.Port)
1426 if p != nil && (p.State == PortStateUp) {
1427 if vpv := GetApplication().GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
1428 // Port down call internally deletes all the flows
1429 vpv.PortDownInd(cntx, vs.Device, vs.Port, true, true)
1430 } else {
1431 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": vs.Device, "port": vs.Port, "SvcName": vs.Name})
1432 }
1433 }
1434 vs.DeactivateInProgress = false
1435 GetApplication().ServiceByName.Store(vs.Name, vs)
1436 vs.WriteToDb(cntx)
1437 logger.Infow(ctx, "Service deactivated after max flow install attempts", log.Fields{"SvcName": vs.Name, "Cookie": cookie})
1438 return true
1439 }
1440 }
1441 vs.ServiceLock.Unlock()
1442 return false
1443}
1444
vinokuma926cb3e2023-03-29 11:41:06 +05301445// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301446// If no more associated flows, DelHSIA indication wil be triggered
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301447func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string, flowEventMap *util.ConcurrentMap) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301448 // if vs.DeleteInProgress {
1449 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1450 // return
1451 // }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301452 flowEventMap.MapLock.Lock()
1453 flowEventMap.Remove(cookie)
1454 flowEventMap.MapLock.Unlock()
1455
Naveen Sampath04696f72022-06-13 15:19:14 +05301456 vs.ServiceLock.Lock()
1457 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1458
1459 if _, ok := vs.AssociatedFlows[cookie]; ok {
1460 delete(vs.AssociatedFlows, cookie)
1461 } else if _, ok := vs.PendingFlows[cookie]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301462 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 +05301463 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301464 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 +05301465 }
1466
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301467 vs.FlowPushCount[cookie] = 0
Naveen Sampath04696f72022-06-13 15:19:14 +05301468 vs.ServiceLock.Unlock()
1469
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301470 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301471
1472 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301473 device := GetApplication().GetDevice(vs.Device)
1474 if device == nil {
1475 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1476 return
1477 } else if device.State != controller.DeviceStateUP {
1478 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1479 return
1480 }
1481
1482 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301483 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301484 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301485 return
1486 }
1487 logger.Infow(ctx, "All Flows removed for Service. Triggering Service De-activation Success indication to NB", log.Fields{"Service": vs.Name, "DeleteFlag": vs.DeleteInProgress})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301488 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301489
1490 return
1491 }
1492 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1493}
1494
vinokuma926cb3e2023-03-29 11:41:06 +05301495// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301496// Trigger service failure indication to NB
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301497func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string, flowEventMap *util.ConcurrentMap) {
1498 vs.ServiceLock.Lock()
1499 logger.Debugw(ctx, "Processing Service Flow Remove Failure Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied, "FlowPushCount": vs.FlowPushCount[cookie]})
Naveen Sampath04696f72022-06-13 15:19:14 +05301500
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301501 vs.FlowPushCount[cookie]++
Naveen Sampath04696f72022-06-13 15:19:14 +05301502 if _, ok := vs.AssociatedFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301503 logger.Warnw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301504 vs.ServiceLock.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301505 return
1506 }
1507 if vs.DeleteInProgress {
1508 delete(vs.AssociatedFlows, cookie)
1509 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301510 vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301511 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 +05301512
1513 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301514 vs.CheckAndDeleteService(cntx)
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 {
1552 va.ServicesToDeactivate[vvs.VoltServiceCfg.Name] = true
1553 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 {
1557 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1558 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
2226 vpv.PortUpInd(cntx, device, portNo)
2227 } else {
2228 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2229 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302230 }
2231 }
2232 }
2233 return true
2234 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302235 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302236}
2237
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302238func (vs *VoltService) SetSvcDeactivationFlags(deactivateRsn SvcDeactivateReason) {
2239 vs.DeactivateInProgress = true
2240 vs.IsActivated = false
2241 vs.ServiceDeactivateReason = deactivateRsn
2242}
2243
Tinoj Josephec742f62022-09-29 19:11:10 +05302244// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302245func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302246 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo, "Svaln": sVlan, "Cvlan": cVlan, "TpID": tpID})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302247
Tinoj Josephec742f62022-09-29 19:11:10 +05302248 va.ServiceByName.Range(func(key, value interface{}) bool {
2249 vs := value.(*VoltService)
2250 // If svlan if provided, then the tags and tpID of service has to be matching
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302251 logger.Debugw(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302252 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302253 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 +05302254 return true
2255 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302256 if portNo == vs.Port && vs.IsActivated {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302257 vs.SetSvcDeactivationFlags(SvcDeacRsn_NB)
Tinoj Josephec742f62022-09-29 19:11:10 +05302258 va.ServiceByName.Store(vs.Name, vs)
2259 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302260 device, err := va.GetDeviceFromPort(portNo)
2261 if err != nil {
2262 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2263 // So no error is returned
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302264 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302265 return true
2266 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302267 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302268 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302269 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2270 // Port down call internally deletes all the flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302271 vpv.PortDownInd(cntx, deviceID, portNo, true, false)
Tinoj Josephec742f62022-09-29 19:11:10 +05302272 if vpv.IgmpEnabled {
2273 va.ReceiverDownInd(cntx, deviceID, portNo)
2274 }
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302275 vs.DeactivateInProgress = false
Tinoj Josephec742f62022-09-29 19:11:10 +05302276 } else {
2277 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2278 }
2279 }
2280 }
2281 return true
2282 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302283 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302284}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302285
vinokuma926cb3e2023-03-29 11:41:06 +05302286// GetServicePbit to get first set bit in the pbit map
2287// returns -1 : If configured to match on all pbits
2288// returns 8 : If no pbits are configured
2289// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302290func (vs *VoltService) GetServicePbit() int {
2291 if vs.IsPbitExist(of.PbitMatchAll) {
2292 return -1
2293 }
vinokuma926cb3e2023-03-29 11:41:06 +05302294 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302295 if vs.IsPbitExist(of.PbitType(pbit)) {
2296 return pbit
2297 }
2298 }
2299 return int(of.PbitMatchNone)
2300}