blob: 1061e21359083555a77d812cd5e9159e24409224 [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
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301113func (va *VoltApplication) DelServiceWithPrefix(cntx context.Context, prefix string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301114 va.ServiceByName.Range(func(key, value interface{}) bool {
1115 srvName := key.(string)
1116 vs := value.(*VoltService)
1117 if strings.Contains(srvName, prefix) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301118 va.DelService(cntx, srvName, true, nil, false)
Naveen Sampath04696f72022-06-13 15:19:14 +05301119
1120 vnetName := strconv.FormatUint(uint64(vs.SVlan), 10) + "-"
1121 vnetName = vnetName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1122 vnetName = vnetName + strconv.FormatUint(uint64(vs.UniVlan), 10)
1123
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301124 if err := va.DelVnet(cntx, vnetName, ""); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301125 logger.Warnw(ctx, "Delete Vnet Failed", log.Fields{"Name": vnetName, "Error": err})
1126 }
1127 }
1128 return true
1129 })
1130}
1131
1132// DelService delete a service form the application
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301133func (va *VoltApplication) DelService(cntx context.Context, name string, forceDelete bool, newSvc *VoltServiceCfg, serviceMigration bool) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301134 AppMutex.ServiceDataMutex.Lock()
1135 defer AppMutex.ServiceDataMutex.Unlock()
1136
1137 logger.Warnw(ctx, "Delete Service Request", log.Fields{"Service": name, "ForceDelete": forceDelete, "serviceMigration": serviceMigration})
1138 var noFlowsPresent bool
1139
1140 vsIntf, ok := va.ServiceByName.Load(name)
1141 if !ok {
1142 logger.Warnw(ctx, "Service doesn't exist", log.Fields{"ServiceName": name})
1143 return
1144 }
1145 vs := vsIntf.(*VoltService)
1146 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1147 if vpv == nil {
1148 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name})
1149 return
1150 }
1151
vinokuma926cb3e2023-03-29 11:41:06 +05301152 // Set this to avoid race-condition during flow result processing
Naveen Sampath04696f72022-06-13 15:19:14 +05301153 vs.DeleteInProgress = true
1154 vs.ForceDelete = forceDelete
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301155 vs.ForceWriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301156
1157 if len(vs.AssociatedFlows) == 0 {
1158 noFlowsPresent = true
1159 }
1160 vpv.VpvLock.Lock()
1161 defer vpv.VpvLock.Unlock()
1162
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301163 vs.DelHsiaFlows(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301164
1165 if vpv.IgmpEnabled {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301166 va.ReceiverDownInd(cntx, vpv.Device, vpv.Port)
Naveen Sampath04696f72022-06-13 15:19:14 +05301167 }
1168 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 +05301169 vpv.DelService(cntx, vs)
Naveen Sampath04696f72022-06-13 15:19:14 +05301170 if vpv.servicesCount.Load() == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301171 va.DelVnetFromPort(cntx, vs.Port, vpv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301172 }
1173
1174 // Delete the service immediately in case of Force Delete
1175 // This will be enabled when profile reconciliation happens after restore
1176 // of backedup data
1177 if vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301178 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301179 GetApplication().ServiceByName.Delete(vs.Name)
1180 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1181 }
1182
Naveen Sampath04696f72022-06-13 15:19:14 +05301183 if nil != newSvc {
1184 logger.Infow(ctx, "Old Service meter profiles", log.Fields{"AGG": vs.AggDsMeterProfile, "DS": vs.DsMeterProfile, "US": vs.UsMeterProfile})
1185 logger.Infow(ctx, "New Service meter profiles", log.Fields{"AGG": newSvc.AggDsMeterProfile, "DS": newSvc.DsMeterProfile, "US": newSvc.UsMeterProfile})
1186 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301187
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301188 logger.Infow(ctx, "About to mark meter for deletion\n", log.Fields{"serviceName": vs.Name})
1189
1190 if aggMeter, ok := va.MeterMgr.GetMeterByID(vs.AggDsMeterID); ok {
1191 if nil == newSvc || (nil != newSvc && aggMeter.Name != newSvc.AggDsMeterProfile) {
vinokuma926cb3e2023-03-29 11:41:06 +05301192 if aggMeter.AssociatedServices > 0 {
1193 aggMeter.AssociatedServices--
1194 logger.Infow(ctx, "Agg Meter associated services updated\n", log.Fields{"MeterID": aggMeter})
1195 va.UpdateMeterProf(cntx, *aggMeter)
1196 }
Sridhar Ravindra2d2ef4e2023-02-08 16:43:38 +05301197 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301198 }
1199 if dsMeter, ok := va.MeterMgr.GetMeterByID(vs.DsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301200 if nil == newSvc || (nil != newSvc && dsMeter.Name != newSvc.DsMeterProfile) {
1201 if dsMeter.AssociatedServices > 0 {
1202 dsMeter.AssociatedServices--
1203 logger.Infow(ctx, "DS Meter associated services updated\n", log.Fields{"MeterID": dsMeter})
1204 va.UpdateMeterProf(cntx, *dsMeter)
1205 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301206 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301207 }
1208 if vs.AggDsMeterID != vs.UsMeterID {
1209 if usMeter, ok := va.MeterMgr.GetMeterByID(vs.UsMeterID); ok {
vinokuma926cb3e2023-03-29 11:41:06 +05301210 if nil == newSvc || (nil != newSvc && usMeter.Name != newSvc.UsMeterProfile) {
1211 if usMeter.AssociatedServices > 0 {
1212 usMeter.AssociatedServices--
1213 logger.Infow(ctx, "US Meter associated services updated\n", log.Fields{"MeterID": usMeter})
1214 va.UpdateMeterProf(cntx, *usMeter)
1215 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301216 }
1217 }
1218 }
1219
1220 if noFlowsPresent || vs.ForceDelete {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301221 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301222 }
1223
vinokuma926cb3e2023-03-29 11:41:06 +05301224 // Delete the per service counter too
Naveen Sampath04696f72022-06-13 15:19:14 +05301225 va.ServiceCounters.Delete(name)
1226 if vs.IgmpEnabled && vs.EnableMulticastKPI {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301227 _ = db.DelAllServiceChannelCounter(cntx, name)
Naveen Sampath04696f72022-06-13 15:19:14 +05301228 }
1229}
1230
vinokuma926cb3e2023-03-29 11:41:06 +05301231// AddFlows - Adds the flow to the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301232// Triggers flow addition after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301233func (vs *VoltService) AddFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301234 // Using locks instead of concurrent map for PendingFlows to avoid
1235 // race condition during flow response indication processing
1236 vs.ServiceLock.Lock()
1237 defer vs.ServiceLock.Unlock()
1238
1239 for cookie := range flow.SubFlows {
1240 cookie := strconv.FormatUint(cookie, 10)
1241 fe := &FlowEvent{
1242 eType: EventTypeServiceFlowAdded,
1243 device: device.Name,
1244 cookie: cookie,
1245 eventData: vs,
1246 }
1247 device.RegisterFlowAddEvent(cookie, fe)
1248 vs.PendingFlows[cookie] = true
1249 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301250 return cntlr.GetController().AddFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301251}
1252
vinokuma926cb3e2023-03-29 11:41:06 +05301253// FlowInstallSuccess - Called when corresponding service flow installation is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301254// If no more pending flows, HSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301255func (vs *VoltService) FlowInstallSuccess(cntx context.Context, cookie string, bwAvailInfo of.BwAvailDetails) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301256 if vs.DeleteInProgress {
1257 logger.Warnw(ctx, "Skipping Flow Add Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1258 return
1259 }
1260 vs.ServiceLock.Lock()
1261
1262 if _, ok := vs.PendingFlows[cookie]; !ok {
1263 logger.Errorw(ctx, "Flow Add Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1264 vs.ServiceLock.Unlock()
1265 return
1266 }
1267
1268 delete(vs.PendingFlows, cookie)
1269 vs.AssociatedFlows[cookie] = true
1270 vs.ServiceLock.Unlock()
1271 var prevBwAvail, presentBwAvail string
1272 if bwAvailInfo.PrevBw != "" && bwAvailInfo.PresentBw != "" {
1273 prevBwAvail = bwAvailInfo.PrevBw
1274 presentBwAvail = bwAvailInfo.PresentBw
1275 vs.BwAvailInfo = prevBwAvail + "," + presentBwAvail
Tinoj Joseph1d108322022-07-13 10:07:39 +05301276 logger.Debugw(ctx, "Bandwidth-value-formed", log.Fields{"BwAvailInfo": vs.BwAvailInfo})
Naveen Sampath04696f72022-06-13 15:19:14 +05301277 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301278 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301279
1280 if len(vs.PendingFlows) == 0 && vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301281 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1282 if err != nil {
1283 logger.Errorw(ctx, "Error Getting Device. Dropping HSIA Success indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1284 return
1285 } else if device.State != controller.DeviceStateUP {
1286 logger.Warnw(ctx, "Device state Down. Dropping HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1287 return
1288 }
1289
1290 if vs.Trigger == ServiceVlanUpdate {
1291 vs.Trigger = NBActivate
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301292 defer vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301293 }
1294 logger.Infow(ctx, "All Flows installed for Service", log.Fields{"Service": vs.Name})
1295 return
1296 }
1297 logger.Infow(ctx, "Processed Service Flow Add Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1298}
1299
vinokuma926cb3e2023-03-29 11:41:06 +05301300// FlowInstallFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301301// Trigger service failure indication to NB
1302func (vs *VoltService) FlowInstallFailure(cookie string, errorCode uint32, errReason string) {
1303 vs.ServiceLock.RLock()
1304
1305 if _, ok := vs.PendingFlows[cookie]; !ok {
1306 logger.Errorw(ctx, "Flow Add Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1307 vs.ServiceLock.RUnlock()
1308 return
1309 }
1310 vs.ServiceLock.RUnlock()
1311 logger.Errorw(ctx, "HSIA Flow Add Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1312 vs.triggerServiceFailureInd(errorCode, errReason)
1313}
1314
vinokuma926cb3e2023-03-29 11:41:06 +05301315// DelFlows - Deletes the flow from the service
Naveen Sampath04696f72022-06-13 15:19:14 +05301316// Triggers flow deletion after registering for flow indication event
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301317func (vs *VoltService) DelFlows(cntx context.Context, device *VoltDevice, flow *of.VoltFlow) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301318 if !vs.ForceDelete {
1319 // Using locks instead of concurrent map for AssociatedFlows to avoid
1320 // race condition during flow response indication processing
1321 vs.ServiceLock.Lock()
1322 defer vs.ServiceLock.Unlock()
1323
1324 for cookie := range flow.SubFlows {
1325 cookie := strconv.FormatUint(cookie, 10)
1326 fe := &FlowEvent{
1327 eType: EventTypeServiceFlowRemoved,
1328 cookie: cookie,
1329 eventData: vs,
1330 }
1331 device.RegisterFlowDelEvent(cookie, fe)
1332 }
1333 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301334 return cntlr.GetController().DelFlows(cntx, vs.Port, device.Name, flow)
Naveen Sampath04696f72022-06-13 15:19:14 +05301335}
1336
vinokuma926cb3e2023-03-29 11:41:06 +05301337// CheckAndDeleteService - remove service from DB is there are no pending flows to be removed
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301338func (vs *VoltService) CheckAndDeleteService(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301339 if vs.DeleteInProgress && len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301340 vs.DelFromDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301341 GetApplication().ServiceByName.Delete(vs.Name)
1342 logger.Warnw(ctx, "Deleted service from DB/Cache successfully", log.Fields{"serviceName": vs.Name})
1343 }
1344}
1345
vinokuma926cb3e2023-03-29 11:41:06 +05301346// FlowRemoveSuccess - Called when corresponding service flow removal is success
Naveen Sampath04696f72022-06-13 15:19:14 +05301347// If no more associated flows, DelHSIA indication wil be triggered
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301348func (vs *VoltService) FlowRemoveSuccess(cntx context.Context, cookie string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301349 // if vs.DeleteInProgress {
1350 // logger.Warnw(ctx, "Skipping Flow Remove Success Notification. Service deletion in-progress", log.Fields{"Cookie": cookie, "Service": vs.Name})
1351 // return
1352 // }
1353 vs.ServiceLock.Lock()
1354 logger.Infow(ctx, "Processing Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1355
1356 if _, ok := vs.AssociatedFlows[cookie]; ok {
1357 delete(vs.AssociatedFlows, cookie)
1358 } else if _, ok := vs.PendingFlows[cookie]; ok {
1359 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})
1360 } else {
1361 logger.Errorw(ctx, "Service Flow Remove Success for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie, "AssociatedFlows": vs.AssociatedFlows, "PendingFlows": vs.PendingFlows})
1362 }
1363
1364 vs.ServiceLock.Unlock()
1365
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301366 vs.WriteToDb(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301367
1368 if len(vs.AssociatedFlows) == 0 && !vs.DsHSIAFlowsApplied {
Naveen Sampath04696f72022-06-13 15:19:14 +05301369 device := GetApplication().GetDevice(vs.Device)
1370 if device == nil {
1371 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1372 return
1373 } else if device.State != controller.DeviceStateUP {
1374 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Success indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1375 return
1376 }
1377
1378 if vs.UpdateInProgress {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301379 vs.updateVnetProfile(cntx, vs.Device)
vinokuma926cb3e2023-03-29 11:41:06 +05301380 // Not sending DEL_HSIA Indication since it wil be generated internally by SubMgr
Naveen Sampath04696f72022-06-13 15:19:14 +05301381 return
1382 }
1383 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 +05301384 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301385
1386 return
1387 }
1388 logger.Infow(ctx, "Processed Service Flow Remove Success Indication", log.Fields{"Cookie": cookie, "Service": vs.Name, "Associated Flows": vs.AssociatedFlows, "DsFlowsApplied": vs.DsHSIAFlowsApplied})
1389}
1390
vinokuma926cb3e2023-03-29 11:41:06 +05301391// FlowRemoveFailure - Called when corresponding service flow installation is failed
Naveen Sampath04696f72022-06-13 15:19:14 +05301392// Trigger service failure indication to NB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301393func (vs *VoltService) FlowRemoveFailure(cntx context.Context, cookie string, errorCode uint32, errReason string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301394 vs.ServiceLock.RLock()
1395
1396 if _, ok := vs.AssociatedFlows[cookie]; !ok {
1397 logger.Errorw(ctx, "Flow Failure for unknown Cookie", log.Fields{"Service": vs.Name, "Cookie": cookie})
1398 vs.ServiceLock.RUnlock()
1399 return
1400 }
1401 if vs.DeleteInProgress {
1402 delete(vs.AssociatedFlows, cookie)
1403 }
1404 vs.ServiceLock.RUnlock()
1405 logger.Errorw(ctx, "Service Flow Remove Failure Notification", log.Fields{"uniPort": vs.Port, "Cookie": cookie, "Service": vs.Name, "ErrorCode": errorCode, "ErrorReason": errReason})
1406
1407 vs.triggerServiceFailureInd(errorCode, errReason)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301408 vs.CheckAndDeleteService(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301409}
1410
1411func (vs *VoltService) triggerServiceFailureInd(errorCode uint32, errReason string) {
1412 device, err := GetApplication().GetDeviceFromPort(vs.Port)
1413 if err != nil {
1414 logger.Errorw(ctx, "Error Getting Device. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Reason": err.Error(), "Service": vs.Name, "Port": vs.Port})
1415 return
1416 } else if device.State != controller.DeviceStateUP {
1417 logger.Warnw(ctx, "Device state Down. Dropping DEL_HSIA Failure indication to NB", log.Fields{"Service": vs.Name, "Port": vs.Port})
1418 return
1419 }
1420}
1421
1422// RestoreSvcsFromDb read from the DB and restore all the services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301423func (va *VoltApplication) RestoreSvcsFromDb(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301424 // VNETS must be learnt first
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301425 vss, _ := db.GetServices(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301426 for _, vs := range vss {
1427 b, ok := vs.Value.([]byte)
1428 if !ok {
1429 logger.Warn(ctx, "The value type is not []byte")
1430 continue
1431 }
1432 var vvs VoltService
1433 err := json.Unmarshal(b, &vvs)
1434 if err != nil {
1435 logger.Warn(ctx, "Unmarshal of VNET failed")
1436 continue
1437 }
1438 logger.Debugw(ctx, "Retrieved Service", log.Fields{"Service": vvs.VoltServiceCfg})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301439 if err := va.AddService(cntx, vvs.VoltServiceCfg, &vvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301440 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": vvs.Name, "Error": err})
1441 }
1442
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301443 if vvs.VoltServiceOper.DeactivateInProgress {
1444 va.ServicesToDeactivate[vvs.VoltServiceCfg.Name] = true
1445 logger.Warnw(ctx, "Service (restored) to be deactivated", log.Fields{"Service": vvs.Name})
1446 }
1447
Naveen Sampath04696f72022-06-13 15:19:14 +05301448 if vvs.VoltServiceOper.DeleteInProgress {
1449 va.ServicesToDelete[vvs.VoltServiceCfg.Name] = true
1450 logger.Warnw(ctx, "Service (restored) to be deleted", log.Fields{"Service": vvs.Name})
1451 }
1452 }
1453}
1454
1455// GetService to get service
1456func (va *VoltApplication) GetService(name string) *VoltService {
1457 if vs, ok := va.ServiceByName.Load(name); ok {
1458 return vs.(*VoltService)
1459 }
1460 return nil
1461}
1462
1463// GetCircuitID to get circuit id
1464func (vs *VoltService) GetCircuitID() []byte {
1465 return []byte(vs.CircuitID)
1466}
1467
1468// GetRemoteID to get remote id
1469func (vs *VoltService) GetRemoteID() []byte {
1470 return []byte(vs.RemoteID)
1471}
1472
1473// IPAssigned to check if ip is assigned
1474func (vs *VoltService) IPAssigned() bool {
1475 if vs.Ipv4Addr != nil && !vs.Ipv4Addr.Equal(net.ParseIP("0.0.0.0")) {
1476 return true
1477 } else if vs.Ipv6Addr != nil && !vs.Ipv6Addr.Equal(net.ParseIP("0:0:0:0:0:0:0:0")) {
1478 return true
1479 }
1480 return false
1481}
1482
1483// GetServiceNameFromCookie to get service name from cookie
1484func (va *VoltApplication) GetServiceNameFromCookie(cookie uint64, portName string, pbit uint8, device string, tableMetadata uint64) *VoltService {
Naveen Sampath04696f72022-06-13 15:19:14 +05301485 var vlan uint64
1486 vlanControl := (tableMetadata >> 32) & 0xF
1487
1488 if vlanControl == uint64(OLTCVlanOLTSVlan) {
1489 // Fetching UniVlan for vlanControl OLTCVLANOLTSVLAN
1490 vlan = (tableMetadata >> 16) & 0xFFFF
1491 } else {
vinokuma926cb3e2023-03-29 11:41:06 +05301492 // Fetching CVlan for other vlanControl
Naveen Sampath04696f72022-06-13 15:19:14 +05301493 vlan = cookie >> 52
1494 }
1495 logger.Infow(ctx, "Configured Params", log.Fields{"VlanControl": vlanControl, "vlan": vlan})
1496 var vlans []of.VlanType
1497 vlans = append(vlans, of.VlanType(vlan))
1498 service := GetApplication().GetServiceFromCvlan(device, portName, vlans, uint8(pbit))
1499 if nil != service {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301500 logger.Infow(ctx, "Service Found for", log.Fields{"serviceName": service.Name, "portName": portName, "ctag": vlan})
Naveen Sampath04696f72022-06-13 15:19:14 +05301501 } else {
1502 logger.Errorw(ctx, "No Service for", log.Fields{"portName": portName, "ctag": vlan, "Pbit": pbit, "device": device, "VlanControl": vlanControl})
1503 }
1504 return service
1505}
1506
vinokuma926cb3e2023-03-29 11:41:06 +05301507// MigrateServicesReqStatus - update vnet request status
Naveen Sampath04696f72022-06-13 15:19:14 +05301508type MigrateServicesReqStatus string
1509
1510const (
vinokuma926cb3e2023-03-29 11:41:06 +05301511 // MigrateSrvsReqInit constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301512 MigrateSrvsReqInit MigrateServicesReqStatus = "Init"
vinokuma926cb3e2023-03-29 11:41:06 +05301513 // MigrateSrvsReqDeactTriggered constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301514 MigrateSrvsReqDeactTriggered MigrateServicesReqStatus = "Profiles Deactivated"
vinokuma926cb3e2023-03-29 11:41:06 +05301515 // MigrateSrvsReqCompleted constant
Naveen Sampath04696f72022-06-13 15:19:14 +05301516 MigrateSrvsReqCompleted MigrateServicesReqStatus = "Update Complete"
1517)
1518
vinokuma926cb3e2023-03-29 11:41:06 +05301519// MigrateServicesRequest - update vnet request params
Naveen Sampath04696f72022-06-13 15:19:14 +05301520type MigrateServicesRequest struct {
1521 ID string
1522 OldVnetID string
1523 NewVnetID string
1524 ServicesList map[string]bool
1525 DeviceID string
1526 Status MigrateServicesReqStatus
1527 MigrateServicesLock sync.RWMutex
1528}
1529
1530func newMigrateServicesRequest(id string, oldVnetID string, newVnetID string, serviceMap map[string]bool, deviceID string) *MigrateServicesRequest {
Naveen Sampath04696f72022-06-13 15:19:14 +05301531 var msr MigrateServicesRequest
1532 msr.OldVnetID = oldVnetID
1533 msr.NewVnetID = newVnetID
1534 msr.ID = id
1535 msr.ServicesList = serviceMap
1536 msr.DeviceID = deviceID
1537 msr.Status = MigrateSrvsReqInit
1538 return &msr
1539}
1540
vinokuma926cb3e2023-03-29 11:41:06 +05301541// GetMsrKey - generates migrate service request key
Naveen Sampath04696f72022-06-13 15:19:14 +05301542func (msr *MigrateServicesRequest) GetMsrKey() string {
1543 return msr.OldVnetID + "-" + msr.ID
1544}
1545
1546// //isRequestComplete - return if all request has been processed and completed
1547// // RequestProcessed indicates that all the profile de-activation has been triggered
1548// // And the associated profiles indicates the profiles awaiting results
1549// func (msr *MigrateServicesRequest) isRequestComplete() bool {
1550// //return edr.RequestProcessed && (len(edr.AssociatedProfiles) == 0)
1551// return (len(edr.AssociatedProfiles) == 0)
1552// }
1553
vinokuma926cb3e2023-03-29 11:41:06 +05301554// WriteToDB - writes the udpate vnet request details ot DB
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301555func (msr *MigrateServicesRequest) WriteToDB(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301556 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)})
1557 if b, err := json.Marshal(msr); err == nil {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301558 if err = db.PutMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey(), string(b)); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301559 logger.Warnw(ctx, "PutMigrateServicesReq Failed", log.Fields{"OldVnet": msr.OldVnetID, "NewVnet": msr.NewVnetID,
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05301560 "Device": msr.DeviceID, "Error": err})
Naveen Sampath04696f72022-06-13 15:19:14 +05301561 }
1562 }
1563}
1564
vinokuma926cb3e2023-03-29 11:41:06 +05301565// MigrateServices - updated vnet profile for services
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301566func (va *VoltApplication) MigrateServices(cntx context.Context, serialNum string, reqID string, oldVnetID, newVnetID string, serviceList []string) error {
Naveen Sampath04696f72022-06-13 15:19:14 +05301567 logger.Warnw(ctx, "Migrate Serviec Request Received", log.Fields{"SerialNum": serialNum, "RequestID": reqID, "OldVnet": oldVnetID, "NewVnet": newVnetID, "ServiceList": serviceList})
1568 if _, ok := va.VnetsByName.Load(oldVnetID); !ok {
1569 return errors.New("Old Vnet Id not found")
1570 }
1571 if _, ok := va.VnetsByName.Load(newVnetID); !ok {
1572 return errors.New("New Vnet Id not found")
1573 }
1574
Tinoj Joseph50d722c2022-12-06 22:53:22 +05301575 d, _ := va.GetDeviceBySerialNo(serialNum)
Naveen Sampath04696f72022-06-13 15:19:14 +05301576 if d == nil {
1577 logger.Errorw(ctx, "Error Getting Device", log.Fields{"SerialNum": serialNum})
1578 return errorCodes.ErrDeviceNotFound
1579 }
1580
1581 serviceMap := make(map[string]bool)
1582
1583 for _, service := range serviceList {
1584 serviceMap[service] = false
1585 }
1586 msr := newMigrateServicesRequest(reqID, oldVnetID, newVnetID, serviceMap, d.Name)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301587 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301588
1589 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301590 go msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301591 return nil
1592}
1593
vinokuma926cb3e2023-03-29 11:41:06 +05301594// ProcessMigrateServicesProfRequest - collects all associated profiles
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301595func (msr *MigrateServicesRequest) ProcessMigrateServicesProfRequest(cntx context.Context) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301596 va := GetApplication()
1597 for srv, processed := range msr.ServicesList {
vinokuma926cb3e2023-03-29 11:41:06 +05301598 // Indicates new service is already created and only deletion of old one is pending
Naveen Sampath04696f72022-06-13 15:19:14 +05301599 if processed {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301600 va.DelService(cntx, srv, true, nil, true)
1601 msr.serviceMigrated(cntx, srv)
Naveen Sampath04696f72022-06-13 15:19:14 +05301602 continue
1603 }
1604
1605 logger.Infow(ctx, "Migrate Service Triggering", log.Fields{"Service": srv})
1606 if vsIntf, ok := va.ServiceByName.Load(srv); ok {
1607 vs := vsIntf.(*VoltService)
1608 vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan)
1609 if vpv == nil {
1610 logger.Errorw(ctx, "Vpv Not found for Service", log.Fields{"vs": vs.Name, "port": vs.Port, "Vnet": vs.VnetID})
1611 continue
1612 }
1613 logger.Infow(ctx, "Migrating Service", log.Fields{"Service": vs.Name, "UsFlowApplied": vs.UsHSIAFlowsApplied})
1614 vpv.Blocked = true
1615
1616 // setDeactTrigger := func(key, value interface{}) bool {
1617 // vs := value.(*VoltService)
1618 vs.ServiceLock.Lock()
1619 vs.UpdateInProgress = true
1620 metadata := &MigrateServiceMetadata{
1621 NewVnetID: msr.NewVnetID,
1622 RequestID: msr.ID,
1623 }
1624 vs.Metadata = metadata
1625 vs.ServiceLock.Unlock()
1626
vinokuma926cb3e2023-03-29 11:41:06 +05301627 // vpv flows will be removed when last service is removed from it and
Naveen Sampath04696f72022-06-13 15:19:14 +05301628 // new vpv flows will be installed when new service is added
1629 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301630 vpv.DelTrapFlows(cntx)
1631 vs.DelHsiaFlows(cntx)
Tinoj Joseph1d108322022-07-13 10:07:39 +05301632 logger.Infow(ctx, "Remove Service Flows Triggered", log.Fields{"Service": srv, "US": vs.UsHSIAFlowsApplied, "DS": vs.DsHSIAFlowsApplied})
Naveen Sampath04696f72022-06-13 15:19:14 +05301633 } else {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301634 vs.updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301635 }
1636 } else {
1637 logger.Warnw(ctx, "Migrate Service Failed: Service Not Found", log.Fields{"Service": srv, "Vnet": msr.OldVnetID})
1638 }
1639 }
1640}
1641
vinokuma926cb3e2023-03-29 11:41:06 +05301642// AddMigratingServices - store msr info to device obj
Naveen Sampath04696f72022-06-13 15:19:14 +05301643func (d *VoltDevice) AddMigratingServices(msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301644 var msrMap *util.ConcurrentMap
1645 if msrMapIntf, ok := d.MigratingServices.Get(msr.OldVnetID); !ok {
1646 msrMap = util.NewConcurrentMap()
1647 } else {
1648 msrMap = msrMapIntf.(*util.ConcurrentMap)
1649 }
1650
1651 msrMap.Set(msr.ID, msr)
1652 logger.Infow(ctx, "1: MsrListLen", log.Fields{"Len": msrMap.Length(), "Vnet": msr.OldVnetID})
1653
1654 d.MigratingServices.Set(msr.OldVnetID, msrMap)
1655 logger.Infow(ctx, "1: DeviceMsr", log.Fields{"Device": d.Name, "Vnet": msr.OldVnetID, "Len": d.MigratingServices.Length()})
Naveen Sampath04696f72022-06-13 15:19:14 +05301656}
1657
vinokuma926cb3e2023-03-29 11:41:06 +05301658// getMigrateServicesRequest - fetches msr info from device
Naveen Sampath04696f72022-06-13 15:19:14 +05301659func (va *VoltApplication) getMigrateServicesRequest(deviceID string, oldVnetID string, requestID string) *MigrateServicesRequest {
1660 if vd := va.GetDevice(deviceID); vd != nil {
1661 logger.Infow(ctx, "2: DeviceMsr", log.Fields{"Device": deviceID, "Vnet": oldVnetID, "Len": vd.MigratingServices.Length()})
1662 if msrListIntf, ok := vd.MigratingServices.Get(oldVnetID); ok {
1663 msrList := msrListIntf.(*util.ConcurrentMap)
1664 logger.Infow(ctx, "2: MsrListLen", log.Fields{"Len": msrList.Length(), "Vnet": oldVnetID})
1665 if msrObj, ok := msrList.Get(requestID); ok {
1666 return msrObj.(*MigrateServicesRequest)
1667 }
Naveen Sampath04696f72022-06-13 15:19:14 +05301668 }
1669 }
1670 logger.Errorw(ctx, "Device Not Found", log.Fields{"Device": deviceID})
1671 return nil
1672}
1673
vinokuma926cb3e2023-03-29 11:41:06 +05301674// updateMigrateServicesRequest - Updates the device with updated msr
Naveen Sampath04696f72022-06-13 15:19:14 +05301675func (va *VoltApplication) updateMigrateServicesRequest(deviceID string, oldVnetID string, requestID string, msr *MigrateServicesRequest) {
1676 if vd := va.GetDevice(deviceID); vd != nil {
1677 if msrList, ok := vd.MigratingServices.Get(oldVnetID); ok {
1678 if _, ok := msrList.(*util.ConcurrentMap).Get(requestID); ok {
1679 msrList.(*util.ConcurrentMap).Set(requestID, msr)
1680 }
1681 }
1682 }
1683}
1684
vinokuma926cb3e2023-03-29 11:41:06 +05301685// updateVnetProfile - Called on flow process completion
1686// Removes old service and creates new VPV & service with updated vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301687func (vs *VoltService) updateVnetProfile(cntx context.Context, deviceID string) {
Tinoj Joseph1d108322022-07-13 10:07:39 +05301688 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 +05301689
1690 nvs := VoltService{}
1691 nvs.VoltServiceCfg = vs.VoltServiceCfg
1692 nvs.Device = vs.Device
1693 nvs.Ipv4Addr = vs.Ipv4Addr
1694 nvs.Ipv6Addr = vs.Ipv6Addr
1695 nvs.UsMeterID = vs.UsMeterID
1696 nvs.DsMeterID = vs.DsMeterID
1697 nvs.AggDsMeterID = vs.AggDsMeterID
1698 nvs.UsHSIAFlowsApplied = vs.UsHSIAFlowsApplied
1699 nvs.DsHSIAFlowsApplied = vs.DsHSIAFlowsApplied
1700 nvs.UsDhcpFlowsApplied = vs.UsDhcpFlowsApplied
1701 nvs.DsDhcpFlowsApplied = vs.DsDhcpFlowsApplied
1702 nvs.IgmpFlowsApplied = vs.IgmpFlowsApplied
1703 nvs.Icmpv6FlowsApplied = vs.Icmpv6FlowsApplied
1704 nvs.PendingFlows = vs.PendingFlows
1705 nvs.AssociatedFlows = vs.AssociatedFlows
1706 nvs.DeleteInProgress = vs.DeleteInProgress
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301707 nvs.DeactivateInProgress = vs.DeactivateInProgress
Naveen Sampath04696f72022-06-13 15:19:14 +05301708 nvs.ForceDelete = vs.ForceDelete
1709 nvs.BwAvailInfo = vs.BwAvailInfo
1710 nvs.UpdateInProgress = vs.UpdateInProgress
1711
1712 if nvs.DeleteInProgress {
1713 logger.Warnw(ctx, "Skipping Service Migration. Service Delete in Progress", log.Fields{"Device": deviceID, "Service": vs.Name, "Vnet": vs.VnetID})
1714 return
1715 }
1716
1717 metadata := vs.Metadata.(*MigrateServiceMetadata)
1718 oldVnetID := vs.VnetID
Naveen Sampath04696f72022-06-13 15:19:14 +05301719 oldSrvName := vs.Name
1720
1721 if metadata == nil || metadata.NewVnetID == "" {
1722 logger.Errorw(ctx, "Migrate Service Metadata not found. Dropping vnet profile update request", log.Fields{"Service": vs.Name, "Vnet": vs.VnetID})
1723 return
1724 }
1725
vinokuma926cb3e2023-03-29 11:41:06 +05301726 nvs.VnetID = metadata.NewVnetID
1727 id := metadata.RequestID
1728
1729 // First add the new service and then only delete the old service
Naveen Sampath04696f72022-06-13 15:19:14 +05301730 // Since if post del service in case of pod crash or reboot, the service data will be lost
1731 va := GetApplication()
1732 msr := va.getMigrateServicesRequest(deviceID, oldVnetID, id)
1733 vnets := strings.Split(metadata.NewVnetID, "-")
1734 svlan, _ := strconv.Atoi(vnets[0])
1735 nvs.SVlan = of.VlanType(svlan)
1736 nvs.UpdateInProgress = false
1737 nvs.Metadata = nil
1738 nvs.Trigger = ServiceVlanUpdate
1739
1740 svcName := vs.Port + "-" + strconv.FormatUint(uint64(nvs.SVlan), 10) + "-"
1741 svcName = svcName + strconv.FormatUint(uint64(vs.CVlan), 10) + "-"
1742 nvs.Name = svcName + strconv.FormatUint(uint64(vs.TechProfileID), 10)
1743
vinokuma926cb3e2023-03-29 11:41:06 +05301744 // TODO:Nav Pass a copy, not the pointer
Naveen Sampath04696f72022-06-13 15:19:14 +05301745 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 +05301746 if err := va.AddService(cntx, nvs.VoltServiceCfg, &nvs.VoltServiceOper); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301747 logger.Warnw(ctx, "Add New Service Failed", log.Fields{"Service": nvs.Name, "Error": err})
1748 }
1749 logger.Infow(ctx, "Add New Service Triggered", log.Fields{"Service": nvs.Name, "US": nvs.UsHSIAFlowsApplied, "DS": nvs.DsHSIAFlowsApplied, "DelFlag": nvs.DeleteInProgress})
1750
1751 msr.ServicesList[oldSrvName] = true
1752 va.updateMigrateServicesRequest(deviceID, oldVnetID, id, msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301753 msr.WriteToDB(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301754
1755 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 +05301756 va.DelService(cntx, oldSrvName, true, nil, true)
Naveen Sampath04696f72022-06-13 15:19:14 +05301757 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 +05301758 msr.serviceMigrated(cntx, oldSrvName)
Naveen Sampath04696f72022-06-13 15:19:14 +05301759}
1760
vinokuma926cb3e2023-03-29 11:41:06 +05301761// serviceMigrated - called on successful service updation
Naveen Sampath04696f72022-06-13 15:19:14 +05301762// Removes the service entry from servicelist and deletes the request on process completion
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301763func (msr *MigrateServicesRequest) serviceMigrated(cntx context.Context, serviceName string) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301764 msr.MigrateServicesLock.Lock()
1765 defer msr.MigrateServicesLock.Unlock()
1766
1767 delete(msr.ServicesList, serviceName)
1768
1769 if len(msr.ServicesList) == 0 {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301770 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301771 return
1772 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301773 msr.WriteToDB(cntx)
vinokuma926cb3e2023-03-29 11:41:06 +05301774 // TODO:Nav - Need for any Response to SubMgr?
Naveen Sampath04696f72022-06-13 15:19:14 +05301775}
1776
vinokuma926cb3e2023-03-29 11:41:06 +05301777// TriggerPendingMigrateServicesReq - trigger pending service request
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301778func (va *VoltApplication) TriggerPendingMigrateServicesReq(cntx context.Context, device string) {
1779 va.FetchAndProcessAllMigrateServicesReq(cntx, device, storeAndProcessMigrateSrvRequest)
Naveen Sampath04696f72022-06-13 15:19:14 +05301780}
1781
vinokuma926cb3e2023-03-29 11:41:06 +05301782// FetchAndProcessAllMigrateServicesReq - fetch all pending migrate services req from DB and process based on provided func
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301783func (va *VoltApplication) FetchAndProcessAllMigrateServicesReq(cntx context.Context, device string, msrAction func(context.Context, *MigrateServicesRequest)) {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301784 msrList, _ := db.GetAllMigrateServicesReq(cntx, device)
Naveen Sampath04696f72022-06-13 15:19:14 +05301785 for _, msr := range msrList {
1786 b, ok := msr.Value.([]byte)
1787 if !ok {
1788 logger.Warn(ctx, "The value type is not []byte")
1789 continue
1790 }
1791 msr := va.createMigrateServicesFromString(b)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301792 msrAction(cntx, msr)
Naveen Sampath04696f72022-06-13 15:19:14 +05301793 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 +05301794 }
1795}
1796
1797// createMigrateServicesFromString to create Service from string
1798func (va *VoltApplication) createMigrateServicesFromString(b []byte) *MigrateServicesRequest {
1799 var msr MigrateServicesRequest
1800 if err := json.Unmarshal(b, &msr); err == nil {
1801 logger.Debugw(ctx, "Adding Migrate Services Request From Db", log.Fields{"Vlan": msr.OldVnetID})
Naveen Sampath04696f72022-06-13 15:19:14 +05301802 } else {
1803 logger.Warn(ctx, "Unmarshal failed")
1804 }
1805 return &msr
1806}
1807
vinokuma926cb3e2023-03-29 11:41:06 +05301808// storeAndProcessMigrateSrvRequest - stores the msr info in device obj and triggers req
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301809func storeAndProcessMigrateSrvRequest(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301810 d := GetApplication().GetDevice(msr.DeviceID)
1811 d.AddMigratingServices(msr)
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301812 msr.ProcessMigrateServicesProfRequest(cntx)
Naveen Sampath04696f72022-06-13 15:19:14 +05301813}
1814
vinokuma926cb3e2023-03-29 11:41:06 +05301815// forceUpdateAllServices - force udpate services with new vnet profile
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301816func forceUpdateAllServices(cntx context.Context, msr *MigrateServicesRequest) {
Naveen Sampath04696f72022-06-13 15:19:14 +05301817 for srv := range msr.ServicesList {
1818 if vsIntf, ok := GetApplication().ServiceByName.Load(srv); ok {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301819 vsIntf.(*VoltService).updateVnetProfile(cntx, msr.DeviceID)
Naveen Sampath04696f72022-06-13 15:19:14 +05301820 }
1821 }
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301822 _ = db.DelMigrateServicesReq(cntx, msr.DeviceID, msr.GetMsrKey())
Naveen Sampath04696f72022-06-13 15:19:14 +05301823}
1824
vinokuma926cb3e2023-03-29 11:41:06 +05301825// nolint: gocyclo
1826// DeepEqualServicecfg - checks if the given service cfgs are same
Naveen Sampath04696f72022-06-13 15:19:14 +05301827func (va *VoltApplication) DeepEqualServicecfg(evs *VoltServiceCfg, nvs *VoltServiceCfg) bool {
1828 if nvs.Name != evs.Name {
1829 return false
1830 }
1831 if nvs.UniVlan != evs.UniVlan {
1832 return false
1833 }
1834 if nvs.CVlan != evs.CVlan {
1835 return false
1836 }
1837 if nvs.SVlan != evs.SVlan {
1838 return false
1839 }
1840 if nvs.SVlanTpid != 0 && nvs.SVlanTpid != evs.SVlanTpid {
1841 return false
1842 }
1843 if !util.IsPbitSliceSame(nvs.Pbits, evs.Pbits) {
1844 return false
1845 }
1846 if !reflect.DeepEqual(nvs.DsRemarkPbitsMap, evs.DsRemarkPbitsMap) {
1847 return false
1848 }
1849 if nvs.TechProfileID != evs.TechProfileID {
1850 return false
1851 }
1852 if nvs.CircuitID != evs.CircuitID {
1853 return false
1854 }
1855 if !bytes.Equal(nvs.RemoteID, evs.RemoteID) {
1856 return false
1857 }
1858 if nvs.Port != evs.Port {
1859 return false
1860 }
1861 if nvs.PonPort != evs.PonPort {
1862 return false
1863 }
1864 if evs.MacLearning == MacLearningNone && !util.MacAddrsMatch(nvs.MacAddr, evs.MacAddr) {
1865 return false
1866 }
Hitesh Chhabra9f9a9df2023-06-13 17:52:15 +05301867 if nvs.IsOption82Enabled != evs.IsOption82Enabled {
Naveen Sampath04696f72022-06-13 15:19:14 +05301868 return false
1869 }
1870 if nvs.IgmpEnabled != evs.IgmpEnabled {
1871 return false
1872 }
1873 if nvs.McastService != evs.McastService {
1874 return false
1875 }
1876 if nvs.ONTEtherTypeClassification != evs.ONTEtherTypeClassification {
1877 return false
1878 }
1879 if nvs.UsMeterProfile != evs.UsMeterProfile {
1880 return false
1881 }
1882 if nvs.DsMeterProfile != evs.DsMeterProfile {
1883 return false
1884 }
1885 if nvs.AggDsMeterProfile != evs.AggDsMeterProfile {
1886 return false
1887 }
1888 if nvs.VnetID != evs.VnetID {
1889 return false
1890 }
1891 if nvs.MvlanProfileName != evs.MvlanProfileName {
1892 return false
1893 }
1894 if nvs.RemoteIDType != evs.RemoteIDType {
1895 return false
1896 }
1897 if nvs.SchedID != evs.SchedID {
1898 return false
1899 }
1900 if nvs.AllowTransparent != evs.AllowTransparent {
1901 return false
1902 }
1903 if nvs.EnableMulticastKPI != evs.EnableMulticastKPI {
1904 return false
1905 }
1906 if nvs.DataRateAttr != evs.DataRateAttr {
1907 return false
1908 }
1909 if nvs.MinDataRateUs != evs.MinDataRateUs {
1910 return false
1911 }
1912 if nvs.MinDataRateDs != evs.MinDataRateDs {
1913 return false
1914 }
1915 if nvs.MaxDataRateUs != evs.MaxDataRateUs {
1916 return false
1917 }
1918 if nvs.MaxDataRateDs != evs.MaxDataRateDs {
1919 return false
1920 }
1921
1922 return true
1923}
1924
vinokuma926cb3e2023-03-29 11:41:06 +05301925// TriggerAssociatedFlowDelete - re-trigger service flow delete for pending delete flows
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301926func (vs *VoltService) TriggerAssociatedFlowDelete(cntx context.Context) bool {
vinokuma926cb3e2023-03-29 11:41:06 +05301927 // Clear the Flows flag if already set
1928 // This case happens only in case of some race condition
Naveen Sampath04696f72022-06-13 15:19:14 +05301929 if vs.UsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301930 if err := vs.DelUsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301931 logger.Errorw(ctx, "DelUsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1932 }
1933 }
1934
1935 if vs.DsHSIAFlowsApplied {
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301936 if err := vs.DelDsHsiaFlows(cntx); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301937 logger.Errorw(ctx, "DelDsHsiaFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Error": err})
1938 }
1939 }
1940
1941 vs.ServiceLock.Lock()
1942 cookieList := []uint64{}
1943 for cookie := range vs.AssociatedFlows {
1944 cookieList = append(cookieList, convertToUInt64(cookie))
1945 }
1946 vs.ServiceLock.Unlock()
1947
1948 if len(cookieList) == 0 {
1949 return false
1950 }
1951
vinokuma926cb3e2023-03-29 11:41:06 +05301952 // Trigger Flow Delete
Naveen Sampath04696f72022-06-13 15:19:14 +05301953 for _, cookie := range cookieList {
1954 if vd := GetApplication().GetDevice(vs.Device); vd != nil {
1955 flow := &of.VoltFlow{}
1956 flow.SubFlows = make(map[uint64]*of.VoltSubFlow)
1957 subFlow := of.NewVoltSubFlow()
1958 subFlow.Cookie = cookie
1959 flow.SubFlows[cookie] = subFlow
1960 logger.Infow(ctx, "Retriggering Service Delete Flow", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie})
Tinoj Joseph07cc5372022-07-18 22:53:51 +05301961 if err := vs.DelFlows(cntx, vd, flow); err != nil {
Naveen Sampath04696f72022-06-13 15:19:14 +05301962 logger.Errorw(ctx, "DelFlows Failed", log.Fields{"Device": vs.Device, "Service": vs.Name, "Cookie": cookie, "Error": err})
1963 }
1964 }
1965 }
1966 return true
1967}
1968
vinokuma926cb3e2023-03-29 11:41:06 +05301969// triggerServiceInProgressInd - Indication is generated when Service is not provisioned after add serviec req from NB
Naveen Sampath04696f72022-06-13 15:19:14 +05301970func (vs *VoltService) triggerServiceInProgressInd() {
1971}
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301972
vinokuma926cb3e2023-03-29 11:41:06 +05301973// JSONMarshal wrapper function for json Marshal VoltService
1974func (vs *VoltService) JSONMarshal() ([]byte, error) {
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301975 return json.Marshal(VoltService{
1976 VoltServiceCfg: vs.VoltServiceCfg,
1977 VoltServiceOper: VoltServiceOper{
Hitesh Chhabra64be2442023-06-21 17:06:34 +05301978 Device: vs.VoltServiceOper.Device,
1979 Ipv4Addr: vs.VoltServiceOper.Ipv4Addr,
1980 Ipv6Addr: vs.VoltServiceOper.Ipv6Addr,
1981 UsMeterID: vs.VoltServiceOper.UsMeterID,
1982 DsMeterID: vs.VoltServiceOper.DsMeterID,
1983 AggDsMeterID: vs.VoltServiceOper.AggDsMeterID,
1984 UsHSIAFlowsApplied: vs.VoltServiceOper.UsHSIAFlowsApplied,
1985 DsHSIAFlowsApplied: vs.VoltServiceOper.DsHSIAFlowsApplied,
1986 UsDhcpFlowsApplied: vs.VoltServiceOper.UsDhcpFlowsApplied,
1987 DsDhcpFlowsApplied: vs.VoltServiceOper.DsDhcpFlowsApplied,
1988 IgmpFlowsApplied: vs.VoltServiceOper.IgmpFlowsApplied,
1989 Icmpv6FlowsApplied: vs.VoltServiceOper.Icmpv6FlowsApplied,
1990 PendingFlows: vs.VoltServiceOper.PendingFlows,
1991 AssociatedFlows: vs.VoltServiceOper.AssociatedFlows,
1992 DeleteInProgress: vs.VoltServiceOper.DeleteInProgress,
1993 DeactivateInProgress: vs.VoltServiceOper.DeactivateInProgress,
1994 ForceDelete: vs.VoltServiceOper.ForceDelete,
1995 BwAvailInfo: vs.VoltServiceOper.BwAvailInfo,
1996 UpdateInProgress: vs.VoltServiceOper.UpdateInProgress,
1997 Metadata: vs.VoltServiceOper.Metadata,
Tinoj Josephc2ccd6b2022-07-19 04:32:15 +05301998 },
1999 })
2000}
Tinoj Josephec742f62022-09-29 19:11:10 +05302001
2002// GetProgrammedSubscribers to get list of programmed subscribers
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302003func (va *VoltApplication) GetProgrammedSubscribers(cntx context.Context, deviceID, portNo string) ([]*VoltService, error) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302004 var svcList []*VoltService
2005 logger.Infow(ctx, "GetProgrammedSubscribers Request ", log.Fields{"Device": deviceID, "Port": portNo})
2006 va.ServiceByName.Range(func(key, value interface{}) bool {
2007 vs := value.(*VoltService)
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302008 if len(deviceID) > 0 {
2009 if len(portNo) > 0 {
Tinoj Josephec742f62022-09-29 19:11:10 +05302010 if deviceID == vs.Device && portNo == vs.Port {
2011 svcList = append(svcList, vs)
2012 }
2013 } else {
2014 if deviceID == vs.Device {
2015 svcList = append(svcList, vs)
2016 }
2017 }
2018 } else {
2019 svcList = append(svcList, vs)
2020 }
2021 return true
2022 })
2023 return svcList, nil
2024}
2025
2026// ActivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302027func (va *VoltApplication) ActivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302028 logger.Infow(ctx, "Service Activate Request ", log.Fields{"Device": deviceID, "Port": portNo})
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302029 device, err := va.GetDeviceFromPort(portNo)
2030 if err != nil {
2031 logger.Errorw(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2032 return errorCodes.ErrPortNotFound
2033 }
2034 // If device id is not provided check only port number
2035 if deviceID == DeviceAny {
2036 deviceID = device.Name
2037 } else if deviceID != device.Name {
2038 logger.Errorw(ctx, "Wrong Device ID", log.Fields{"Device": deviceID, "Port": portNo})
2039 return errorCodes.ErrDeviceNotFound
2040 }
Tinoj Josephec742f62022-09-29 19:11:10 +05302041 va.ServiceByName.Range(func(key, value interface{}) bool {
2042 vs := value.(*VoltService)
Tinoj Josephec742f62022-09-29 19:11:10 +05302043 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302044 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
Tinoj Joseph50d722c2022-12-06 22:53:22 +05302045 logger.Infow(ctx, "Service Activate Request Does not match", log.Fields{"Device": deviceID, "voltService": vs})
Tinoj Josephec742f62022-09-29 19:11:10 +05302046 return true
2047 }
2048 if portNo == vs.Port && !vs.IsActivated {
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302049 p := device.GetPort(vs.Port)
Tinoj Josephec742f62022-09-29 19:11:10 +05302050 if p == nil {
2051 logger.Warnw(ctx, "Wrong device or port", log.Fields{"Device": deviceID, "Port": portNo})
2052 return true
2053 }
2054 logger.Infow(ctx, "Service Activate", log.Fields{"Name": vs.Name})
2055 vs.IsActivated = true
2056 va.ServiceByName.Store(vs.Name, vs)
2057 vs.WriteToDb(cntx)
2058 // If port is already up send indication to vpv
2059 if p.State == PortStateUp {
2060 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2061 // PortUp call initiates flow addition
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302062 vpv.PortUpInd(cntx, device, portNo)
Tinoj Josephec742f62022-09-29 19:11:10 +05302063 } else {
2064 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2065 }
2066 }
2067 }
2068 return true
2069 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302070 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302071}
2072
2073// DeactivateService to activate pre-provisioned service
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302074func (va *VoltApplication) DeactivateService(cntx context.Context, deviceID, portNo string, sVlan, cVlan of.VlanType, tpID uint16) error {
Tinoj Josephec742f62022-09-29 19:11:10 +05302075 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2076 va.ServiceByName.Range(func(key, value interface{}) bool {
2077 vs := value.(*VoltService)
2078 // If svlan if provided, then the tags and tpID of service has to be matching
Tinoj Josephd5b4f2f2022-11-11 19:25:24 +05302079 logger.Infow(ctx, "Service Deactivate Request ", log.Fields{"Device": deviceID, "Port": portNo})
2080 if sVlan != of.VlanNone && (sVlan != vs.SVlan || cVlan != vs.CVlan || tpID != vs.TechProfileID) {
vinokuma926cb3e2023-03-29 11:41:06 +05302081 logger.Infow(ctx, "condition not matched", log.Fields{"Device": deviceID, "Port": portNo, "sVlan": sVlan, "cVlan": cVlan, "tpID": tpID})
Tinoj Josephec742f62022-09-29 19:11:10 +05302082 return true
2083 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302084 if portNo == vs.Port && vs.IsActivated {
Tinoj Josephec742f62022-09-29 19:11:10 +05302085 vs.IsActivated = false
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302086 vs.DeactivateInProgress = true
Tinoj Josephec742f62022-09-29 19:11:10 +05302087 va.ServiceByName.Store(vs.Name, vs)
2088 vs.WriteToDb(cntx)
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302089 device, err := va.GetDeviceFromPort(portNo)
2090 if err != nil {
2091 // Even if the port/device does not exists at this point in time, the deactivate request is succss.
2092 // So no error is returned
2093 logger.Infow(ctx, "Error Getting Device", log.Fields{"Reason": err.Error(), "Port": portNo})
2094 return true
2095 }
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302096 p := device.GetPort(vs.Port)
vinokuma926cb3e2023-03-29 11:41:06 +05302097 if p != nil && (p.State == PortStateUp || !va.OltFlowServiceConfig.RemoveFlowsOnDisable) {
Tinoj Josephec742f62022-09-29 19:11:10 +05302098 if vpv := va.GetVnetByPort(vs.Port, vs.SVlan, vs.CVlan, vs.UniVlan); vpv != nil {
2099 // Port down call internally deletes all the flows
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302100 vpv.PortDownInd(cntx, deviceID, portNo, true)
Tinoj Josephec742f62022-09-29 19:11:10 +05302101 if vpv.IgmpEnabled {
2102 va.ReceiverDownInd(cntx, deviceID, portNo)
2103 }
Hitesh Chhabra64be2442023-06-21 17:06:34 +05302104 vs.DeactivateInProgress = false
Tinoj Josephec742f62022-09-29 19:11:10 +05302105 } else {
2106 logger.Warnw(ctx, "VPV does not exists!!!", log.Fields{"Device": deviceID, "port": portNo, "SvcName": vs.Name})
2107 }
2108 }
2109 }
2110 return true
2111 })
Tinoj Josephaf37ce82022-12-28 11:59:43 +05302112 return nil
Tinoj Josephec742f62022-09-29 19:11:10 +05302113}
Tinoj Joseph4ead4e02023-01-30 03:12:44 +05302114
vinokuma926cb3e2023-03-29 11:41:06 +05302115// GetServicePbit to get first set bit in the pbit map
2116// returns -1 : If configured to match on all pbits
2117// returns 8 : If no pbits are configured
2118// returns first pbit if specific pbit is configured
Tinoj Josephec742f62022-09-29 19:11:10 +05302119func (vs *VoltService) GetServicePbit() int {
2120 if vs.IsPbitExist(of.PbitMatchAll) {
2121 return -1
2122 }
vinokuma926cb3e2023-03-29 11:41:06 +05302123 for pbit := 0; pbit < int(of.PbitMatchNone); pbit++ {
Tinoj Josephec742f62022-09-29 19:11:10 +05302124 if vs.IsPbitExist(of.PbitType(pbit)) {
2125 return pbit
2126 }
2127 }
2128 return int(of.PbitMatchNone)
2129}