blob: 5f7178b662ead08df424008f273b9ef1b7cb81b4 [file] [log] [blame]
Joey Armstrongaca03cf2024-04-23 09:29:52 -04001/* -----------------------------------------------------------------------
2 * Copyright 2022-2024 Open Networking Foundation Contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 * -----------------------------------------------------------------------
16 * SPDX-FileCopyrightText: 2022-2024 Open Networking Foundation Contributors
17 * SPDX-License-Identifier: Apache-2.0
18 * -----------------------------------------------------------------------
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053019 */
Naveen Sampath04696f72022-06-13 15:19:14 +053020
21package application
22
23import (
24 "bytes"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053025 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053026 "encoding/json"
27 "errors"
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +053028 "fmt"
Naveen Sampath04696f72022-06-13 15:19:14 +053029 "net"
30 "reflect"
Naveen Sampath04696f72022-06-13 15:19:14 +053031 "sort"
32 "strconv"
33 "strings"
34 "sync"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053035 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053036
37 "github.com/google/gopacket/layers"
38
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053039 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053040 "voltha-go-controller/internal/pkg/controller"
41 cntlr "voltha-go-controller/internal/pkg/controller"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053042 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053043 "voltha-go-controller/internal/pkg/of"
44 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053045 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053046)
47
48const (
49 // DSLAttrEnabled constant
50 DSLAttrEnabled string = "ENABLED"
Tinoj Josephec742f62022-09-29 19:11:10 +053051 // DeviceAny constant
52 DeviceAny string = "DEVICE-ANY"
Akash Soni634d9bf2023-07-10 12:11:10 +053053
54 ALL_FLOWS_PROVISIONED string = "ALL_FLOWS_PROVISIONED"
55
56 NO_FLOWS_PROVISIONED string = "NO_FLOWS_PROVISIONED"
57
58 FLOWS_PROVISIONED_PARTIALLY string = "FLOWS_PROVISIONED_PARTIALLY"
59
60 SUBSCRIBER_DISABLED_IN_CONTROLLER string = "DISABLED_IN_CONTROLLER"
61
62 SUBSCRIBER_NOT_IN_CONTROLLER string = "NOT_IN_CONTROLLER"
63
64 ONT_FLOWS_PROVISION_STATE_UNUSED string = "ONT_FLOWS_PROVISION_STATE_UNUSED"
Naveen Sampath04696f72022-06-13 15:19:14 +053065)
66
67// VoltServiceCfg structure
68// Name - Uniquely identifies a service across the entire application
69// UniVlan - The VLAN of the packets entering the UNI of ONU
70// CVlan - The VLAN to transalate to/from on the PON link
71// SVlan - The outer VLAN to be used on the NNI of OLT.
vinokuma926cb3e2023-03-29 11:41:06 +053072// - In general, 4096 is used as NO VLAN for all the above
73// SVlanTpid - SVlan Tag Protocol Identifier
Naveen Sampath04696f72022-06-13 15:19:14 +053074// Pbits - Each bit of uint8 represents one p-bit. MSB is pbit 7
75// DhcpRelay - Whether it is turned on/off
76// CircuitId - The circuit id to be used with DHCP relay. Unused otherwise
77// RemoveId - Same as above
78// Port - The access port for the service. Each service has a single access
vinokuma926cb3e2023-03-29 11:41:06 +053079// port. The converse is not always true
Naveen Sampath04696f72022-06-13 15:19:14 +053080// MacLearning - If MAC learning is turned on, the MAC address learned from the
vinokuma926cb3e2023-03-29 11:41:06 +053081// the service activation is used in programming flows
Naveen Sampath04696f72022-06-13 15:19:14 +053082// MacAddress - The MAC hardware address learnt on the UNI interface
83// MacAddresses - Not yet implemented. To be used to learn more MAC addresses
84type VoltServiceCfg struct {
Naveen Sampath04696f72022-06-13 15:19:14 +053085 Pbits []of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +053086 Name string
Naveen Sampath04696f72022-06-13 15:19:14 +053087 CircuitID string
Naveen Sampath04696f72022-06-13 15:19:14 +053088 Port string
Naveen Sampath04696f72022-06-13 15:19:14 +053089 UsMeterProfile string
90 DsMeterProfile string
91 AggDsMeterProfile string
92 VnetID string
93 MvlanProfileName string
94 RemoteIDType string
Naveen Sampath04696f72022-06-13 15:19:14 +053095 DataRateAttr string
vinokuma926cb3e2023-03-29 11:41:06 +053096 ServiceType string
97 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
98 RemoteID []byte
99 MacAddr net.HardwareAddr
100 ONTEtherTypeClassification int
101 SchedID int
102 Trigger ServiceTrigger
103 MacLearning MacLearningType
104 PonPort uint32
Naveen Sampath04696f72022-06-13 15:19:14 +0530105 MinDataRateUs uint32
106 MinDataRateDs uint32
107 MaxDataRateUs uint32
108 MaxDataRateDs uint32
vinokuma926cb3e2023-03-29 11:41:06 +0530109 TechProfileID uint16
110 SVlanTpid layers.EthernetType
111 UniVlan of.VlanType
112 CVlan of.VlanType
113 SVlan of.VlanType
114 UsPonCTagPriority of.PbitType
115 UsPonSTagPriority of.PbitType
116 DsPonSTagPriority of.PbitType
117 DsPonCTagPriority of.PbitType
118 VlanControl VlanControl
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530119 IsOption82Enabled bool
vinokuma926cb3e2023-03-29 11:41:06 +0530120 IgmpEnabled bool
121 McastService bool
122 AllowTransparent bool
123 EnableMulticastKPI bool
Tinoj Josephec742f62022-09-29 19:11:10 +0530124 IsActivated bool
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530125 FlowPushCount map[string]uint32 // Tracks the number of flow install/delete failure attempts per cookie in order to throttle flow auditing
126 ServiceDeactivateReason SvcDeactivateReason // Mentions why the service was deactivated
Naveen Sampath04696f72022-06-13 15:19:14 +0530127}
128
129// VoltServiceOper structure
130type VoltServiceOper struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530131 Metadata interface{}
132 PendingFlows map[string]bool
133 AssociatedFlows map[string]bool
134 BwAvailInfo string
Naveen Sampath04696f72022-06-13 15:19:14 +0530135 //MacLearning bool
136 //MacAddr net.HardwareAddr
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530137 Device string
138 Ipv4Addr net.IP
139 Ipv6Addr net.IP
140 ServiceLock sync.RWMutex `json:"-"`
141 UsMeterID uint32
142 DsMeterID uint32
143 AggDsMeterID uint32
144 UpdateInProgress bool
145 DeleteInProgress bool
146 DeactivateInProgress bool
147 ForceDelete bool
vinokuma926cb3e2023-03-29 11:41:06 +0530148 // Multiservice-Fix
Naveen Sampath04696f72022-06-13 15:19:14 +0530149 UsHSIAFlowsApplied bool
150 DsHSIAFlowsApplied bool
151 UsDhcpFlowsApplied bool
152 DsDhcpFlowsApplied bool
153 IgmpFlowsApplied bool
154 Icmpv6FlowsApplied bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530155}
156
157// VoltService structure
158type VoltService struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530159 VoltServiceOper
160 Version string
vinokuma926cb3e2023-03-29 11:41:06 +0530161 VoltServiceCfg
Naveen Sampath04696f72022-06-13 15:19:14 +0530162}
163
vinokuma926cb3e2023-03-29 11:41:06 +0530164// ServiceTrigger - Service activation trigger
Naveen Sampath04696f72022-06-13 15:19:14 +0530165type ServiceTrigger int
166
167const (
vinokuma926cb3e2023-03-29 11:41:06 +0530168 // NBActivate - Service added due to NB Action
Naveen Sampath04696f72022-06-13 15:19:14 +0530169 NBActivate ServiceTrigger = 0
vinokuma926cb3e2023-03-29 11:41:06 +0530170 // ServiceVlanUpdate - Service added due to Svlan Update
Naveen Sampath04696f72022-06-13 15:19:14 +0530171 ServiceVlanUpdate ServiceTrigger = 1
172)
173
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530174// SvcDeactivateReason - Reason for service deactivation
175type SvcDeactivateReason uint8
176
177const (
178 // Service deactivated reason - none
179 SvcDeacRsn_None SvcDeactivateReason = 0
180 // Service deactivate reason - NB
181 SvcDeacRsn_NB SvcDeactivateReason = 1
182 // Service deactivate reason - Controller
183 SvcDeacRsn_Controller SvcDeactivateReason = 2
184)
185
Naveen Sampath04696f72022-06-13 15:19:14 +0530186// AppMutexes structure
187type AppMutexes struct {
188 ServiceDataMutex sync.Mutex `json:"-"`
189 VnetMutex sync.Mutex `json:"-"`
190}
191
vinokuma926cb3e2023-03-29 11:41:06 +0530192// MigrateServiceMetadata - migrate services request metadata
Naveen Sampath04696f72022-06-13 15:19:14 +0530193type MigrateServiceMetadata struct {
194 NewVnetID string
195 RequestID string
196}
197
198// AppMutex variable
199var AppMutex AppMutexes
200
201// NewVoltService for constructor for volt service
202func NewVoltService(cfg *VoltServiceCfg) *VoltService {
203 var vs VoltService
204 vs.VoltServiceCfg = *cfg
205 vs.UsHSIAFlowsApplied = false
206 vs.DsHSIAFlowsApplied = false
207 vs.DeleteInProgress = false
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530208 vs.DeactivateInProgress = false
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530209 vs.ServiceDeactivateReason = SvcDeacRsn_None
Naveen Sampath04696f72022-06-13 15:19:14 +0530210 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530211
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530212 vs.IsOption82Enabled = cfg.IsOption82Enabled
Naveen Sampath04696f72022-06-13 15:19:14 +0530213 vs.MacAddr = cfg.MacAddr
214 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
215 vs.Ipv6Addr = net.ParseIP("::")
216 vs.PendingFlows = make(map[string]bool)
217 vs.AssociatedFlows = make(map[string]bool)
Sridhar Ravindra3ec14232024-01-01 19:11:48 +0530218 vs.FlowPushCount = make(map[string]uint32)
Naveen Sampath04696f72022-06-13 15:19:14 +0530219 return &vs
220}
221
222// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530223func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530224 vs.ServiceLock.RLock()
225 defer vs.ServiceLock.RUnlock()
226
227 if vs.DeleteInProgress {
228 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
229 return
230 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530231 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530232}
233
vinokuma926cb3e2023-03-29 11:41:06 +0530234// ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530235func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530236 b, err := json.Marshal(vs)
237
238 if err != nil {
239 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
240 return
241 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530242 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530243 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
244 }
245}
246
247// isDataRateAttrPresent to check if data attribute is present
248func (vs *VoltService) isDataRateAttrPresent() bool {
249 return vs.DataRateAttr == DSLAttrEnabled
250}
251
252// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530253func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530254 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
vinokuma926cb3e2023-03-29 11:41:06 +0530255 // TODO - Need to understand and delete the second call
256 // Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530257 _ = db.DelService(cntx, vs.Name)
258 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530259}
260
261// MatchesVlans find the service that matches the VLANs. In this case it is
262// purely based on CVLAN. The CVLAN can sufficiently be used to
263// match a service
264func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
265 if len(vlans) != 1 {
266 return false
267 }
268
269 if vlans[0] == vs.CVlan {
270 return true
271 }
272 return false
273}
274
275// MatchesPbits allows matching a service to a pbit. This is used
276// to search for a service matching the pbits, typically to identify
277// attributes for other flows such as DHCP, IGMP, etc.
278func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
279 for _, pbit := range pbits {
280 for _, pb := range vs.Pbits {
281 if pb == pbit {
282 return true
283 }
284 }
285 }
286 return false
287}
288
289// IsPbitExist allows matching a service to a pbit. This is used
290// to search for a service matching the pbit
291func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530292 logger.Debugw(ctx, "Request for IsPbitExist", log.Fields{"pbit": pbit})
Naveen Sampath04696f72022-06-13 15:19:14 +0530293 for _, pb := range vs.Pbits {
294 if pb == pbit {
295 return true
296 }
297 }
298 return false
299}
300
301// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530302func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530303 logger.Debugw(ctx, "Add US & DS HSIA Flows for the service", log.Fields{"ServiceName": vs.Name})
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530304 if err := vs.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530305 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
306 vs.triggerServiceFailureInd(statusCode, statusMessage)
307 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530308 if err := vs.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530309 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
310 vs.triggerServiceFailureInd(statusCode, statusMessage)
311 }
312}
313
vinokuma926cb3e2023-03-29 11:41:06 +0530314// DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530315func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530316 logger.Debugw(ctx, "Delete US & DS HSIA Flows for the service", log.Fields{"ServiceName": vs.Name})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530317 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530318 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
319 vs.triggerServiceFailureInd(statusCode, statusMessage)
320 }
321
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530322 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530323 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
324 vs.triggerServiceFailureInd(statusCode, statusMessage)
325 }
326}
327
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530328func (vs *VoltService) AddMeterToDevice(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530329 logger.Debugw(ctx, "Add Meter To Device for the service", log.Fields{"ServiceName": vs.Name})
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530330 if vs.DeleteInProgress || vs.UpdateInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530331 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 +0530332 }
333 va := GetApplication()
334 logger.Infow(ctx, "Configuring Meters for FTTB", log.Fields{"ServiceName": vs.Name})
335 device, err := va.GetDeviceFromPort(vs.Port)
336 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530337 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 +0530338 } else if device.State != controller.DeviceStateUP {
339 logger.Warnw(ctx, "Device state Down. Ignoring Meter Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
340 return nil
341 }
342 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
343 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
344 return nil
345}
346
Naveen Sampath04696f72022-06-13 15:19:14 +0530347// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530348func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530349 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530350 if vs.DeleteInProgress || vs.UpdateInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530351 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 +0530352 return nil
353 }
354
355 va := GetApplication()
Naveen Sampath04696f72022-06-13 15:19:14 +0530356 if !vs.UsHSIAFlowsApplied || vgcRebooted {
357 device, err := va.GetDeviceFromPort(vs.Port)
358 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530359 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 +0530360 } else if device.State != controller.DeviceStateUP {
361 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
362 return nil
363 }
364
365 vs.Device = device.Name
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530366 /* In case of DPU_MGMT_TRAFFIC the meters will be configured before US flow creation*/
vinokuma926cb3e2023-03-29 11:41:06 +0530367 if vs.ServiceType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530368 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
369 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
370 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530371 pBits := vs.Pbits
372
vinokuma926cb3e2023-03-29 11:41:06 +0530373 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530374 if len(vs.Pbits) == 0 {
375 pBits = append(pBits, PbitMatchNone)
376 }
377 for _, pbits := range pBits {
378 usflows, err := vs.BuildUsHsiaFlows(pbits)
379 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530380 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 +0530381 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
382 vs.triggerServiceFailureInd(statusCode, statusMessage)
383 continue
384 }
385 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530386 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530387 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 +0530388 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
389 vs.triggerServiceFailureInd(statusCode, statusMessage)
390 }
391 }
392 vs.UsHSIAFlowsApplied = true
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530393 logger.Debugw(ctx, "Pushed US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530394 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530395 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530396 return nil
397}
398
399// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530400func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530401 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530402 if vs.DeleteInProgress {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530403 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 +0530404 return nil
405 }
406
407 va := GetApplication()
Naveen Sampath04696f72022-06-13 15:19:14 +0530408 if !vs.DsHSIAFlowsApplied || vgcRebooted {
409 device, err := va.GetDeviceFromPort(vs.Port)
410 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530411 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 +0530412 } else if device.State != controller.DeviceStateUP {
413 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
414 return nil
415 }
416
417 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
Naveen Sampath04696f72022-06-13 15:19:14 +0530418
419 //If no pbits configured for service, hence add PbitNone for flows
420 if len(vs.DsRemarkPbitsMap) == 0 {
421 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
422 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530423 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 +0530424 }
425 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530426 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530427 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 +0530428 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
429 vs.triggerServiceFailureInd(statusCode, statusMessage)
430 }
431 } else {
432 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
433 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
434 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
435 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530436 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 +0530437 }
438 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
439 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530440 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530441 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 +0530442 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
443 vs.triggerServiceFailureInd(statusCode, statusMessage)
444 }
445 } else {
446 for matchPbit := range vs.DsRemarkPbitsMap {
447 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
448 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530449 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 +0530450 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
451 vs.triggerServiceFailureInd(statusCode, statusMessage)
452 continue
453 }
454 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530455 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530456 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 +0530457 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
458 vs.triggerServiceFailureInd(statusCode, statusMessage)
459 }
460 }
461 }
462 }
463 vs.DsHSIAFlowsApplied = true
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530464 logger.Debugw(ctx, "Pushed DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530465 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530466 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530467 return nil
468}
469
470// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530471func (vs *VoltService) DelUsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530472 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530473 if vs.UsHSIAFlowsApplied || vgcRebooted {
474 device, err := GetApplication().GetDeviceFromPort(vs.Port)
475 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530476 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 +0530477 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530478 pBits := vs.Pbits
479
vinokuma926cb3e2023-03-29 11:41:06 +0530480 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530481 if len(vs.Pbits) == 0 {
482 pBits = append(pBits, PbitMatchNone)
483 }
484 for _, pbits := range pBits {
485 usflows, err := vs.BuildUsHsiaFlows(pbits)
486 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530487 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 +0530488 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
489 vs.triggerServiceFailureInd(statusCode, statusMessage)
490 continue
491 }
492 usflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530493 if err = vs.DelFlows(cntx, device, usflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530494 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 +0530495 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
496 vs.triggerServiceFailureInd(statusCode, statusMessage)
497 }
498 }
499 vs.UsHSIAFlowsApplied = false
500 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530501 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530502 return nil
503}
504
505// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530506func (vs *VoltService) DelDsHsiaFlows(cntx context.Context, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530507 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530508 if vs.DsHSIAFlowsApplied || vgcRebooted {
509 device, err := GetApplication().GetDeviceFromPort(vs.Port)
510 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530511 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 +0530512 }
513
Naveen Sampath04696f72022-06-13 15:19:14 +0530514 var matchPbit int
vinokuma926cb3e2023-03-29 11:41:06 +0530515 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530516 if len(vs.DsRemarkPbitsMap) == 0 {
517 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
518 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530519 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 +0530520 }
521 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530522 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530523 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 +0530524 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
525 vs.triggerServiceFailureInd(statusCode, statusMessage)
526 }
527 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
528 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
529 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530530 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 +0530531 }
532 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530533 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530534 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 +0530535 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
536 vs.triggerServiceFailureInd(statusCode, statusMessage)
537 }
538 } else {
539 for matchPbit = range vs.DsRemarkPbitsMap {
540 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
541 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530542 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 +0530543 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
544 vs.triggerServiceFailureInd(statusCode, statusMessage)
545 continue
546 }
547 dsflows.MigrateCookie = vgcRebooted
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +0530548 if err = vs.DelFlows(cntx, device, dsflows, delFlowsInDevice); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530549 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 +0530550 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
551 vs.triggerServiceFailureInd(statusCode, statusMessage)
552 }
553 }
554 }
555 vs.DsHSIAFlowsApplied = false
556 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530557 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 +0530558 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530559 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530560 return nil
561}
562
563// BuildDsHsiaFlows build the DS HSIA flows
564// Called for add/delete HSIA flows
565func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530566 logger.Debugw(ctx, "Building DS HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530567 flow := &of.VoltFlow{}
568 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
569
570 // Get the out and in ports for the flows
571 device, err := GetApplication().GetDeviceFromPort(vs.Port)
572 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530573 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 +0530574 }
575 inport, _ := GetApplication().GetPortID(device.NniPort)
576 outport, _ := GetApplication().GetPortID(vs.Port)
577 // PortName and PortID to be used for validation of port before flow pushing
578 flow.PortID = outport
579 flow.PortName = vs.Port
580 allowTransparent := 0
581 if vs.AllowTransparent {
582 allowTransparent = 1
583 }
584
585 // initialized actnPbit to 0 for cookie genration backward compatibility.
586 var actnPbit of.PbitType
587 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
588
589 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530590 // | 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 +0530591 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
592 cookie = cookie | of.DsFlowMask
593 cookie = cookie + (valToShift << 4) + uint64(pbits)
594 return cookie
595 }
596
597 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
598 if err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530599 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 +0530600 }
601
602 // Add Table-0 flow that deals with the outer VLAN in pOLT
603 {
604 subflow1 := of.NewVoltSubFlow()
605 subflow1.SetTableID(0)
606 subflow1.SetGoToTable(1)
607 subflow1.SetInPort(inport)
608
609 if pbits != PbitMatchNone {
610 subflow1.SetMatchPbit(pbits)
611 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530612 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
613 subflow1.SetPcp(of.PbitType(remarkPbit))
614 // match & action pbits are different, set remark-pbit action
615 actnPbit = of.PbitType(remarkPbit)
616 // mask remark p-bit to 4bits
617 actnPbit = actnPbit & 0x0F
618 }
619
620 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
621 return nil, err
622 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530623 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530624 if NonZeroMacAddress(vs.MacAddr) {
625 subflow1.SetMatchDstMac(vs.MacAddr)
626 }
627 subflow1.Priority = of.HsiaFlowPriority
628 subflow1.SetMeterID(vs.DsMeterID)
629
630 /* WriteMetaData 8 Byte(uint64) usage:
631 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
632 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
633 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530634 if vs.ServiceType == FttbSubscriberTraffic {
635 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
636 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530637 subflow1.SetWriteMetadata(metadata)
638
639 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
640 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
641 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
642 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
643
644 //TODO-COMM:
645 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
646 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
647 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
648 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
649
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530650 if vs.ServiceType != FttbSubscriberTraffic {
651 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
652 subflow1.SetTableMetadata(metadata)
653 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530654 // TODO - We are using cookie as key and must come up with better cookie
655 // allocation algorithm
656 /**
657 * Cokies may clash when -
658 * on same uni-port we have two sub-service
659 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
660 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
661 * However, this p-bit re-use will not be allowed by sub-mgr.
662 */
663 if vs.VlanControl == OLTCVlanOLTSVlan {
664 /**
665 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
666 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
667 * use old cookie.
668 */
669 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
670 if vgcRebooted {
671 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
672 }
673 } else {
674 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
675 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
676 }
677
678 flow.SubFlows[subflow1.Cookie] = subflow1
679 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
680 "subflow": subflow1})
681 }
682
vinokuma926cb3e2023-03-29 11:41:06 +0530683 // Add Table-1 flow that deals with inner VLAN at the ONU
Naveen Sampath04696f72022-06-13 15:19:14 +0530684 {
685 subflow2 := of.NewVoltSubFlow()
686 subflow2.SetTableID(1)
687 subflow2.SetInPort(inport)
688 if NonZeroMacAddress(vs.MacAddr) {
689 subflow2.SetMatchDstMac(vs.MacAddr)
690 }
691
692 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
693 return nil, err
694 }
695 if pbits != PbitMatchNone {
696 subflow2.SetMatchPbit(pbits)
697 }
698
699 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
700 subflow2.SetPcp(of.PbitType(remarkPbit))
701 }
702
703 subflow2.SetOutPort(outport)
704 subflow2.SetMeterID(vs.DsMeterID)
705
706 // refer Table-0 flow generation for byte information
707 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530708 if vs.ServiceType == FttbSubscriberTraffic {
709 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
710 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530711 subflow2.SetWriteMetadata(metadata)
712
713 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
714 if util.IsNniPort(inport) {
715 metadata = uint64(outport)
716 } else {
717 // refer Table-0 flow generation for byte information
718 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
719 }
720 subflow2.SetTableMetadata(metadata)
721 // Setting of Cookie - TODO - Improve the allocation algorithm
722 if vs.VlanControl == OLTCVlanOLTSVlan {
723 /**
724 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
725 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
726 * use old cookie.
727 */
728 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
729 if vgcRebooted {
730 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
731 }
732 } else {
733 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
734 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
735 }
736
737 subflow2.Priority = of.HsiaFlowPriority
738 flow.SubFlows[subflow2.Cookie] = subflow2
739 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
740 "subflow": subflow2})
741 }
742
743 return flow, nil
744}
745
746// BuildUsHsiaFlows build the US HSIA flows
747// Called for add/delete HSIA flows
748func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530749 logger.Debugw(ctx, "Building US HSIA Service Flows", log.Fields{"Device": vs.Device, "ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530750 flow := &of.VoltFlow{}
751 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
752
753 // Get the out and in ports for the flows
754 device, err := GetApplication().GetDeviceFromPort(vs.Port)
755 if err != nil {
756 return nil, errorCodes.ErrDeviceNotFound
757 }
758 outport, _ := GetApplication().GetPortID(device.NniPort)
759 inport, _ := GetApplication().GetPortID(vs.Port)
760 // PortName and PortID to be used for validation of port before flow pushing
761 flow.PortID = inport
762 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530763
764 // Add Table-0 flow that deals with the inner VLAN in ONU
765 {
766 subflow1 := of.NewVoltSubFlow()
767 subflow1.SetTableID(0)
768 subflow1.SetGoToTable(1)
769 subflow1.SetInPort(inport)
770
vinokuma926cb3e2023-03-29 11:41:06 +0530771 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530772 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
773 subflow1.SetPcp(vs.UsPonSTagPriority)
vinokuma926cb3e2023-03-29 11:41:06 +0530774 } else if vs.ServiceType == DpuAncpTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530775 subflow1.SetPcp(vs.UsPonSTagPriority)
776 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530777 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
778 return nil, err
779 }
780 subflow1.SetMeterID(vs.UsMeterID)
781
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530782 /* WriteMetaData 8 Byte(uint64) usage:
783 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
784 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
785 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
786 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530787 if vs.ServiceType == FttbSubscriberTraffic {
788 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
789 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530790 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530791
Naveen Sampath04696f72022-06-13 15:19:14 +0530792 if vs.VlanControl == OLTCVlanOLTSVlan {
793 /**
794 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
795 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
796 * use old cookie.
797 */
798 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
799 if vgcRebooted {
800 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
801 }
802 } else {
803 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
804 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
805 }
806 subflow1.Priority = of.HsiaFlowPriority
807 flow.SubFlows[subflow1.Cookie] = subflow1
808 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
809 }
810
vinokuma926cb3e2023-03-29 11:41:06 +0530811 // Add Table-1 flow that deals with the outer vlan in pOLT
Naveen Sampath04696f72022-06-13 15:19:14 +0530812 {
813 subflow2 := of.NewVoltSubFlow()
814 subflow2.SetTableID(1)
815 subflow2.SetInPort(inport)
816
Naveen Sampath04696f72022-06-13 15:19:14 +0530817 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
818 return nil, err
819 }
vinokuma926cb3e2023-03-29 11:41:06 +0530820 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530821 subflow2.SetMatchSrcMac(vs.MacAddr)
822 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530823 subflow2.SetInPort(inport)
824 subflow2.SetOutPort(outport)
825 subflow2.SetMeterID(vs.UsMeterID)
826
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530827 // refer Table-0 flow generation for byte information
828 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530829 if vs.ServiceType == FttbSubscriberTraffic {
830 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
831 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530832 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530833
Naveen Sampath04696f72022-06-13 15:19:14 +0530834 if vs.VlanControl == OLTCVlanOLTSVlan {
835 /**
836 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
837 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
838 * use old cookie.
839 */
840 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
841 if vgcRebooted {
842 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
843 }
844 } else {
845 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
846 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
847 }
848 subflow2.Priority = of.HsiaFlowPriority
849
850 flow.SubFlows[subflow2.Cookie] = subflow2
851 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
852 }
853
854 return flow, nil
855}
856
857func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530858 // | 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 +0530859 logger.Debugw(ctx, "Generate US Cookie", log.Fields{"Vlan": vlan, "ValToShift": vlan, "Inport": inport, "Pbits": pbits})
Naveen Sampath04696f72022-06-13 15:19:14 +0530860 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
861 cookie = cookie | of.UsFlowMask
862 cookie = cookie + (valToShift << 4) + uint64(pbits)
863 return cookie
864}
865
866// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
867// based on different Vlan Controls
868func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530869 logger.Debugw(ctx, "Set US Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530870 switch vs.VlanControl {
871 case None:
872 flow.SetMatchVlan(vs.SVlan)
873 case ONUCVlanOLTSVlan:
874 flow.SetMatchVlan(vs.CVlan)
875 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
876 case OLTCVlanOLTSVlan:
877 flow.SetMatchVlan(vs.UniVlan)
878 flow.SetSetVlan(vs.CVlan)
879 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
880 case ONUCVlan:
881 flow.SetMatchVlan(vs.SVlan)
882 case OLTSVlan:
883 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
884 flow.SetMatchVlan(vs.UniVlan)
885 flow.SetSetVlan(vs.SVlan)
886 } else if vs.UniVlan != of.VlanNone {
887 flow.SetMatchVlan(vs.UniVlan)
888 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
889 } else {
890 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
891 }
892 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530893 err := errorCodes.ErrInvalidParamInRequest
894 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530895 }
896 return nil
897}
898
899// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
900// based on different Vlan Controls
901func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530902 logger.Debugw(ctx, "Set DS Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530903 switch vs.VlanControl {
904 case None:
905 flow.SetMatchVlan(vs.SVlan)
906 case ONUCVlanOLTSVlan:
907 flow.SetMatchVlan(vs.SVlan)
908 flow.SetPopVlan()
909 case OLTCVlanOLTSVlan:
910 flow.SetMatchVlan(vs.SVlan)
911 flow.SetPopVlan()
912 flow.SetSetVlan(vs.UniVlan)
913 case ONUCVlan:
914 flow.SetMatchVlan(vs.SVlan)
915 case OLTSVlan:
916 flow.SetMatchVlan(vs.SVlan)
917 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
918 flow.SetSetVlan(vs.UniVlan)
919 } else {
920 flow.SetPopVlan()
921 }
922 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530923 err := errorCodes.ErrInvalidParamInRequest
924 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530925 }
926 return nil
927}
928
929// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
930// based on different Vlan Controls
931func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530932 logger.Debugw(ctx, "Set US Match Action Vlan T0", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530933 switch vs.VlanControl {
934 case None:
935 flow.SetMatchVlan(vs.SVlan)
936 case ONUCVlanOLTSVlan:
937 if vs.UniVlan != of.VlanNone {
938 flow.SetMatchVlan(vs.UniVlan)
939 flow.SetSetVlan(vs.CVlan)
940 } else {
941 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
942 }
943 case OLTCVlanOLTSVlan:
944 flow.SetMatchVlan(vs.UniVlan)
945 case ONUCVlan:
946 if vs.UniVlan != of.VlanNone {
947 flow.SetMatchVlan(vs.UniVlan)
948 flow.SetSetVlan(vs.SVlan)
949 } else {
950 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
951 }
952 case OLTSVlan:
953 flow.SetMatchVlan(vs.UniVlan)
954 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530955 err := errorCodes.ErrInvalidParamInRequest
956 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530957 }
958 return nil
959}
960
961// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
962// based on different Vlan Controls
963func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530964 logger.Debugw(ctx, "Set DS Match Action Vlan T1", log.Fields{"Value": vs.VlanControl})
Naveen Sampath04696f72022-06-13 15:19:14 +0530965 switch vs.VlanControl {
966 case None:
967 flow.SetMatchVlan(vs.SVlan)
968 case ONUCVlanOLTSVlan:
969 flow.SetMatchVlan(vs.CVlan)
970 if vs.UniVlan != of.VlanNone {
971 flow.SetSetVlan(vs.UniVlan)
972 } else {
973 flow.SetPopVlan()
974 }
975 case OLTCVlanOLTSVlan:
976 flow.SetMatchVlan(vs.UniVlan)
977 case ONUCVlan:
978 flow.SetMatchVlan(vs.SVlan)
979 if vs.UniVlan != of.VlanNone {
980 flow.SetSetVlan(vs.UniVlan)
981 } else {
982 flow.SetPopVlan()
983 }
984 case OLTSVlan:
985 flow.SetMatchVlan(vs.UniVlan)
986 default:
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +0530987 err := errorCodes.ErrInvalidParamInRequest
988 return fmt.Errorf("Invalid Vlan Control Option %d : %w", vs.VlanControl, err)
Naveen Sampath04696f72022-06-13 15:19:14 +0530989 }
990 return nil
991}
992
993// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530994func (vs *VoltService) SvcUpInd(cntx context.Context) {
995 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530996}
997
998// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530999func (vs *VoltService) SvcDownInd(cntx context.Context) {
1000 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301001}
1002
1003// SetIpv4Addr to set ipv4 address
1004func (vs *VoltService) SetIpv4Addr(addr net.IP) {
1005 vs.Ipv4Addr = addr
1006}
1007
1008// SetIpv6Addr to set ipv6 address
1009func (vs *VoltService) SetIpv6Addr(addr net.IP) {
1010 vs.Ipv6Addr = addr
1011}
1012
1013// SetMacAddr to set mac address
1014func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
1015 vs.MacAddr = addr
1016}
1017
1018// ----------------------------------------------
1019// VOLT Application - Related to services
1020// ---------------------------------------------
1021// ---------------------------------------------------------------
1022// Service CRUD functions. These are exposed to the overall binary
1023// to be invoked from the point where the CRUD operations are received
1024// from the external entities
1025
1026// AddService : A service in the context of VOLT is a subscriber or service of a
1027// subscriber which is uniquely identified by a combination of MAC
1028// address, VLAN tags, 802.1p bits. However, in the context of the
1029// current implementation, a service is an entity that is identified by a
1030// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
1031// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301032func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301033 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
Naveen Sampath04696f72022-06-13 15:19:14 +05301034 var mmUs, mmDs *VoltMeter
1035 var err error
1036
vinokuma926cb3e2023-03-29 11:41:06 +05301037 // Take the Device lock only in case of NB add request.
Naveen Sampath04696f72022-06-13 15:19:14 +05301038 // Allow internal adds since internal add happen only under
1039 // 1. Restore Service from DB
1040 // 2. Service Migration
1041 if oper == nil {
1042 if svc := va.GetService(cfg.Name); svc != nil {
1043 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301044 return errors.New("service already exists")
Naveen Sampath04696f72022-06-13 15:19:14 +05301045 }
1046 }
1047
Naveen Sampath04696f72022-06-13 15:19:14 +05301048 // Service doesn't exist. So create it and add to the port
1049 vs := NewVoltService(&cfg)
1050 if oper != nil {
1051 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1052 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1053 vs.Ipv4Addr = oper.Ipv4Addr
1054 vs.Ipv6Addr = oper.Ipv6Addr
1055 vs.MacLearning = cfg.MacLearning
1056 vs.PendingFlows = oper.PendingFlows
1057 vs.AssociatedFlows = oper.AssociatedFlows
1058 vs.DeleteInProgress = oper.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301059 vs.DeactivateInProgress = oper.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301060 vs.BwAvailInfo = oper.BwAvailInfo
1061 vs.Device = oper.Device
Sridhar Ravindra45589a72024-01-04 17:57:35 +05301062 // FlowPushCount is newly introduced map and it can be nil when VGC is upgraded. Hence adding a nil check to handle backward compatibility
1063 if cfg.FlowPushCount != nil {
1064 vs.FlowPushCount = cfg.FlowPushCount
1065 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301066 vs.ServiceDeactivateReason = cfg.ServiceDeactivateReason
Naveen Sampath04696f72022-06-13 15:19:14 +05301067 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301068 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301069 sort.Slice(vs.Pbits, func(i, j int) bool {
1070 return vs.Pbits[i] > vs.Pbits[j]
1071 })
1072 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1073 }
1074 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1075
1076 // The bandwidth and shaper profile combined into meter
1077 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1078 vs.DsMeterID = mmDs.ID
1079 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301080 return errors.New("downStream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301081 }
1082
1083 // The aggregated downstream meter profile
1084 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1085 // vs.AggDsMeterID = mmAg.ID
1086 // } else {
1087 // return errors.New("Aggregated meter profile not found")
1088 // }
1089
1090 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1091 // vs.UsMeterID = mmAg.ID
1092 // } else {
1093 // The bandwidth and shaper profile combined into meter
1094 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1095 vs.UsMeterID = mmUs.ID
1096 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301097 return errors.New("upstream meter profile not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301098 }
1099 //}
1100
1101 AppMutex.ServiceDataMutex.Lock()
1102 defer AppMutex.ServiceDataMutex.Unlock()
1103
1104 // Add the service to the VNET
1105 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1106 if vnet != nil {
1107 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1108 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301109 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301110 vpv.VpvLock.Unlock()
1111 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301112 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301113 }
1114 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301115 logger.Warnw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
1116 return errors.New("vnet doesn't exist")
Naveen Sampath04696f72022-06-13 15:19:14 +05301117 }
1118
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301119 // If the device is already discovered, update the device name in service
1120 d, err := va.GetDeviceFromPort(vs.Port)
1121 if err == nil {
1122 vs.Device = d.Name
1123 }
1124
Naveen Sampath04696f72022-06-13 15:19:14 +05301125 vs.Version = database.PresentVersionMap[database.ServicePath]
1126 // Add the service to the volt application
1127 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301128 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301129
1130 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301131 if !vs.UsHSIAFlowsApplied {
1132 vs.triggerServiceInProgressInd()
1133 }
1134
vinokuma926cb3e2023-03-29 11:41:06 +05301135 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301136 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301137 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301138 if mmUs != nil {
1139 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301140 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301141 }
1142 //mmAg.AssociatedServices++
1143 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301144 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301145 }
1146
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301147 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 +05301148 return nil
1149}
1150
vinokuma926cb3e2023-03-29 11:41:06 +05301151// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301152// Added for DT/TT usecase with sadis replica interface
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301153func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301154 logger.Infow(ctx, "Delete Service With provided Prefix", log.Fields{"Prefix": prefix})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301155 var isServiceExist bool
Naveen Sampath04696f72022-06-13 15:19:14 +05301156 va.ServiceByName.Range(func(key, value interface{}) bool {
1157 srvName := key.(string)
1158 vs := value.(*VoltService)
1159 if strings.Contains(srvName, prefix) {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301160 isServiceExist = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301161 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301162
1163 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1164 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1165 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1166
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301167 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301168 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1169 }
1170 }
1171 return true
1172 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301173
1174 if !isServiceExist {
1175 return errorCodes.ErrServiceNotFound
1176 }
1177 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301178}
1179
1180// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301181func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301182 AppMutex.ServiceDataMutex.Lock()
1183 defer AppMutex.ServiceDataMutex.Unlock()
1184
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301185 logger.Infow(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
Naveen Sampath04696f72022-06-13 15:19:14 +05301186 var noFlowsPresent bool
1187
1188 vsIntf, ok := va.ServiceByName.Load(name)
1189 if !ok {
1190 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1191 return
1192 }
1193 vs := vsIntf.(*VoltService)
1194 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1195 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301196 logger.Warnw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301197 return
1198 }
1199
vinokuma926cb3e2023-03-29 11:41:06 +05301200 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301201 vs.DeleteInProgress = true
1202 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301203 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301204
1205 if len(vs.AssociatedFlows) == 0 {
1206 noFlowsPresent = true
1207 }
1208 vpv.VpvLock.Lock()
1209 defer vpv.VpvLock.Unlock()
1210
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301211 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301212
1213 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301214 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301215 }
1216 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 +05301217 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301218 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301219 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301220 }
1221
1222 // Delete the service immediately in case of Force Delete
1223 // This will be enabled when profile reconciliation happens after restore
1224 // of backedup data
1225 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301226 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301227 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301228 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301229 }
1230
Naveen Sampath04696f72022-06-13 15:19:14 +05301231 if nil != newSvc {
1232 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1233 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1234 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301235
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301236 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1237
1238 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1239 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301240 if aggMeter.AssociatedServices > 0 {
1241 aggMeter.AssociatedServices--
1242 logger.Infow(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
1243 va.UpdateMeterProf(cntx, *aggMeter)
1244 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301245 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301246 }
1247 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301248 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1249 if dsMeter.AssociatedServices > 0 {
1250 dsMeter.AssociatedServices--
1251 logger.Infow(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
1252 va.UpdateMeterProf(cntx, *dsMeter)
1253 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301254 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301255 }
1256 if vs.AggDsMeterID != vs.UsMeterID {
1257 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301258 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1259 if usMeter.AssociatedServices > 0 {
1260 usMeter.AssociatedServices--
1261 logger.Infow(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
1262 va.UpdateMeterProf(cntx, *usMeter)
1263 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301264 }
1265 }
1266 }
1267
1268 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301269 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301270 }
1271
vinokuma926cb3e2023-03-29 11:41:06 +05301272 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301273 va.ServiceCounters.Delete(name)
1274 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301275 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301276 }
1277}
1278
vinokuma926cb3e2023-03-29 11:41:06 +05301279// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301280// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301281func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301282 // Using locks instead of concurrent map for PendingFlows to avoid
1283 // race condition during flow response indication processing
1284 vs.ServiceLock.Lock()
1285 defer vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301286 logger.Debugw(ctx, "Adds the flow to the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301287
1288 for cookie := range flow.SubFlows {
1289 cookie := strconv.FormatUint(cookie, 10)
1290 fe := &FlowEvent{
1291 eType: EventTypeServiceFlowAdded,
1292 device: device.Name,
1293 cookie: cookie,
1294 eventData: vs,
1295 }
1296 device.RegisterFlowAddEvent(cookie, fe)
1297 vs.PendingFlows[cookie] = true
1298 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301299 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301300}
1301
vinokuma926cb3e2023-03-29 11:41:06 +05301302// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301303// If no more pending flows, HSIA indication wil be triggered
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301304func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails, flowEventMap *util.ConcurrentMap) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301305 logger.Debugw(ctx, "Flow Add Success Notification", log.Fields{"Cookie": cookie, "bwAvailInfo": bwAvailInfo, "Service": vs.Name})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301306 flowEventMap.MapLock.Lock()
1307 flowEventMap.Remove(cookie)
1308 flowEventMap.MapLock.Unlock()
1309
Naveen Sampath04696f72022-06-13 15:19:14 +05301310 if vs.DeleteInProgress {
1311 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1312 return
1313 }
1314 vs.ServiceLock.Lock()
1315
1316 if _, ok := vs.PendingFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301317 logger.Warnw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Naveen Sampath04696f72022-06-13 15:19:14 +05301318 vs.ServiceLock.Unlock()
1319 return
1320 }
1321
1322 delete(vs.PendingFlows, cookie)
1323 vs.AssociatedFlows[cookie] = true
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301324 vs.FlowPushCount[cookie] = 0
Naveen Sampath04696f72022-06-13 15:19:14 +05301325 vs.ServiceLock.Unlock()
1326 var prevBwAvail, presentBwAvail string
1327 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1328 prevBwAvail = bwAvailInfo.PrevBw
1329 presentBwAvail = bwAvailInfo.PresentBw
1330 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301331 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301332 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301333 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301334
1335 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301336 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1337 if err != nil {
1338 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1339 return
1340 } else if device.State != controller.DeviceStateUP {
1341 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1342 return
1343 }
1344
1345 if vs.Trigger == ServiceVlanUpdate {
1346 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301347 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301348 }
1349 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1350 return
1351 }
1352 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1353}
1354
vinokuma926cb3e2023-03-29 11:41:06 +05301355// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301356// Trigger service failure indication to NB
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301357func (vs *VoltService) FlowInstallFailure(cntx context.Context, cookie string, errorCode uint32, errReason string, flowEventMap *util.ConcurrentMap) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301358 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 +05301359
1360 isServiceDeactivated := vs.CheckAndDeactivateService(cntx, cookie)
1361 if isServiceDeactivated {
1362 flowEventMap.MapLock.Lock()
1363 for ck := range vs.PendingFlows {
1364 flowEventMap.Remove(ck)
1365 }
1366 flowEventMap.MapLock.Unlock()
1367 }
1368
1369 vs.ServiceLock.RLock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301370 if _, ok := vs.PendingFlows[cookie]; !ok {
1371 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1372 vs.ServiceLock.RUnlock()
1373 return
1374 }
1375 vs.ServiceLock.RUnlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301376 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 +05301377 vs.triggerServiceFailureInd(errorCode, errReason)
1378}
1379
vinokuma926cb3e2023-03-29 11:41:06 +05301380// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301381// Triggers flow deletion after registering for flow indication event
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301382func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow, delFlowsInDevice bool) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301383 logger.Debugw(ctx, "Delete the flow from the service", log.Fields{"Port": vs.Port, "Device": device.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301384 if !vs.ForceDelete {
1385 // Using locks instead of concurrent map for AssociatedFlows to avoid
1386 // race condition during flow response indication processing
1387 vs.ServiceLock.Lock()
1388 defer vs.ServiceLock.Unlock()
1389
1390 for cookie := range flow.SubFlows {
1391 cookie := strconv.FormatUint(cookie, 10)
1392 fe := &FlowEvent{
1393 eType: EventTypeServiceFlowRemoved,
1394 cookie: cookie,
1395 eventData: vs,
1396 }
1397 device.RegisterFlowDelEvent(cookie, fe)
1398 }
1399 }
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05301400 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow, delFlowsInDevice)
Naveen Sampath04696f72022-06-13 15:19:14 +05301401}
1402
vinokuma926cb3e2023-03-29 11:41:06 +05301403// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301404func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301405 logger.Debugw(ctx, "Delete service from DB/Cache", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301406 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301407 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301408 GetApplication().ServiceByName.Delete(vs.Name)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301409 logger.Debugw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301410 }
1411}
1412
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301413// CheckAndDeactivateService - deactivate service and remove flows from DB, if the max flows retry attempt has reached
1414func (vs *VoltService) CheckAndDeactivateService(cntx context.Context, cookie string) bool {
1415 vs.ServiceLock.Lock()
1416 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]})
1417 vs.FlowPushCount[cookie]++
1418 if vs.FlowPushCount[cookie] == controller.GetController().GetMaxFlowRetryAttempt() {
1419 if vs.IsActivated {
1420 vs.ServiceLock.Unlock()
1421 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1422 if err != nil {
1423 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
1424 // So no error is returned
1425 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": vs.Port})
1426 return false
1427 }
1428 vs.SetSvcDeactivationFlags(SvcDeacRsn_Controller)
1429 GetApplication().ServiceByName.Store(vs.Name, vs)
1430 p := device.GetPort(vs.Port)
1431 if p != nil && (p.State == PortStateUp) {
1432 if vpv := GetApplication().GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
1433 // Port down call internally deletes all the flows
1434 vpv.PortDownInd(cntx, vs.Device, vs.Port, true, true)
1435 } else {
1436 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": vs.Device, "port": vs.Port, "SvcName": vs.Name})
1437 }
1438 }
1439 vs.DeactivateInProgress = false
1440 GetApplication().ServiceByName.Store(vs.Name, vs)
1441 vs.WriteToDb(cntx)
1442 logger.Infow(ctx, "Service deactivated after max flow install attempts", log.Fields{"SvcName": vs.Name, "Cookie": cookie})
1443 return true
1444 }
1445 }
1446 vs.ServiceLock.Unlock()
1447 return false
1448}
1449
vinokuma926cb3e2023-03-29 11:41:06 +05301450// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301451// If no more associated flows, DelHSIA indication wil be triggered
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301452func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string, flowEventMap *util.ConcurrentMap) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301453 // if vs.DeleteInProgress {
1454 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1455 // return
1456 // }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301457 flowEventMap.MapLock.Lock()
1458 flowEventMap.Remove(cookie)
1459 flowEventMap.MapLock.Unlock()
1460
Naveen Sampath04696f72022-06-13 15:19:14 +05301461 vs.ServiceLock.Lock()
1462 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1463
1464 if _, ok := vs.AssociatedFlows[cookie]; ok {
1465 delete(vs.AssociatedFlows, cookie)
1466 } else if _, ok := vs.PendingFlows[cookie]; ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301467 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 +05301468 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301469 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 +05301470 }
1471
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301472 vs.FlowPushCount[cookie] = 0
Naveen Sampath04696f72022-06-13 15:19:14 +05301473 vs.ServiceLock.Unlock()
1474
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301475 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301476
1477 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301478 device := GetApplication().GetDevice(vs.Device)
1479 if device == nil {
1480 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1481 return
1482 } else if device.State != controller.DeviceStateUP {
1483 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1484 return
1485 }
1486
1487 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301488 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301489 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301490 return
1491 }
1492 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 +05301493 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301494
1495 return
1496 }
1497 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1498}
1499
vinokuma926cb3e2023-03-29 11:41:06 +05301500// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301501// Trigger service failure indication to NB
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301502func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string, flowEventMap *util.ConcurrentMap) {
1503 vs.ServiceLock.Lock()
1504 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 +05301505
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301506 vs.FlowPushCount[cookie]++
Naveen Sampath04696f72022-06-13 15:19:14 +05301507 if _, ok := vs.AssociatedFlows[cookie]; !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301508 logger.Warnw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301509 vs.ServiceLock.Unlock()
Naveen Sampath04696f72022-06-13 15:19:14 +05301510 return
1511 }
1512 if vs.DeleteInProgress {
1513 delete(vs.AssociatedFlows, cookie)
1514 }
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05301515 vs.ServiceLock.Unlock()
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301516 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 +05301517
1518 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301519 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301520}
1521
1522func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301523 logger.Debugw(ctx, "Trigger Service Failure Ind", log.Fields{"Service": vs.Name, "Port": vs.Port})
Naveen Sampath04696f72022-06-13 15:19:14 +05301524 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1525 if err != nil {
1526 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1527 return
1528 } else if device.State != controller.DeviceStateUP {
1529 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1530 return
1531 }
1532}
1533
1534// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301535func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301536 // VNETS must be learnt first
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301537 logger.Debug(ctx, "Restore Svcs From Db")
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301538 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301539 for _, vs := range vss {
1540 b, ok := vs.Value.([]byte)
1541 if !ok {
1542 logger.Warn(ctx, "The value type is not []byte")
1543 continue
1544 }
1545 var vvs VoltService
1546 err := json.Unmarshal(b, &vvs)
1547 if err != nil {
1548 logger.Warn(ctx, "Unmarshal of VNET failed")
1549 continue
1550 }
1551 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301552 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301553 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1554 }
1555
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301556 if vvs.VoltServiceOper.DeactivateInProgress {
1557 va.ServicesToDeactivate[vvs.VoltServiceCfg.Name] = true
1558 logger.Warnw(ctx, "Service (restored) to be deactivated", log.Fields{"Service": vvs.Name})
1559 }
1560
Naveen Sampath04696f72022-06-13 15:19:14 +05301561 if vvs.VoltServiceOper.DeleteInProgress {
1562 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1563 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1564 }
1565 }
1566}
1567
1568// GetService to get service
1569func (va *VoltApplication) GetService(name string) *VoltService {
1570 if vs, ok := va.ServiceByName.Load(name); ok {
1571 return vs.(*VoltService)
1572 }
1573 return nil
1574}
1575
1576// GetCircuitID to get circuit id
1577func (vs *VoltService) GetCircuitID() []byte {
1578 return []byte(vs.CircuitID)
1579}
1580
1581// GetRemoteID to get remote id
1582func (vs *VoltService) GetRemoteID() []byte {
1583 return []byte(vs.RemoteID)
1584}
1585
1586// IPAssigned to check if ip is assigned
1587func (vs *VoltService) IPAssigned() bool {
1588 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1589 return true
1590 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1591 return true
1592 }
1593 return false
1594}
1595
1596// GetServiceNameFromCookie to get service name from cookie
1597func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301598 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 +05301599 var vlan uint64
1600 vlanControl := (tableMetadata >> 32) & 0xF
1601
1602 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1603 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1604 vlan = (tableMetadata >> 16) & 0xFFFF
1605 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301606 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301607 vlan = cookie >> 52
1608 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301609 logger.Debugw(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301610 var vlans []of.VlanType
1611 vlans = append(vlans, of.VlanType(vlan))
1612 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1613 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301614 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301615 } else {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301616 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 +05301617 }
1618 return service
1619}
1620
vinokuma926cb3e2023-03-29 11:41:06 +05301621// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301622type MigrateServicesReqStatus string
1623
1624const (
vinokuma926cb3e2023-03-29 11:41:06 +05301625 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301626 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301627 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301628 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301629 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301630 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1631)
1632
vinokuma926cb3e2023-03-29 11:41:06 +05301633// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301634type MigrateServicesRequest struct {
1635 ID string
1636 OldVnetID string
1637 NewVnetID string
1638 ServicesList map[string]bool
1639 DeviceID string
1640 Status MigrateServicesReqStatus
1641 MigrateServicesLock sync.RWMutex
1642}
1643
1644func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301645 var msr MigrateServicesRequest
1646 msr.OldVnetID = oldVnetID
1647 msr.NewVnetID = newVnetID
1648 msr.ID = id
1649 msr.ServicesList = serviceMap
1650 msr.DeviceID = deviceID
1651 msr.Status = MigrateSrvsReqInit
1652 return &msr
1653}
1654
vinokuma926cb3e2023-03-29 11:41:06 +05301655// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301656func (msr *MigrateServicesRequest) GetMsrKey() string {
1657 return msr.OldVnetID + "-" + msr.ID
1658}
1659
1660// //isRequestComplete - return if all request has been processed and completed
1661// // RequestProcessed indicates that all the profile de-activation has been triggered
1662// // And the associated profiles indicates the profiles awaiting results
1663// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1664// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1665// return (len(edr.AssociatedProfiles) == 0)
1666// }
1667
vinokuma926cb3e2023-03-29 11:41:06 +05301668// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301669func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301670 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)})
1671 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301672 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301673 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301674 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301675 }
1676 }
1677}
1678
vinokuma926cb3e2023-03-29 11:41:06 +05301679// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301680func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301681 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 +05301682 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301683 return errors.New("old vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301684 }
1685 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301686 return errors.New("new vnet id not found")
Naveen Sampath04696f72022-06-13 15:19:14 +05301687 }
1688
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301689 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301690 if d == nil {
1691 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1692 return errorCodes.ErrDeviceNotFound
1693 }
1694
1695 serviceMap := make(map[string]bool)
1696
1697 for _, service := range serviceList {
1698 serviceMap[service] = false
1699 }
1700 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301701 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301702
1703 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301704 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301705 return nil
1706}
1707
vinokuma926cb3e2023-03-29 11:41:06 +05301708// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301709func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301710 logger.Debug(ctx, "Process Migrate Services Prof Request")
Naveen Sampath04696f72022-06-13 15:19:14 +05301711 va := GetApplication()
1712 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301713 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301714 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301715 va.DelService(cntx, srv, true, nil, true)
1716 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301717 continue
1718 }
1719
1720 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1721 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1722 vs := vsIntf.(*VoltService)
1723 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1724 if vpv == nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301725 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 +05301726 continue
1727 }
1728 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1729 vpv.Blocked = true
1730
1731 // setDeactTrigger := func(key, value interface{}) bool {
1732 // vs := value.(*VoltService)
1733 vs.ServiceLock.Lock()
1734 vs.UpdateInProgress = true
1735 metadata := &MigrateServiceMetadata{
1736 NewVnetID: msr.NewVnetID,
1737 RequestID: msr.ID,
1738 }
1739 vs.Metadata = metadata
1740 vs.ServiceLock.Unlock()
1741
vinokuma926cb3e2023-03-29 11:41:06 +05301742 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301743 // new vpv flows will be installed when new service is added
1744 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301745 vpv.DelTrapFlows(cntx)
1746 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301747 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301748 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301749 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301750 }
1751 } else {
1752 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1753 }
1754 }
1755}
1756
vinokuma926cb3e2023-03-29 11:41:06 +05301757// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301758func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301759 logger.Infow(ctx, "Add Migrating Services", log.Fields{"Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301760 var msrMap *util.ConcurrentMap
1761 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1762 msrMap = util.NewConcurrentMap()
1763 } else {
1764 msrMap = msrMapIntf.(*util.ConcurrentMap)
1765 }
1766
1767 msrMap.Set(msr.ID, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301768 logger.Debugw(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301769
1770 d.MigratingServices.Set(msr.OldVnetID, msrMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301771 logger.Debugw(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301772}
1773
vinokuma926cb3e2023-03-29 11:41:06 +05301774// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301775func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301776 logger.Debugw(ctx, "Get Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301777 if vd := va.GetDevice(deviceID); vd != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301778 logger.Debugw(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301779 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1780 msrList := msrListIntf.(*util.ConcurrentMap)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301781 logger.Debugw(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301782 if msrObj, ok := msrList.Get(requestID); ok {
1783 return msrObj.(*MigrateServicesRequest)
1784 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301785 }
1786 }
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301787 logger.Warnw(ctx, "Device Not Found", log.Fields{"DeviceID": deviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301788 return nil
1789}
1790
vinokuma926cb3e2023-03-29 11:41:06 +05301791// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301792func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301793 logger.Debugw(ctx, "Update Migrate Services Request", log.Fields{"DeviceID": deviceID, "OldVnetID": oldVnetID, "RequestID": requestID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301794 if vd := va.GetDevice(deviceID); vd != nil {
1795 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1796 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1797 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1798 }
1799 }
1800 }
1801}
1802
vinokuma926cb3e2023-03-29 11:41:06 +05301803// updateVnetProfile - Called on flow process completion
1804// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301805func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301806 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 +05301807
1808 nvs := VoltService{}
1809 nvs.VoltServiceCfg = vs.VoltServiceCfg
1810 nvs.Device = vs.Device
1811 nvs.Ipv4Addr = vs.Ipv4Addr
1812 nvs.Ipv6Addr = vs.Ipv6Addr
1813 nvs.UsMeterID = vs.UsMeterID
1814 nvs.DsMeterID = vs.DsMeterID
1815 nvs.AggDsMeterID = vs.AggDsMeterID
1816 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1817 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1818 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1819 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1820 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1821 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1822 nvs.PendingFlows = vs.PendingFlows
1823 nvs.AssociatedFlows = vs.AssociatedFlows
1824 nvs.DeleteInProgress = vs.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301825 nvs.DeactivateInProgress = vs.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301826 nvs.ForceDelete = vs.ForceDelete
1827 nvs.BwAvailInfo = vs.BwAvailInfo
1828 nvs.UpdateInProgress = vs.UpdateInProgress
1829
1830 if nvs.DeleteInProgress {
1831 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1832 return
1833 }
1834
1835 metadata := vs.Metadata.(*MigrateServiceMetadata)
1836 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301837 oldSrvName := vs.Name
1838
1839 if metadata == nil || metadata.NewVnetID == "" {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301840 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 +05301841 return
1842 }
1843
vinokuma926cb3e2023-03-29 11:41:06 +05301844 nvs.VnetID = metadata.NewVnetID
1845 id := metadata.RequestID
1846
1847 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301848 // Since if post del service in case of pod crash or reboot, the service data will be lost
1849 va := GetApplication()
1850 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1851 vnets := strings.Split(metadata.NewVnetID, "-")
1852 svlan, _ := strconv.Atoi(vnets[0])
1853 nvs.SVlan = of.VlanType(svlan)
1854 nvs.UpdateInProgress = false
1855 nvs.Metadata = nil
1856 nvs.Trigger = ServiceVlanUpdate
1857
1858 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1859 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1860 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1861
vinokuma926cb3e2023-03-29 11:41:06 +05301862 // TODO:Nav Pass a copy, not the pointer
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301863 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 +05301864 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301865 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1866 }
1867 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1868
1869 msr.ServicesList[oldSrvName] = true
1870 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301871 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301872
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301873 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 +05301874 va.DelService(cntx, oldSrvName, true, nil, true)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301875 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 +05301876 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301877}
1878
vinokuma926cb3e2023-03-29 11:41:06 +05301879// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301880// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301881func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301882 logger.Infow(ctx, "Service Migrated", log.Fields{"ServiceName": serviceName})
Naveen Sampath04696f72022-06-13 15:19:14 +05301883 msr.MigrateServicesLock.Lock()
1884 defer msr.MigrateServicesLock.Unlock()
1885
1886 delete(msr.ServicesList, serviceName)
1887
1888 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301889 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301890 return
1891 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301892 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301893 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301894}
1895
vinokuma926cb3e2023-03-29 11:41:06 +05301896// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301897func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1898 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301899}
1900
vinokuma926cb3e2023-03-29 11:41:06 +05301901// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301902func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301903 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 +05301904 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301905 for _, msr := range msrList {
1906 b, ok := msr.Value.([]byte)
1907 if !ok {
1908 logger.Warn(ctx, "The value type is not []byte")
1909 continue
1910 }
1911 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301912 msrAction(cntx, msr)
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301913 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 +05301914 }
1915}
1916
1917// createMigrateServicesFromString to create Service from string
1918func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301919 logger.Info(ctx, "Create Migrate Services From String")
Naveen Sampath04696f72022-06-13 15:19:14 +05301920 var msr MigrateServicesRequest
1921 if err := json.Unmarshal(b, &msr); err == nil {
1922 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301923 } else {
1924 logger.Warn(ctx, "Unmarshal failed")
1925 }
1926 return &msr
1927}
1928
vinokuma926cb3e2023-03-29 11:41:06 +05301929// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301930func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301931 logger.Infow(ctx, "Store And Process Migrate Srv Request", log.Fields{"MsrID": msr.DeviceID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301932 d := GetApplication().GetDevice(msr.DeviceID)
1933 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301934 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301935}
1936
vinokuma926cb3e2023-03-29 11:41:06 +05301937// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301938func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05301939 logger.Infow(ctx, "Force udpate services with new vnet profile", log.Fields{"MsrID": msr.NewVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301940 for srv := range msr.ServicesList {
1941 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301942 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301943 }
1944 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301945 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301946}
1947
vinokuma926cb3e2023-03-29 11:41:06 +05301948// nolint: gocyclo
1949// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301950func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1951 if nvs.Name != evs.Name {
1952 return false
1953 }
1954 if nvs.UniVlan != evs.UniVlan {
1955 return false
1956 }
1957 if nvs.CVlan != evs.CVlan {
1958 return false
1959 }
1960 if nvs.SVlan != evs.SVlan {
1961 return false
1962 }
1963 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1964 return false
1965 }
1966 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1967 return false
1968 }
1969 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1970 return false
1971 }
1972 if nvs.TechProfileID != evs.TechProfileID {
1973 return false
1974 }
1975 if nvs.CircuitID != evs.CircuitID {
1976 return false
1977 }
1978 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1979 return false
1980 }
1981 if nvs.Port != evs.Port {
1982 return false
1983 }
1984 if nvs.PonPort != evs.PonPort {
1985 return false
1986 }
1987 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1988 return false
1989 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301990 if nvs.IsOption82Enabled != evs.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +05301991 return false
1992 }
1993 if nvs.IgmpEnabled != evs.IgmpEnabled {
1994 return false
1995 }
1996 if nvs.McastService != evs.McastService {
1997 return false
1998 }
1999 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
2000 return false
2001 }
2002 if nvs.UsMeterProfile != evs.UsMeterProfile {
2003 return false
2004 }
2005 if nvs.DsMeterProfile != evs.DsMeterProfile {
2006 return false
2007 }
2008 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
2009 return false
2010 }
2011 if nvs.VnetID != evs.VnetID {
2012 return false
2013 }
2014 if nvs.MvlanProfileName != evs.MvlanProfileName {
2015 return false
2016 }
2017 if nvs.RemoteIDType != evs.RemoteIDType {
2018 return false
2019 }
2020 if nvs.SchedID != evs.SchedID {
2021 return false
2022 }
2023 if nvs.AllowTransparent != evs.AllowTransparent {
2024 return false
2025 }
2026 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
2027 return false
2028 }
2029 if nvs.DataRateAttr != evs.DataRateAttr {
2030 return false
2031 }
2032 if nvs.MinDataRateUs != evs.MinDataRateUs {
2033 return false
2034 }
2035 if nvs.MinDataRateDs != evs.MinDataRateDs {
2036 return false
2037 }
2038 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
2039 return false
2040 }
2041 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
2042 return false
2043 }
2044
2045 return true
2046}
2047
vinokuma926cb3e2023-03-29 11:41:06 +05302048// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05302049func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05302050 // Clear the Flows flag if already set
2051 // This case happens only in case of some race condition
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302052 logger.Infow(ctx, "Trigger Associated Flow Delete", log.Fields{"Device": vs.Device, "Service": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05302053 if vs.UsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302054 if err := vs.DelUsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302055 logger.Warnw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302056 }
2057 }
2058
2059 if vs.DsHSIAFlowsApplied {
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302060 if err := vs.DelDsHsiaFlows(cntx, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302061 logger.Warnw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302062 }
2063 }
2064
2065 vs.ServiceLock.Lock()
2066 cookieList := []uint64{}
2067 for cookie := range vs.AssociatedFlows {
2068 cookieList = append(cookieList, convertToUInt64(cookie))
2069 }
2070 vs.ServiceLock.Unlock()
2071
2072 if len(cookieList) == 0 {
2073 return false
2074 }
2075
vinokuma926cb3e2023-03-29 11:41:06 +05302076 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05302077 for _, cookie := range cookieList {
2078 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
2079 flow := &of.VoltFlow{}
2080 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
2081 subFlow := of.NewVoltSubFlow()
2082 subFlow.Cookie = cookie
2083 flow.SubFlows[cookie] = subFlow
2084 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302085 if err := vs.DelFlows(cntx, vd, flow, false); err != nil {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302086 logger.Warnw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05302087 }
2088 }
2089 }
2090 return true
2091}
2092
vinokuma926cb3e2023-03-29 11:41:06 +05302093// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05302094func (vs *VoltService) triggerServiceInProgressInd() {
2095}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302096
vinokuma926cb3e2023-03-29 11:41:06 +05302097// JSONMarshal wrapper function for json Marshal VoltService
2098func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302099 return json.Marshal(VoltService{
2100 VoltServiceCfg: vs.VoltServiceCfg,
2101 VoltServiceOper: VoltServiceOper{
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302102 Device: vs.VoltServiceOper.Device,
2103 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
2104 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
2105 UsMeterID: vs.VoltServiceOper.UsMeterID,
2106 DsMeterID: vs.VoltServiceOper.DsMeterID,
2107 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
2108 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
2109 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
2110 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
2111 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
2112 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
2113 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
2114 PendingFlows: vs.VoltServiceOper.PendingFlows,
2115 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
2116 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2117 DeactivateInProgress: vs.VoltServiceOper.DeactivateInProgress,
2118 ForceDelete: vs.VoltServiceOper.ForceDelete,
2119 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2120 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2121 Metadata: vs.VoltServiceOper.Metadata,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302122 },
2123 })
2124}
Tinoj Josephec742f62022-09-29 19:11:10 +05302125
2126// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302127func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302128 var svcList []*VoltService
2129 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2130 va.ServiceByName.Range(func(key, value interface{}) bool {
2131 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302132 if len(deviceID) > 0 {
2133 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302134 if deviceID == vs.Device && portNo == vs.Port {
2135 svcList = append(svcList, vs)
2136 }
2137 } else {
2138 if deviceID == vs.Device {
2139 svcList = append(svcList, vs)
2140 }
2141 }
2142 } else {
2143 svcList = append(svcList, vs)
2144 }
2145 return true
2146 })
2147 return svcList, nil
2148}
2149
Akash Soni634d9bf2023-07-10 12:11:10 +05302150type FlowProvisionStatus struct {
2151 FlowProvisionStatus string
2152}
2153
2154// GetFlowProvisionStatus to get status of the subscriber and flow provisioned in controller
Akash Soni3c391e72023-08-16 12:21:33 +05302155func (va *VoltApplication) GetFlowProvisionStatus(portNo string) FlowProvisionStatus {
Akash Soni634d9bf2023-07-10 12:11:10 +05302156 logger.Infow(ctx, "GetFlowProvisionStatus Request ", log.Fields{"Port": portNo})
2157 flowProvisionStatus := FlowProvisionStatus{}
Akash Soni3c391e72023-08-16 12:21:33 +05302158 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_NOT_IN_CONTROLLER
Akash Soni634d9bf2023-07-10 12:11:10 +05302159 va.ServiceByName.Range(func(key, value interface{}) bool {
2160 vs := value.(*VoltService)
2161 logger.Debugw(ctx, "Volt Service ", log.Fields{"VS": vs})
Akash Soni3c391e72023-08-16 12:21:33 +05302162 if portNo == vs.Port {
2163 if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() == 0 {
2164 flowProvisionStatus.FlowProvisionStatus = ALL_FLOWS_PROVISIONED
2165 return false
2166 } else if !vs.IsActivated {
2167 flowProvisionStatus.FlowProvisionStatus = SUBSCRIBER_DISABLED_IN_CONTROLLER
2168 return false
2169 } else if !vs.DsHSIAFlowsApplied && !vs.UsHSIAFlowsApplied {
2170 flowProvisionStatus.FlowProvisionStatus = NO_FLOWS_PROVISIONED
2171 return false
Akash Soni230e6212023-10-16 10:46:07 +05302172 } else if vs.DsHSIAFlowsApplied && vs.UsHSIAFlowsApplied && vs.LenOfPendingFlows() > 0 {
Akash Soni3c391e72023-08-16 12:21:33 +05302173 flowProvisionStatus.FlowProvisionStatus = FLOWS_PROVISIONED_PARTIALLY
2174 return false
Akash Soni634d9bf2023-07-10 12:11:10 +05302175 }
2176 }
2177 return true
2178 })
Akash Soni634d9bf2023-07-10 12:11:10 +05302179 return flowProvisionStatus
2180}
2181
2182func (vs *VoltService) LenOfPendingFlows() int {
2183 vs.ServiceLock.RLock()
2184 lth := len(vs.PendingFlows)
2185 vs.ServiceLock.RUnlock()
2186 return lth
2187}
2188
Tinoj Josephec742f62022-09-29 19:11:10 +05302189// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302190func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302191 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 +05302192 device, err := va.GetDeviceFromPort(portNo)
2193 if err != nil {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302194 // Lets activate the service even though port was not found. We will push the flows once the port is added by voltha
2195 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 +05302196 }
2197 // If device id is not provided check only port number
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302198 if device != nil {
2199 if deviceID == DeviceAny {
2200 deviceID = device.Name
2201 } else if deviceID != device.Name {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302202 err := errorCodes.ErrDeviceNotFound
2203 return fmt.Errorf("wrong device id %s : %w", deviceID, err)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302204 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302205 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302206 va.ServiceByName.Range(func(key, value interface{}) bool {
2207 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302208 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302209 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302210 logger.Warnw(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302211 return true
2212 }
2213 if portNo == vs.Port && !vs.IsActivated {
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302214 // 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 +05302215 logger.Debugw(ctx, "Service Activate", log.Fields{"Name": vs.Name})
Tinoj Josephec742f62022-09-29 19:11:10 +05302216 vs.IsActivated = true
2217 va.ServiceByName.Store(vs.Name, vs)
2218 vs.WriteToDb(cntx)
Sridhar Ravindraf8251e72023-09-06 17:09:30 +05302219
2220 // Push the flows only if the port is already added and we have a valid device
2221 if device != nil {
2222 p := device.GetPort(vs.Port)
2223 if p == nil {
2224 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2225 return true
2226 }
2227 // If port is already up send indication to vpv
2228 if p.State == PortStateUp {
2229 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2230 // PortUp call initiates flow addition
2231 vpv.PortUpInd(cntx, device, portNo)
2232 } else {
2233 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2234 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302235 }
2236 }
2237 }
2238 return true
2239 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302240 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302241}
2242
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302243func (vs *VoltService) SetSvcDeactivationFlags(deactivateRsn SvcDeactivateReason) {
2244 vs.DeactivateInProgress = true
2245 vs.IsActivated = false
2246 vs.ServiceDeactivateReason = deactivateRsn
2247}
2248
Tinoj Josephec742f62022-09-29 19:11:10 +05302249// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302250func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302251 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo, "Svaln": sVlan, "Cvlan": cVlan, "TpID": tpID})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302252
Tinoj Josephec742f62022-09-29 19:11:10 +05302253 va.ServiceByName.Range(func(key, value interface{}) bool {
2254 vs := value.(*VoltService)
2255 // If svlan if provided, then the tags and tpID of service has to be matching
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302256 logger.Debugw(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302257 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302258 logger.Warnw(ctx, "condition not matched", log.Fields{"Device": deviceID, "Port": portNo, "sVlan": sVlan, "cVlan": cVlan, "tpID": tpID})
Tinoj Josephec742f62022-09-29 19:11:10 +05302259 return true
2260 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302261 if portNo == vs.Port && vs.IsActivated {
Sridhar Ravindra3ec14232024-01-01 19:11:48 +05302262 vs.SetSvcDeactivationFlags(SvcDeacRsn_NB)
Tinoj Josephec742f62022-09-29 19:11:10 +05302263 va.ServiceByName.Store(vs.Name, vs)
2264 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302265 device, err := va.GetDeviceFromPort(portNo)
2266 if err != nil {
2267 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2268 // So no error is returned
Hitesh Chhabra2b2347d2023-07-31 17:36:48 +05302269 logger.Warnw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302270 return true
2271 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302272 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302273 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302274 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2275 // Port down call internally deletes all the flows
Sridhar Ravindra03aa0bf2023-09-12 17:46:40 +05302276 vpv.PortDownInd(cntx, deviceID, portNo, true, false)
Tinoj Josephec742f62022-09-29 19:11:10 +05302277 if vpv.IgmpEnabled {
2278 va.ReceiverDownInd(cntx, deviceID, portNo)
2279 }
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302280 vs.DeactivateInProgress = false
Tinoj Josephec742f62022-09-29 19:11:10 +05302281 } else {
2282 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2283 }
2284 }
2285 }
2286 return true
2287 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302288 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302289}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302290
vinokuma926cb3e2023-03-29 11:41:06 +05302291// GetServicePbit to get first set bit in the pbit map
2292// returns -1 : If configured to match on all pbits
2293// returns 8 : If no pbits are configured
2294// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302295func (vs *VoltService) GetServicePbit() int {
2296 if vs.IsPbitExist(of.PbitMatchAll) {
2297 return -1
2298 }
vinokuma926cb3e2023-03-29 11:41:06 +05302299 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302300 if vs.IsPbitExist(of.PbitType(pbit)) {
2301 return pbit
2302 }
2303 }
2304 return int(of.PbitMatchNone)
2305}