blob: 38d41c2adea888e943e33d07b111978a4f94b5a8 [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 Ravindra3ec14232024-01-01 19:11:48 +05301057 vs.FlowPushCount = cfg.FlowPushCount
1058 vs.ServiceDeactivateReason = cfg.ServiceDeactivateReason
Naveen Sampath04696f72022-06-13 15:19:14 +05301059 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301060 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301061 sort.Slice(vs.Pbits, func(i, j int) bool {
1062 return vs.Pbits[i] > vs.Pbits[j]
1063 })
1064 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1065 }
1066 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1067
1068 // The bandwidth and shaper profile combined into meter
1069 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1070 vs.DsMeterID = mmDs.ID
1071 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301072 return errors.New("downStream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301073 }
1074
1075 // The aggregated downstream meter profile
1076 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1077 // vs.AggDsMeterID = mmAg.ID
1078 // } else {
1079 // return errors.New("Aggregated meter profile not found")
1080 // }
1081
1082 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1083 // vs.UsMeterID = mmAg.ID
1084 // } else {
1085 // The bandwidth and shaper profile combined into meter
1086 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1087 vs.UsMeterID = mmUs.ID
1088 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301089 return errors.New("upstream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301090 }
1091 //}
1092
1093 AppMutex.ServiceDataMutex.Lock()
1094 defer AppMutex.ServiceDataMutex.Unlock()
1095
1096 // Add the service to the VNET
1097 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1098 if vnet != nil {
1099 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1100 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301101 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301102 vpv.VpvLock.Unlock()
1103 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301104 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301105 }
1106 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301107 logger.Warnw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
1108 return errors.New("vnet doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301109 }
1110
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301111 // If the device is already discovered, update the device name in service
1112 d, err := va.GetDeviceFromPort(vs.Port)
1113 if err == nil {
1114 vs.Device = d.Name
1115 }
1116
Naveen Sampath04696f72022-06-13 15:19:14 +05301117 vs.Version = database.PresentVersionMap[database.ServicePath]
1118 // Add the service to the volt application
1119 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301120 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301121
1122 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301123 if !vs.UsHSIAFlowsApplied {
1124 vs.triggerServiceInProgressInd()
1125 }
1126
vinokuma926cb3e2023-03-29 11:41:06 +05301127 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301128 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301129 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301130 if mmUs != nil {
1131 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301132 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301133 }
1134 //mmAg.AssociatedServices++
1135 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301136 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301137 }
1138
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301139 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 +05301140 return nil
1141}
1142
vinokuma926cb3e2023-03-29 11:41:06 +05301143// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301144// Added for DT/TT usecase with sadis replica interface
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301145func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301146 logger.Infow(ctx, "Delete Service With provided Prefix", log.Fields{"Prefix": prefix})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301147 var isServiceExist bool
Naveen Sampath04696f72022-06-13 15:19:14 +05301148 va.ServiceByName.Range(func(key, value interface{}) bool {
1149 srvName := key.(string)
1150 vs := value.(*VoltService)
1151 if strings.Contains(srvName, prefix) {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301152 isServiceExist = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301153 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301154
1155 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1156 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1157 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1158
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301159 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301160 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1161 }
1162 }
1163 return true
1164 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301165
1166 if !isServiceExist {
1167 return errorCodes.ErrServiceNotFound
1168 }
1169 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301170}
1171
1172// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301173func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301174 AppMutex.ServiceDataMutex.Lock()
1175 defer AppMutex.ServiceDataMutex.Unlock()
1176
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301177 logger.Infow(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
Naveen Sampath04696f72022-06-13 15:19:14 +05301178 var noFlowsPresent bool
1179
1180 vsIntf, ok := va.ServiceByName.Load(name)
1181 if !ok {
1182 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1183 return
1184 }
1185 vs := vsIntf.(*VoltService)
1186 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1187 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301188 logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301189 return
1190 }
1191
vinokuma926cb3e2023-03-29 11:41:06 +05301192 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301193 vs.DeleteInProgress = true
1194 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301195 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301196
1197 if len(vs.AssociatedFlows) == 0 {
1198 noFlowsPresent = true
1199 }
1200 vpv.VpvLock.Lock()
1201 defer vpv.VpvLock.Unlock()
1202
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301203 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301204
1205 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301206 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301207 }
1208 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 +05301209 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301210 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301211 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301212 }
1213
1214 // Delete the service immediately in case of Force Delete
1215 // This will be enabled when profile reconciliation happens after restore
1216 // of backedup data
1217 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301218 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301219 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301220 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301221 }
1222
Naveen Sampath04696f72022-06-13 15:19:14 +05301223 if nil != newSvc {
1224 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1225 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1226 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301227
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301228 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1229
1230 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1231 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301232 if aggMeter.AssociatedServices > 0 {
1233 aggMeter.AssociatedServices--
1234 logger.Infow(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
1235 va.UpdateMeterProf(cntx, *aggMeter)
1236 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301237 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301238 }
1239 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301240 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1241 if dsMeter.AssociatedServices > 0 {
1242 dsMeter.AssociatedServices--
1243 logger.Infow(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
1244 va.UpdateMeterProf(cntx, *dsMeter)
1245 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301246 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301247 }
1248 if vs.AggDsMeterID != vs.UsMeterID {
1249 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301250 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1251 if usMeter.AssociatedServices > 0 {
1252 usMeter.AssociatedServices--
1253 logger.Infow(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
1254 va.UpdateMeterProf(cntx, *usMeter)
1255 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301256 }
1257 }
1258 }
1259
1260 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301261 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301262 }
1263
vinokuma926cb3e2023-03-29 11:41:06 +05301264 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301265 va.ServiceCounters.Delete(name)
1266 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301267 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301268 }
1269}
1270
vinokuma926cb3e2023-03-29 11:41:06 +05301271// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301272// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301273func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301274 // Using locks instead of concurrent map for PendingFlows to avoid
1275 // race condition during flow response indication processing
1276 vs.ServiceLock.Lock()
1277 defer vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301278 logger.Debugw(ctx, "Adds the flow to the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301279
1280 for cookie := range flow.SubFlows {
1281 cookie := strconv.FormatUint(cookie, 10)
1282 fe := &FlowEvent{
1283 eType: EventTypeServiceFlowAdded,
1284 device: device.Name,
1285 cookie: cookie,
1286 eventData: vs,
1287 }
1288 device.RegisterFlowAddEvent(cookie, fe)
1289 vs.PendingFlows[cookie] = true
1290 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301291 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301292}
1293
vinokuma926cb3e2023-03-29 11:41:06 +05301294// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301295// If no more pending flows, HSIA indication wil be triggered
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301296func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails, flowEventMap *util.ConcurrentMap) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301297 logger.Debugw(ctx, "Flow Add Success Notification", log.Fields{"Cookie": cookie, "bwAvailInfo": bwAvailInfo, "Service": vs.Name})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301298 flowEventMap.MapLock.Lock()
1299 flowEventMap.Remove(cookie)
1300 flowEventMap.MapLock.Unlock()
1301
Naveen Sampath04696f72022-06-13 15:19:14 +05301302 if vs.DeleteInProgress {
1303 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1304 return
1305 }
1306 vs.ServiceLock.Lock()
1307
1308 if _, ok := vs.PendingFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301309 logger.Warnw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301310 vs.ServiceLock.Unlock()
1311 return
1312 }
1313
1314 delete(vs.PendingFlows, cookie)
1315 vs.AssociatedFlows[cookie] = true
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301316 vs.FlowPushCount[cookie] = 0
Naveen Sampath04696f72022-06-13 15:19:14 +05301317 vs.ServiceLock.Unlock()
1318 var prevBwAvail, presentBwAvail string
1319 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1320 prevBwAvail = bwAvailInfo.PrevBw
1321 presentBwAvail = bwAvailInfo.PresentBw
1322 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301323 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301324 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301325 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301326
1327 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301328 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1329 if err != nil {
1330 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1331 return
1332 } else if device.State != controller.DeviceStateUP {
1333 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1334 return
1335 }
1336
1337 if vs.Trigger == ServiceVlanUpdate {
1338 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301339 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301340 }
1341 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1342 return
1343 }
1344 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1345}
1346
vinokuma926cb3e2023-03-29 11:41:06 +05301347// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301348// Trigger service failure indication to NB
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301349func (vs *VoltService) FlowInstallFailure(cntx context.Context, cookie string, errorCode uint32, errReason string, flowEventMap *util.ConcurrentMap) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301350 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 +05301351
1352 isServiceDeactivated := vs.CheckAndDeactivateService(cntx, cookie)
1353 if isServiceDeactivated {
1354 flowEventMap.MapLock.Lock()
1355 for ck := range vs.PendingFlows {
1356 flowEventMap.Remove(ck)
1357 }
1358 flowEventMap.MapLock.Unlock()
1359 }
1360
1361 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301362 if _, ok := vs.PendingFlows[cookie]; !ok {
1363 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1364 vs.ServiceLock.RUnlock()
1365 return
1366 }
1367 vs.ServiceLock.RUnlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301368 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 +05301369 vs.triggerServiceFailureInd(errorCode, errReason)
1370}
1371
vinokuma926cb3e2023-03-29 11:41:06 +05301372// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301373// Triggers flow deletion after registering for flow indication event
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301374func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301375 logger.Debugw(ctx, "Delete the flow from the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301376 if !vs.ForceDelete {
1377 // Using locks instead of concurrent map for AssociatedFlows to avoid
1378 // race condition during flow response indication processing
1379 vs.ServiceLock.Lock()
1380 defer vs.ServiceLock.Unlock()
1381
1382 for cookie := range flow.SubFlows {
1383 cookie := strconv.FormatUint(cookie, 10)
1384 fe := &FlowEvent{
1385 eType: EventTypeServiceFlowRemoved,
1386 cookie: cookie,
1387 eventData: vs,
1388 }
1389 device.RegisterFlowDelEvent(cookie, fe)
1390 }
1391 }
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301392 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow, delFlowsInDevice)
Naveen Sampath04696f72022-06-13 15:19:14 +05301393}
1394
vinokuma926cb3e2023-03-29 11:41:06 +05301395// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301396func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301397 logger.Debugw(ctx, "Delete service from DB/Cache", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301398 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301399 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301400 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301401 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301402 }
1403}
1404
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301405// CheckAndDeactivateService - deactivate service and remove flows from DB, if the max flows retry attempt has reached
1406func (vs *VoltService) CheckAndDeactivateService(cntx context.Context, cookie string) bool {
1407 vs.ServiceLock.Lock()
1408 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]})
1409 vs.FlowPushCount[cookie]++
1410 if vs.FlowPushCount[cookie] == controller.GetController().GetMaxFlowRetryAttempt() {
1411 if vs.IsActivated {
1412 vs.ServiceLock.Unlock()
1413 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1414 if err != nil {
1415 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
1416 // So no error is returned
1417 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": vs.Port})
1418 return false
1419 }
1420 vs.SetSvcDeactivationFlags(SvcDeacRsn_Controller)
1421 GetApplication().ServiceByName.Store(vs.Name, vs)
1422 p := device.GetPort(vs.Port)
1423 if p != nil && (p.State == PortStateUp) {
1424 if vpv := GetApplication().GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
1425 // Port down call internally deletes all the flows
1426 vpv.PortDownInd(cntx, vs.Device, vs.Port, true, true)
1427 } else {
1428 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": vs.Device, "port": vs.Port, "SvcName": vs.Name})
1429 }
1430 }
1431 vs.DeactivateInProgress = false
1432 GetApplication().ServiceByName.Store(vs.Name, vs)
1433 vs.WriteToDb(cntx)
1434 logger.Infow(ctx, "Service deactivated after max flow install attempts", log.Fields{"SvcName": vs.Name, "Cookie": cookie})
1435 return true
1436 }
1437 }
1438 vs.ServiceLock.Unlock()
1439 return false
1440}
1441
vinokuma926cb3e2023-03-29 11:41:06 +05301442// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301443// If no more associated flows, DelHSIA indication wil be triggered
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301444func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string, flowEventMap *util.ConcurrentMap) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301445 // if vs.DeleteInProgress {
1446 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1447 // return
1448 // }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301449 flowEventMap.MapLock.Lock()
1450 flowEventMap.Remove(cookie)
1451 flowEventMap.MapLock.Unlock()
1452
Naveen Sampath04696f72022-06-13 15:19:14 +05301453 vs.ServiceLock.Lock()
1454 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1455
1456 if _, ok := vs.AssociatedFlows[cookie]; ok {
1457 delete(vs.AssociatedFlows, cookie)
1458 } else if _, ok := vs.PendingFlows[cookie]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301459 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 +05301460 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301461 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 +05301462 }
1463
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301464 vs.FlowPushCount[cookie] = 0
Naveen Sampath04696f72022-06-13 15:19:14 +05301465 vs.ServiceLock.Unlock()
1466
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301467 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301468
1469 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301470 device := GetApplication().GetDevice(vs.Device)
1471 if device == nil {
1472 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1473 return
1474 } else if device.State != controller.DeviceStateUP {
1475 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1476 return
1477 }
1478
1479 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301480 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301481 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301482 return
1483 }
1484 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 +05301485 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301486
1487 return
1488 }
1489 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1490}
1491
vinokuma926cb3e2023-03-29 11:41:06 +05301492// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301493// Trigger service failure indication to NB
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301494func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string, flowEventMap *util.ConcurrentMap) {
1495 vs.ServiceLock.Lock()
1496 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 +05301497
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301498 vs.FlowPushCount[cookie]++
Naveen Sampath04696f72022-06-13 15:19:14 +05301499 if _, ok := vs.AssociatedFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301500 logger.Warnw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301501 vs.ServiceLock.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301502 return
1503 }
1504 if vs.DeleteInProgress {
1505 delete(vs.AssociatedFlows, cookie)
1506 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301507 vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301508 logger.Debugw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
Naveen Sampath04696f72022-06-13 15:19:14 +05301509
1510 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301511 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301512}
1513
1514func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301515 logger.Debugw(ctx, "Trigger Service Failure Ind", log.Fields{"Service": vs.Name, "Port": vs.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301516 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1517 if err != nil {
1518 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1519 return
1520 } else if device.State != controller.DeviceStateUP {
1521 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1522 return
1523 }
1524}
1525
1526// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301527func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301528 // VNETS must be learnt first
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301529 logger.Debug(ctx, "Restore Svcs From Db")
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301530 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301531 for _, vs := range vss {
1532 b, ok := vs.Value.([]byte)
1533 if !ok {
1534 logger.Warn(ctx, "The value type is not []byte")
1535 continue
1536 }
1537 var vvs VoltService
1538 err := json.Unmarshal(b, &vvs)
1539 if err != nil {
1540 logger.Warn(ctx, "Unmarshal of VNET failed")
1541 continue
1542 }
1543 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301544 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301545 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1546 }
1547
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301548 if vvs.VoltServiceOper.DeactivateInProgress {
1549 va.ServicesToDeactivate[vvs.VoltServiceCfg.Name] = true
1550 logger.Warnw(ctx, "Service (restored) to be deactivated", log.Fields{"Service": vvs.Name})
1551 }
1552
Naveen Sampath04696f72022-06-13 15:19:14 +05301553 if vvs.VoltServiceOper.DeleteInProgress {
1554 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1555 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1556 }
1557 }
1558}
1559
1560// GetService to get service
1561func (va *VoltApplication) GetService(name string) *VoltService {
1562 if vs, ok := va.ServiceByName.Load(name); ok {
1563 return vs.(*VoltService)
1564 }
1565 return nil
1566}
1567
1568// GetCircuitID to get circuit id
1569func (vs *VoltService) GetCircuitID() []byte {
1570 return []byte(vs.CircuitID)
1571}
1572
1573// GetRemoteID to get remote id
1574func (vs *VoltService) GetRemoteID() []byte {
1575 return []byte(vs.RemoteID)
1576}
1577
1578// IPAssigned to check if ip is assigned
1579func (vs *VoltService) IPAssigned() bool {
1580 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1581 return true
1582 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1583 return true
1584 }
1585 return false
1586}
1587
1588// GetServiceNameFromCookie to get service name from cookie
1589func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301590 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 +05301591 var vlan uint64
1592 vlanControl := (tableMetadata >> 32) & 0xF
1593
1594 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1595 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1596 vlan = (tableMetadata >> 16) & 0xFFFF
1597 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301598 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301599 vlan = cookie >> 52
1600 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301601 logger.Debugw(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301602 var vlans []of.VlanType
1603 vlans = append(vlans, of.VlanType(vlan))
1604 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1605 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301606 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301607 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301608 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 +05301609 }
1610 return service
1611}
1612
vinokuma926cb3e2023-03-29 11:41:06 +05301613// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301614type MigrateServicesReqStatus string
1615
1616const (
vinokuma926cb3e2023-03-29 11:41:06 +05301617 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301618 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301619 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301620 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301621 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301622 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1623)
1624
vinokuma926cb3e2023-03-29 11:41:06 +05301625// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301626type MigrateServicesRequest struct {
1627 ID string
1628 OldVnetID string
1629 NewVnetID string
1630 ServicesList map[string]bool
1631 DeviceID string
1632 Status MigrateServicesReqStatus
1633 MigrateServicesLock sync.RWMutex
1634}
1635
1636func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301637 var msr MigrateServicesRequest
1638 msr.OldVnetID = oldVnetID
1639 msr.NewVnetID = newVnetID
1640 msr.ID = id
1641 msr.ServicesList = serviceMap
1642 msr.DeviceID = deviceID
1643 msr.Status = MigrateSrvsReqInit
1644 return &msr
1645}
1646
vinokuma926cb3e2023-03-29 11:41:06 +05301647// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301648func (msr *MigrateServicesRequest) GetMsrKey() string {
1649 return msr.OldVnetID + "-" + msr.ID
1650}
1651
1652// //isRequestComplete - return if all request has been processed and completed
1653// // RequestProcessed indicates that all the profile de-activation has been triggered
1654// // And the associated profiles indicates the profiles awaiting results
1655// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1656// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1657// return (len(edr.AssociatedProfiles) == 0)
1658// }
1659
vinokuma926cb3e2023-03-29 11:41:06 +05301660// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301661func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301662 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)})
1663 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301664 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301665 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301666 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301667 }
1668 }
1669}
1670
vinokuma926cb3e2023-03-29 11:41:06 +05301671// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301672func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301673 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 +05301674 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301675 return errors.New("old vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301676 }
1677 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301678 return errors.New("new vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301679 }
1680
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301681 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301682 if d == nil {
1683 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1684 return errorCodes.ErrDeviceNotFound
1685 }
1686
1687 serviceMap := make(map[string]bool)
1688
1689 for _, service := range serviceList {
1690 serviceMap[service] = false
1691 }
1692 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301693 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301694
1695 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301696 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301697 return nil
1698}
1699
vinokuma926cb3e2023-03-29 11:41:06 +05301700// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301701func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301702 logger.Debug(ctx, "Process Migrate Services Prof Request")
Naveen Sampath04696f72022-06-13 15:19:14 +05301703 va := GetApplication()
1704 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301705 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301706 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301707 va.DelService(cntx, srv, true, nil, true)
1708 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301709 continue
1710 }
1711
1712 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1713 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1714 vs := vsIntf.(*VoltService)
1715 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1716 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301717 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 +05301718 continue
1719 }
1720 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1721 vpv.Blocked = true
1722
1723 // setDeactTrigger := func(key, value interface{}) bool {
1724 // vs := value.(*VoltService)
1725 vs.ServiceLock.Lock()
1726 vs.UpdateInProgress = true
1727 metadata := &MigrateServiceMetadata{
1728 NewVnetID: msr.NewVnetID,
1729 RequestID: msr.ID,
1730 }
1731 vs.Metadata = metadata
1732 vs.ServiceLock.Unlock()
1733
vinokuma926cb3e2023-03-29 11:41:06 +05301734 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301735 // new vpv flows will be installed when new service is added
1736 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301737 vpv.DelTrapFlows(cntx)
1738 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301739 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301740 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301741 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301742 }
1743 } else {
1744 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1745 }
1746 }
1747}
1748
vinokuma926cb3e2023-03-29 11:41:06 +05301749// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301750func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301751 logger.Infow(ctx, "Add Migrating Services", log.Fields{"Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301752 var msrMap *util.ConcurrentMap
1753 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1754 msrMap = util.NewConcurrentMap()
1755 } else {
1756 msrMap = msrMapIntf.(*util.ConcurrentMap)
1757 }
1758
1759 msrMap.Set(msr.ID, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301760 logger.Debugw(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301761
1762 d.MigratingServices.Set(msr.OldVnetID, msrMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301763 logger.Debugw(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301764}
1765
vinokuma926cb3e2023-03-29 11:41:06 +05301766// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301767func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301768 logger.Debugw(ctx, "Get Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301769 if vd := va.GetDevice(deviceID); vd != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301770 logger.Debugw(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301771 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1772 msrList := msrListIntf.(*util.ConcurrentMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301773 logger.Debugw(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301774 if msrObj, ok := msrList.Get(requestID); ok {
1775 return msrObj.(*MigrateServicesRequest)
1776 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301777 }
1778 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301779 logger.Warnw(ctx, "Device Not Found", log.Fields{"DeviceID": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301780 return nil
1781}
1782
vinokuma926cb3e2023-03-29 11:41:06 +05301783// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301784func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301785 logger.Debugw(ctx, "Update Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301786 if vd := va.GetDevice(deviceID); vd != nil {
1787 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1788 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1789 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1790 }
1791 }
1792 }
1793}
1794
vinokuma926cb3e2023-03-29 11:41:06 +05301795// updateVnetProfile - Called on flow process completion
1796// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301797func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301798 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 +05301799
1800 nvs := VoltService{}
1801 nvs.VoltServiceCfg = vs.VoltServiceCfg
1802 nvs.Device = vs.Device
1803 nvs.Ipv4Addr = vs.Ipv4Addr
1804 nvs.Ipv6Addr = vs.Ipv6Addr
1805 nvs.UsMeterID = vs.UsMeterID
1806 nvs.DsMeterID = vs.DsMeterID
1807 nvs.AggDsMeterID = vs.AggDsMeterID
1808 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1809 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1810 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1811 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1812 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1813 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1814 nvs.PendingFlows = vs.PendingFlows
1815 nvs.AssociatedFlows = vs.AssociatedFlows
1816 nvs.DeleteInProgress = vs.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301817 nvs.DeactivateInProgress = vs.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301818 nvs.ForceDelete = vs.ForceDelete
1819 nvs.BwAvailInfo = vs.BwAvailInfo
1820 nvs.UpdateInProgress = vs.UpdateInProgress
1821
1822 if nvs.DeleteInProgress {
1823 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1824 return
1825 }
1826
1827 metadata := vs.Metadata.(*MigrateServiceMetadata)
1828 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301829 oldSrvName := vs.Name
1830
1831 if metadata == nil || metadata.NewVnetID == "" {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301832 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 +05301833 return
1834 }
1835
vinokuma926cb3e2023-03-29 11:41:06 +05301836 nvs.VnetID = metadata.NewVnetID
1837 id := metadata.RequestID
1838
1839 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301840 // Since if post del service in case of pod crash or reboot, the service data will be lost
1841 va := GetApplication()
1842 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1843 vnets := strings.Split(metadata.NewVnetID, "-")
1844 svlan, _ := strconv.Atoi(vnets[0])
1845 nvs.SVlan = of.VlanType(svlan)
1846 nvs.UpdateInProgress = false
1847 nvs.Metadata = nil
1848 nvs.Trigger = ServiceVlanUpdate
1849
1850 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1851 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1852 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1853
vinokuma926cb3e2023-03-29 11:41:06 +05301854 // TODO:Nav Pass a copy, not the pointer
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301855 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 +05301856 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301857 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1858 }
1859 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1860
1861 msr.ServicesList[oldSrvName] = true
1862 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301863 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301864
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301865 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 +05301866 va.DelService(cntx, oldSrvName, true, nil, true)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301867 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 +05301868 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301869}
1870
vinokuma926cb3e2023-03-29 11:41:06 +05301871// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301872// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301873func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301874 logger.Infow(ctx, "Service Migrated", log.Fields{"ServiceName": serviceName})
Naveen Sampath04696f72022-06-13 15:19:14 +05301875 msr.MigrateServicesLock.Lock()
1876 defer msr.MigrateServicesLock.Unlock()
1877
1878 delete(msr.ServicesList, serviceName)
1879
1880 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301881 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301882 return
1883 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301884 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301885 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301886}
1887
vinokuma926cb3e2023-03-29 11:41:06 +05301888// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301889func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1890 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301891}
1892
vinokuma926cb3e2023-03-29 11:41:06 +05301893// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301894func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301895 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 +05301896 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301897 for _, msr := range msrList {
1898 b, ok := msr.Value.([]byte)
1899 if !ok {
1900 logger.Warn(ctx, "The value type is not []byte")
1901 continue
1902 }
1903 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301904 msrAction(cntx, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301905 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 +05301906 }
1907}
1908
1909// createMigrateServicesFromString to create Service from string
1910func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301911 logger.Info(ctx, "Create Migrate Services From String")
Naveen Sampath04696f72022-06-13 15:19:14 +05301912 var msr MigrateServicesRequest
1913 if err := json.Unmarshal(b, &msr); err == nil {
1914 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301915 } else {
1916 logger.Warn(ctx, "Unmarshal failed")
1917 }
1918 return &msr
1919}
1920
vinokuma926cb3e2023-03-29 11:41:06 +05301921// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301922func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301923 logger.Infow(ctx, "Store And Process Migrate Srv Request", log.Fields{"MsrID": msr.DeviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301924 d := GetApplication().GetDevice(msr.DeviceID)
1925 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301926 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301927}
1928
vinokuma926cb3e2023-03-29 11:41:06 +05301929// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301930func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301931 logger.Infow(ctx, "Force udpate services with new vnet profile", log.Fields{"MsrID": msr.NewVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301932 for srv := range msr.ServicesList {
1933 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301934 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301935 }
1936 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301937 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301938}
1939
vinokuma926cb3e2023-03-29 11:41:06 +05301940// nolint: gocyclo
1941// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301942func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1943 if nvs.Name != evs.Name {
1944 return false
1945 }
1946 if nvs.UniVlan != evs.UniVlan {
1947 return false
1948 }
1949 if nvs.CVlan != evs.CVlan {
1950 return false
1951 }
1952 if nvs.SVlan != evs.SVlan {
1953 return false
1954 }
1955 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1956 return false
1957 }
1958 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1959 return false
1960 }
1961 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1962 return false
1963 }
1964 if nvs.TechProfileID != evs.TechProfileID {
1965 return false
1966 }
1967 if nvs.CircuitID != evs.CircuitID {
1968 return false
1969 }
1970 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1971 return false
1972 }
1973 if nvs.Port != evs.Port {
1974 return false
1975 }
1976 if nvs.PonPort != evs.PonPort {
1977 return false
1978 }
1979 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1980 return false
1981 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301982 if nvs.IsOption82Enabled != evs.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +05301983 return false
1984 }
1985 if nvs.IgmpEnabled != evs.IgmpEnabled {
1986 return false
1987 }
1988 if nvs.McastService != evs.McastService {
1989 return false
1990 }
1991 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1992 return false
1993 }
1994 if nvs.UsMeterProfile != evs.UsMeterProfile {
1995 return false
1996 }
1997 if nvs.DsMeterProfile != evs.DsMeterProfile {
1998 return false
1999 }
2000 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
2001 return false
2002 }
2003 if nvs.VnetID != evs.VnetID {
2004 return false
2005 }
2006 if nvs.MvlanProfileName != evs.MvlanProfileName {
2007 return false
2008 }
2009 if nvs.RemoteIDType != evs.RemoteIDType {
2010 return false
2011 }
2012 if nvs.SchedID != evs.SchedID {
2013 return false
2014 }
2015 if nvs.AllowTransparent != evs.AllowTransparent {
2016 return false
2017 }
2018 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
2019 return false
2020 }
2021 if nvs.DataRateAttr != evs.DataRateAttr {
2022 return false
2023 }
2024 if nvs.MinDataRateUs != evs.MinDataRateUs {
2025 return false
2026 }
2027 if nvs.MinDataRateDs != evs.MinDataRateDs {
2028 return false
2029 }
2030 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
2031 return false
2032 }
2033 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
2034 return false
2035 }
2036
2037 return true
2038}
2039
vinokuma926cb3e2023-03-29 11:41:06 +05302040// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302041func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05302042 // Clear the Flows flag if already set
2043 // This case happens only in case of some race condition
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302044 logger.Infow(ctx, "Trigger Associated Flow Delete", log.Fields{"Device": vs.Device, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05302045 if vs.UsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302046 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302047 logger.Warnw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302048 }
2049 }
2050
2051 if vs.DsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302052 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302053 logger.Warnw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302054 }
2055 }
2056
2057 vs.ServiceLock.Lock()
2058 cookieList := []uint64{}
2059 for cookie := range vs.AssociatedFlows {
2060 cookieList = append(cookieList, convertToUInt64(cookie))
2061 }
2062 vs.ServiceLock.Unlock()
2063
2064 if len(cookieList) == 0 {
2065 return false
2066 }
2067
vinokuma926cb3e2023-03-29 11:41:06 +05302068 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05302069 for _, cookie := range cookieList {
2070 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
2071 flow := &of.VoltFlow{}
2072 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2073 subFlow := of.NewVoltSubFlow()
2074 subFlow.Cookie = cookie
2075 flow.SubFlows[cookie] = subFlow
2076 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302077 if err := vs.DelFlows(cntx, vd, flow, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302078 logger.Warnw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302079 }
2080 }
2081 }
2082 return true
2083}
2084
vinokuma926cb3e2023-03-29 11:41:06 +05302085// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05302086func (vs *VoltService) triggerServiceInProgressInd() {
2087}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302088
vinokuma926cb3e2023-03-29 11:41:06 +05302089// JSONMarshal wrapper function for json Marshal VoltService
2090func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302091 return json.Marshal(VoltService{
2092 VoltServiceCfg: vs.VoltServiceCfg,
2093 VoltServiceOper: VoltServiceOper{
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302094 Device: vs.VoltServiceOper.Device,
2095 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
2096 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
2097 UsMeterID: vs.VoltServiceOper.UsMeterID,
2098 DsMeterID: vs.VoltServiceOper.DsMeterID,
2099 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
2100 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
2101 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
2102 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
2103 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
2104 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
2105 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
2106 PendingFlows: vs.VoltServiceOper.PendingFlows,
2107 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2108 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2109 DeactivateInProgress: vs.VoltServiceOper.DeactivateInProgress,
2110 ForceDelete: vs.VoltServiceOper.ForceDelete,
2111 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2112 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2113 Metadata: vs.VoltServiceOper.Metadata,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302114 },
2115 })
2116}
Tinoj Josephec742f62022-09-29 19:11:10 +05302117
2118// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302119func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302120 var svcList []*VoltService
2121 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2122 va.ServiceByName.Range(func(key, value interface{}) bool {
2123 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302124 if len(deviceID) > 0 {
2125 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302126 if deviceID == vs.Device && portNo == vs.Port {
2127 svcList = append(svcList, vs)
2128 }
2129 } else {
2130 if deviceID == vs.Device {
2131 svcList = append(svcList, vs)
2132 }
2133 }
2134 } else {
2135 svcList = append(svcList, vs)
2136 }
2137 return true
2138 })
2139 return svcList, nil
2140}
2141
Akash Soni634d9bf2023-07-10 12:11:10 +05302142type FlowProvisionStatus struct {
2143 FlowProvisionStatus string
2144}
2145
2146// GetFlowProvisionStatus to get status of the subscriber and flow provisioned in controller
Akash Soni3c391e72023-08-16 12:21:33 +05302147func (va *VoltApplication) GetFlowProvisionStatus(portNo string) FlowProvisionStatus {
Akash Soni634d9bf2023-07-10 12:11:10 +05302148 logger.Infow(ctx, "GetFlowProvisionStatus Request ", log.Fields{"Port": portNo})
2149 flowProvisionStatus := FlowProvisionStatus{}
Akash Soni3c391e72023-08-16 12:21:33 +05302150 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_NOT_IN_CONTROLLER
Akash Soni634d9bf2023-07-10 12:11:10 +05302151 va.ServiceByName.Range(func(key, value interface{}) bool {
2152 vs := value.(*VoltService)
2153 logger.Debugw(ctx, "Volt Service ", log.Fields{"VS": vs})
Akash Soni3c391e72023-08-16 12:21:33 +05302154 if portNo == vs.Port {
2155 if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() == 0 {
2156 flowProvisionStatus.FlowProvisionStatus = ALL_FLOWS_PROVISIONED
2157 return false
2158 } else if !vs.IsActivated {
2159 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_DISABLED_IN_CONTROLLER
2160 return false
2161 } else if !vs.DsHSIAFlowsApplied && !vs.UsHSIAFlowsApplied {
2162 flowProvisionStatus.FlowProvisionStatus = NO_FLOWS_PROVISIONED
2163 return false
Akash Soni230e6212023-10-16 10:46:07 +05302164 } else if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() > 0 {
Akash Soni3c391e72023-08-16 12:21:33 +05302165 flowProvisionStatus.FlowProvisionStatus = FLOWS_PROVISIONED_PARTIALLY
2166 return false
Akash Soni634d9bf2023-07-10 12:11:10 +05302167 }
2168 }
2169 return true
2170 })
Akash Soni634d9bf2023-07-10 12:11:10 +05302171 return flowProvisionStatus
2172}
2173
2174func (vs *VoltService) LenOfPendingFlows() int {
2175 vs.ServiceLock.RLock()
2176 lth := len(vs.PendingFlows)
2177 vs.ServiceLock.RUnlock()
2178 return lth
2179}
2180
Tinoj Josephec742f62022-09-29 19:11:10 +05302181// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302182func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302183 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 +05302184 device, err := va.GetDeviceFromPort(portNo)
2185 if err != nil {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302186 // Lets activate the service even though port was not found. We will push the flows once the port is added by voltha
2187 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 +05302188 }
2189 // If device id is not provided check only port number
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302190 if device != nil {
2191 if deviceID == DeviceAny {
2192 deviceID = device.Name
2193 } else if deviceID != device.Name {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302194 err := errorCodes.ErrDeviceNotFound
2195 return fmt.Errorf("wrong device id %s : %w", deviceID, err)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302196 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302197 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302198 va.ServiceByName.Range(func(key, value interface{}) bool {
2199 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302200 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302201 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302202 logger.Warnw(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302203 return true
2204 }
2205 if portNo == vs.Port && !vs.IsActivated {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302206 // 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 +05302207 logger.Debugw(ctx, "Service Activate", log.Fields{"Name": vs.Name})
Tinoj Josephec742f62022-09-29 19:11:10 +05302208 vs.IsActivated = true
2209 va.ServiceByName.Store(vs.Name, vs)
2210 vs.WriteToDb(cntx)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302211
2212 // Push the flows only if the port is already added and we have a valid device
2213 if device != nil {
2214 p := device.GetPort(vs.Port)
2215 if p == nil {
2216 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2217 return true
2218 }
2219 // If port is already up send indication to vpv
2220 if p.State == PortStateUp {
2221 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2222 // PortUp call initiates flow addition
2223 vpv.PortUpInd(cntx, device, portNo)
2224 } else {
2225 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2226 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302227 }
2228 }
2229 }
2230 return true
2231 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302232 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302233}
2234
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302235func (vs *VoltService) SetSvcDeactivationFlags(deactivateRsn SvcDeactivateReason) {
2236 vs.DeactivateInProgress = true
2237 vs.IsActivated = false
2238 vs.ServiceDeactivateReason = deactivateRsn
2239}
2240
Tinoj Josephec742f62022-09-29 19:11:10 +05302241// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302242func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302243 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 +05302244
Tinoj Josephec742f62022-09-29 19:11:10 +05302245 va.ServiceByName.Range(func(key, value interface{}) bool {
2246 vs := value.(*VoltService)
2247 // If svlan if provided, then the tags and tpID of service has to be matching
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302248 logger.Debugw(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302249 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302250 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 +05302251 return true
2252 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302253 if portNo == vs.Port && vs.IsActivated {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302254 vs.SetSvcDeactivationFlags(SvcDeacRsn_NB)
Tinoj Josephec742f62022-09-29 19:11:10 +05302255 va.ServiceByName.Store(vs.Name, vs)
2256 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302257 device, err := va.GetDeviceFromPort(portNo)
2258 if err != nil {
2259 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2260 // So no error is returned
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302261 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302262 return true
2263 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302264 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302265 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302266 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2267 // Port down call internally deletes all the flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302268 vpv.PortDownInd(cntx, deviceID, portNo, true, false)
Tinoj Josephec742f62022-09-29 19:11:10 +05302269 if vpv.IgmpEnabled {
2270 va.ReceiverDownInd(cntx, deviceID, portNo)
2271 }
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302272 vs.DeactivateInProgress = false
Tinoj Josephec742f62022-09-29 19:11:10 +05302273 } else {
2274 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2275 }
2276 }
2277 }
2278 return true
2279 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302280 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302281}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302282
vinokuma926cb3e2023-03-29 11:41:06 +05302283// GetServicePbit to get first set bit in the pbit map
2284// returns -1 : If configured to match on all pbits
2285// returns 8 : If no pbits are configured
2286// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302287func (vs *VoltService) GetServicePbit() int {
2288 if vs.IsPbitExist(of.PbitMatchAll) {
2289 return -1
2290 }
vinokuma926cb3e2023-03-29 11:41:06 +05302291 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302292 if vs.IsPbitExist(of.PbitType(pbit)) {
2293 return pbit
2294 }
2295 }
2296 return int(of.PbitMatchNone)
2297}