blob: 5d7bc43482eaa4cb03f5a19e928cccbeeaef67d8 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301/*
2* Copyright 2022-present Open Networking Foundation
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053014 */
Naveen Sampath04696f72022-06-13 15:19:14 +053015
16package application
17
18import (
19 "bytes"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053020 "context"
Naveen Sampath04696f72022-06-13 15:19:14 +053021 "encoding/json"
22 "errors"
23 "net"
24 "reflect"
Naveen Sampath04696f72022-06-13 15:19:14 +053025 "sort"
26 "strconv"
27 "strings"
28 "sync"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053029 infraerrorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053030
31 "github.com/google/gopacket/layers"
32
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053033 "voltha-go-controller/database"
Naveen Sampath04696f72022-06-13 15:19:14 +053034 "voltha-go-controller/internal/pkg/controller"
35 cntlr "voltha-go-controller/internal/pkg/controller"
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +053036 errorCodes "voltha-go-controller/internal/pkg/errorcodes"
Naveen Sampath04696f72022-06-13 15:19:14 +053037 "voltha-go-controller/internal/pkg/of"
38 "voltha-go-controller/internal/pkg/util"
Tinoj Joseph1d108322022-07-13 10:07:39 +053039 "voltha-go-controller/log"
Naveen Sampath04696f72022-06-13 15:19:14 +053040)
41
42const (
43 // DSLAttrEnabled constant
44 DSLAttrEnabled string = "ENABLED"
Tinoj Josephec742f62022-09-29 19:11:10 +053045 // DeviceAny constant
46 DeviceAny string = "DEVICE-ANY"
Naveen Sampath04696f72022-06-13 15:19:14 +053047)
48
49// VoltServiceCfg structure
50// Name - Uniquely identifies a service across the entire application
51// UniVlan - The VLAN of the packets entering the UNI of ONU
52// CVlan - The VLAN to transalate to/from on the PON link
53// SVlan - The outer VLAN to be used on the NNI of OLT.
vinokuma926cb3e2023-03-29 11:41:06 +053054// - In general, 4096 is used as NO VLAN for all the above
55// SVlanTpid - SVlan Tag Protocol Identifier
Naveen Sampath04696f72022-06-13 15:19:14 +053056// Pbits - Each bit of uint8 represents one p-bit. MSB is pbit 7
57// DhcpRelay - Whether it is turned on/off
58// CircuitId - The circuit id to be used with DHCP relay. Unused otherwise
59// RemoveId - Same as above
60// Port - The access port for the service. Each service has a single access
vinokuma926cb3e2023-03-29 11:41:06 +053061// port. The converse is not always true
Naveen Sampath04696f72022-06-13 15:19:14 +053062// MacLearning - If MAC learning is turned on, the MAC address learned from the
vinokuma926cb3e2023-03-29 11:41:06 +053063// the service activation is used in programming flows
Naveen Sampath04696f72022-06-13 15:19:14 +053064// MacAddress - The MAC hardware address learnt on the UNI interface
65// MacAddresses - Not yet implemented. To be used to learn more MAC addresses
66type VoltServiceCfg struct {
Naveen Sampath04696f72022-06-13 15:19:14 +053067 Pbits []of.PbitType
vinokuma926cb3e2023-03-29 11:41:06 +053068 Name string
Naveen Sampath04696f72022-06-13 15:19:14 +053069 CircuitID string
Naveen Sampath04696f72022-06-13 15:19:14 +053070 Port string
Naveen Sampath04696f72022-06-13 15:19:14 +053071 UsMeterProfile string
72 DsMeterProfile string
73 AggDsMeterProfile string
74 VnetID string
75 MvlanProfileName string
76 RemoteIDType string
Naveen Sampath04696f72022-06-13 15:19:14 +053077 DataRateAttr string
vinokuma926cb3e2023-03-29 11:41:06 +053078 ServiceType string
79 DsRemarkPbitsMap map[int]int // Ex: Remark case {0:0,1:0} and No-remark case {1:1}
80 RemoteID []byte
81 MacAddr net.HardwareAddr
82 ONTEtherTypeClassification int
83 SchedID int
84 Trigger ServiceTrigger
85 MacLearning MacLearningType
86 PonPort uint32
Naveen Sampath04696f72022-06-13 15:19:14 +053087 MinDataRateUs uint32
88 MinDataRateDs uint32
89 MaxDataRateUs uint32
90 MaxDataRateDs uint32
vinokuma926cb3e2023-03-29 11:41:06 +053091 TechProfileID uint16
92 SVlanTpid layers.EthernetType
93 UniVlan of.VlanType
94 CVlan of.VlanType
95 SVlan of.VlanType
96 UsPonCTagPriority of.PbitType
97 UsPonSTagPriority of.PbitType
98 DsPonSTagPriority of.PbitType
99 DsPonCTagPriority of.PbitType
100 VlanControl VlanControl
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530101 IsOption82Enabled bool
vinokuma926cb3e2023-03-29 11:41:06 +0530102 IgmpEnabled bool
103 McastService bool
104 AllowTransparent bool
105 EnableMulticastKPI bool
Tinoj Josephec742f62022-09-29 19:11:10 +0530106 IsActivated bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530107}
108
109// VoltServiceOper structure
110type VoltServiceOper struct {
vinokuma926cb3e2023-03-29 11:41:06 +0530111 Metadata interface{}
112 PendingFlows map[string]bool
113 AssociatedFlows map[string]bool
114 BwAvailInfo string
Naveen Sampath04696f72022-06-13 15:19:14 +0530115 //MacLearning bool
116 //MacAddr net.HardwareAddr
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530117 Device string
118 Ipv4Addr net.IP
119 Ipv6Addr net.IP
120 ServiceLock sync.RWMutex `json:"-"`
121 UsMeterID uint32
122 DsMeterID uint32
123 AggDsMeterID uint32
124 UpdateInProgress bool
125 DeleteInProgress bool
126 DeactivateInProgress bool
127 ForceDelete bool
vinokuma926cb3e2023-03-29 11:41:06 +0530128 // Multiservice-Fix
Naveen Sampath04696f72022-06-13 15:19:14 +0530129 UsHSIAFlowsApplied bool
130 DsHSIAFlowsApplied bool
131 UsDhcpFlowsApplied bool
132 DsDhcpFlowsApplied bool
133 IgmpFlowsApplied bool
134 Icmpv6FlowsApplied bool
Naveen Sampath04696f72022-06-13 15:19:14 +0530135}
136
137// VoltService structure
138type VoltService struct {
Naveen Sampath04696f72022-06-13 15:19:14 +0530139 VoltServiceOper
140 Version string
vinokuma926cb3e2023-03-29 11:41:06 +0530141 VoltServiceCfg
Naveen Sampath04696f72022-06-13 15:19:14 +0530142}
143
vinokuma926cb3e2023-03-29 11:41:06 +0530144// ServiceTrigger - Service activation trigger
Naveen Sampath04696f72022-06-13 15:19:14 +0530145type ServiceTrigger int
146
147const (
vinokuma926cb3e2023-03-29 11:41:06 +0530148 // NBActivate - Service added due to NB Action
Naveen Sampath04696f72022-06-13 15:19:14 +0530149 NBActivate ServiceTrigger = 0
vinokuma926cb3e2023-03-29 11:41:06 +0530150 // ServiceVlanUpdate - Service added due to Svlan Update
Naveen Sampath04696f72022-06-13 15:19:14 +0530151 ServiceVlanUpdate ServiceTrigger = 1
152)
153
154// AppMutexes structure
155type AppMutexes struct {
156 ServiceDataMutex sync.Mutex `json:"-"`
157 VnetMutex sync.Mutex `json:"-"`
158}
159
vinokuma926cb3e2023-03-29 11:41:06 +0530160// MigrateServiceMetadata - migrate services request metadata
Naveen Sampath04696f72022-06-13 15:19:14 +0530161type MigrateServiceMetadata struct {
162 NewVnetID string
163 RequestID string
164}
165
166// AppMutex variable
167var AppMutex AppMutexes
168
169// NewVoltService for constructor for volt service
170func NewVoltService(cfg *VoltServiceCfg) *VoltService {
171 var vs VoltService
172 vs.VoltServiceCfg = *cfg
173 vs.UsHSIAFlowsApplied = false
174 vs.DsHSIAFlowsApplied = false
175 vs.DeleteInProgress = false
Hitesh Chhabra64be2442023-06-21 17:06:34 +0530176 vs.DeactivateInProgress = false
Naveen Sampath04696f72022-06-13 15:19:14 +0530177 //vs.MacAddr, _ = net.ParseMAC("00:00:00:00:00:00")
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +0530178 vs.IsOption82Enabled = cfg.IsOption82Enabled
Naveen Sampath04696f72022-06-13 15:19:14 +0530179 vs.MacAddr = cfg.MacAddr
180 vs.Ipv4Addr = net.ParseIP("0.0.0.0")
181 vs.Ipv6Addr = net.ParseIP("::")
182 vs.PendingFlows = make(map[string]bool)
183 vs.AssociatedFlows = make(map[string]bool)
184 return &vs
185}
186
187// WriteToDb commit a service to the DB if service delete is not in-progress
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530188func (vs *VoltService) WriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530189 vs.ServiceLock.RLock()
190 defer vs.ServiceLock.RUnlock()
191
192 if vs.DeleteInProgress {
193 logger.Warnw(ctx, "Skipping Redis Update for Service, Service delete in progress", log.Fields{"Service": vs.Name})
194 return
195 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530196 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530197}
198
vinokuma926cb3e2023-03-29 11:41:06 +0530199// ForceWriteToDb force commit a service to the DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530200func (vs *VoltService) ForceWriteToDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530201 b, err := json.Marshal(vs)
202
203 if err != nil {
204 logger.Errorw(ctx, "Json Marshal Failed for Service", log.Fields{"Service": vs.Name})
205 return
206 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530207 if err1 := db.PutService(cntx, vs.Name, string(b)); err1 != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530208 logger.Errorw(ctx, "DB write oper failed for Service", log.Fields{"Service": vs.Name})
209 }
210}
211
212// isDataRateAttrPresent to check if data attribute is present
213func (vs *VoltService) isDataRateAttrPresent() bool {
214 return vs.DataRateAttr == DSLAttrEnabled
215}
216
217// DelFromDb delete a service from DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530218func (vs *VoltService) DelFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530219 logger.Debugw(ctx, "Deleting Service from DB", log.Fields{"Name": vs.Name})
vinokuma926cb3e2023-03-29 11:41:06 +0530220 // TODO - Need to understand and delete the second call
221 // Calling twice has worked though don't know why
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530222 _ = db.DelService(cntx, vs.Name)
223 _ = db.DelService(cntx, vs.Name)
Naveen Sampath04696f72022-06-13 15:19:14 +0530224}
225
226// MatchesVlans find the service that matches the VLANs. In this case it is
227// purely based on CVLAN. The CVLAN can sufficiently be used to
228// match a service
229func (vs *VoltService) MatchesVlans(vlans []of.VlanType) bool {
230 if len(vlans) != 1 {
231 return false
232 }
233
234 if vlans[0] == vs.CVlan {
235 return true
236 }
237 return false
238}
239
240// MatchesPbits allows matching a service to a pbit. This is used
241// to search for a service matching the pbits, typically to identify
242// attributes for other flows such as DHCP, IGMP, etc.
243func (vs *VoltService) MatchesPbits(pbits []of.PbitType) bool {
244 for _, pbit := range pbits {
245 for _, pb := range vs.Pbits {
246 if pb == pbit {
247 return true
248 }
249 }
250 }
251 return false
252}
253
254// IsPbitExist allows matching a service to a pbit. This is used
255// to search for a service matching the pbit
256func (vs *VoltService) IsPbitExist(pbit of.PbitType) bool {
257 for _, pb := range vs.Pbits {
258 if pb == pbit {
259 return true
260 }
261 }
262 return false
263}
264
265// AddHsiaFlows - Adds US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530266func (vs *VoltService) AddHsiaFlows(cntx context.Context) {
267 if err := vs.AddUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530268 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
269 vs.triggerServiceFailureInd(statusCode, statusMessage)
270 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530271 if err := vs.AddDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530272 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
273 vs.triggerServiceFailureInd(statusCode, statusMessage)
274 }
275}
276
vinokuma926cb3e2023-03-29 11:41:06 +0530277// DelHsiaFlows - Deletes US & DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530278func (vs *VoltService) DelHsiaFlows(cntx context.Context) {
279 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530280 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
281 vs.triggerServiceFailureInd(statusCode, statusMessage)
282 }
283
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530284 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530285 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
286 vs.triggerServiceFailureInd(statusCode, statusMessage)
287 }
288}
289
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530290func (vs *VoltService) AddMeterToDevice(cntx context.Context) error {
291 if vs.DeleteInProgress || vs.UpdateInProgress {
292 logger.Errorw(ctx, "Ignoring Meter Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
293 }
294 va := GetApplication()
295 logger.Infow(ctx, "Configuring Meters for FTTB", log.Fields{"ServiceName": vs.Name})
296 device, err := va.GetDeviceFromPort(vs.Port)
297 if err != nil {
298 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
299 return errorCodes.ErrDeviceNotFound
300 } else if device.State != controller.DeviceStateUP {
301 logger.Warnw(ctx, "Device state Down. Ignoring Meter Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
302 return nil
303 }
304 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
305 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
306 return nil
307}
308
Naveen Sampath04696f72022-06-13 15:19:14 +0530309// AddUsHsiaFlows - Add US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530310func (vs *VoltService) AddUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530311 if vs.DeleteInProgress || vs.UpdateInProgress {
312 logger.Errorw(ctx, "Ignoring US HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
313 return nil
314 }
315
316 va := GetApplication()
317 logger.Infow(ctx, "Configuring US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
318 if !vs.UsHSIAFlowsApplied || vgcRebooted {
319 device, err := va.GetDeviceFromPort(vs.Port)
320 if err != nil {
321 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
322 return errorCodes.ErrDeviceNotFound
323 } else if device.State != controller.DeviceStateUP {
324 logger.Warnw(ctx, "Device state Down. Ignoring US HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
325 return nil
326 }
327
328 vs.Device = device.Name
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530329 /* In case of DPU_MGMT_TRAFFIC the meters will be configured before US flow creation*/
vinokuma926cb3e2023-03-29 11:41:06 +0530330 if vs.ServiceType != DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530331 va.AddMeterToDevice(vs.Port, device.Name, vs.UsMeterID, 0)
332 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
333 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530334 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
335 pBits := vs.Pbits
336
vinokuma926cb3e2023-03-29 11:41:06 +0530337 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530338 if len(vs.Pbits) == 0 {
339 pBits = append(pBits, PbitMatchNone)
340 }
341 for _, pbits := range pBits {
342 usflows, err := vs.BuildUsHsiaFlows(pbits)
343 if err != nil {
344 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
345 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
346 vs.triggerServiceFailureInd(statusCode, statusMessage)
347 continue
348 }
349 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530350 if err := vs.AddFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530351 logger.Errorw(ctx, "Error adding HSIA US flows", log.Fields{"Reason": err.Error()})
352 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
353 vs.triggerServiceFailureInd(statusCode, statusMessage)
354 }
355 }
356 vs.UsHSIAFlowsApplied = true
357 logger.Infow(ctx, "Pushed US HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
358 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530359 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530360 return nil
361}
362
363// AddDsHsiaFlows - Add DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530364func (vs *VoltService) AddDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530365 if vs.DeleteInProgress {
366 logger.Errorw(ctx, "Ignoring DS HSIA Flow Push, Service deleteion In-Progress", log.Fields{"Device": vs.Device, "Service": vs.Name})
367 return nil
368 }
369
370 va := GetApplication()
371 logger.Infow(ctx, "Configuring DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
372 if !vs.DsHSIAFlowsApplied || vgcRebooted {
373 device, err := va.GetDeviceFromPort(vs.Port)
374 if err != nil {
375 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
376 return errorCodes.ErrDeviceNotFound
377 } else if device.State != controller.DeviceStateUP {
378 logger.Warnw(ctx, "Device state Down. Ignoring DS HSIA Flow Push", log.Fields{"Service": vs.Name, "Port": vs.Port})
379 return nil
380 }
381
382 va.AddMeterToDevice(vs.Port, device.Name, vs.DsMeterID, vs.AggDsMeterID)
383 logger.Infow(ctx, "Adding HSIA flows", log.Fields{"Name": vs.Name})
384
385 //If no pbits configured for service, hence add PbitNone for flows
386 if len(vs.DsRemarkPbitsMap) == 0 {
387 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchNone))
388 if err != nil {
389 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
390 return err
391 }
392 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530393 if err = vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530394 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
395 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
396 vs.triggerServiceFailureInd(statusCode, statusMessage)
397 }
398 } else {
399 // if all 8 p-bits are to be remarked to one-pbit, configure all-to-one remarking flow
400 if _, ok := vs.DsRemarkPbitsMap[int(of.PbitMatchAll)]; ok {
401 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(of.PbitMatchAll))
402 if err != nil {
403 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
404 return err
405 }
406 logger.Debug(ctx, "Add-one-match-all-pbit-flow")
407 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530408 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530409 logger.Errorw(ctx, "Failed to add HSIA DS flows", log.Fields{"Reason": err})
410 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
411 vs.triggerServiceFailureInd(statusCode, statusMessage)
412 }
413 } else {
414 for matchPbit := range vs.DsRemarkPbitsMap {
415 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
416 if err != nil {
417 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
418 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
419 vs.triggerServiceFailureInd(statusCode, statusMessage)
420 continue
421 }
422 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530423 if err := vs.AddFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530424 logger.Errorw(ctx, "Failed to Add HSIA DS flows", log.Fields{"Reason": err})
425 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
426 vs.triggerServiceFailureInd(statusCode, statusMessage)
427 }
428 }
429 }
430 }
431 vs.DsHSIAFlowsApplied = true
432 logger.Infow(ctx, "Pushed DS HSIA Service Flows", log.Fields{"ServiceName": vs.Name})
433 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530434 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530435 return nil
436}
437
438// DelUsHsiaFlows - Deletes US HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530439func (vs *VoltService) DelUsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530440 logger.Infow(ctx, "Removing US HSIA Services", log.Fields{"Services": vs.Name})
441 if vs.UsHSIAFlowsApplied || vgcRebooted {
442 device, err := GetApplication().GetDeviceFromPort(vs.Port)
443 if err != nil {
444 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
445 return errorCodes.ErrDeviceNotFound
446 }
447
448 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
449 pBits := vs.Pbits
450
vinokuma926cb3e2023-03-29 11:41:06 +0530451 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530452 if len(vs.Pbits) == 0 {
453 pBits = append(pBits, PbitMatchNone)
454 }
455 for _, pbits := range pBits {
456 usflows, err := vs.BuildUsHsiaFlows(pbits)
457 if err != nil {
458 logger.Errorw(ctx, "Error Building HSIA US flows", log.Fields{"Reason": err.Error()})
459 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
460 vs.triggerServiceFailureInd(statusCode, statusMessage)
461 continue
462 }
463 usflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530464 if err = vs.DelFlows(cntx, device, usflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530465 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
466 vs.triggerServiceFailureInd(statusCode, statusMessage)
467 }
468 }
469 vs.UsHSIAFlowsApplied = false
470 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530471 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530472 return nil
473}
474
475// DelDsHsiaFlows - Deletes DS HSIA Flows for the service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530476func (vs *VoltService) DelDsHsiaFlows(cntx context.Context) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530477 logger.Infow(ctx, "Removing DS HSIA Services", log.Fields{"Services": vs.Name})
478 if vs.DsHSIAFlowsApplied || vgcRebooted {
479 device, err := GetApplication().GetDeviceFromPort(vs.Port)
480 if err != nil {
481 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error()})
482 return errorCodes.ErrDeviceNotFound
483 }
484
485 logger.Infow(ctx, "Removing HSIA flows", log.Fields{"Name": vs.Name})
486 var matchPbit int
vinokuma926cb3e2023-03-29 11:41:06 +0530487 // If no pbits configured for service, hence add PbitNone for flows
Naveen Sampath04696f72022-06-13 15:19:14 +0530488 if len(vs.DsRemarkPbitsMap) == 0 {
489 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(PbitMatchNone))
490 if err != nil {
491 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
492 return err
493 }
494 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530495 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530496 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
497 vs.triggerServiceFailureInd(statusCode, statusMessage)
498 }
499 } else if _, ok := vs.DsRemarkPbitsMap[int(PbitMatchAll)]; ok {
500 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(int(PbitMatchAll)))
501 if err != nil {
502 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
503 return err
504 }
505 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530506 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530507 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
508 vs.triggerServiceFailureInd(statusCode, statusMessage)
509 }
510 } else {
511 for matchPbit = range vs.DsRemarkPbitsMap {
512 dsflows, err := vs.BuildDsHsiaFlows(of.PbitType(matchPbit))
513 if err != nil {
514 logger.Errorw(ctx, "Error Building HSIA DS flows", log.Fields{"Reason": err.Error()})
515 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
516 vs.triggerServiceFailureInd(statusCode, statusMessage)
517 continue
518 }
519 dsflows.MigrateCookie = vgcRebooted
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530520 if err = vs.DelFlows(cntx, device, dsflows); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +0530521 statusCode, statusMessage := infraerrorCodes.GetErrorInfo(err)
522 vs.triggerServiceFailureInd(statusCode, statusMessage)
523 }
524 }
525 }
526 vs.DsHSIAFlowsApplied = false
527 }
vinokuma926cb3e2023-03-29 11:41:06 +0530528 logger.Infow(ctx, "Deleted HSIA DS flows from DB successfully", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +0530529 // Post HSIA configuration success indication on message bus
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530530 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530531 return nil
532}
533
534// BuildDsHsiaFlows build the DS HSIA flows
535// Called for add/delete HSIA flows
536func (vs *VoltService) BuildDsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
537 flow := &of.VoltFlow{}
538 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
539
540 // Get the out and in ports for the flows
541 device, err := GetApplication().GetDeviceFromPort(vs.Port)
542 if err != nil {
543 return nil, errorCodes.ErrDeviceNotFound
544 }
545 inport, _ := GetApplication().GetPortID(device.NniPort)
546 outport, _ := GetApplication().GetPortID(vs.Port)
547 // PortName and PortID to be used for validation of port before flow pushing
548 flow.PortID = outport
549 flow.PortName = vs.Port
550 allowTransparent := 0
551 if vs.AllowTransparent {
552 allowTransparent = 1
553 }
554
555 // initialized actnPbit to 0 for cookie genration backward compatibility.
556 var actnPbit of.PbitType
557 remarkPbit, remarkExists := vs.DsRemarkPbitsMap[int(pbits)]
558
559 generateDSCookie := func(vlan of.VlanType, valToShift uint64) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530560 // | 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 +0530561 cookie := uint64(vlan)<<52 + uint64(actnPbit)<<48 + uint64(outport)<<16 | of.HsiaFlowMask
562 cookie = cookie | of.DsFlowMask
563 cookie = cookie + (valToShift << 4) + uint64(pbits)
564 return cookie
565 }
566
567 l2ProtoValue, err := GetMetadataForL2Protocol(vs.SVlanTpid)
568 if err != nil {
569 logger.Errorw(ctx, "DS HSIA flow push failed: Invalid SvlanTpid", log.Fields{"SvlanTpid": vs.SVlanTpid, "Service": vs.Name})
570 return nil, err
571 }
572
573 // Add Table-0 flow that deals with the outer VLAN in pOLT
574 {
575 subflow1 := of.NewVoltSubFlow()
576 subflow1.SetTableID(0)
577 subflow1.SetGoToTable(1)
578 subflow1.SetInPort(inport)
579
580 if pbits != PbitMatchNone {
581 subflow1.SetMatchPbit(pbits)
582 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530583 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
584 subflow1.SetPcp(of.PbitType(remarkPbit))
585 // match & action pbits are different, set remark-pbit action
586 actnPbit = of.PbitType(remarkPbit)
587 // mask remark p-bit to 4bits
588 actnPbit = actnPbit & 0x0F
589 }
590
591 if err := vs.setDSMatchActionVlanT0(subflow1); err != nil {
592 return nil, err
593 }
Tinoj Joseph1d108322022-07-13 10:07:39 +0530594 logger.Infow(ctx, "HSIA DS flows MAC Learning & MAC", log.Fields{"ML": vs.MacLearning, "Mac": vs.MacAddr})
Naveen Sampath04696f72022-06-13 15:19:14 +0530595 if NonZeroMacAddress(vs.MacAddr) {
596 subflow1.SetMatchDstMac(vs.MacAddr)
597 }
598 subflow1.Priority = of.HsiaFlowPriority
599 subflow1.SetMeterID(vs.DsMeterID)
600
601 /* WriteMetaData 8 Byte(uint64) usage:
602 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
603 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
604 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530605 if vs.ServiceType == FttbSubscriberTraffic {
606 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
607 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530608 subflow1.SetWriteMetadata(metadata)
609
610 /* TableMetaData 8 Byte(uint64) Voltha usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
611 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
612 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
613 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | unitag | unitag | ctag | ctag | */
614
615 //TODO-COMM:
616 /* TableMetaData 8 Byte(uint64) Community usage: (Considering MSB bit as 63rd bit and LSB bit as 0th bit)
617 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
618 | 0000 | 00 | 0 | 0 | 00000000 | 00000000 | 0000 0000 | 00000000 | 00000000 | 00000000 | 00000000|
619 | reserved | svlanTpID | Buff us | AT | schedID | schedID | onteth vlanCtrl | ctag | ctag | ctag | ctag | */
620
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530621 if vs.ServiceType != FttbSubscriberTraffic {
622 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
623 subflow1.SetTableMetadata(metadata)
624 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530625 // TODO - We are using cookie as key and must come up with better cookie
626 // allocation algorithm
627 /**
628 * Cokies may clash when -
629 * on same uni-port we have two sub-service
630 * 1. U=10, C=100, S=310, p-bit=4 - VLAN_Control = OLT_CVLAN_OLT_SVLAN
631 * 2. U=10, C=10, S=320, p-bit=4 - VLAN_control = ONU_CVLAN_ONU_SVLAN
632 * However, this p-bit re-use will not be allowed by sub-mgr.
633 */
634 if vs.VlanControl == OLTCVlanOLTSVlan {
635 /**
636 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
637 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
638 * use old cookie.
639 */
640 subflow1.Cookie = generateDSCookie(vs.UniVlan, 0)
641 if vgcRebooted {
642 subflow1.OldCookie = generateDSCookie(vs.CVlan, 0)
643 }
644 } else {
645 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
646 subflow1.Cookie = generateDSCookie(vs.CVlan, 0)
647 }
648
649 flow.SubFlows[subflow1.Cookie] = subflow1
650 logger.Infow(ctx, "Building downstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie,
651 "subflow": subflow1})
652 }
653
vinokuma926cb3e2023-03-29 11:41:06 +0530654 // Add Table-1 flow that deals with inner VLAN at the ONU
Naveen Sampath04696f72022-06-13 15:19:14 +0530655 {
656 subflow2 := of.NewVoltSubFlow()
657 subflow2.SetTableID(1)
658 subflow2.SetInPort(inport)
659 if NonZeroMacAddress(vs.MacAddr) {
660 subflow2.SetMatchDstMac(vs.MacAddr)
661 }
662
663 if err := vs.setDSMatchActionVlanT1(subflow2); err != nil {
664 return nil, err
665 }
666 if pbits != PbitMatchNone {
667 subflow2.SetMatchPbit(pbits)
668 }
669
670 if remarkExists && (of.PbitType(remarkPbit) != pbits) {
671 subflow2.SetPcp(of.PbitType(remarkPbit))
672 }
673
674 subflow2.SetOutPort(outport)
675 subflow2.SetMeterID(vs.DsMeterID)
676
677 // refer Table-0 flow generation for byte information
678 metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530679 if vs.ServiceType == FttbSubscriberTraffic {
680 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
681 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530682 subflow2.SetWriteMetadata(metadata)
683
684 // Table-1 and inport is NNI: It is a DS flow for ONU, add uniport in metadata to make it unique
685 if util.IsNniPort(inport) {
686 metadata = uint64(outport)
687 } else {
688 // refer Table-0 flow generation for byte information
689 metadata = uint64(l2ProtoValue)<<58 | uint64(allowTransparent)<<56 | uint64(vs.SchedID)<<40 | uint64(vs.ONTEtherTypeClassification)<<36 | uint64(vs.VlanControl)<<32 | uint64(vs.CVlan)
690 }
691 subflow2.SetTableMetadata(metadata)
692 // Setting of Cookie - TODO - Improve the allocation algorithm
693 if vs.VlanControl == OLTCVlanOLTSVlan {
694 /**
695 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
696 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
697 * use old cookie.
698 */
699 subflow2.Cookie = generateDSCookie(vs.UniVlan, 1)
700 if vgcRebooted {
701 subflow2.OldCookie = generateDSCookie(vs.CVlan, 1)
702 }
703 } else {
704 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
705 subflow2.Cookie = generateDSCookie(vs.CVlan, 1)
706 }
707
708 subflow2.Priority = of.HsiaFlowPriority
709 flow.SubFlows[subflow2.Cookie] = subflow2
710 logger.Infow(ctx, "Building downstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie,
711 "subflow": subflow2})
712 }
713
714 return flow, nil
715}
716
717// BuildUsHsiaFlows build the US HSIA flows
718// Called for add/delete HSIA flows
719func (vs *VoltService) BuildUsHsiaFlows(pbits of.PbitType) (*of.VoltFlow, error) {
720 flow := &of.VoltFlow{}
721 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
722
723 // Get the out and in ports for the flows
724 device, err := GetApplication().GetDeviceFromPort(vs.Port)
725 if err != nil {
726 return nil, errorCodes.ErrDeviceNotFound
727 }
728 outport, _ := GetApplication().GetPortID(device.NniPort)
729 inport, _ := GetApplication().GetPortID(vs.Port)
730 // PortName and PortID to be used for validation of port before flow pushing
731 flow.PortID = inport
732 flow.PortName = vs.Port
Naveen Sampath04696f72022-06-13 15:19:14 +0530733
734 // Add Table-0 flow that deals with the inner VLAN in ONU
735 {
736 subflow1 := of.NewVoltSubFlow()
737 subflow1.SetTableID(0)
738 subflow1.SetGoToTable(1)
739 subflow1.SetInPort(inport)
740
vinokuma926cb3e2023-03-29 11:41:06 +0530741 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530742 subflow1.SetMatchPbit(vs.UsPonCTagPriority)
743 subflow1.SetPcp(vs.UsPonSTagPriority)
vinokuma926cb3e2023-03-29 11:41:06 +0530744 } else if vs.ServiceType == DpuAncpTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530745 subflow1.SetPcp(vs.UsPonSTagPriority)
746 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530747 if err := vs.setUSMatchActionVlanT0(subflow1); err != nil {
748 return nil, err
749 }
750 subflow1.SetMeterID(vs.UsMeterID)
751
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530752 /* WriteMetaData 8 Byte(uint64) usage:
753 | Byte8 | Byte7 | Byte6 | Byte5 | Byte4 | Byte3 | Byte2 | Byte1 |
754 | reserved | reserved | TpID | TpID | uinID | uniID | uniID | uniID | */
755 //metadata := uint64(vs.CVlan)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
756 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530757 if vs.ServiceType == FttbSubscriberTraffic {
758 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
759 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530760 subflow1.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530761
Naveen Sampath04696f72022-06-13 15:19:14 +0530762 if vs.VlanControl == OLTCVlanOLTSVlan {
763 /**
764 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
765 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
766 * use old cookie.
767 */
768 subflow1.Cookie = vs.generateUSCookie(vs.UniVlan, 0, inport, pbits)
769 if vgcRebooted {
770 subflow1.OldCookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
771 }
772 } else {
773 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
774 subflow1.Cookie = vs.generateUSCookie(vs.CVlan, 0, inport, pbits)
775 }
776 subflow1.Priority = of.HsiaFlowPriority
777 flow.SubFlows[subflow1.Cookie] = subflow1
778 logger.Infow(ctx, "Building upstream HSIA flow for T0", log.Fields{"cookie": subflow1.Cookie, "subflow": subflow1})
779 }
780
vinokuma926cb3e2023-03-29 11:41:06 +0530781 // Add Table-1 flow that deals with the outer vlan in pOLT
Naveen Sampath04696f72022-06-13 15:19:14 +0530782 {
783 subflow2 := of.NewVoltSubFlow()
784 subflow2.SetTableID(1)
785 subflow2.SetInPort(inport)
786
Naveen Sampath04696f72022-06-13 15:19:14 +0530787 if err := vs.setUSMatchActionVlanT1(subflow2); err != nil {
788 return nil, err
789 }
vinokuma926cb3e2023-03-29 11:41:06 +0530790 if vs.ServiceType == DpuMgmtTraffic {
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530791 subflow2.SetMatchSrcMac(vs.MacAddr)
792 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530793 subflow2.SetInPort(inport)
794 subflow2.SetOutPort(outport)
795 subflow2.SetMeterID(vs.UsMeterID)
796
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530797 // refer Table-0 flow generation for byte information
798 metadata := uint64(vs.TechProfileID)<<32 + uint64(outport)
Sridhar Ravindrab8374ae2023-04-14 15:49:25 +0530799 if vs.ServiceType == FttbSubscriberTraffic {
800 metadata = uint64(of.VlanAny)<<48 + uint64(vs.TechProfileID)<<32 + uint64(outport)
801 }
Tinoj Joseph50d722c2022-12-06 22:53:22 +0530802 subflow2.SetWriteMetadata(metadata)
Naveen Sampath04696f72022-06-13 15:19:14 +0530803
Naveen Sampath04696f72022-06-13 15:19:14 +0530804 if vs.VlanControl == OLTCVlanOLTSVlan {
805 /**
806 * The new cookie generation is only for OLT_CVLAN_OLT_SVLAN case (TEF residential case) within a UNI.
807 * After vgc upgrade, if we have to deactivate an already existing TEF residential service, then we have to
808 * use old cookie.
809 */
810 subflow2.Cookie = vs.generateUSCookie(vs.UniVlan, 1, inport, pbits)
811 if vgcRebooted {
812 subflow2.OldCookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
813 }
814 } else {
815 // In case of Olt_Svlan , CVLAN=UNIVLAN so cookie can be constructed with CVLAN as well
816 subflow2.Cookie = vs.generateUSCookie(vs.CVlan, 1, inport, pbits)
817 }
818 subflow2.Priority = of.HsiaFlowPriority
819
820 flow.SubFlows[subflow2.Cookie] = subflow2
821 logger.Infow(ctx, "Building upstream HSIA flow for T1", log.Fields{"cookie": subflow2.Cookie, "subflow": subflow2})
822 }
823
824 return flow, nil
825}
826
827func (vs *VoltService) generateUSCookie(vlan of.VlanType, valToShift uint64, inport uint32, pbits of.PbitType) uint64 {
vinokuma926cb3e2023-03-29 11:41:06 +0530828 // | 12-bit cvlan/UniVlan | 4 bits empty | <32-bits uniport>| 16-bits HSIA mask OR flow mask OR pbit |
Naveen Sampath04696f72022-06-13 15:19:14 +0530829 cookie := uint64(vlan)<<52 + uint64(inport)<<16 | of.HsiaFlowMask
830 cookie = cookie | of.UsFlowMask
831 cookie = cookie + (valToShift << 4) + uint64(pbits)
832 return cookie
833}
834
835// setUSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for US Table-1
836// based on different Vlan Controls
837func (vs *VoltService) setUSMatchActionVlanT1(flow *of.VoltSubFlow) error {
838 switch vs.VlanControl {
839 case None:
840 flow.SetMatchVlan(vs.SVlan)
841 case ONUCVlanOLTSVlan:
842 flow.SetMatchVlan(vs.CVlan)
843 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
844 case OLTCVlanOLTSVlan:
845 flow.SetMatchVlan(vs.UniVlan)
846 flow.SetSetVlan(vs.CVlan)
847 flow.SetPushVlan(vs.SVlan, vs.SVlanTpid)
848 case ONUCVlan:
849 flow.SetMatchVlan(vs.SVlan)
850 case OLTSVlan:
851 if vs.UniVlan != of.VlanAny && vs.UniVlan != of.VlanNone {
852 flow.SetMatchVlan(vs.UniVlan)
853 flow.SetSetVlan(vs.SVlan)
854 } else if vs.UniVlan != of.VlanNone {
855 flow.SetMatchVlan(vs.UniVlan)
856 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
857 } else {
858 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
859 }
860 default:
861 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
862 return errorCodes.ErrInvalidParamInRequest
863 }
864 return nil
865}
866
867// setDSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for DS Table-0
868// based on different Vlan Controls
869func (vs *VoltService) setDSMatchActionVlanT0(flow *of.VoltSubFlow) error {
870 switch vs.VlanControl {
871 case None:
872 flow.SetMatchVlan(vs.SVlan)
873 case ONUCVlanOLTSVlan:
874 flow.SetMatchVlan(vs.SVlan)
875 flow.SetPopVlan()
876 case OLTCVlanOLTSVlan:
877 flow.SetMatchVlan(vs.SVlan)
878 flow.SetPopVlan()
879 flow.SetSetVlan(vs.UniVlan)
880 case ONUCVlan:
881 flow.SetMatchVlan(vs.SVlan)
882 case OLTSVlan:
883 flow.SetMatchVlan(vs.SVlan)
884 if vs.UniVlan != of.VlanNone && vs.UniVlan != of.VlanAny {
885 flow.SetSetVlan(vs.UniVlan)
886 } else {
887 flow.SetPopVlan()
888 }
889 default:
890 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
891 return errorCodes.ErrInvalidParamInRequest
892 }
893 return nil
894}
895
896// setUSMatchActionVlanT0 - Sets the Match & Action w.r.t Vlans for US Table-0
897// based on different Vlan Controls
898func (vs *VoltService) setUSMatchActionVlanT0(flow *of.VoltSubFlow) error {
899 switch vs.VlanControl {
900 case None:
901 flow.SetMatchVlan(vs.SVlan)
902 case ONUCVlanOLTSVlan:
903 if vs.UniVlan != of.VlanNone {
904 flow.SetMatchVlan(vs.UniVlan)
905 flow.SetSetVlan(vs.CVlan)
906 } else {
907 flow.SetPushVlan(vs.CVlan, layers.EthernetTypeDot1Q)
908 }
909 case OLTCVlanOLTSVlan:
910 flow.SetMatchVlan(vs.UniVlan)
911 case ONUCVlan:
912 if vs.UniVlan != of.VlanNone {
913 flow.SetMatchVlan(vs.UniVlan)
914 flow.SetSetVlan(vs.SVlan)
915 } else {
916 flow.SetPushVlan(vs.SVlan, layers.EthernetTypeDot1Q)
917 }
918 case OLTSVlan:
919 flow.SetMatchVlan(vs.UniVlan)
920 default:
921 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
922 return errorCodes.ErrInvalidParamInRequest
923 }
924 return nil
925}
926
927// setDSMatchActionVlanT1 - Sets the Match & Action w.r.t Vlans for DS Table-1
928// based on different Vlan Controls
929func (vs *VoltService) setDSMatchActionVlanT1(flow *of.VoltSubFlow) error {
930 switch vs.VlanControl {
931 case None:
932 flow.SetMatchVlan(vs.SVlan)
933 case ONUCVlanOLTSVlan:
934 flow.SetMatchVlan(vs.CVlan)
935 if vs.UniVlan != of.VlanNone {
936 flow.SetSetVlan(vs.UniVlan)
937 } else {
938 flow.SetPopVlan()
939 }
940 case OLTCVlanOLTSVlan:
941 flow.SetMatchVlan(vs.UniVlan)
942 case ONUCVlan:
943 flow.SetMatchVlan(vs.SVlan)
944 if vs.UniVlan != of.VlanNone {
945 flow.SetSetVlan(vs.UniVlan)
946 } else {
947 flow.SetPopVlan()
948 }
949 case OLTSVlan:
950 flow.SetMatchVlan(vs.UniVlan)
951 default:
952 logger.Errorw(ctx, "Invalid Vlan Control Option", log.Fields{"Value": vs.VlanControl})
953 return errorCodes.ErrInvalidParamInRequest
954 }
955 return nil
956}
957
958// SvcUpInd for service up indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530959func (vs *VoltService) SvcUpInd(cntx context.Context) {
960 vs.AddHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530961}
962
963// SvcDownInd for service down indication
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530964func (vs *VoltService) SvcDownInd(cntx context.Context) {
965 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +0530966}
967
968// SetIpv4Addr to set ipv4 address
969func (vs *VoltService) SetIpv4Addr(addr net.IP) {
970 vs.Ipv4Addr = addr
971}
972
973// SetIpv6Addr to set ipv6 address
974func (vs *VoltService) SetIpv6Addr(addr net.IP) {
975 vs.Ipv6Addr = addr
976}
977
978// SetMacAddr to set mac address
979func (vs *VoltService) SetMacAddr(addr net.HardwareAddr) {
980 vs.MacAddr = addr
981}
982
983// ----------------------------------------------
984// VOLT Application - Related to services
985// ---------------------------------------------
986// ---------------------------------------------------------------
987// Service CRUD functions. These are exposed to the overall binary
988// to be invoked from the point where the CRUD operations are received
989// from the external entities
990
991// AddService : A service in the context of VOLT is a subscriber or service of a
992// subscriber which is uniquely identified by a combination of MAC
993// address, VLAN tags, 802.1p bits. However, in the context of the
994// current implementation, a service is an entity that is identified by a
995// unique L2 (MAC address + VLANs) or unique L3 (VLANs + IP address)
996// FUNC: Add Service
Tinoj Joseph07cc5372022-07-18 22:53:51 +0530997func (va *VoltApplication) AddService(cntx context.Context, cfg VoltServiceCfg, oper *VoltServiceOper) error {
Naveen Sampath04696f72022-06-13 15:19:14 +0530998 var mmUs, mmDs *VoltMeter
999 var err error
1000
vinokuma926cb3e2023-03-29 11:41:06 +05301001 // Take the Device lock only in case of NB add request.
Naveen Sampath04696f72022-06-13 15:19:14 +05301002 // Allow internal adds since internal add happen only under
1003 // 1. Restore Service from DB
1004 // 2. Service Migration
1005 if oper == nil {
1006 if svc := va.GetService(cfg.Name); svc != nil {
1007 logger.Warnw(ctx, "Service Already Exists. Ignoring Add Service Request", log.Fields{"Name": cfg.Name})
1008 return errors.New("Service Already Exists")
1009 }
1010 }
1011
1012 logger.Infow(ctx, "Service to be configured", log.Fields{"Cfg": cfg})
1013 // Service doesn't exist. So create it and add to the port
1014 vs := NewVoltService(&cfg)
1015 if oper != nil {
1016 vs.UsHSIAFlowsApplied = oper.UsHSIAFlowsApplied
1017 vs.DsHSIAFlowsApplied = oper.DsHSIAFlowsApplied
1018 vs.Ipv4Addr = oper.Ipv4Addr
1019 vs.Ipv6Addr = oper.Ipv6Addr
1020 vs.MacLearning = cfg.MacLearning
1021 vs.PendingFlows = oper.PendingFlows
1022 vs.AssociatedFlows = oper.AssociatedFlows
1023 vs.DeleteInProgress = oper.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301024 vs.DeactivateInProgress = oper.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301025 vs.BwAvailInfo = oper.BwAvailInfo
1026 vs.Device = oper.Device
1027 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301028 // Sorting Pbit from highest
Naveen Sampath04696f72022-06-13 15:19:14 +05301029 sort.Slice(vs.Pbits, func(i, j int) bool {
1030 return vs.Pbits[i] > vs.Pbits[j]
1031 })
1032 logger.Infow(ctx, "Sorted Pbits", log.Fields{"Pbits": vs.Pbits})
1033 }
1034 logger.Infow(ctx, "VolthService...", log.Fields{"vs": vs.Name})
1035
1036 // The bandwidth and shaper profile combined into meter
1037 if mmDs, err = va.GetMeter(cfg.DsMeterProfile); err == nil {
1038 vs.DsMeterID = mmDs.ID
1039 } else {
1040 return errors.New("DownStream meter profile not found")
1041 }
1042
1043 // The aggregated downstream meter profile
1044 // if mmAg, err = va.GetMeter(cfg.AggDsMeterProfile); err == nil {
1045 // vs.AggDsMeterID = mmAg.ID
1046 // } else {
1047 // return errors.New("Aggregated meter profile not found")
1048 // }
1049
1050 // if cfg.AggDsMeterProfile == cfg.UsMeterProfile {
1051 // vs.UsMeterID = mmAg.ID
1052 // } else {
1053 // The bandwidth and shaper profile combined into meter
1054 if mmUs, err = va.GetMeter(cfg.UsMeterProfile); err == nil {
1055 vs.UsMeterID = mmUs.ID
1056 } else {
1057 return errors.New("Upstream meter profile not found")
1058 }
1059 //}
1060
1061 AppMutex.ServiceDataMutex.Lock()
1062 defer AppMutex.ServiceDataMutex.Unlock()
1063
1064 // Add the service to the VNET
1065 vnet := va.GetVnet(cfg.SVlan, cfg.CVlan, cfg.UniVlan)
1066 if vnet != nil {
1067 if vpv := va.GetVnetByPort(vs.Port, cfg.SVlan, cfg.CVlan, cfg.UniVlan); vpv != nil {
1068 vpv.VpvLock.Lock()
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301069 vpv.AddSvc(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301070 vpv.VpvLock.Unlock()
1071 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301072 va.AddVnetToPort(cntx, vs.Port, vnet, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301073 }
1074 } else {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301075 logger.Errorw(ctx, "VNET-does-not-exist-for-service", log.Fields{"ServiceName": cfg.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301076 return errors.New("VNET doesn't exist")
1077 }
1078
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301079 // If the device is already discovered, update the device name in service
1080 d, err := va.GetDeviceFromPort(vs.Port)
1081 if err == nil {
1082 vs.Device = d.Name
1083 }
1084
Naveen Sampath04696f72022-06-13 15:19:14 +05301085 vs.Version = database.PresentVersionMap[database.ServicePath]
1086 // Add the service to the volt application
1087 va.ServiceByName.Store(vs.Name, vs)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301088 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301089
1090 if nil == oper {
Naveen Sampath04696f72022-06-13 15:19:14 +05301091 if !vs.UsHSIAFlowsApplied {
1092 vs.triggerServiceInProgressInd()
1093 }
1094
vinokuma926cb3e2023-03-29 11:41:06 +05301095 // Update meter profiles service count if service is being added from northbound
Naveen Sampath04696f72022-06-13 15:19:14 +05301096 mmDs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301097 va.UpdateMeterProf(cntx, *mmDs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301098 if mmUs != nil {
1099 mmUs.AssociatedServices++
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301100 va.UpdateMeterProf(cntx, *mmUs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301101 }
1102 //mmAg.AssociatedServices++
1103 //va.UpdateMeterProf(*mmAg)
vinokuma926cb3e2023-03-29 11:41:06 +05301104 logger.Debugw(ctx, "northbound-service-add-successful", log.Fields{"ServiceName": vs.Name})
Naveen Sampath04696f72022-06-13 15:19:14 +05301105 }
1106
1107 logger.Warnw(ctx, "Added Service to DB", log.Fields{"Name": vs.Name, "Port": (vs.Port), "ML": vs.MacLearning})
1108 return nil
1109}
1110
vinokuma926cb3e2023-03-29 11:41:06 +05301111// DelServiceWithPrefix - Deletes service with the provided prefix.
Naveen Sampath04696f72022-06-13 15:19:14 +05301112// Added for DT/TT usecase with sadis replica interface
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301113func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) error {
1114 var isServiceExist bool
Naveen Sampath04696f72022-06-13 15:19:14 +05301115 va.ServiceByName.Range(func(key, value interface{}) bool {
1116 srvName := key.(string)
1117 vs := value.(*VoltService)
1118 if strings.Contains(srvName, prefix) {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301119 isServiceExist = true
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301120 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301121
1122 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1123 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1124 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1125
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301126 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301127 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1128 }
1129 }
1130 return true
1131 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05301132
1133 if !isServiceExist {
1134 return errorCodes.ErrServiceNotFound
1135 }
1136 return nil
Naveen Sampath04696f72022-06-13 15:19:14 +05301137}
1138
1139// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301140func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301141 AppMutex.ServiceDataMutex.Lock()
1142 defer AppMutex.ServiceDataMutex.Unlock()
1143
1144 logger.Warnw(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
1145 var noFlowsPresent bool
1146
1147 vsIntf, ok := va.ServiceByName.Load(name)
1148 if !ok {
1149 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1150 return
1151 }
1152 vs := vsIntf.(*VoltService)
1153 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1154 if vpv == nil {
1155 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
1156 return
1157 }
1158
vinokuma926cb3e2023-03-29 11:41:06 +05301159 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301160 vs.DeleteInProgress = true
1161 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301162 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301163
1164 if len(vs.AssociatedFlows) == 0 {
1165 noFlowsPresent = true
1166 }
1167 vpv.VpvLock.Lock()
1168 defer vpv.VpvLock.Unlock()
1169
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301170 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301171
1172 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301173 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301174 }
1175 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 +05301176 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301177 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301178 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301179 }
1180
1181 // Delete the service immediately in case of Force Delete
1182 // This will be enabled when profile reconciliation happens after restore
1183 // of backedup data
1184 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301185 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301186 GetApplication().ServiceByName.Delete(vs.Name)
1187 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1188 }
1189
Naveen Sampath04696f72022-06-13 15:19:14 +05301190 if nil != newSvc {
1191 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1192 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1193 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301194
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301195 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1196
1197 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1198 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301199 if aggMeter.AssociatedServices > 0 {
1200 aggMeter.AssociatedServices--
1201 logger.Infow(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
1202 va.UpdateMeterProf(cntx, *aggMeter)
1203 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301204 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301205 }
1206 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301207 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1208 if dsMeter.AssociatedServices > 0 {
1209 dsMeter.AssociatedServices--
1210 logger.Infow(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
1211 va.UpdateMeterProf(cntx, *dsMeter)
1212 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301213 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301214 }
1215 if vs.AggDsMeterID != vs.UsMeterID {
1216 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301217 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1218 if usMeter.AssociatedServices > 0 {
1219 usMeter.AssociatedServices--
1220 logger.Infow(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
1221 va.UpdateMeterProf(cntx, *usMeter)
1222 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301223 }
1224 }
1225 }
1226
1227 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301228 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301229 }
1230
vinokuma926cb3e2023-03-29 11:41:06 +05301231 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301232 va.ServiceCounters.Delete(name)
1233 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301234 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301235 }
1236}
1237
vinokuma926cb3e2023-03-29 11:41:06 +05301238// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301239// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301240func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301241 // Using locks instead of concurrent map for PendingFlows to avoid
1242 // race condition during flow response indication processing
1243 vs.ServiceLock.Lock()
1244 defer vs.ServiceLock.Unlock()
1245
1246 for cookie := range flow.SubFlows {
1247 cookie := strconv.FormatUint(cookie, 10)
1248 fe := &FlowEvent{
1249 eType: EventTypeServiceFlowAdded,
1250 device: device.Name,
1251 cookie: cookie,
1252 eventData: vs,
1253 }
1254 device.RegisterFlowAddEvent(cookie, fe)
1255 vs.PendingFlows[cookie] = true
1256 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301257 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301258}
1259
vinokuma926cb3e2023-03-29 11:41:06 +05301260// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301261// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301262func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301263 if vs.DeleteInProgress {
1264 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1265 return
1266 }
1267 vs.ServiceLock.Lock()
1268
1269 if _, ok := vs.PendingFlows[cookie]; !ok {
1270 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1271 vs.ServiceLock.Unlock()
1272 return
1273 }
1274
1275 delete(vs.PendingFlows, cookie)
1276 vs.AssociatedFlows[cookie] = true
1277 vs.ServiceLock.Unlock()
1278 var prevBwAvail, presentBwAvail string
1279 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1280 prevBwAvail = bwAvailInfo.PrevBw
1281 presentBwAvail = bwAvailInfo.PresentBw
1282 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301283 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301284 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301285 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301286
1287 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301288 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1289 if err != nil {
1290 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1291 return
1292 } else if device.State != controller.DeviceStateUP {
1293 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1294 return
1295 }
1296
1297 if vs.Trigger == ServiceVlanUpdate {
1298 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301299 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301300 }
1301 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1302 return
1303 }
1304 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1305}
1306
vinokuma926cb3e2023-03-29 11:41:06 +05301307// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301308// Trigger service failure indication to NB
1309func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1310 vs.ServiceLock.RLock()
1311
1312 if _, ok := vs.PendingFlows[cookie]; !ok {
1313 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1314 vs.ServiceLock.RUnlock()
1315 return
1316 }
1317 vs.ServiceLock.RUnlock()
1318 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1319 vs.triggerServiceFailureInd(errorCode, errReason)
1320}
1321
vinokuma926cb3e2023-03-29 11:41:06 +05301322// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301323// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301324func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301325 if !vs.ForceDelete {
1326 // Using locks instead of concurrent map for AssociatedFlows to avoid
1327 // race condition during flow response indication processing
1328 vs.ServiceLock.Lock()
1329 defer vs.ServiceLock.Unlock()
1330
1331 for cookie := range flow.SubFlows {
1332 cookie := strconv.FormatUint(cookie, 10)
1333 fe := &FlowEvent{
1334 eType: EventTypeServiceFlowRemoved,
1335 cookie: cookie,
1336 eventData: vs,
1337 }
1338 device.RegisterFlowDelEvent(cookie, fe)
1339 }
1340 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301341 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301342}
1343
vinokuma926cb3e2023-03-29 11:41:06 +05301344// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301345func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301346 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301347 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301348 GetApplication().ServiceByName.Delete(vs.Name)
1349 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1350 }
1351}
1352
vinokuma926cb3e2023-03-29 11:41:06 +05301353// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301354// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301355func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301356 // if vs.DeleteInProgress {
1357 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1358 // return
1359 // }
1360 vs.ServiceLock.Lock()
1361 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1362
1363 if _, ok := vs.AssociatedFlows[cookie]; ok {
1364 delete(vs.AssociatedFlows, cookie)
1365 } else if _, ok := vs.PendingFlows[cookie]; ok {
1366 logger.Errorw(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})
1367 } else {
1368 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1369 }
1370
1371 vs.ServiceLock.Unlock()
1372
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301373 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301374
1375 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301376 device := GetApplication().GetDevice(vs.Device)
1377 if device == nil {
1378 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1379 return
1380 } else if device.State != controller.DeviceStateUP {
1381 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1382 return
1383 }
1384
1385 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301386 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301387 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301388 return
1389 }
1390 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 +05301391 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301392
1393 return
1394 }
1395 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1396}
1397
vinokuma926cb3e2023-03-29 11:41:06 +05301398// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301399// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301400func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301401 vs.ServiceLock.RLock()
1402
1403 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1404 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1405 vs.ServiceLock.RUnlock()
1406 return
1407 }
1408 if vs.DeleteInProgress {
1409 delete(vs.AssociatedFlows, cookie)
1410 }
1411 vs.ServiceLock.RUnlock()
1412 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1413
1414 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301415 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301416}
1417
1418func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1419 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1420 if err != nil {
1421 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1422 return
1423 } else if device.State != controller.DeviceStateUP {
1424 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1425 return
1426 }
1427}
1428
1429// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301430func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301431 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301432 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301433 for _, vs := range vss {
1434 b, ok := vs.Value.([]byte)
1435 if !ok {
1436 logger.Warn(ctx, "The value type is not []byte")
1437 continue
1438 }
1439 var vvs VoltService
1440 err := json.Unmarshal(b, &vvs)
1441 if err != nil {
1442 logger.Warn(ctx, "Unmarshal of VNET failed")
1443 continue
1444 }
1445 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301446 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301447 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1448 }
1449
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301450 if vvs.VoltServiceOper.DeactivateInProgress {
1451 va.ServicesToDeactivate[vvs.VoltServiceCfg.Name] = true
1452 logger.Warnw(ctx, "Service (restored) to be deactivated", log.Fields{"Service": vvs.Name})
1453 }
1454
Naveen Sampath04696f72022-06-13 15:19:14 +05301455 if vvs.VoltServiceOper.DeleteInProgress {
1456 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1457 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1458 }
1459 }
1460}
1461
1462// GetService to get service
1463func (va *VoltApplication) GetService(name string) *VoltService {
1464 if vs, ok := va.ServiceByName.Load(name); ok {
1465 return vs.(*VoltService)
1466 }
1467 return nil
1468}
1469
1470// GetCircuitID to get circuit id
1471func (vs *VoltService) GetCircuitID() []byte {
1472 return []byte(vs.CircuitID)
1473}
1474
1475// GetRemoteID to get remote id
1476func (vs *VoltService) GetRemoteID() []byte {
1477 return []byte(vs.RemoteID)
1478}
1479
1480// IPAssigned to check if ip is assigned
1481func (vs *VoltService) IPAssigned() bool {
1482 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1483 return true
1484 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1485 return true
1486 }
1487 return false
1488}
1489
1490// GetServiceNameFromCookie to get service name from cookie
1491func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Naveen Sampath04696f72022-06-13 15:19:14 +05301492 var vlan uint64
1493 vlanControl := (tableMetadata >> 32) & 0xF
1494
1495 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1496 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1497 vlan = (tableMetadata >> 16) & 0xFFFF
1498 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301499 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301500 vlan = cookie >> 52
1501 }
1502 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1503 var vlans []of.VlanType
1504 vlans = append(vlans, of.VlanType(vlan))
1505 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1506 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301507 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301508 } else {
1509 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1510 }
1511 return service
1512}
1513
vinokuma926cb3e2023-03-29 11:41:06 +05301514// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301515type MigrateServicesReqStatus string
1516
1517const (
vinokuma926cb3e2023-03-29 11:41:06 +05301518 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301519 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301520 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301521 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301522 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301523 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1524)
1525
vinokuma926cb3e2023-03-29 11:41:06 +05301526// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301527type MigrateServicesRequest struct {
1528 ID string
1529 OldVnetID string
1530 NewVnetID string
1531 ServicesList map[string]bool
1532 DeviceID string
1533 Status MigrateServicesReqStatus
1534 MigrateServicesLock sync.RWMutex
1535}
1536
1537func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301538 var msr MigrateServicesRequest
1539 msr.OldVnetID = oldVnetID
1540 msr.NewVnetID = newVnetID
1541 msr.ID = id
1542 msr.ServicesList = serviceMap
1543 msr.DeviceID = deviceID
1544 msr.Status = MigrateSrvsReqInit
1545 return &msr
1546}
1547
vinokuma926cb3e2023-03-29 11:41:06 +05301548// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301549func (msr *MigrateServicesRequest) GetMsrKey() string {
1550 return msr.OldVnetID + "-" + msr.ID
1551}
1552
1553// //isRequestComplete - return if all request has been processed and completed
1554// // RequestProcessed indicates that all the profile de-activation has been triggered
1555// // And the associated profiles indicates the profiles awaiting results
1556// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1557// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1558// return (len(edr.AssociatedProfiles) == 0)
1559// }
1560
vinokuma926cb3e2023-03-29 11:41:06 +05301561// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301562func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301563 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)})
1564 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301565 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301566 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301567 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301568 }
1569 }
1570}
1571
vinokuma926cb3e2023-03-29 11:41:06 +05301572// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301573func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301574 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1575 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1576 return errors.New("Old Vnet Id not found")
1577 }
1578 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1579 return errors.New("New Vnet Id not found")
1580 }
1581
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301582 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301583 if d == nil {
1584 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1585 return errorCodes.ErrDeviceNotFound
1586 }
1587
1588 serviceMap := make(map[string]bool)
1589
1590 for _, service := range serviceList {
1591 serviceMap[service] = false
1592 }
1593 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301594 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301595
1596 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301597 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301598 return nil
1599}
1600
vinokuma926cb3e2023-03-29 11:41:06 +05301601// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301602func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301603 va := GetApplication()
1604 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301605 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301606 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301607 va.DelService(cntx, srv, true, nil, true)
1608 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301609 continue
1610 }
1611
1612 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1613 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1614 vs := vsIntf.(*VoltService)
1615 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1616 if vpv == nil {
1617 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1618 continue
1619 }
1620 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1621 vpv.Blocked = true
1622
1623 // setDeactTrigger := func(key, value interface{}) bool {
1624 // vs := value.(*VoltService)
1625 vs.ServiceLock.Lock()
1626 vs.UpdateInProgress = true
1627 metadata := &MigrateServiceMetadata{
1628 NewVnetID: msr.NewVnetID,
1629 RequestID: msr.ID,
1630 }
1631 vs.Metadata = metadata
1632 vs.ServiceLock.Unlock()
1633
vinokuma926cb3e2023-03-29 11:41:06 +05301634 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301635 // new vpv flows will be installed when new service is added
1636 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301637 vpv.DelTrapFlows(cntx)
1638 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301639 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301640 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301641 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301642 }
1643 } else {
1644 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1645 }
1646 }
1647}
1648
vinokuma926cb3e2023-03-29 11:41:06 +05301649// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301650func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301651 var msrMap *util.ConcurrentMap
1652 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1653 msrMap = util.NewConcurrentMap()
1654 } else {
1655 msrMap = msrMapIntf.(*util.ConcurrentMap)
1656 }
1657
1658 msrMap.Set(msr.ID, msr)
1659 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1660
1661 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1662 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301663}
1664
vinokuma926cb3e2023-03-29 11:41:06 +05301665// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301666func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1667 if vd := va.GetDevice(deviceID); vd != nil {
1668 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1669 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1670 msrList := msrListIntf.(*util.ConcurrentMap)
1671 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1672 if msrObj, ok := msrList.Get(requestID); ok {
1673 return msrObj.(*MigrateServicesRequest)
1674 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301675 }
1676 }
1677 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1678 return nil
1679}
1680
vinokuma926cb3e2023-03-29 11:41:06 +05301681// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301682func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1683 if vd := va.GetDevice(deviceID); vd != nil {
1684 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1685 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1686 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1687 }
1688 }
1689 }
1690}
1691
vinokuma926cb3e2023-03-29 11:41:06 +05301692// updateVnetProfile - Called on flow process completion
1693// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301694func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301695 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 +05301696
1697 nvs := VoltService{}
1698 nvs.VoltServiceCfg = vs.VoltServiceCfg
1699 nvs.Device = vs.Device
1700 nvs.Ipv4Addr = vs.Ipv4Addr
1701 nvs.Ipv6Addr = vs.Ipv6Addr
1702 nvs.UsMeterID = vs.UsMeterID
1703 nvs.DsMeterID = vs.DsMeterID
1704 nvs.AggDsMeterID = vs.AggDsMeterID
1705 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1706 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1707 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1708 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1709 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1710 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1711 nvs.PendingFlows = vs.PendingFlows
1712 nvs.AssociatedFlows = vs.AssociatedFlows
1713 nvs.DeleteInProgress = vs.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301714 nvs.DeactivateInProgress = vs.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301715 nvs.ForceDelete = vs.ForceDelete
1716 nvs.BwAvailInfo = vs.BwAvailInfo
1717 nvs.UpdateInProgress = vs.UpdateInProgress
1718
1719 if nvs.DeleteInProgress {
1720 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1721 return
1722 }
1723
1724 metadata := vs.Metadata.(*MigrateServiceMetadata)
1725 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301726 oldSrvName := vs.Name
1727
1728 if metadata == nil || metadata.NewVnetID == "" {
1729 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1730 return
1731 }
1732
vinokuma926cb3e2023-03-29 11:41:06 +05301733 nvs.VnetID = metadata.NewVnetID
1734 id := metadata.RequestID
1735
1736 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301737 // Since if post del service in case of pod crash or reboot, the service data will be lost
1738 va := GetApplication()
1739 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1740 vnets := strings.Split(metadata.NewVnetID, "-")
1741 svlan, _ := strconv.Atoi(vnets[0])
1742 nvs.SVlan = of.VlanType(svlan)
1743 nvs.UpdateInProgress = false
1744 nvs.Metadata = nil
1745 nvs.Trigger = ServiceVlanUpdate
1746
1747 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1748 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1749 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1750
vinokuma926cb3e2023-03-29 11:41:06 +05301751 // TODO:Nav Pass a copy, not the pointer
Naveen Sampath04696f72022-06-13 15:19:14 +05301752 logger.Infow(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 +05301753 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301754 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1755 }
1756 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1757
1758 msr.ServicesList[oldSrvName] = true
1759 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301760 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301761
1762 logger.Infow(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 +05301763 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301764 logger.Infow(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 +05301765 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301766}
1767
vinokuma926cb3e2023-03-29 11:41:06 +05301768// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301769// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301770func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301771 msr.MigrateServicesLock.Lock()
1772 defer msr.MigrateServicesLock.Unlock()
1773
1774 delete(msr.ServicesList, serviceName)
1775
1776 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301777 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301778 return
1779 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301780 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301781 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301782}
1783
vinokuma926cb3e2023-03-29 11:41:06 +05301784// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301785func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1786 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301787}
1788
vinokuma926cb3e2023-03-29 11:41:06 +05301789// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301790func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301791 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301792 for _, msr := range msrList {
1793 b, ok := msr.Value.([]byte)
1794 if !ok {
1795 logger.Warn(ctx, "The value type is not []byte")
1796 continue
1797 }
1798 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301799 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301800 logger.Warnw(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 +05301801 }
1802}
1803
1804// createMigrateServicesFromString to create Service from string
1805func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1806 var msr MigrateServicesRequest
1807 if err := json.Unmarshal(b, &msr); err == nil {
1808 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301809 } else {
1810 logger.Warn(ctx, "Unmarshal failed")
1811 }
1812 return &msr
1813}
1814
vinokuma926cb3e2023-03-29 11:41:06 +05301815// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301816func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301817 d := GetApplication().GetDevice(msr.DeviceID)
1818 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301819 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301820}
1821
vinokuma926cb3e2023-03-29 11:41:06 +05301822// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301823func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301824 for srv := range msr.ServicesList {
1825 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301826 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301827 }
1828 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301829 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301830}
1831
vinokuma926cb3e2023-03-29 11:41:06 +05301832// nolint: gocyclo
1833// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301834func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1835 if nvs.Name != evs.Name {
1836 return false
1837 }
1838 if nvs.UniVlan != evs.UniVlan {
1839 return false
1840 }
1841 if nvs.CVlan != evs.CVlan {
1842 return false
1843 }
1844 if nvs.SVlan != evs.SVlan {
1845 return false
1846 }
1847 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1848 return false
1849 }
1850 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1851 return false
1852 }
1853 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1854 return false
1855 }
1856 if nvs.TechProfileID != evs.TechProfileID {
1857 return false
1858 }
1859 if nvs.CircuitID != evs.CircuitID {
1860 return false
1861 }
1862 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1863 return false
1864 }
1865 if nvs.Port != evs.Port {
1866 return false
1867 }
1868 if nvs.PonPort != evs.PonPort {
1869 return false
1870 }
1871 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1872 return false
1873 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301874 if nvs.IsOption82Enabled != evs.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +05301875 return false
1876 }
1877 if nvs.IgmpEnabled != evs.IgmpEnabled {
1878 return false
1879 }
1880 if nvs.McastService != evs.McastService {
1881 return false
1882 }
1883 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1884 return false
1885 }
1886 if nvs.UsMeterProfile != evs.UsMeterProfile {
1887 return false
1888 }
1889 if nvs.DsMeterProfile != evs.DsMeterProfile {
1890 return false
1891 }
1892 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1893 return false
1894 }
1895 if nvs.VnetID != evs.VnetID {
1896 return false
1897 }
1898 if nvs.MvlanProfileName != evs.MvlanProfileName {
1899 return false
1900 }
1901 if nvs.RemoteIDType != evs.RemoteIDType {
1902 return false
1903 }
1904 if nvs.SchedID != evs.SchedID {
1905 return false
1906 }
1907 if nvs.AllowTransparent != evs.AllowTransparent {
1908 return false
1909 }
1910 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1911 return false
1912 }
1913 if nvs.DataRateAttr != evs.DataRateAttr {
1914 return false
1915 }
1916 if nvs.MinDataRateUs != evs.MinDataRateUs {
1917 return false
1918 }
1919 if nvs.MinDataRateDs != evs.MinDataRateDs {
1920 return false
1921 }
1922 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1923 return false
1924 }
1925 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1926 return false
1927 }
1928
1929 return true
1930}
1931
vinokuma926cb3e2023-03-29 11:41:06 +05301932// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301933func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05301934 // Clear the Flows flag if already set
1935 // This case happens only in case of some race condition
Naveen Sampath04696f72022-06-13 15:19:14 +05301936 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301937 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301938 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1939 }
1940 }
1941
1942 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301943 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301944 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1945 }
1946 }
1947
1948 vs.ServiceLock.Lock()
1949 cookieList := []uint64{}
1950 for cookie := range vs.AssociatedFlows {
1951 cookieList = append(cookieList, convertToUInt64(cookie))
1952 }
1953 vs.ServiceLock.Unlock()
1954
1955 if len(cookieList) == 0 {
1956 return false
1957 }
1958
vinokuma926cb3e2023-03-29 11:41:06 +05301959 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05301960 for _, cookie := range cookieList {
1961 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1962 flow := &of.VoltFlow{}
1963 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1964 subFlow := of.NewVoltSubFlow()
1965 subFlow.Cookie = cookie
1966 flow.SubFlows[cookie] = subFlow
1967 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301968 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301969 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1970 }
1971 }
1972 }
1973 return true
1974}
1975
vinokuma926cb3e2023-03-29 11:41:06 +05301976// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05301977func (vs *VoltService) triggerServiceInProgressInd() {
1978}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301979
vinokuma926cb3e2023-03-29 11:41:06 +05301980// JSONMarshal wrapper function for json Marshal VoltService
1981func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301982 return json.Marshal(VoltService{
1983 VoltServiceCfg: vs.VoltServiceCfg,
1984 VoltServiceOper: VoltServiceOper{
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301985 Device: vs.VoltServiceOper.Device,
1986 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
1987 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
1988 UsMeterID: vs.VoltServiceOper.UsMeterID,
1989 DsMeterID: vs.VoltServiceOper.DsMeterID,
1990 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
1991 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
1992 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
1993 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
1994 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
1995 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
1996 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
1997 PendingFlows: vs.VoltServiceOper.PendingFlows,
1998 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
1999 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
2000 DeactivateInProgress: vs.VoltServiceOper.DeactivateInProgress,
2001 ForceDelete: vs.VoltServiceOper.ForceDelete,
2002 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
2003 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
2004 Metadata: vs.VoltServiceOper.Metadata,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05302005 },
2006 })
2007}
Tinoj Josephec742f62022-09-29 19:11:10 +05302008
2009// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302010func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302011 var svcList []*VoltService
2012 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2013 va.ServiceByName.Range(func(key, value interface{}) bool {
2014 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302015 if len(deviceID) > 0 {
2016 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302017 if deviceID == vs.Device && portNo == vs.Port {
2018 svcList = append(svcList, vs)
2019 }
2020 } else {
2021 if deviceID == vs.Device {
2022 svcList = append(svcList, vs)
2023 }
2024 }
2025 } else {
2026 svcList = append(svcList, vs)
2027 }
2028 return true
2029 })
2030 return svcList, nil
2031}
2032
2033// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302034func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302035 var isParmsInvalid bool
Tinoj Josephec742f62022-09-29 19:11:10 +05302036 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302037 device, err := va.GetDeviceFromPort(portNo)
2038 if err != nil {
2039 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2040 return errorCodes.ErrPortNotFound
2041 }
2042 // If device id is not provided check only port number
2043 if deviceID == DeviceAny {
2044 deviceID = device.Name
2045 } else if deviceID != device.Name {
2046 logger.Errorw(ctx, "Wrong Device ID", log.Fields{"Device": deviceID, "Port": portNo})
2047 return errorCodes.ErrDeviceNotFound
2048 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302049 va.ServiceByName.Range(func(key, value interface{}) bool {
2050 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302051 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302052 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302053 logger.Infow(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302054 isParmsInvalid = true
Tinoj Josephec742f62022-09-29 19:11:10 +05302055 return true
2056 }
2057 if portNo == vs.Port && !vs.IsActivated {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302058 isParmsInvalid = false
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302059 p := device.GetPort(vs.Port)
Tinoj Josephec742f62022-09-29 19:11:10 +05302060 if p == nil {
2061 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2062 return true
2063 }
2064 logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
2065 vs.IsActivated = true
2066 va.ServiceByName.Store(vs.Name, vs)
2067 vs.WriteToDb(cntx)
2068 // If port is already up send indication to vpv
2069 if p.State == PortStateUp {
2070 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2071 // PortUp call initiates flow addition
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302072 vpv.PortUpInd(cntx, device, portNo)
Tinoj Josephec742f62022-09-29 19:11:10 +05302073 } else {
2074 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2075 }
2076 }
2077 }
2078 return true
2079 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302080
2081 if isParmsInvalid {
2082 return errorCodes.ErrInvalidParamInRequest
2083 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302084 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302085}
2086
2087// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302088func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302089 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302090 var isServiceExist bool
2091 var isParmsInvalid bool
2092
Tinoj Josephec742f62022-09-29 19:11:10 +05302093 va.ServiceByName.Range(func(key, value interface{}) bool {
2094 vs := value.(*VoltService)
2095 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302096 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2097 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
vinokuma926cb3e2023-03-29 11:41:06 +05302098 logger.Infow(ctx, "condition not matched", log.Fields{"Device": deviceID, "Port": portNo, "sVlan": sVlan, "cVlan": cVlan, "tpID": tpID})
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302099 isParmsInvalid = true
Tinoj Josephec742f62022-09-29 19:11:10 +05302100 return true
2101 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302102 if portNo == vs.Port && vs.IsActivated {
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302103 isServiceExist = true
2104 isParmsInvalid = false
Tinoj Josephec742f62022-09-29 19:11:10 +05302105 vs.IsActivated = false
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302106 vs.DeactivateInProgress = true
Tinoj Josephec742f62022-09-29 19:11:10 +05302107 va.ServiceByName.Store(vs.Name, vs)
2108 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302109 device, err := va.GetDeviceFromPort(portNo)
2110 if err != nil {
2111 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2112 // So no error is returned
2113 logger.Infow(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2114 return true
2115 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302116 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302117 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302118 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2119 // Port down call internally deletes all the flows
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302120 vpv.PortDownInd(cntx, deviceID, portNo, true)
Tinoj Josephec742f62022-09-29 19:11:10 +05302121 if vpv.IgmpEnabled {
2122 va.ReceiverDownInd(cntx, deviceID, portNo)
2123 }
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302124 vs.DeactivateInProgress = false
Tinoj Josephec742f62022-09-29 19:11:10 +05302125 } else {
2126 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2127 }
2128 }
2129 }
2130 return true
2131 })
Hitesh Chhabra7d249a02023-07-04 21:33:49 +05302132
2133 if isParmsInvalid {
2134 return errorCodes.ErrInvalidParamInRequest
2135 } else if !isServiceExist && !isParmsInvalid {
2136 return errorCodes.ErrPortNotFound
2137 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302138 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302139}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302140
vinokuma926cb3e2023-03-29 11:41:06 +05302141// GetServicePbit to get first set bit in the pbit map
2142// returns -1 : If configured to match on all pbits
2143// returns 8 : If no pbits are configured
2144// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302145func (vs *VoltService) GetServicePbit() int {
2146 if vs.IsPbitExist(of.PbitMatchAll) {
2147 return -1
2148 }
vinokuma926cb3e2023-03-29 11:41:06 +05302149 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302150 if vs.IsPbitExist(of.PbitType(pbit)) {
2151 return pbit
2152 }
2153 }
2154 return int(of.PbitMatchNone)
2155}